diff --git a/godot-macros/Cargo.toml b/godot-macros/Cargo.toml index 269b6cb65..e4abfd38f 100644 --- a/godot-macros/Cargo.toml +++ b/godot-macros/Cargo.toml @@ -14,7 +14,7 @@ homepage = "https://godot-rust.github.io" api-custom = ["godot-bindings/api-custom"] api-custom-json = ["godot-bindings/api-custom-json"] codegen-full = ["godot/__codegen-full"] -experimental-wasm = ["dep:libc"] +experimental-wasm = [] register-docs = ["dep:markdown", "dep:litrs"] [lib] @@ -28,10 +28,6 @@ markdown = { workspace = true, optional = true } litrs = { workspace = true, optional = true } venial = { workspace = true } -# Cannot use [target.'cfg(target_family = "wasm")'.dependencies], as proc-macro crates are always compiled for host platform, not target. -# Thus solved via feature. -libc = { workspace = true, optional = true } - [build-dependencies] godot-bindings = { path = "../godot-bindings", version = "=0.3.1" } # emit_godot_version_cfg diff --git a/godot-macros/src/ffi_macros.rs b/godot-macros/src/ffi_macros.rs index 961ece185..e23e786ca 100644 --- a/godot-macros/src/ffi_macros.rs +++ b/godot-macros/src/ffi_macros.rs @@ -13,22 +13,34 @@ use crate::util::bail; use crate::ParseResult; use proc_macro2::TokenStream; use quote::{format_ident, quote}; +use std::env; +use std::sync::atomic::{AtomicU32, Ordering}; + +// Note: global state in proc-macros may become problematic in the future, see: +// https://users.rust-lang.org/t/simple-state-in-procedural-macro/68204/2 +static FUNCTION_COUNTER: AtomicU32 = AtomicU32::new(0); pub(super) fn wasm_declare_init_fn(input: TokenStream) -> ParseResult { if !input.is_empty() { return bail!(input, "macro expects no arguments"); } - // Create sufficiently unique identifier without entire `uuid` (let alone `rand`) crate dependency. - let a = unsafe { libc::rand() }; - let b = unsafe { libc::rand() }; + let crate_name = env::var("CARGO_CRATE_NAME") + .expect("CARGO_CRATE_NAME env var not found. This macro must be run by Cargo."); + + let crate_version = env::var("CARGO_PKG_VERSION") + .expect("CARGO_PKG_VERSION env var not found. This macro must be run by Cargo.") + .replace(['.', '+', '-'], "_"); // version must follow semver, which allows digits, dots, hyphens, and plus signs, and alphanumeric characters. + + let index = FUNCTION_COUNTER.fetch_add(1, Ordering::Relaxed); // Rust presently requires that statics with a custom `#[link_section]` must be a simple // list of bytes on the Wasm target (with no extra levels of indirection such as references). // - // As such, instead we export a function with a random name of known prefix to be used by the embedder. + // As such, instead we export a function with a known prefix to be used by the embedder. // This prefix is queried at load time, see godot-macros/src/gdextension.rs. - let function_name = format_ident!("__godot_rust_registrant_{a}_{b}"); + let function_name = + format_ident!("__godot_rust_registrant__{crate_name}__v{crate_version}__i{index}"); let code = quote! { #[cfg(target_family = "wasm")] // Strictly speaking not necessary, as this macro is only invoked for Wasm.