From d0642ef1f71f9f3f34bb2573cf3d262a8f49a8d9 Mon Sep 17 00:00:00 2001 From: Kenny Date: Fri, 13 Mar 2026 16:23:27 -0700 Subject: [PATCH 1/3] [rust] bindgen path supports env!() macro This makes it possible to refer to a wit path by a path that includes things like OUT_DIR or CARGO_MANIFEST_DIR. Relative paths that navigate up, like `../wit/`, don't work well with cargo publish, and symlinks have difficulties between git and cargo. Using [macro-string](https://github.com/dtolnay/macro-string), this replaces the `path` option's `syn::LitStr` with MacroString. --- Cargo.lock | 12 +++++++++++ Cargo.toml | 1 + crates/guest-rust/macro/Cargo.toml | 1 + crates/guest-rust/macro/src/lib.rs | 21 ++++++++++++------- crates/guest-rust/src/examples.rs | 9 ++++++++ .../src/examples/_5_import_directory.rs | 6 ++++++ crates/guest-rust/wit/_5_import_directory.wit | 5 +++++ 7 files changed, 48 insertions(+), 7 deletions(-) create mode 100644 crates/guest-rust/src/examples/_5_import_directory.rs create mode 100644 crates/guest-rust/wit/_5_import_directory.wit diff --git a/Cargo.lock b/Cargo.lock index afc846c84..3f469c114 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -654,6 +654,17 @@ dependencies = [ "logos-codegen", ] +[[package]] +name = "macro-string" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59a9dbbfc75d2688ed057456ce8a3ee3f48d12eec09229f560f3643b9f275653" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "memchr" version = "2.7.6" @@ -1604,6 +1615,7 @@ name = "wit-bindgen-rust-macro" version = "0.53.1" dependencies = [ "anyhow", + "macro-string", "prettyplease", "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 86e224127..beb93a8ed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,6 +45,7 @@ indexmap = "2.0.0" prettyplease = "0.2.20" syn = { version = "2.0.89", features = ["printing"] } futures = "0.3.31" +macro-string = "0.2.0" wat = "1.245.1" wasmparser = "0.245.1" diff --git a/crates/guest-rust/macro/Cargo.toml b/crates/guest-rust/macro/Cargo.toml index 5fb9c1ea6..0764d61b2 100644 --- a/crates/guest-rust/macro/Cargo.toml +++ b/crates/guest-rust/macro/Cargo.toml @@ -23,6 +23,7 @@ wit-bindgen-rust = { workspace = true } anyhow = { workspace = true } syn = { workspace = true } prettyplease = { workspace = true } +macro-string = { workspace = true } [features] async = [] diff --git a/crates/guest-rust/macro/src/lib.rs b/crates/guest-rust/macro/src/lib.rs index 91d4335dd..e5586e0d3 100644 --- a/crates/guest-rust/macro/src/lib.rs +++ b/crates/guest-rust/macro/src/lib.rs @@ -5,8 +5,7 @@ use std::path::{Path, PathBuf}; use std::sync::atomic::{AtomicUsize, Ordering::Relaxed}; use syn::parse::{Error, Parse, ParseStream, Result}; use syn::punctuated::Punctuated; -use syn::spanned::Spanned; -use syn::{LitStr, Token, braced, token}; +use syn::{Token, braced, token}; use wit_bindgen_core::AsyncFilterSet; use wit_bindgen_core::WorldGenerator; use wit_bindgen_core::wit_parser::{PackageId, Resolve, UnresolvedPackageGroup, WorldId}; @@ -76,7 +75,13 @@ impl Parse for Config { for field in fields.into_pairs() { match field.into_value() { Opt::Path(span, p) => { - let paths = p.into_iter().map(|f| PathBuf::from(f.value())).collect(); + let paths = p + .into_iter() + .map(|f| f.eval()) + .collect::>>()? + .into_iter() + .map(PathBuf::from) + .collect(); source = Some(match source { Some(Source::Paths(_)) | Some(Source::Inline(_, Some(_))) => { @@ -348,7 +353,7 @@ impl From for wit_bindgen_rust::ExportKey { enum Opt { World(syn::LitStr), - Path(Span, Vec), + Path(Span, Vec), Inline(syn::LitStr), UseStdFeature, RawStrings, @@ -387,11 +392,13 @@ impl Parse for Opt { if input.peek(token::Bracket) { let contents; syn::bracketed!(contents in input); + let span = input.span(); let list = Punctuated::<_, Token![,]>::parse_terminated(&contents)?; - Ok(Opt::Path(list.span(), list.into_iter().collect())) + Ok(Opt::Path(span, list.into_iter().collect())) } else { - let path: LitStr = input.parse()?; - Ok(Opt::Path(path.span(), vec![path])) + let span = input.span(); + let path: macro_string::MacroString = input.parse()?; + Ok(Opt::Path(span, vec![path])) } } else if l.peek(kw::inline) { input.parse::()?; diff --git a/crates/guest-rust/src/examples.rs b/crates/guest-rust/src/examples.rs index a63996889..653cb717a 100644 --- a/crates/guest-rust/src/examples.rs +++ b/crates/guest-rust/src/examples.rs @@ -53,3 +53,12 @@ pub mod _3_world_exports; #[doc = include_str!("./examples/_4_exported_resources.rs")] /// ``` pub mod _4_exported_resources; + +/// An example of importing a compile-time directory of wit files. +/// +/// The code used to generate this module is: +/// +/// ```rust +#[doc = include_str!("./examples/_5_import_directory.rs")] +/// ``` +pub mod _5_import_directory; diff --git a/crates/guest-rust/src/examples/_5_import_directory.rs b/crates/guest-rust/src/examples/_5_import_directory.rs new file mode 100644 index 000000000..a6905e944 --- /dev/null +++ b/crates/guest-rust/src/examples/_5_import_directory.rs @@ -0,0 +1,6 @@ +crate::generate!({ + path: concat!( + env!("CARGO_MANIFEST_DIR"), + "/wit/" + ), +}); diff --git a/crates/guest-rust/wit/_5_import_directory.wit b/crates/guest-rust/wit/_5_import_directory.wit new file mode 100644 index 000000000..e43771793 --- /dev/null +++ b/crates/guest-rust/wit/_5_import_directory.wit @@ -0,0 +1,5 @@ +package example:import-directory; + +world import-directory { + import hello: func() -> string; +} From eee80f0d7db8facdb658597974ea68fd33b0b042 Mon Sep 17 00:00:00 2001 From: Kenny Date: Mon, 16 Mar 2026 12:14:51 -0700 Subject: [PATCH 2/3] add macro-string feature to wit-bindgen-rust-macro gates the macro-string dependency on the new default feature macro-string. --- crates/guest-rust/macro/Cargo.toml | 4 +++- crates/guest-rust/macro/src/lib.rs | 31 ++++++++++++++++++++++++++---- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/crates/guest-rust/macro/Cargo.toml b/crates/guest-rust/macro/Cargo.toml index 0764d61b2..4c3a5fb8a 100644 --- a/crates/guest-rust/macro/Cargo.toml +++ b/crates/guest-rust/macro/Cargo.toml @@ -23,7 +23,9 @@ wit-bindgen-rust = { workspace = true } anyhow = { workspace = true } syn = { workspace = true } prettyplease = { workspace = true } -macro-string = { workspace = true } +macro-string = { workspace = true, optional = true } [features] +default = ["macro-string"] async = [] +macro-string = ["dep:macro-string"] diff --git a/crates/guest-rust/macro/src/lib.rs b/crates/guest-rust/macro/src/lib.rs index e5586e0d3..d8b4170bd 100644 --- a/crates/guest-rust/macro/src/lib.rs +++ b/crates/guest-rust/macro/src/lib.rs @@ -77,7 +77,7 @@ impl Parse for Config { Opt::Path(span, p) => { let paths = p .into_iter() - .map(|f| f.eval()) + .map(|f| f.evaluate_string()) .collect::>>()? .into_iter() .map(PathBuf::from) @@ -351,9 +351,32 @@ impl From for wit_bindgen_rust::ExportKey { } } +#[cfg(feature = "macro-string")] +type PathType = macro_string::MacroString; +#[cfg(not(feature = "macro-string"))] +type PathType = syn::LitStr; + +trait EvaluateString { + fn evaluate_string(&self) -> Result; +} + +#[cfg(feature = "macro-string")] +impl EvaluateString for macro_string::MacroString { + fn evaluate_string(&self) -> Result { + self.eval() + } +} + +#[cfg(not(feature = "macro-string"))] +impl EvaluateString for syn::LitStr { + fn evaluate_string(&self) -> Result { + Ok(self.value()) + } +} + enum Opt { World(syn::LitStr), - Path(Span, Vec), + Path(Span, Vec), Inline(syn::LitStr), UseStdFeature, RawStrings, @@ -393,11 +416,11 @@ impl Parse for Opt { let contents; syn::bracketed!(contents in input); let span = input.span(); - let list = Punctuated::<_, Token![,]>::parse_terminated(&contents)?; + let list = Punctuated::::parse_terminated(&contents)?; Ok(Opt::Path(span, list.into_iter().collect())) } else { let span = input.span(); - let path: macro_string::MacroString = input.parse()?; + let path: PathType = input.parse()?; Ok(Opt::Path(span, vec![path])) } } else if l.peek(kw::inline) { From 183a7762af4c39831f8e337960005cef08caf146 Mon Sep 17 00:00:00 2001 From: Kenny Date: Mon, 16 Mar 2026 12:53:56 -0700 Subject: [PATCH 3/3] lift macro-string feature toggle to wit-bindgen --- crates/guest-rust/Cargo.toml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/guest-rust/Cargo.toml b/crates/guest-rust/Cargo.toml index 9d07cbdd5..064bd89dd 100644 --- a/crates/guest-rust/Cargo.toml +++ b/crates/guest-rust/Cargo.toml @@ -19,7 +19,7 @@ workspace = true all-features = true [dependencies] -wit-bindgen-rust-macro = { path = "./macro", optional = true, version = "0.53.1" } +wit-bindgen-rust-macro = { path = "./macro", optional = true, default-features = false, version = "0.53.1" } bitflags = { workspace = true, optional = true } futures = { version = "0.3.30", optional = true } @@ -28,13 +28,14 @@ core = { version = "1.0", optional = true, package = "rustc-std-workspace-core" alloc = { version = "1.0", optional = true, package = "rustc-std-workspace-alloc" } [features] -default = ["macros", "realloc", "async", "std", "bitflags"] +default = ["macros", "realloc", "async", "std", "bitflags", "macro-string"] macros = ["dep:wit-bindgen-rust-macro"] realloc = [] std = [] async = ["std", "wit-bindgen-rust-macro?/async"] bitflags = ["dep:bitflags"] async-spawn = ['async', 'dep:futures'] +macro-string = ["wit-bindgen-rust-macro?/macro-string"] # Unstable feature to support being a libstd dependency rustc-dep-of-std = ["dep:core", "dep:alloc"]