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

Explicit initialisation of Node-API addons #44853

Closed
cosinusoidally opened this issue Oct 1, 2022 · 3 comments
Closed

Explicit initialisation of Node-API addons #44853

cosinusoidally opened this issue Oct 1, 2022 · 3 comments
Labels
feature request Issues that request new features to be added to Node.js.

Comments

@cosinusoidally
Copy link

cosinusoidally commented Oct 1, 2022

What is the problem this feature will solve?

I have been trying to build a Node-API module using the Tiny C Compiler (https://bellard.org/tcc/) . I've managed to do it (with a couple of work arounds) but I ran into some issues around the use of __attribute__((constructor)) . Is there a reason this particular API design was chosen? Could an explicitly known init function be called if a module failed to self register?

tcc has a couple of issues around the use of __attribute__((constructor)):

  1. support was not added until late 2019. Not an issue now, but easy to get caught out if you use the most recent "official" release of tcc from late 2017.
  2. including glibc headers (like string.h) will strip out all uses of __attribute__((constructor)) by tcc. I think this is a bug in the glibc headers, see https://lists.nongnu.org/archive/html/tinycc-devel/2022-10/msg00000.html

To work around this I used a newer version of tcc, and also had to expand out the NAPI_MODULE macro and move the _register_... declaration to the top of my source file: https://github.com/cosinusoidally/mishmashvm/blob/dev/tests/nodejs/stub.c (build script is https://github.com/cosinusoidally/mishmashvm/blob/dev/tests/nodejs/mk)

Having an explicit init function could also be useful for compilers for other languages that potentially do not have support for constructors in shared libraries.

What is the feature you are proposing to solve the problem?

The ability to define an explicit init funtion to avoid the use of __attribute__((constructor)) .

What alternatives have you considered?

No response

@cosinusoidally cosinusoidally added the feature request Issues that request new features to be added to Node.js. label Oct 1, 2022
@bnoordhuis
Copy link
Member

You can export a function called napi_register_module_v1 with a function prototype of napi_value (*)(napi_env, napi_value). The second argument is the exports object.

There's also node_register_module_vXX for "native" (non n-api) add-ons, see #18934 for an example.

including glibc headers (like string.h) will strip out all uses of attribute((constructor)) by tcc.

Are you including tcc.h? It contains an #undef __attribute__.

@cosinusoidally
Copy link
Author

You can export a function called napi_register_module_v1 with a function prototype of napi_value (*)(napi_env, napi_value). The second argument is the exports object.

There's also node_register_module_vXX for "native" (non n-api) add-ons, see #18934 for an example.

Ah, I see NAPI_MODULE_INIT in the docs now, thanks (which seems to boil down to napi_register_module_v1). I am using the node.js v8.x node_api headers, which doesn't seem to have that macro. I needed to be able to use the official linux x86 nodejs binaries so I was using older headers. The following works for me (win32/linux x86) for >= v12.x (I assume v10.x will also work, but I didn't check):

__declspec(dllexport) napi_value napi_register_module_v1(napi_env env, napi_value exports) {
  napi_property_descriptor desc[2] = {
    DECLARE_NAPI_PROPERTY("RunCallback", RunCallback),
  };
  NAPI_CALL(env, napi_define_properties(env, exports, 1, desc));
  return exports;
}

For linux I just removed the __declspec(dllexport) . I'll probably stick to NAPI_MODULE for now and maybe move to NAPI_MODULE_INIT if/when I'm ready to bump my lowest supported version of nodejs.

including glibc headers (like string.h) will strip out all uses of attribute((constructor)) by tcc.

Are you including tcc.h? It contains an #undef __attribute__.

Nope I think the culprit is sys/cdefs.h (see tcc mailing list thread)

$ tcc -vv -I ../include/node/ -c ../stub.c
tcc version 0.9.27 (i386 Linux)
-> ../stub.c
->  ../common.h
->   ../include/node//node_api.h
->    /tmp/tcc-cross/lib/tcc/include/stddef.h
->    /tmp/tcc-cross/lib/tcc/include/stdbool.h
->    ../include/node//node_api_types.h
->     /tmp/tcc-cross/lib/tcc/include/stddef.h
->     /usr/include/stdint.h
->      /usr/include/i386-linux-gnu/bits/libc-header-start.h
->       /usr/include/features.h
->        /usr/include/stdc-predef.h
->        /usr/include/i386-linux-gnu/sys/cdefs.h
->         /usr/include/i386-linux-gnu/bits/wordsize.h
->         /usr/include/i386-linux-gnu/bits/long-double.h
->        /usr/include/i386-linux-gnu/gnu/stubs.h
->         /usr/include/i386-linux-gnu/gnu/stubs-32.h
->      /usr/include/i386-linux-gnu/bits/types.h
->       /usr/include/i386-linux-gnu/bits/wordsize.h
->       /usr/include/i386-linux-gnu/bits/typesizes.h
->      /usr/include/i386-linux-gnu/bits/wchar.h
->      /usr/include/i386-linux-gnu/bits/wordsize.h
->      /usr/include/i386-linux-gnu/bits/stdint-intn.h
->      /usr/include/i386-linux-gnu/bits/stdint-uintn.h
->  ../binding.h
->  /usr/include/string.h
->   /usr/include/i386-linux-gnu/bits/libc-header-start.h
->   /tmp/tcc-cross/lib/tcc/include/stddef.h
->   /usr/include/i386-linux-gnu/bits/types/locale_t.h
->    /usr/include/i386-linux-gnu/bits/types/__locale_t.h
->   /usr/include/strings.h
->    /tmp/tcc-cross/lib/tcc/include/stddef.h
<- stub.o

Thanks for your help, you can close off this ticket if you want.

@bnoordhuis
Copy link
Member

Glad to hear you found a working solution. Closing then.

@bnoordhuis bnoordhuis closed this as not planned Won't fix, can't repro, duplicate, stale Oct 5, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature request Issues that request new features to be added to Node.js.
Projects
None yet
Development

No branches or pull requests

2 participants