Partially support building and locating wasm proc-macros
Project: rust-lang/rust | Language: Rust | Concepts: api-design, configuration-management, backwards-compatibility | Difficulty: senior
Link: https://github.com/rust-lang/rust/pull/160981
The problem
Rust's procedural macros (proc-macros) are typically compiled for the host platform. There is ongoing work to support compiling and loading proc-macros as WebAssembly (wasm), which is needed for environments like WASI (WebAssembly System Interface). Before this PR, rustc did not have the ability to build or locate proc-macros for wasm targets, nor did it expose the relevant target tuple for tooling like Cargo.
Why it's non-trivial
Supporting wasm proc-macros requires more than just allowing a different target:
- The build system and loader must distinguish between host and wasm proc-macros.
- The correct target triple and file search paths must be wired through the compiler.
- The system must be opt-in and backwards-compatible, as the feature is unstable and not all metadata/ABI support is present.
- Tooling (like Cargo) needs a way to query the correct wasm proc-macro target.
The approach
Exposing the wasm proc-macro target tuple
A new --print option is added to expose the wasm proc-macro target tuple:
+ WasmProcMacroTuple,
This adds a new variant to the PrintKind enum.
+ WasmProcMacroTuple => println_info!("{}", sess.wasm_proc_macro_tuple),
This enables rustc --print=wasm-proc-macro-tuple to print the tuple, which is needed for future Cargo integration.
Wiring up the wasm proc-macro target and filesearch
New fields are added to the Session struct to store the wasm proc-macro target and its tuple:
+ pub wasm_proc_macro_tuple: TargetTuple,
+ pub wasm_proc_macro_target: Target,
...
+ wasm_proc_macro_filesearch: Option<Arc<FileSearch>>,
These are initialized in build_session:
+ let wasm_proc_macro_tuple = TargetTuple::from_tuple("wasm32-wasip2");
+ let (wasm_proc_macro_target, target_warnings) = Target::search(
+ &wasm_proc_macro_tuple,
+ sopts.sysroot.path(),
+ sopts.unstable_opts.unstable_options,
+ )
...
+ let wasm_proc_macro_filesearch = if sopts.unstable_opts.wasm_proc_macros {
+ Some(Arc::new(FileSearch::new(
+ &sopts.search_paths,
+ &wasm_proc_macro_tlib_path,
+ &wasm_proc_macro_target,
+ sopts.unstable_opts.implicit_sysroot_deps,
+ )))
+ } else {
+ None
+ };
This ensures that, when the unstable option is enabled, the session has the correct target and file search paths for wasm proc-macros.
Allowing proc-macros to be built for the wasm target
The default restriction that prevents building proc-macros for non-host targets is relaxed for wasm when the unstable option is enabled:
+ if crate_type == CrateType::ProcMacro {
+ if sess.opts.target_triple == sess.wasm_proc_macro_tuple
+ && sess.opts.unstable_opts.wasm_proc_macros
+ {
+ return false;
+ }
+ }
This means rustc will not reject building a proc-macro for the wasm target if the option is set.
Locating wasm proc-macros
The crate locator is updated to support searching for wasm proc-macros:
+ pub(crate) fn for_wasm_proc_macro(&mut self, sess: &'a Session, path_kind: PathKind) {
+ self.is_proc_macro = true;
+ self.target = &sess.wasm_proc_macro_target;
+ self.tuple = sess.wasm_proc_macro_tuple.clone();
+ self.filesearch = sess.wasm_proc_macro_filesearch();
+ self.path_kind = path_kind;
+ }
This function configures the locator to search for wasm proc-macros using the correct target and search paths.
+ } else if sess.opts.unstable_opts.wasm_proc_macros {
+ // Load the proc macro crate for wasm
+ proc_macro_locator.for_wasm_proc_macro(sess, path_kind);
+
+ match self.load(&mut proc_macro_locator, &mut CrateRejections::default())? {
+ Some(host_result) => Ok(Some((host_result, None))),
+ None => Ok(None),
+ }
+ } else {
+ Ok(None)
+ }
If the unstable option is set and loading the host proc-macro fails, rustc will attempt to locate a wasm proc-macro instead.
Updating compiletest for wasm proc-macro file naming
Test infrastructure is updated to expect .wasm files for wasm proc-macros:
+ AuxType::ProcMacro if wasm_proc_macros => Some(format!("{name}.wasm")),
This ensures tests for wasm proc-macros look for the correct file extension.
Documentation and help output
A new unstable book page documents the new print option, and help output is updated to mention it.
+ <all-target-specs-json|...|wasm-proc-macro-tuple>.
From the review thread
bjorn3: I've added
--print wasm-proc-macro-tupleas preparation for future cargo support for-Zwasm-proc-macros.
bjorn3: These changes are based on my wasip1 PR and I have rebased that PR on top of this. It should work just fine for wasip2 too though.
Takeaways
- When introducing new target-specific features, expose configuration and query points (like
--print) for toolchain integration and future-proofing. - Backwards compatibility and opt-in gating are essential when adding unstable or experimental features to a compiler.
- Updating test infrastructure and documentation is necessary to support new targets and file formats, ensuring smooth developer experience and CI coverage.