mirror of
https://github.com/denoland/deno.git
synced 2024-11-24 15:19:26 -05:00
fix(cli): add NAPI support in standalone mode (#24642)
Currently, importing Node-Addons modules in a standalone binary results in a `missing symbol called` error (https://github.com/denoland/deno/issues/24614). Because the NAPI symbols are not exported in this mode. This PR should fix the issue.
This commit is contained in:
parent
bb1c6c49bb
commit
4e8f5875bc
5 changed files with 174 additions and 12 deletions
47
cli/build.rs
47
cli/build.rs
|
@ -404,16 +404,28 @@ fn main() {
|
|||
);
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
println!(
|
||||
"cargo:rustc-link-arg-bin=deno=/DEF:{}",
|
||||
symbols_path.display()
|
||||
);
|
||||
{
|
||||
println!(
|
||||
"cargo:rustc-link-arg-bin=deno=/DEF:{}",
|
||||
symbols_path.display()
|
||||
);
|
||||
println!(
|
||||
"cargo:rustc-link-arg-bin=denort=/DEF:{}",
|
||||
symbols_path.display()
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
println!(
|
||||
"cargo:rustc-link-arg-bin=deno=-Wl,-exported_symbols_list,{}",
|
||||
symbols_path.display()
|
||||
);
|
||||
{
|
||||
println!(
|
||||
"cargo:rustc-link-arg-bin=deno=-Wl,-exported_symbols_list,{}",
|
||||
symbols_path.display()
|
||||
);
|
||||
println!(
|
||||
"cargo:rustc-link-arg-bin=denort=-Wl,-exported_symbols_list,{}",
|
||||
symbols_path.display()
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
|
@ -426,19 +438,30 @@ fn main() {
|
|||
{
|
||||
println!("cargo:warning=Compiling with all symbols exported, this will result in a larger binary. Please use glibc 2.35 or later for an optimised build.");
|
||||
println!("cargo:rustc-link-arg-bin=deno=-rdynamic");
|
||||
println!("cargo:rustc-link-arg-bin=denort=-rdynamic");
|
||||
} else {
|
||||
println!(
|
||||
"cargo:rustc-link-arg-bin=deno=-Wl,--export-dynamic-symbol-list={}",
|
||||
symbols_path.display()
|
||||
);
|
||||
println!(
|
||||
"cargo:rustc-link-arg-bin=denort=-Wl,--export-dynamic-symbol-list={}",
|
||||
symbols_path.display()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
println!(
|
||||
"cargo:rustc-link-arg-bin=deno=-Wl,--export-dynamic-symbol-list={}",
|
||||
symbols_path.display()
|
||||
);
|
||||
{
|
||||
println!(
|
||||
"cargo:rustc-link-arg-bin=deno=-Wl,--export-dynamic-symbol-list={}",
|
||||
symbols_path.display()
|
||||
);
|
||||
println!(
|
||||
"cargo:rustc-link-arg-bin=denort=-Wl,--export-dynamic-symbol-list={}",
|
||||
symbols_path.display()
|
||||
);
|
||||
}
|
||||
|
||||
// To debug snapshot issues uncomment:
|
||||
// op_fetch_asset::trace_serializer();
|
||||
|
|
|
@ -15,6 +15,7 @@ mod errors;
|
|||
mod file_fetcher;
|
||||
mod http_util;
|
||||
mod js;
|
||||
mod napi;
|
||||
mod node;
|
||||
mod npm;
|
||||
mod resolver;
|
||||
|
|
|
@ -1283,3 +1283,66 @@ fn standalone_jsr_dynamic_import() {
|
|||
output.assert_exit_code(0);
|
||||
output.assert_matches_text("Hello world\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn standalone_require_node_addons() {
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
{
|
||||
let context = TestContextBuilder::for_jsr().build();
|
||||
let dir = context.temp_dir();
|
||||
let libout = dir.path().join("module.node");
|
||||
|
||||
let cc = context
|
||||
.new_command()
|
||||
.name("cc")
|
||||
.current_dir(util::testdata_path());
|
||||
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
let c_module = cc
|
||||
.arg("./compile/napi/module.c")
|
||||
.arg("-shared")
|
||||
.arg("-o")
|
||||
.arg(&libout);
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
let c_module = {
|
||||
cc.arg("./compile/napi/module.c")
|
||||
.arg("-undefined")
|
||||
.arg("dynamic_lookup")
|
||||
.arg("-shared")
|
||||
.arg("-Wl,-no_fixup_chains")
|
||||
.arg("-dynamic")
|
||||
.arg("-o")
|
||||
.arg(&libout)
|
||||
};
|
||||
let c_module_output = c_module.output().unwrap();
|
||||
|
||||
assert!(c_module_output.status.success());
|
||||
|
||||
let exe = if cfg!(windows) {
|
||||
dir.path().join("main.exe")
|
||||
} else {
|
||||
dir.path().join("main")
|
||||
};
|
||||
|
||||
context
|
||||
.new_command()
|
||||
.env("NPM_CONFIG_REGISTRY", "https://registry.npmjs.org/")
|
||||
.args_vec([
|
||||
"compile",
|
||||
"--allow-read",
|
||||
"--allow-ffi",
|
||||
"--output",
|
||||
&exe.to_string_lossy(),
|
||||
"./compile/napi/main.ts",
|
||||
])
|
||||
.run()
|
||||
.skip_output_check()
|
||||
.assert_exit_code(0);
|
||||
|
||||
let output = context.new_command().name(&exe).arg(&libout).run();
|
||||
|
||||
output.assert_exit_code(0);
|
||||
output.assert_matches_text("{}\n");
|
||||
}
|
||||
}
|
||||
|
|
7
tests/testdata/compile/napi/main.ts
vendored
Normal file
7
tests/testdata/compile/napi/main.ts
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
import Module from "node:module";
|
||||
|
||||
const mod = new Module("");
|
||||
|
||||
const filepath = Deno.args[0];
|
||||
|
||||
console.log(mod.require(filepath));
|
68
tests/testdata/compile/napi/module.c
vendored
Normal file
68
tests/testdata/compile/napi/module.c
vendored
Normal file
|
@ -0,0 +1,68 @@
|
|||
typedef struct napi_module {
|
||||
int nm_version;
|
||||
unsigned int nm_flags;
|
||||
const char* nm_filename;
|
||||
void* nm_register_func;
|
||||
const char* nm_modname;
|
||||
void* nm_priv;
|
||||
void* reserved[4];
|
||||
} napi_module;
|
||||
|
||||
#ifdef _WIN32
|
||||
#define NAPI_EXTERN __declspec(dllexport)
|
||||
#define NAPI_CDECL __cdecl
|
||||
#else
|
||||
#define NAPI_EXTERN __attribute__((visibility("default")))
|
||||
#define NAPI_CDECL
|
||||
#endif
|
||||
|
||||
NAPI_EXTERN void NAPI_CDECL
|
||||
napi_module_register(napi_module* mod);
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#if defined(__cplusplus)
|
||||
#define NAPI_C_CTOR(fn) \
|
||||
static void NAPI_CDECL fn(void); \
|
||||
namespace { \
|
||||
struct fn##_ { \
|
||||
fn##_() { fn(); } \
|
||||
} fn##_v_; \
|
||||
} \
|
||||
static void NAPI_CDECL fn(void)
|
||||
#else // !defined(__cplusplus)
|
||||
#pragma section(".CRT$XCU", read)
|
||||
// The NAPI_C_CTOR macro defines a function fn that is called during CRT
|
||||
// initialization.
|
||||
// C does not support dynamic initialization of static variables and this code
|
||||
// simulates C++ behavior. Exporting the function pointer prevents it from being
|
||||
// optimized. See for details:
|
||||
// https://docs.microsoft.com/en-us/cpp/c-runtime-library/crt-initialization?view=msvc-170
|
||||
#define NAPI_C_CTOR(fn) \
|
||||
static void NAPI_CDECL fn(void); \
|
||||
__declspec(dllexport, allocate(".CRT$XCU")) void(NAPI_CDECL * fn##_)(void) = \
|
||||
fn; \
|
||||
static void NAPI_CDECL fn(void)
|
||||
#endif // defined(__cplusplus)
|
||||
#else
|
||||
#define NAPI_C_CTOR(fn) \
|
||||
static void fn(void) __attribute__((constructor)); \
|
||||
static void fn(void)
|
||||
#endif
|
||||
|
||||
#define NAPI_MODULE_TEST(modname, regfunc) \
|
||||
static napi_module _module = { \
|
||||
1, \
|
||||
0, \
|
||||
__FILE__, \
|
||||
regfunc, \
|
||||
#modname, \
|
||||
0, \
|
||||
{0}, \
|
||||
}; \
|
||||
NAPI_C_CTOR(_register_##modname) { napi_module_register(&_module); } \
|
||||
|
||||
void* init(void* env __attribute__((unused)), void* exports) {
|
||||
return exports;
|
||||
}
|
||||
|
||||
NAPI_MODULE_TEST(TEST_NAPI_MODULE_NAME, init)
|
Loading…
Reference in a new issue