Skip to content

Commit 4fae6e3

Browse files
bnoordhuisMylesBorins
authored andcommitted
src: make process.dlopen() load well-known symbol
Look for symbol `node_register_module_v${NODE_MODULE_VERSION}` if the add-on didn't self-register. This can be used to create add-ons that support multiple Node.js versions from a single shared object. PR-URL: #18934 Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Daniel Bevenius <[email protected]> Reviewed-By: Franziska Hinkelmann <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Joyee Cheung <[email protected]> Reviewed-By: Matheus Marchini <[email protected]> Reviewed-By: Tobias Nießen <[email protected]>
1 parent 89edbae commit 4fae6e3

File tree

3 files changed

+37
-5
lines changed

3 files changed

+37
-5
lines changed

src/node.cc

+27-2
Original file line numberDiff line numberDiff line change
@@ -2483,6 +2483,7 @@ struct DLib {
24832483

24842484
inline bool Open();
24852485
inline void Close();
2486+
inline void* GetSymbolAddress(const char* name);
24862487

24872488
const std::string filename_;
24882489
const int flags_;
@@ -2510,6 +2511,10 @@ void DLib::Close() {
25102511
dlclose(handle_);
25112512
handle_ = nullptr;
25122513
}
2514+
2515+
void* DLib::GetSymbolAddress(const char* name) {
2516+
return dlsym(handle_, name);
2517+
}
25132518
#else // !__POSIX__
25142519
bool DLib::Open() {
25152520
int ret = uv_dlopen(filename_.c_str(), &lib_);
@@ -2527,8 +2532,23 @@ void DLib::Close() {
25272532
uv_dlclose(&lib_);
25282533
handle_ = nullptr;
25292534
}
2535+
2536+
void* DLib::GetSymbolAddress(const char* name) {
2537+
void* address;
2538+
if (0 == uv_dlsym(&lib_, name, &address)) return address;
2539+
return nullptr;
2540+
}
25302541
#endif // !__POSIX__
25312542

2543+
using InitializerCallback = void (*)(Local<Object> exports,
2544+
Local<Value> module,
2545+
Local<Context> context);
2546+
2547+
inline InitializerCallback GetInitializerCallback(DLib* dlib) {
2548+
const char* name = "node_register_module_v" STRINGIFY(NODE_MODULE_VERSION);
2549+
return reinterpret_cast<InitializerCallback>(dlib->GetSymbolAddress(name));
2550+
}
2551+
25322552
// DLOpen is process.dlopen(module, filename, flags).
25332553
// Used to load 'module.node' dynamically shared objects.
25342554
//
@@ -2583,10 +2603,15 @@ static void DLOpen(const FunctionCallbackInfo<Value>& args) {
25832603
}
25842604

25852605
if (mp == nullptr) {
2586-
dlib.Close();
2587-
env->ThrowError("Module did not self-register.");
2606+
if (auto callback = GetInitializerCallback(&dlib)) {
2607+
callback(exports, module, context);
2608+
} else {
2609+
dlib.Close();
2610+
env->ThrowError("Module did not self-register.");
2611+
}
25882612
return;
25892613
}
2614+
25902615
if (mp->nm_version == -1) {
25912616
if (env->EmitNapiWarning()) {
25922617
if (ProcessEmitWarning(env, "N-API is an experimental feature and could "

src/node.h

+3
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,9 @@ extern "C" NODE_EXTERN void node_module_register(void* mod);
532532
} \
533533
}
534534

535+
// Usage: `NODE_MODULE(NODE_GYP_MODULE_NAME, InitializerFunction)`
536+
// If no NODE_MODULE is declared, Node.js looks for the well-known
537+
// symbol `node_register_module_v${NODE_MODULE_VERSION}`.
535538
#define NODE_MODULE(modname, regfunc) \
536539
NODE_MODULE_X(modname, regfunc, NULL, 0) // NOLINT (readability/null_usage)
537540

test/addons/hello-world/binding.cc

+7-3
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,12 @@ void Method(const v8::FunctionCallbackInfo<v8::Value>& args) {
66
args.GetReturnValue().Set(v8::String::NewFromUtf8(isolate, "world"));
77
}
88

9-
void init(v8::Local<v8::Object> exports) {
9+
#define CONCAT(a, b) CONCAT_HELPER(a, b)
10+
#define CONCAT_HELPER(a, b) a##b
11+
#define INITIALIZER CONCAT(node_register_module_v, NODE_MODULE_VERSION)
12+
13+
extern "C" NODE_MODULE_EXPORT void INITIALIZER(v8::Local<v8::Object> exports,
14+
v8::Local<v8::Value> module,
15+
v8::Local<v8::Context> context) {
1016
NODE_SET_METHOD(exports, "hello", Method);
1117
}
12-
13-
NODE_MODULE(NODE_GYP_MODULE_NAME, init)

0 commit comments

Comments
 (0)