Skip to content

Commit 0cddeb3

Browse files
bnoordhuisMayaLekova
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: nodejs#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 0bcdcba commit 0cddeb3

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
@@ -2158,6 +2158,7 @@ struct DLib {
21582158

21592159
inline bool Open();
21602160
inline void Close();
2161+
inline void* GetSymbolAddress(const char* name);
21612162

21622163
const std::string filename_;
21632164
const int flags_;
@@ -2185,6 +2186,10 @@ void DLib::Close() {
21852186
dlclose(handle_);
21862187
handle_ = nullptr;
21872188
}
2189+
2190+
void* DLib::GetSymbolAddress(const char* name) {
2191+
return dlsym(handle_, name);
2192+
}
21882193
#else // !__POSIX__
21892194
bool DLib::Open() {
21902195
int ret = uv_dlopen(filename_.c_str(), &lib_);
@@ -2202,8 +2207,23 @@ void DLib::Close() {
22022207
uv_dlclose(&lib_);
22032208
handle_ = nullptr;
22042209
}
2210+
2211+
void* DLib::GetSymbolAddress(const char* name) {
2212+
void* address;
2213+
if (0 == uv_dlsym(&lib_, name, &address)) return address;
2214+
return nullptr;
2215+
}
22052216
#endif // !__POSIX__
22062217

2218+
using InitializerCallback = void (*)(Local<Object> exports,
2219+
Local<Value> module,
2220+
Local<Context> context);
2221+
2222+
inline InitializerCallback GetInitializerCallback(DLib* dlib) {
2223+
const char* name = "node_register_module_v" STRINGIFY(NODE_MODULE_VERSION);
2224+
return reinterpret_cast<InitializerCallback>(dlib->GetSymbolAddress(name));
2225+
}
2226+
22072227
// DLOpen is process.dlopen(module, filename, flags).
22082228
// Used to load 'module.node' dynamically shared objects.
22092229
//
@@ -2258,10 +2278,15 @@ static void DLOpen(const FunctionCallbackInfo<Value>& args) {
22582278
}
22592279

22602280
if (mp == nullptr) {
2261-
dlib.Close();
2262-
env->ThrowError("Module did not self-register.");
2281+
if (auto callback = GetInitializerCallback(&dlib)) {
2282+
callback(exports, module, context);
2283+
} else {
2284+
dlib.Close();
2285+
env->ThrowError("Module did not self-register.");
2286+
}
22632287
return;
22642288
}
2289+
22652290
if (mp->nm_version == -1) {
22662291
if (env->EmitNapiWarning()) {
22672292
if (ProcessEmitWarning(env, "N-API is an experimental feature and could "

src/node.h

+3
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,9 @@ extern "C" NODE_EXTERN void node_module_register(void* mod);
535535
} \
536536
}
537537

538+
// Usage: `NODE_MODULE(NODE_GYP_MODULE_NAME, InitializerFunction)`
539+
// If no NODE_MODULE is declared, Node.js looks for the well-known
540+
// symbol `node_register_module_v${NODE_MODULE_VERSION}`.
538541
#define NODE_MODULE(modname, regfunc) \
539542
NODE_MODULE_X(modname, regfunc, NULL, 0) // NOLINT (readability/null_usage)
540543

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)