fix!(napi): upgrade to ctor 0.3.6 (#2472)

This commit is contained in:
LongYinan 2025-02-20 12:22:29 +08:00 committed by GitHub
parent 384dcac588
commit d96bd288de
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 58 additions and 64 deletions

View File

@ -260,7 +260,7 @@ jobs:
- name: Setup node
uses: actions/setup-node@v4
with:
node-version: 20
node-version: 22
cache: 'yarn'
- name: Install
@ -475,7 +475,7 @@ jobs:
run: |
node -e "console.info('docker-image=${{ matrix.settings.image }}'.replace('{:version}', ${{ matrix.node }}))" >> "$GITHUB_OUTPUT"
- name: Run test
run: docker run --rm ${{ matrix.settings.args }} -v ${{ github.workspace }}:/build -w /build ${{ steps.image-name.outputs.docker-image }} sh -c "DISABLE_V8_COMPILE_CACHE=1 yarn workspace @examples/napi test -s"
run: docker run --rm ${{ matrix.settings.args }} -v ${{ github.workspace }}:/build -w /build ${{ steps.image-name.outputs.docker-image }} sh -c "NODE_OPTIONS=--max-old-space-size=6000 DISABLE_V8_COMPILE_CACHE=1 yarn workspace @examples/napi test -s"
build-and-test-linux-armv7:
name: stable - armv7-unknown-linux-gnueabihf - node@20

View File

@ -9,7 +9,6 @@ version = "0.1.0"
crate-type = ["cdylib"]
[dependencies]
ctor = "0.3"
napi = { path = "../crates/napi", features = [
"tokio_rt",
"serde-json",

View File

@ -36,7 +36,7 @@ impl NapiConst {
#[allow(non_snake_case)]
#[allow(clippy::all)]
#[cfg(all(not(test), not(target_family = "wasm")))]
#[napi::bindgen_prelude::ctor]
#[napi::ctor::ctor(crate_path=::napi::ctor)]
fn #register_name() {
napi::bindgen_prelude::register_module_export(#js_mod_ident, #js_name_lit, #cb_name);
}

View File

@ -254,7 +254,7 @@ impl NapiEnum {
#[allow(non_snake_case)]
#[allow(clippy::all)]
#[cfg(all(not(test), not(target_family = "wasm")))]
#[napi::bindgen_prelude::ctor]
#[napi::ctor::ctor(crate_path=napi::ctor)]
fn #register_name() {
napi::bindgen_prelude::register_module_export(#js_mod_ident, #js_name_lit, #callback_name);
}

View File

@ -702,7 +702,7 @@ impl NapiFn {
#[allow(clippy::all)]
#[allow(non_snake_case)]
#[cfg(all(not(test), not(target_family = "wasm")))]
#[napi::bindgen_prelude::ctor]
#[napi::ctor::ctor(crate_path=::napi::ctor)]
fn #module_register_name() {
napi::bindgen_prelude::register_module_export(#js_mod_ident, #js_name, #cb_name);
}

View File

@ -869,7 +869,7 @@ impl NapiStruct {
#[allow(non_snake_case)]
#[allow(clippy::all)]
#[cfg(all(not(test), not(target_family = "wasm")))]
#[napi::bindgen_prelude::ctor]
#[napi::ctor::ctor(crate_path=napi::ctor)]
fn #struct_register_name() {
napi::__private::register_class(std::any::TypeId::of::<#name>(), #js_mod_ident, #js_name, vec![#(#props),*]);
}
@ -1402,7 +1402,7 @@ impl NapiImpl {
#(#methods)*
#[cfg(all(not(test), not(target_family = "wasm")))]
#[napi::bindgen_prelude::ctor]
#[napi::ctor::ctor(crate_path=napi::ctor)]
fn #register_name() {
napi::__private::register_class(std::any::TypeId::of::<#name>(), #js_mod_ident, #js_name, vec![#(#props),*]);
}

View File

@ -151,7 +151,7 @@ pub fn module_exports(_attr: TokenStream, input: TokenStream) -> TokenStream {
};
let register = quote! {
#[cfg_attr(not(target_family = "wasm"), napi::bindgen_prelude::ctor)]
#[cfg_attr(not(target_family = "wasm"), napi::ctor::ctor(crate_path=napi::ctor))]
fn __napi_explicit_module_register() {
unsafe fn register(raw_env: napi::sys::napi_env, raw_exports: napi::sys::napi_value) -> napi::Result<()> {
use napi::{Env, JsObject, NapiValue};
@ -174,3 +174,13 @@ pub fn module_exports(_attr: TokenStream, input: TokenStream) -> TokenStream {
})
.into()
}
#[proc_macro_attribute]
pub fn module_init(_: TokenStream, input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as ItemFn);
quote! {
#[napi::ctor::ctor(crate_path=napi::ctor)]
#input
}
.into()
}

View File

@ -62,7 +62,7 @@ node_version_detect = []
[dependencies]
bitflags = "2"
ctor = "0.3"
ctor = "0.3.6"
[dependencies.anyhow]
optional = true

View File

@ -7,7 +7,7 @@ use std::mem::MaybeUninit;
#[cfg(not(feature = "noop"))]
use std::ptr;
#[cfg(not(feature = "noop"))]
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::{LazyLock, RwLock};
use std::thread::ThreadId;
use std::{any::TypeId, collections::HashMap};
@ -52,6 +52,7 @@ impl<K, V> Default for PersistedPerInstanceHashMap<K, V> {
}
}
#[cfg(not(feature = "noop"))]
type ModuleRegisterCallback =
RwLock<Vec<(Option<&'static str>, (&'static str, ExportRegisterCallback))>>;
@ -65,10 +66,12 @@ type FnRegisterMap =
PersistedPerInstanceHashMap<ExportRegisterCallback, (sys::napi_callback, &'static str)>;
type RegisteredClassesMap = PersistedPerInstanceHashMap<ThreadId, RegisteredClasses>;
#[cfg(not(feature = "noop"))]
static MODULE_REGISTER_CALLBACK: LazyLock<ModuleRegisterCallback> = LazyLock::new(Default::default);
#[cfg(not(feature = "noop"))]
static MODULE_CLASS_PROPERTIES: LazyLock<ModuleClassProperty> = LazyLock::new(Default::default);
#[cfg(not(feature = "noop"))]
static IS_FIRST_MODULE: AtomicBool = AtomicBool::new(true);
static MODULE_COUNT: AtomicUsize = AtomicUsize::new(0);
#[cfg(not(feature = "noop"))]
static FIRST_MODULE_REGISTERED: AtomicBool = AtomicBool::new(false);
static REGISTERED_CLASSES: LazyLock<RegisteredClassesMap> = LazyLock::new(Default::default);
@ -109,6 +112,7 @@ pub fn register_module_exports(callback: ModuleExportsCallback) {
.push(callback);
}
#[cfg(not(feature = "noop"))]
#[doc(hidden)]
pub fn register_module_export(
js_mod: Option<&'static str>,
@ -142,6 +146,7 @@ pub fn get_class_constructor(js_name: &'static str) -> Option<sys::napi_ref> {
})?
}
#[cfg(not(feature = "noop"))]
#[doc(hidden)]
pub fn register_class(
rust_type_id: TypeId,
@ -212,10 +217,7 @@ pub unsafe extern "C" fn napi_register_module_v1(
env: sys::napi_env,
exports: sys::napi_value,
) -> sys::napi_value {
#[cfg(all(
any(target_env = "msvc", feature = "dyn-symbols"),
not(feature = "noop")
))]
#[cfg(any(target_env = "msvc", feature = "dyn-symbols"))]
unsafe {
sys::setup();
}
@ -234,11 +236,11 @@ pub unsafe extern "C" fn napi_register_module_v1(
NODE_VERSION_PATCH = node_version.patch;
};
}
if IS_FIRST_MODULE.load(Ordering::SeqCst) {
IS_FIRST_MODULE.store(false, Ordering::SeqCst);
} else {
if MODULE_COUNT.fetch_add(1, Ordering::SeqCst) != 0 {
wait_first_thread_registered();
}
let mut exports_objects: HashSet<String> = HashSet::default();
{
@ -424,29 +426,21 @@ pub unsafe extern "C" fn napi_register_module_v1(
})
}
#[cfg(feature = "napi4")]
let current_thread_id = std::thread::current().id();
#[cfg(all(not(target_family = "wasm"), feature = "napi3"))]
// attach cleanup hook to the `module` object
// we don't use the `napi_add_env_cleanup_hook` because it's required napi3
check_status_or_throw!(
env,
unsafe {
sys::napi_add_env_cleanup_hook(
sys::napi_wrap(
env,
Some(thread_cleanup),
exports,
Box::into_raw(Box::new(current_thread_id)).cast(),
)
},
"Failed to add remove thread id cleanup hook"
);
#[cfg(all(target_family = "wasm", feature = "napi3"))]
check_status_or_throw!(
env,
unsafe {
crate::napi_add_env_cleanup_hook(
env,
Some(thread_cleanup),
Box::into_raw(Box::new(current_thread_id)).cast(),
ptr::null_mut(),
ptr::null_mut(),
)
},
"Failed to add remove thread id cleanup hook"
@ -538,19 +532,24 @@ fn create_custom_gc(env: sys::napi_env, current_thread_id: ThreadId) {
THREADS_CAN_ACCESS_ENV.borrow_mut(|m| m.insert(current_thread_id, true));
}
#[cfg(all(feature = "napi3", not(feature = "noop")))]
unsafe extern "C" fn thread_cleanup(id: *mut std::ffi::c_void) {
let thread_id = unsafe { Box::from_raw(id.cast::<ThreadId>()) };
REGISTERED_CLASSES.borrow_mut(|m| {
m.remove(&thread_id);
});
#[cfg(feature = "napi4")]
{
THREADS_CAN_ACCESS_ENV.borrow_mut(|m| m.remove(&thread_id));
#[cfg(feature = "tokio_rt")]
#[cfg(not(feature = "noop"))]
unsafe extern "C" fn thread_cleanup(
_: sys::napi_env,
#[allow(unused_variables)] id: *mut std::ffi::c_void,
_data: *mut std::ffi::c_void,
) {
if MODULE_COUNT.fetch_sub(1, Ordering::Relaxed) == 1 {
#[cfg(all(feature = "tokio_rt", feature = "napi4"))]
{
crate::tokio_runtime::drop_runtime();
}
crate::bindgen_runtime::REFERENCE_MAP.borrow_mut(|m| m.clear());
return;
}
#[cfg(feature = "napi4")]
{
let thread_id = unsafe { Box::from_raw(id.cast::<ThreadId>()) };
THREADS_CAN_ACCESS_ENV.borrow_mut(|m| m.remove(&thread_id));
}
}

View File

@ -7,7 +7,7 @@
//!
//! ## Feature flags
//!
//! ### napi1 ~ napi8
//! ### napi1 ~ napi9
//!
//! Because `Node.js` N-API has versions. So there are feature flags to choose what version of `N-API` you want to build for.
//! For example, if you want build a library which can be used by `node@10.17.0`, you should choose the `napi5` or lower.
@ -149,8 +149,6 @@ macro_rules! assert_type_of {
};
}
pub use crate::bindgen_runtime::ctor as module_init;
pub mod bindgen_prelude {
#[cfg(all(feature = "compat-mode", not(feature = "noop")))]
pub use crate::bindgen_runtime::register_module_exports;
@ -213,6 +211,8 @@ pub mod __private {
}
}
pub extern crate ctor;
#[cfg(feature = "tokio_rt")]
pub extern crate tokio;

View File

@ -62,33 +62,22 @@ pub fn create_custom_tokio_runtime(rt: Runtime) {
USER_DEFINED_RT.get_or_init(move || Mutex::new(Some(rt)));
}
#[cfg(not(feature = "noop"))]
static RT_REFERENCE_COUNT: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0);
#[cfg(not(feature = "noop"))]
/// Ensure that the Tokio runtime is initialized.
/// In windows the Tokio runtime will be dropped when Node env exits.
/// But in Electron renderer process, the Node env will exits and recreate when the window reloads.
/// So we need to ensure that the Tokio runtime is initialized when the Node env is created.
pub(crate) fn ensure_runtime() {
use std::sync::atomic::Ordering;
let mut rt = RT.write().unwrap();
if rt.is_none() {
*rt = create_runtime();
}
RT_REFERENCE_COUNT.fetch_add(1, Ordering::Relaxed);
}
#[cfg(not(feature = "noop"))]
pub(crate) fn drop_runtime() {
use std::sync::atomic::Ordering;
if RT_REFERENCE_COUNT.fetch_sub(1, Ordering::AcqRel) == 1 {
if let Some(rt) = RT.write().unwrap().take() {
rt.shutdown_background();
}
if let Some(rt) = RT.write().unwrap().take() {
rt.shutdown_background();
}
}

View File

@ -14,7 +14,6 @@ napi3 = ["napi/napi3"]
dyn-symbols = ["napi/dyn-symbols"]
[dependencies]
ctor = "0.3"
futures = "0.3"
napi = { path = "../../crates/napi", features = [
"tokio_rt",

View File

@ -15,7 +15,6 @@ error_try_builds = []
[dependencies]
chrono = "0.4"
ctor = "0.3"
futures = "0.3"
bytes = "1"
napi-derive = { path = "../../crates/macro", features = ["type-def"] }

View File

@ -18,7 +18,7 @@ extern crate serde_derive;
static ALLOC: snmalloc_rs::SnMalloc = snmalloc_rs::SnMalloc;
#[cfg(not(target_family = "wasm"))]
#[napi::module_init]
#[napi_derive::module_init]
fn init() {
let rt = tokio::runtime::Builder::new_multi_thread()
.enable_all()

View File

@ -9,7 +9,6 @@ version = "0.1.0"
crate-type = ["cdylib"]
[dependencies]
ctor = "0.3"
futures = "0.3"
napi = { path = "../crates/napi", features = [
"tokio_rt",