diff options
author | Gabriel Schulhof <gabriel.schulhof@intel.com> | 2021-02-03 10:07:34 +0300 |
---|---|---|
committer | Gabriel Schulhof <gabriel.schulhof@intel.com> | 2021-02-10 10:34:30 +0300 |
commit | ad3ebed046ef457530b046f2a62313a7e16b7e29 (patch) | |
tree | 26a3e1308a5989eeb4c64dba0ffc99ece41ea784 /src/node_api.cc | |
parent | 79d44baae28d64e0a0ee1765df3eb637e429e7a6 (diff) |
node-api: allow retrieval of add-on file name
Unlike JS-only modules, native add-ons are always associated with a
dynamic shared object from which they are loaded. Being able to
retrieve its absolute path is important to native-only add-ons, i.e.
add-ons that are not themselves being loaded from a JS-only module
located in the same package as the native add-on itself.
Currently, the file name is obtained at environment construction time
from the JS `module.filename`. Nevertheless, the presence of `module`
is not required, because the file name could also be passed in via a
private property added onto `exports` from the `process.dlopen`
binding.
As an attempt at future-proofing, the file name is provided as a URL,
i.e. prefixed with the `file://` protocol.
Fixes: https://github.com/nodejs/node-addon-api/issues/449
PR-URL: https://github.com/nodejs/node/pull/37195
Co-authored-by: Michael Dawson <mdawson@devrus.com>
Reviewed-By: Michael Dawson <midawson@redhat.com>
Diffstat (limited to 'src/node_api.cc')
-rw-r--r-- | src/node_api.cc | 45 |
1 files changed, 39 insertions, 6 deletions
diff --git a/src/node_api.cc b/src/node_api.cc index f1a5265b6a7..8dbf48d466d 100644 --- a/src/node_api.cc +++ b/src/node_api.cc @@ -15,8 +15,9 @@ #include <memory> struct node_napi_env__ : public napi_env__ { - explicit node_napi_env__(v8::Local<v8::Context> context): - napi_env__(context) { + explicit node_napi_env__(v8::Local<v8::Context> context, + const std::string& module_filename): + napi_env__(context), filename(module_filename) { CHECK_NOT_NULL(node_env()); } @@ -46,6 +47,10 @@ struct node_napi_env__ : public napi_env__ { }); }); } + + const char* GetFilename() const { return filename.c_str(); } + + std::string filename; }; typedef node_napi_env__* node_napi_env; @@ -87,10 +92,11 @@ class BufferFinalizer : private Finalizer { }; }; -static inline napi_env NewEnv(v8::Local<v8::Context> context) { +static inline napi_env +NewEnv(v8::Local<v8::Context> context, const std::string& module_filename) { node_napi_env result; - result = new node_napi_env__(context); + result = new node_napi_env__(context, module_filename); // TODO(addaleax): There was previously code that tried to delete the // napi_env when its v8::Context was garbage collected; // However, as long as N-API addons using this napi_env are in place, @@ -552,16 +558,35 @@ void napi_module_register_by_symbol(v8::Local<v8::Object> exports, v8::Local<v8::Value> module, v8::Local<v8::Context> context, napi_addon_register_func init) { + node::Environment* node_env = node::Environment::GetCurrent(context); + std::string module_filename = ""; if (init == nullptr) { - node::Environment* node_env = node::Environment::GetCurrent(context); CHECK_NOT_NULL(node_env); node_env->ThrowError( "Module has no declared entry point."); return; } + // We set `env->filename` from `module.filename` here, but we could just as + // easily add a private property to `exports` in `process.dlopen`, which + // receives the file name from JS, and retrieve *that* here. Thus, we are not + // endorsing commonjs here by making use of `module.filename`. + v8::Local<v8::Value> filename_js; + v8::Local<v8::Object> modobj; + if (module->ToObject(context).ToLocal(&modobj) && + modobj->Get(context, node_env->filename_string()).ToLocal(&filename_js) && + filename_js->IsString()) { + node::Utf8Value filename(node_env->isolate(), filename_js); // Cast + + // Turn the absolute path into a URL. Currently the absolute path is always + // a file system path. + // TODO(gabrielschulhof): Pass the `filename` through unchanged if/when we + // receive it as a URL already. + module_filename = std::string("file://") + (*filename); + } + // Create a new napi_env for this specific module. - napi_env env = v8impl::NewEnv(context); + napi_env env = v8impl::NewEnv(context, module_filename); napi_value _exports; env->CallIntoModule([&](napi_env env) { @@ -1257,3 +1282,11 @@ napi_ref_threadsafe_function(napi_env env, napi_threadsafe_function func) { CHECK_NOT_NULL(func); return reinterpret_cast<v8impl::ThreadSafeFunction*>(func)->Ref(); } + +napi_status node_api_get_module_file_name(napi_env env, const char** result) { + CHECK_ENV(env); + CHECK_ARG(env, result); + + *result = static_cast<node_napi_env>(env)->GetFilename(); + return napi_clear_last_error(env); +} |