-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Description
Problem
Cargo has rustc-wrapper for wrapping rustc,
but there is no way to wrap other host executables like build scripts and proc macros.
This makes several use cases awkward or impossible:
-
Distributed builds:
Tools like distcc/sccache work as compiler wrappers that intercept invocations,
decide whether to run locally or remotely, and handle the handoff.
For build scripts, we'd want the same pattern to avoid wrapping the entirecargo
or modifying cargo source code. -
Build system integration:
Build system like Nix keeps dependencies in a read-only store for reproducibility.
Some build scripts try to write to their own source directory not just OUT_DIR,
which breaks in build sandbox (granted, they shouldn't do that in the first place).
Existing workarounds are like copying all vendored sources to a writable temp directory
before every build, or patch the build scripts directly.
This is usually expensive and not recommended (see Crane docs).
With a wrapper,
Build system could intercept the build script, redirect writes,
or fail fast with a clear error instead of subtle breakage. -
Debugging:
Build scripts buffer their output and only show it at the end.
If a build script crashes or hangs, you don't see what it was doing.
A wrapper could stream output earlier, add timestamps,
catch crashes and provide stack traces.
This gives a good playground for experimenting diferent build script output for Cargo itself. -
Environment control:
Currently you'd set env vars globally for the whole Cargo process,
which affects rustc too.
While rustc has an unstable--env-setto control whatenv!()sees,
build scripts don't have equivalent mechanisms yet. -
Process isolation (i.e., sandboxing:
Tools like bubblewrap or seccomp filters can restrict filesystem/network access.
Without a wrapper, you'd need to wrap the entirecargoprocess which affects rustc too.
A wrapper lets you apply restrictions per build script.
Context
The Cargo team has discussed full sandboxing of build scripts and proc-macros multiple times.
The general consensus has been that built-in sandboxing is likely out of scope for Cargo at this moment,
due to its complexity and hard to satisfy different needs with a single solution.
The focus right now be on reducing reliance on build scripts and making them easier to audit.
In a recent Cargo team discussion https://github.com/rust-lang/cargo-team/blob/0cf1414e1012445262a335a6b1c2b11983d31639/meetings/sync-meeting/2026-01-20.md#build-script-wrapper,
the team agreed with a host runner unstable feature to offer a low-level hook for experimentation.
External tools can try different approaches without Cargo committing to any particular design.
Proposed Solution
Add host.runner config that wraps host build targets like build scripts during the build
This follows the existing pattern of [host] config,
which currently supports linker and rustflags.
It is similar to how target.<triple>.runner works for cargo test/cargo run executables
but for host build targets.
Config example:
[host]
runner = ["wrapper", "--custom-flag"]Invocation:
wrapper --custom-flag <actual-build-script-executable> <args...>
The goal is to enable experimentation,
not to commit to stabilizing the current design.
Different use cases may need different APIs,
and we should gather real-world feedback before deciding what to stabilize,
or different features for different use cases
For example, we might want first-class support for distributed builds to avoid process-forking cost.
Implementation plan
This can reuse the existing -Zhost-config unstable feature.
The infrastructure is already in place:
TargetConfigstruct has arunnerfieldload_host_triple()already loads[host]config includingrunnerbut unused[host]already applies to build scripts and proc-macros
Main work needed:
- Add tests documenting the current behavior
- In
custom_build.rs, usehost.runnerwhen executing build scripts, and update test snapshots. - Update unstable documentation for
-Zhost-config - Announce in #t-cargo/build-integration for tools to start experiment
Limitations
- Proc-macro wrapping:
Proc-macros can't be wrapped by Cargo, as they're loaded and executed by rustc directly.
This can still establish patterns for future rustc changes.
Related issues
- Add the ability to provide build flags for the build-script-build #3349
- Cargo should support explicitly specifying a host target for build scripts #3915
- There is no way to set RUSTFLAGS for build scripts (or proc macros) when cross-compiling #4423
- Sanitize environment variables for build scripts #5282
- Sandbox/jail build scripts #5720
- Provide a way to specify configuration for host compilation #5754
- Indicate to build scripts that the crate they are being run for is being built for the host #5755
- REAPI (Google/Bazel Remote Execution API) Support #7468
- Tracking Issue for host-config #9452
- Tracking Issue for target-applies-to-host #9453
- Build script allowlist mode #13681
- Tell
rustcwrappers which envs to pass through to allow env sandboxing #14444 - idea on how to get sandboxed build-scripts #15672
- Set
TMPDIRfor build scripts andrustc#16427 - Build-time execution sandboxing compiler-team#475
- feat(sandbox): add -Zsandbox unstable flag weihanglo/cargo#66