diff --git a/Cargo.lock b/Cargo.lock index e9293a627..94671373b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -86,7 +86,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.39", + "syn 2.0.53", "which", ] @@ -300,6 +300,26 @@ dependencies = [ "memchr", ] +[[package]] +name = "linkme" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb2cfee0de9bd869589fb9a015e155946d1be5ff415cb844c2caccc6cc4b5db9" +dependencies = [ + "linkme-impl", +] + +[[package]] +name = "linkme-impl" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adf157a4dc5a29b7b464aa8fe7edeff30076e07e13646a1c3874f58477dc99f8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.53", +] + [[package]] name = "linux-raw-sys" version = "0.4.12" @@ -354,6 +374,7 @@ dependencies = [ "getrandom", "libloading 0.8.1", "linkify", + "linkme", "neon-macros", "nodejs-sys", "once_cell", @@ -370,7 +391,7 @@ name = "neon-macros" version = "1.0.0" dependencies = [ "quote", - "syn 2.0.39", + "syn 2.0.53", "syn-mid", ] @@ -490,7 +511,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" dependencies = [ "proc-macro2", - "syn 2.0.39", + "syn 2.0.53", ] [[package]] @@ -519,9 +540,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.70" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" dependencies = [ "unicode-ident", ] @@ -537,9 +558,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.33" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -657,7 +678,7 @@ checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.53", ] [[package]] @@ -691,9 +712,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.39" +version = "2.0.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032" dependencies = [ "proc-macro2", "quote", @@ -708,7 +729,7 @@ checksum = "b5dc35bb08dd1ca3dfb09dce91fd2d13294d6711c88897d9a9d60acf39bce049" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.53", ] [[package]] @@ -728,7 +749,7 @@ checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.53", ] [[package]] diff --git a/crates/neon-macros/src/lib.rs b/crates/neon-macros/src/lib.rs index 4063fda41..236a8a888 100644 --- a/crates/neon-macros/src/lib.rs +++ b/crates/neon-macros/src/lib.rs @@ -52,3 +52,38 @@ pub fn main( ) .into() } + +#[proc_macro_attribute] +/// Export a function +pub fn export( + _attr: proc_macro::TokenStream, + item: proc_macro::TokenStream, +) -> proc_macro::TokenStream { + let input = syn::parse_macro_input!(item as syn_mid::ItemFn); + + let attrs = &input.attrs; + let vis = &input.vis; + let sig = &input.sig; + let block = &input.block; + let name = &sig.ident; + let exported_name = quote::format_ident!("__EXPORTED__{name}"); + + quote::quote!( + #(#attrs)* + #vis #sig { + #[neon::macro_internal::linkme::distributed_slice(neon::macro_internal::EXPORTS)] + #[linkme(crate = neon::macro_internal::linkme)] + fn #exported_name<'cx>( + cx: &mut neon::context::ModuleContext<'cx>, + ) -> neon::result::NeonResult<(&'cx str, neon::handle::Handle<'cx, neon::types::JsValue>)> { + neon::types::JsFunction::new(cx, #name).map(|v| ( + stringify!(#name), + neon::handle::Handle::upcast(&v), + )) + } + + #block + } + ) + .into() +} diff --git a/crates/neon/Cargo.toml b/crates/neon/Cargo.toml index 9c7045642..e4d07804c 100644 --- a/crates/neon/Cargo.toml +++ b/crates/neon/Cargo.toml @@ -26,6 +26,7 @@ getrandom = { version = "0.2.11", optional = true } libloading = "0.8.1" semver = "1.0.20" smallvec = "1.11.2" +linkme = "0.3.25" once_cell = "1.18.0" neon-macros = { version = "=1.0.0", path = "../neon-macros" } aquamarine = { version = "0.3.2", optional = true } diff --git a/crates/neon/src/context/internal.rs b/crates/neon/src/context/internal.rs index 0386afff5..77c78d7e0 100644 --- a/crates/neon/src/context/internal.rs +++ b/crates/neon/src/context/internal.rs @@ -66,7 +66,13 @@ pub unsafe fn initialize_module( let env = Env(env); let exports = Handle::new_internal(JsObject::from_local(env, exports.cast())); - ModuleContext::with(env, exports, |cx| { + ModuleContext::with(env, exports, |mut cx| { + for create in crate::macro_internal::EXPORTS { + if let Ok((k, v)) = create(&mut cx) { + let _ = cx.export_value(k, v); + } + } + let _ = init(cx); }); } diff --git a/crates/neon/src/macro_internal/mod.rs b/crates/neon/src/macro_internal/mod.rs index 54b2cf6c8..b77df124a 100644 --- a/crates/neon/src/macro_internal/mod.rs +++ b/crates/neon/src/macro_internal/mod.rs @@ -1,3 +1,9 @@ //! Internals needed by macros. These have to be exported for the macros to work +pub use linkme; pub use crate::context::internal::initialize_module; + +use crate::{context::ModuleContext, handle::Handle, result::NeonResult, types::JsValue}; + +#[linkme::distributed_slice] +pub static EXPORTS: [for<'cx> fn(&mut ModuleContext<'cx>) -> NeonResult<(&'cx str, Handle<'cx, JsValue>)>]; diff --git a/test/napi/src/lib.rs b/test/napi/src/lib.rs index 4bdbe1402..2d85f5c77 100644 --- a/test/napi/src/lib.rs +++ b/test/napi/src/lib.rs @@ -400,3 +400,8 @@ fn main(mut cx: ModuleContext) -> NeonResult<()> { Ok(()) } + +#[neon::export] +fn hello_world(mut cx: FunctionContext) -> JsResult { + Ok(cx.string("Hello, World!")) +}