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‎

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2483,6 +2483,7 @@ struct DLib{
24832483

24842484
inlineboolOpen();
24852485
inlinevoidClose();
2486+
inlinevoid* GetSymbolAddress(constchar* name);
24862487

24872488
const std::string filename_;
24882489
constint flags_;
@@ -2510,6 +2511,10 @@ void DLib::Close(){
25102511
dlclose(handle_);
25112512
handle_ = nullptr;
25122513
}
2514+
2515+
void* DLib::GetSymbolAddress(constchar* name){
2516+
returndlsym(handle_, name);
2517+
}
25132518
#else// !__POSIX__
25142519
boolDLib::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(constchar* name){
2537+
void* address;
2538+
if (0 == uv_dlsym(&lib_, name, &address)) return address;
2539+
returnnullptr;
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+
constchar* name = "node_register_module_v"STRINGIFY(NODE_MODULE_VERSION);
2549+
returnreinterpret_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‎

Lines changed: 3 additions & 0 deletions
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
#defineNODE_MODULE(modname, regfunc) \
536539
NODE_MODULE_X(modname, regfunc, NULL, 0) // NOLINT (readability/null_usage)
537540

‎test/addons/hello-world/binding.cc‎

Lines changed: 7 additions & 3 deletions
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-
voidinit(v8::Local<v8::Object> exports){
9+
#defineCONCAT(a, b) CONCAT_HELPER(a, b)
10+
#defineCONCAT_HELPER(a, b) a##b
11+
#defineINITIALIZERCONCAT(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)