mirror of
https://github.com/denoland/deno.git
synced 2024-11-25 15:29:32 -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")]
|
#[cfg(target_os = "windows")]
|
||||||
println!(
|
{
|
||||||
"cargo:rustc-link-arg-bin=deno=/DEF:{}",
|
println!(
|
||||||
symbols_path.display()
|
"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")]
|
#[cfg(target_os = "macos")]
|
||||||
println!(
|
{
|
||||||
"cargo:rustc-link-arg-bin=deno=-Wl,-exported_symbols_list,{}",
|
println!(
|
||||||
symbols_path.display()
|
"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")]
|
#[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: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=deno=-rdynamic");
|
||||||
|
println!("cargo:rustc-link-arg-bin=denort=-rdynamic");
|
||||||
} else {
|
} else {
|
||||||
println!(
|
println!(
|
||||||
"cargo:rustc-link-arg-bin=deno=-Wl,--export-dynamic-symbol-list={}",
|
"cargo:rustc-link-arg-bin=deno=-Wl,--export-dynamic-symbol-list={}",
|
||||||
symbols_path.display()
|
symbols_path.display()
|
||||||
);
|
);
|
||||||
|
println!(
|
||||||
|
"cargo:rustc-link-arg-bin=denort=-Wl,--export-dynamic-symbol-list={}",
|
||||||
|
symbols_path.display()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
println!(
|
{
|
||||||
"cargo:rustc-link-arg-bin=deno=-Wl,--export-dynamic-symbol-list={}",
|
println!(
|
||||||
symbols_path.display()
|
"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:
|
// To debug snapshot issues uncomment:
|
||||||
// op_fetch_asset::trace_serializer();
|
// op_fetch_asset::trace_serializer();
|
||||||
|
|
|
@ -15,6 +15,7 @@ mod errors;
|
||||||
mod file_fetcher;
|
mod file_fetcher;
|
||||||
mod http_util;
|
mod http_util;
|
||||||
mod js;
|
mod js;
|
||||||
|
mod napi;
|
||||||
mod node;
|
mod node;
|
||||||
mod npm;
|
mod npm;
|
||||||
mod resolver;
|
mod resolver;
|
||||||
|
|
|
@ -1283,3 +1283,66 @@ fn standalone_jsr_dynamic_import() {
|
||||||
output.assert_exit_code(0);
|
output.assert_exit_code(0);
|
||||||
output.assert_matches_text("Hello world\n");
|
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