From bcf5022f8c6ad3011ef1e4e1aa1c1302cdd39b03 Mon Sep 17 00:00:00 2001 From: Tomas Olvecky Date: Sun, 30 Nov 2025 18:52:50 +0100 Subject: [PATCH 1/2] Add new functions to generate rust bindings in `build.rs` Add `RustWasm::generate_to_out_dir` that parses the `wit` folder, selects a world, generates bindings and places them in a file in the `OUT_DIR`. `generate_to_out_dir_modify` allows modifying the generated file. --- crates/guest-rust/macro/src/lib.rs | 1 + crates/rust/src/lib.rs | 36 +++++++++++++++++++++++++++--- src/bin/wit-bindgen.rs | 2 +- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/crates/guest-rust/macro/src/lib.rs b/crates/guest-rust/macro/src/lib.rs index c2b616f97..b813585c4 100644 --- a/crates/guest-rust/macro/src/lib.rs +++ b/crates/guest-rust/macro/src/lib.rs @@ -8,6 +8,7 @@ use syn::punctuated::Punctuated; use syn::spanned::Spanned; use syn::{LitStr, Token, braced, token}; use wit_bindgen_core::AsyncFilterSet; +use wit_bindgen_core::WorldGenerator; use wit_bindgen_core::wit_parser::{PackageId, Resolve, UnresolvedPackageGroup, WorldId}; use wit_bindgen_rust::{Opts, Ownership, WithOption}; diff --git a/crates/rust/src/lib.rs b/crates/rust/src/lib.rs index dece973ba..02f9cef55 100644 --- a/crates/rust/src/lib.rs +++ b/crates/rust/src/lib.rs @@ -3,9 +3,11 @@ use anyhow::{Result, bail}; use core::panic; use heck::*; use indexmap::{IndexMap, IndexSet}; +use std::borrow::Cow; use std::collections::{BTreeMap, HashMap, HashSet}; use std::fmt::{self, Write as _}; use std::mem; +use std::path::Path; use std::str::FromStr; use wit_bindgen_core::abi::{Bitcast, WasmType}; use wit_bindgen_core::{ @@ -26,7 +28,7 @@ struct InterfaceName { } #[derive(Default)] -struct RustWasm { +pub struct RustWasm { types: Types, src_preamble: Source, src: Source, @@ -277,15 +279,43 @@ pub struct Opts { } impl Opts { - pub fn build(self) -> Box { + pub fn build(self) -> RustWasm { let mut r = RustWasm::new(); r.skip = self.skip.iter().cloned().collect(); r.opts = self; - Box::new(r) + r } } +const GENERATED_FILE_NAME: &str = "wit_bindgen_generated.rs"; impl RustWasm { + pub fn generate_to_out_dir(self, world: Option<&str>) -> Result<()> { + self.generate_to_out_dir_modify(world, |s| Cow::Borrowed(s)) + } + + pub fn generate_to_out_dir_modify( + mut self, + world: Option<&str>, + modify: impl FnOnce(&[u8]) -> Cow<[u8]>, + ) -> Result<()> { + let mut resolve = Resolve::default(); + println!("cargo:rerun-if-changed=wit/"); + let (pkg, _files) = resolve.push_path("wit")?; + let main_packages = vec![pkg]; + let world = resolve.select_world(&main_packages, world)?; + let mut files = Files::default(); + self.generate(&resolve, world, &mut files)?; + let out_dir = std::env::var("OUT_DIR").expect("cargo sets OUT_DIR"); + let dst = Path::new(&out_dir).join(GENERATED_FILE_NAME); + let (_name, contents) = files + .iter() + .next() + .expect("exactly one file should be generated"); + let contents = modify(contents); + std::fs::write(&dst, contents)?; + Ok(()) + } + fn new() -> RustWasm { RustWasm::default() } diff --git a/src/bin/wit-bindgen.rs b/src/bin/wit-bindgen.rs index 3415dd71a..7f2ff75a5 100644 --- a/src/bin/wit-bindgen.rs +++ b/src/bin/wit-bindgen.rs @@ -145,7 +145,7 @@ fn main() -> Result<()> { #[cfg(feature = "cpp")] Opt::Cpp { opts, args } => (opts.build(args.out_dir.as_ref()), args), #[cfg(feature = "rust")] - Opt::Rust { opts, args } => (opts.build(), args), + Opt::Rust { opts, args } => (Box::new(opts.build()) as Box, args), #[cfg(feature = "go")] Opt::Go { opts, args } => (opts.build(), args), #[cfg(feature = "csharp")] From 4a431925f66c9be433dbaeed4dbb53fe8cd3957f Mon Sep 17 00:00:00 2001 From: Tomas Olvecky Date: Wed, 10 Dec 2025 17:54:38 +0100 Subject: [PATCH 2/2] Use world name as output path in `generate_to_out_dir` --- crates/rust/src/lib.rs | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/crates/rust/src/lib.rs b/crates/rust/src/lib.rs index 02f9cef55..89de0eca2 100644 --- a/crates/rust/src/lib.rs +++ b/crates/rust/src/lib.rs @@ -3,11 +3,10 @@ use anyhow::{Result, bail}; use core::panic; use heck::*; use indexmap::{IndexMap, IndexSet}; -use std::borrow::Cow; use std::collections::{BTreeMap, HashMap, HashSet}; use std::fmt::{self, Write as _}; use std::mem; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::str::FromStr; use wit_bindgen_core::abi::{Bitcast, WasmType}; use wit_bindgen_core::{ @@ -287,33 +286,31 @@ impl Opts { } } -const GENERATED_FILE_NAME: &str = "wit_bindgen_generated.rs"; impl RustWasm { - pub fn generate_to_out_dir(self, world: Option<&str>) -> Result<()> { - self.generate_to_out_dir_modify(world, |s| Cow::Borrowed(s)) - } - - pub fn generate_to_out_dir_modify( - mut self, - world: Option<&str>, - modify: impl FnOnce(&[u8]) -> Cow<[u8]>, - ) -> Result<()> { + /// Generates Rust bindings from the `wit/` directory and writes + /// the result into Cargo’s `OUT_DIR`. Intended for use in `build.rs`. + /// + /// The `world` parameter specifies the world name to select. + /// It must be provided unless the main package contains exactly one world. + /// + /// Returns the full path to the generated bindings file. + pub fn generate_to_out_dir(mut self, world: Option<&str>) -> Result { let mut resolve = Resolve::default(); println!("cargo:rerun-if-changed=wit/"); let (pkg, _files) = resolve.push_path("wit")?; let main_packages = vec![pkg]; let world = resolve.select_world(&main_packages, world)?; + let mut files = Files::default(); self.generate(&resolve, world, &mut files)?; let out_dir = std::env::var("OUT_DIR").expect("cargo sets OUT_DIR"); - let dst = Path::new(&out_dir).join(GENERATED_FILE_NAME); - let (_name, contents) = files + let (name, contents) = files .iter() .next() .expect("exactly one file should be generated"); - let contents = modify(contents); + let dst = Path::new(&out_dir).join(name); std::fs::write(&dst, contents)?; - Ok(()) + Ok(dst) } fn new() -> RustWasm {