feat(napi-sys): support load Node-API symbols dynamically (#2014)
This commit is contained in:
parent
0550c56fcf
commit
f2e5094345
8 changed files with 74 additions and 68 deletions
2
.github/workflows/test-release.yaml
vendored
2
.github/workflows/test-release.yaml
vendored
|
@ -548,7 +548,7 @@ jobs:
|
|||
- name: Build
|
||||
run: |
|
||||
bun run build
|
||||
bun run build:test
|
||||
yarn workspace @examples/napi build --features dyn-symbols
|
||||
- name: Test
|
||||
continue-on-error: true
|
||||
run: bun run test:bun
|
||||
|
|
|
@ -55,6 +55,7 @@ tokio_stats = ["tokio/stats"]
|
|||
tokio_sync = ["tokio/sync"]
|
||||
tokio_test_util = ["tokio/test-util"]
|
||||
tokio_time = ["tokio/time"]
|
||||
dyn-symbols = ["napi-sys/dyn-symbols"]
|
||||
|
||||
[dependencies]
|
||||
bitflags = "2"
|
||||
|
|
|
@ -243,7 +243,7 @@ pub fn get_c_callback(raw_fn: ExportRegisterCallback) -> Result<crate::Callback>
|
|||
})
|
||||
}
|
||||
|
||||
#[cfg(all(windows, not(feature = "noop")))]
|
||||
#[cfg(all(any(windows, feature = "dyn-symbols"), not(feature = "noop")))]
|
||||
#[ctor::ctor]
|
||||
fn load_host() {
|
||||
unsafe {
|
||||
|
|
|
@ -12,6 +12,7 @@ rust-version = "1.65"
|
|||
version = "2.3.0"
|
||||
|
||||
[features]
|
||||
dyn-symbols = ["libloading"]
|
||||
experimental = []
|
||||
napi1 = []
|
||||
napi2 = ["napi1"]
|
||||
|
@ -26,5 +27,8 @@ napi9 = ["napi8"]
|
|||
[package.metadata.workspaces]
|
||||
independent = true
|
||||
|
||||
[target.'cfg(windows)'.dependencies.libloading]
|
||||
version = "0.8"
|
||||
[dependencies]
|
||||
libloading = { version = "0.8", optional = true }
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
libloading = "0.8"
|
||||
|
|
|
@ -780,15 +780,13 @@ pub use napi8::*;
|
|||
#[cfg(feature = "napi9")]
|
||||
pub use napi9::*;
|
||||
|
||||
#[cfg(windows)]
|
||||
#[cfg(any(windows, feature = "dyn-symbols"))]
|
||||
pub(super) unsafe fn load_all() -> Result<libloading::Library, libloading::Error> {
|
||||
let host = match libloading::os::windows::Library::this() {
|
||||
Ok(lib) => lib.into(),
|
||||
Err(err) => {
|
||||
eprintln!("Initialize libloading failed {}", err);
|
||||
return Err(err);
|
||||
}
|
||||
};
|
||||
#[cfg(windows)]
|
||||
let host = libloading::os::windows::Library::this()?.into();
|
||||
|
||||
#[cfg(unix)]
|
||||
let host = libloading::os::unix::Library::this().into();
|
||||
|
||||
napi1::load(&host)?;
|
||||
#[cfg(feature = "napi2")]
|
||||
|
|
|
@ -1,73 +1,74 @@
|
|||
// borrowed from https://github.com/neon-bindings/neon/tree/main/crates/neon/src/sys/bindings
|
||||
|
||||
#![allow(ambiguous_glob_reexports)]
|
||||
|
||||
#[cfg(windows)]
|
||||
#[cfg(any(windows, feature = "dyn-symbols"))]
|
||||
macro_rules! generate {
|
||||
(extern "C" {
|
||||
$(fn $name:ident($($param:ident: $ptype:ty$(,)?)*)$( -> $rtype:ty)?;)+
|
||||
$(fn $name:ident($($param:ident: $ptype:ty$(,)?)*)$( -> $rtype:ty)?;)+
|
||||
}) => {
|
||||
struct Napi {
|
||||
$(
|
||||
$name: unsafe extern "C" fn(
|
||||
$($param: $ptype,)*
|
||||
)$( -> $rtype)*,
|
||||
)*
|
||||
}
|
||||
struct Napi {
|
||||
$(
|
||||
$name: unsafe extern "C" fn(
|
||||
$($param: $ptype,)*
|
||||
)$( -> $rtype)*,
|
||||
)*
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
fn panic_load<T>() -> T {
|
||||
panic!("Must load N-API bindings")
|
||||
}
|
||||
#[inline(never)]
|
||||
fn panic_load<T>() -> T {
|
||||
panic!("Node-API symbol has not been loaded")
|
||||
}
|
||||
|
||||
static mut NAPI: Napi = {
|
||||
$(
|
||||
unsafe extern "C" fn $name($(_: $ptype,)*)$( -> $rtype)* {
|
||||
panic_load()
|
||||
static mut NAPI: Napi = {
|
||||
$(
|
||||
unsafe extern "C" fn $name($(_: $ptype,)*)$( -> $rtype)* {
|
||||
panic_load()
|
||||
}
|
||||
)*
|
||||
|
||||
Napi {
|
||||
$(
|
||||
$name,
|
||||
)*
|
||||
}
|
||||
};
|
||||
|
||||
#[allow(clippy::missing_safety_doc)]
|
||||
pub unsafe fn load(
|
||||
host: &libloading::Library,
|
||||
) -> Result<(), libloading::Error> {
|
||||
NAPI = Napi {
|
||||
$(
|
||||
$name: {
|
||||
let symbol: Result<libloading::Symbol<unsafe extern "C" fn ($(_: $ptype,)*)$( -> $rtype)*>, libloading::Error> = host.get(stringify!($name).as_bytes());
|
||||
match symbol {
|
||||
Ok(f) => *f,
|
||||
Err(e) => {
|
||||
#[cfg(debug_assertions)] {
|
||||
eprintln!("Load Node-API [{}] from host runtime failed: {}", stringify!($name), e);
|
||||
}
|
||||
NAPI.$name
|
||||
}
|
||||
)*
|
||||
|
||||
Napi {
|
||||
$(
|
||||
$name,
|
||||
)*
|
||||
}
|
||||
}
|
||||
},
|
||||
)*
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
$(
|
||||
#[inline]
|
||||
#[allow(clippy::missing_safety_doc)]
|
||||
pub unsafe fn load(
|
||||
host: &libloading::Library,
|
||||
) -> Result<(), libloading::Error> {
|
||||
NAPI = Napi {
|
||||
$(
|
||||
$name: {
|
||||
let symbol: Result<libloading::Symbol<unsafe extern "C" fn ($(_: $ptype,)*)$( -> $rtype)*>, libloading::Error> = host.get(stringify!($name).as_bytes());
|
||||
match symbol {
|
||||
Ok(f) => *f,
|
||||
Err(e) => {
|
||||
debug_assert!({
|
||||
println!("Load Node-API [{}] from host runtime failed: {}", stringify!($name), e);
|
||||
true
|
||||
});
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
},
|
||||
)*
|
||||
};
|
||||
|
||||
Ok(())
|
||||
pub unsafe fn $name($($param: $ptype,)*)$( -> $rtype)* {
|
||||
(NAPI.$name)($($param,)*)
|
||||
}
|
||||
|
||||
$(
|
||||
#[inline]
|
||||
#[allow(clippy::missing_safety_doc)]
|
||||
pub unsafe fn $name($($param: $ptype,)*)$( -> $rtype)* {
|
||||
(NAPI.$name)($($param,)*)
|
||||
}
|
||||
)*
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
#[cfg(not(any(windows, feature = "dyn-symbols")))]
|
||||
macro_rules! generate {
|
||||
(extern "C" {
|
||||
$(fn $name:ident($($param:ident: $ptype:ty$(,)?)*)$( -> $rtype:ty)?;)+
|
||||
|
@ -90,7 +91,7 @@ pub use types::*;
|
|||
/// Must be called at least once before using any functions in bindings or
|
||||
/// they will panic.
|
||||
/// Safety: `env` must be a valid `napi_env` for the current thread
|
||||
#[cfg(windows)]
|
||||
#[cfg(any(windows, feature = "dyn-symbols"))]
|
||||
#[allow(clippy::missing_safety_doc)]
|
||||
pub unsafe fn setup() -> libloading::Library {
|
||||
match load_all() {
|
||||
|
|
|
@ -11,6 +11,7 @@ crate-type = ["cdylib"]
|
|||
[features]
|
||||
latest = ["napi/napi9"]
|
||||
napi3 = ["napi/napi3"]
|
||||
dyn-symbols = ["napi/dyn-symbols"]
|
||||
|
||||
[dependencies]
|
||||
futures = "0.3"
|
||||
|
|
|
@ -10,6 +10,7 @@ crate-type = ["cdylib"]
|
|||
|
||||
[features]
|
||||
snmalloc = ["snmalloc-rs"]
|
||||
dyn-symbols = ["napi/dyn-symbols"]
|
||||
|
||||
[dependencies]
|
||||
chrono = "0.4"
|
||||
|
|
Loading…
Reference in a new issue