Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

how does NODE_STATIC_LIBRARY work ? #9

Closed
tommyZZM opened this issue Oct 5, 2017 · 8 comments
Closed

how does NODE_STATIC_LIBRARY work ? #9

tommyZZM opened this issue Oct 5, 2017 · 8 comments
Labels

Comments

@tommyZZM
Copy link

tommyZZM commented Oct 5, 2017

  • Version: node-chakracore v8.4.0 / node-mobile v0.1.2
  • Platform: macOS 10.12.6
  • Subsystem:

how does NODE_STATIC_LIBRARY work in this commit?

7ee73e9 ios: Exports node.h symbols when building static

not found NODE_STATIC_LIBRARY definition searching in the remote

@jaimecbernardo
Copy link
Member

Hi @tommyZZM ,
That's a very good catch, that flag is currently not turned on. Thank you for that.

It was supposed to remove the static attribute so we assure the NODE_C_CTOR symbols were included in the final static library binaries, but they will be included anyway, due to having __attribute__((constructor)) added to the definition in:

https://github.com/janeasystems/nodejs-mobile/blob/c1c346086edb48d72ee255a3946c0959ef117d1a/src/node.h#L481

#define NODE_C_CTOR(fn)                                               \
  NODE_CTOR_PREFIX void fn(void) __attribute__((constructor));        \
  NODE_CTOR_PREFIX void fn(void)
#endif

The __atribute__((constructor)) will make it so the NODE_C_CTOR functions will run when the library/executable containing them is loaded at runtime.

Since you're trying to use static libraries in your build system, you need to make sure that:
1 - Your static libraries include those symbols.
2 - When you use your static libraries, the linker doesn't strip those symbols, since they will not be referenced anywhere, which I believe was your issue in JaneaSystems/node-mobile-react-demo#3

Hope this is helpful.

@tommyZZM
Copy link
Author

tommyZZM commented Oct 6, 2017

Hi @jaimecbernardo

Thankyou!

Following your tips i embed node.js as static library successfully already~.

Those __atribute__((constructor)) functions would not run automatily while node is compile as static library (at least in xcode9 llvm9.0).

Then, once those bulitin module functions was referenced in the main code, those functions will run automatily as usual. There are few points should be notice:

  1. export those register functions symbols without static (janeasystems/nodejs-mobile@7ee73e9) in node.h and define them in a custom header
  2. don't execute them! or modules would be duplicate register with node_module_register node.cc#L2573 ,then make process.binding('natives') bootstrap_node.js#L512 hangs with dead loop node.cc#L2593
  3. do something like assign those functions to a never used variable, so linker would recognize them, and default constructor will be called before main,

i use header file below to do so.

#ifndef ref_node_modules_builtin
#define ref_node_modules_builtin

#include <node.h>

extern "C" {
  void _register_async_wrap(void);
  void _register_cares_wrap(void);
  void _register_fs_event_wrap(void);
  void _register_js_stream(void);
  void _register_buffer(void);
  void _register_contextify(void);
  void _register_crypto(void);
  void _register_fs(void);
  void _register_http_parser(void);
  void _register_os(void);
  void _register_util(void);
  void _register_v8(void);
  void _register_zlib(void);
  void _register_pipe_wrap(void);
  void _register_process_wrap(void);
  void _register_signal_wrap(void);
  void _register_spawn_sync(void);
  void _register_stream_wrap(void);
  void _register_tcp_wrap(void);
  void _register_timer_wrap(void);
  void _register_tls_wrap(void);
  void _register_tty_wrap(void);
  void _register_udp_wrap(void);
  void _register_uv(void);
  void _register_config(void);
  void _register_url(void);
  void _register_module_wrap(void);
}

static void (*_place_holder_builtin_modules)();

void _ref_node_modules_builtin(void) __attribute__((constructor)) {
  // assign register functions in a never used variable
  // so thattell linker to recognize the default caller in libnode.a
  _place_holder_builtin_modules = _register_async_wrap;
  _place_holder_builtin_modules = _register_cares_wrap;
  _place_holder_builtin_modules = _register_fs_event_wrap;
  _place_holder_builtin_modules = _register_js_stream;
  _place_holder_builtin_modules = _register_contextify;
  _place_holder_builtin_modules = _register_crypto;
  _place_holder_builtin_modules = _register_fs;
  _place_holder_builtin_modules = _register_http_parser;
  _place_holder_builtin_modules = _register_os;
  _place_holder_builtin_modules = _register_util;
  _place_holder_builtin_modules = _register_v8;
  _place_holder_builtin_modules = _register_zlib;
  _place_holder_builtin_modules = _register_pipe_wrap;
  _place_holder_builtin_modules = _register_process_wrap;
  _place_holder_builtin_modules = _register_signal_wrap;
  _place_holder_builtin_modules = _register_spawn_sync;
  _place_holder_builtin_modules = _register_stream_wrap;
  _place_holder_builtin_modules = _register_tcp_wrap;
  _place_holder_builtin_modules = _register_timer_wrap;
  _place_holder_builtin_modules = _register_tls_wrap;
  _place_holder_builtin_modules = _register_tty_wrap;
  _place_holder_builtin_modules = _register_udp_wrap;
  _place_holder_builtin_modules = _register_uv;
  _place_holder_builtin_modules = _register_config;
  _place_holder_builtin_modules = _register_url;
  _place_holder_builtin_modules = _register_module_wrap;
}

#endif /* ref_node_modules_builtin */
#include <node.h>
#include "ref_node_modules_builtin.h"

int main(int argc, char *argv[]) {
    return node::Start(argc, argv);
}

@jaimecbernardo
Copy link
Member

Thanks @tommyZZM ,

Glad we could help. In our case, we build a shared library with those static libraries and instruct the linker to include all symbols. Your solution also helps the linker include those symbols in the final binary. Good job.

I'm closing this issue now, then :)

@tommyZZM
Copy link
Author

tommyZZM commented Oct 7, 2017

reference this nodejs pull request nodejs/node#14986.

@yhwang
Copy link

yhwang commented Oct 13, 2017

one question:
how about create an explicit function to do the module registration and remove the __attribute__((constructor))? Then we can fully control the node_module_register in normal executable, static lib and shared lib cases?

@jaimecbernardo
Copy link
Member

Hi @yhwang ,

Thanks for the question.

This way to register modules is the one that is used in nodejs/node and nodejs/node-chakracore, and is also used by native modules, since they are expecting to be registered when they are dynamically loaded. One of this project's goals is to diverge as little from the base Node.js projects.

If module registering changes in nodejs/node, we'll probably end up adopting it too. For the meanwhile, embedding Node.js as a static library seems like an advanced use case, having the same issues it has in the base projects, so our view is that it would require an upstream discussion and change first.

The supported and released binaries use case is to use nodejs-mobile as a shared library, which doesn't run into these issues. You can still use the project as a static library with @tommyZZM's workaround or by configuring your build environment so that the symbols aren't removed by the linker when you consume the libraries (this problem is caused by a common linker optimization of not including symbols that are not referenced by your code in the final binaries).

If you feel strongly about this change, I believe this would be a more useful discussion in nodejs/node, and would like to encourage you to discuss it there, since it seems to be a long standing architectural aspect of Node.JS .

Hope this was helpful.

@yhwang
Copy link

yhwang commented Oct 17, 2017

@jaimecbernardo thanks for the comments. I followed the link in nodejs to get here and I didn't notice that this is another repo. Sure, I will move the discussion back to nodejs and thanks for the sharing of shared/static lib usage.

@tommyZZM
Copy link
Author

reference nodejs/node-v0.x-archive#7336

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants