From 293d600000a2a159eaae9bf86af538d1cdbc739f Mon Sep 17 00:00:00 2001 From: Deepesh Varatharajan Date: Tue, 14 Jul 2026 09:26:13 -0700 Subject: [PATCH] bootstrap: add RUSTC_EXTRA_REMAP for reproducible host builds Right now, `rust.remap-debuginfo = true` doesn't completely remap all paths embedded in compiled artifacts. While source directories are remapped via RUSTC_DEBUGINFO_MAP (to `/rustc/$sha` for compiler sources, virtual paths for std) and Cargo registry sources are remapped via RUSTC_CARGO_REGISTRY_SRC_TO_REMAP (to `/rust/deps`), the build output directory is not remapped for host compilations. The existing remapping coverage: RUSTC_DEBUGINFO_MAP: - compiler/ -> /rustc-dev/$sha/compiler - $src_dir -> /rustc-dev/$sha - library/ -> /rustc/$sha/library RUSTC_CARGO_REGISTRY_SRC_TO_REMAP: - $CARGO_HOME/registry/src/* -> /rust/deps RUSTFLAGS (via Cargo): - Covers --remap-path-prefix for target compilations only What is NOT covered: Build output directories (where OUT_DIR lives) for host compilations. Cargo only passes RUSTFLAGS to target builds (see cargo issue 4423). The bootstrap rustc shim only passes RUSTC_HOST_FLAGS (linker args) and RUSTC_DEBUGINFO_MAP (source paths) to host builds. There is no mechanism to remap the build output directory for host compilations. This matters because crates like `thiserror` and `rustc_macros` use build scripts that generate source files in OUT_DIR via `include!()`. The absolute OUT_DIR path (e.g., build/x86_64-.../stage0-rustc//out/) gets embedded into the crate's SVH (Strict Version Hash). With -Zdual-proc-macros enabled during cross-compilation, host proc macros carry these unremapped paths, causing the SVH to differ between builds with different build directories. This cascades into rustc_driver and other final artifacts, breaking reproducibility. Fix this by adding support for a RUSTC_EXTRA_REMAP environment variable in the rustc shim. Like RUSTC_DEBUGINFO_MAP and RUSTC_CARGO_REGISTRY_SRC_TO_REMAP, it uses tab-separated `from=to` mappings and applies `--remap-path-prefix` to all compilations (both host and target). This allows external build systems to remap paths that bootstrap doesn't know about (such as out-of-tree build directories used in cross-compilation environments like Yocto/OpenEmbedded and Nix). The variable is only active when explicitly set, so it has no effect on default builds or CI. Signed-off-by: Deepesh Varatharajan --- src/bootstrap/src/bin/rustc.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/bootstrap/src/bin/rustc.rs b/src/bootstrap/src/bin/rustc.rs index c8aff10b6355b..a8e3c08729556 100644 --- a/src/bootstrap/src/bin/rustc.rs +++ b/src/bootstrap/src/bin/rustc.rs @@ -186,6 +186,18 @@ fn main() { } } + // Additional remap flags for reproducible builds, covering build output directories + // (e.g., OUT_DIR from build scripts) that are not covered by RUSTC_DEBUGINFO_MAP or + // RUSTC_CARGO_REGISTRY_SRC_TO_REMAP. Applied to both host and target compilations. + // This is needed because RUSTFLAGS remaps only apply to target compilations (Cargo + // does not pass RUSTFLAGS to host/proc-macro builds, see rust-lang/cargo#4423), + // and RUSTC_DEBUGINFO_MAP only remaps source directories, not build output paths. + if let Ok(maps) = env::var("RUSTC_EXTRA_REMAP") { + for map in maps.split('\t') { + cmd.arg("--remap-path-prefix").arg(map); + } + } + // Here we pass additional paths that essentially act as a sysroot. // These are used to load rustc crates (e.g. `extern crate rustc_ast;`) // for rustc_private tools, so that we do not have to copy them into the