Skip to content

Commit

Permalink
feat(napi-sys): support load Node-API symbols dynamically (#2014)
Browse files Browse the repository at this point in the history
  • Loading branch information
Brooooooklyn committed Apr 10, 2024
1 parent 0337c83 commit a603e00
Show file tree
Hide file tree
Showing 8 changed files with 73 additions and 67 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test-release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions crates/napi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
2 changes: 1 addition & 1 deletion crates/napi/src/bindgen_runtime/module_register.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
8 changes: 6 additions & 2 deletions crates/sys/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ rust-version = "1.65"
version = "2.3.0"

[features]
dyn-symbols = ["libloading"]
experimental = []
napi1 = []
napi2 = ["napi1"]
Expand All @@ -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"
14 changes: 6 additions & 8 deletions crates/sys/src/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
Expand Down
111 changes: 56 additions & 55 deletions crates/sys/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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!("Node-API symbol has not been loaded")
}

static mut NAPI: Napi = {
$(
unsafe extern "C" fn $name($(_: $ptype,)*)$( -> $rtype)* {
panic_load()
}
)*

#[inline(never)]
fn panic_load<T>() -> T {
panic!("Must load N-API bindings")
Napi {
$(
$name,
)*
}
};

static mut NAPI: Napi = {
$(
unsafe extern "C" fn $name($(_: $ptype,)*)$( -> $rtype)* {
panic_load()
#[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,
)*
}
}
},
)*
};

#[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(())
}

Ok(())
$(
#[inline]
#[allow(clippy::missing_safety_doc)]
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)?;)+
Expand All @@ -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() {
Expand Down
1 change: 1 addition & 0 deletions examples/napi-compat-mode/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ crate-type = ["cdylib"]
[features]
latest = ["napi/napi9"]
napi3 = ["napi/napi3"]
dyn-symbols = ["napi/dyn-symbols"]

[dependencies]
futures = "0.3"
Expand Down
1 change: 1 addition & 0 deletions examples/napi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ crate-type = ["cdylib"]

[features]
snmalloc = ["snmalloc-rs"]
dyn-symbols = ["napi/dyn-symbols"]

[dependencies]
chrono = "0.4"
Expand Down

0 comments on commit a603e00

Please sign in to comment.