Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions rust/private/rustc.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -1022,11 +1022,21 @@ def construct_arguments(

# Both ctx.label.workspace_root and ctx.label.package are relative paths
# and either can be empty strings. Avoid trailing/double slashes in the path.
components = "${{pwd}}/{}/{}".format(ctx.label.workspace_root, ctx.label.package).split("/")
#
# Use ${exec_root} (sandbox-invariant absolute path to Bazel's real execroot)
# instead of ${pwd} here. Under sandboxed execution every rustc action runs
# in its own per-pid sandbox cwd, so ${pwd} resolves to a different absolute
# string for each action. rustc's env!() macro bakes the raw string into the
# compiled crate and hashes it into the SVH; --remap-path-prefix does not
# normalize env!() values. Result: nondeterministic SVHs for crates that do
# `PathBuf::from(env!("OUT_DIR"))` (e.g. pyo3-build-config), breaking
# pipelined compilation (full/hollow rlib SVHs diverge) and poisoning the
# remote/disk cache.
components = "${{exec_root}}/{}/{}".format(ctx.label.workspace_root, ctx.label.package).split("/")
env["CARGO_MANIFEST_DIR"] = "/".join([c for c in components if c])

if out_dir != None:
env["OUT_DIR"] = "${pwd}/" + out_dir
env["OUT_DIR"] = "${exec_root}/" + out_dir

# Arguments for launching rustc from the process wrapper
rustc_path = ctx.actions.args()
Expand Down
21 changes: 19 additions & 2 deletions util/process_wrapper/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,12 @@ pub(crate) fn options() -> Result<Options, OptionError> {
.to_str()
.ok_or_else(|| OptionError::Generic("current directory not utf-8".to_owned()))?
.to_owned();
// ${output_base} has historically resolved to the sandbox's local cwd
// (parent of canonicalized `cwd/external`) rather than Bazel's real output_base.
// Downstream consumers — in particular the `--remap-path-prefix=${output_base}=.`
// flag emitted by rules_rust — rely on that sandbox-local value to fully
// strip the sandbox cwd prefix from paths embedded in rmeta/debuginfo.
// Leaving ${output_base} untouched preserves that behavior.
let output_base = {
let external = std::path::Path::new(&current_dir).join("external");
match std::fs::canonicalize(external) {
Expand All @@ -157,12 +163,23 @@ pub(crate) fn options() -> Result<Options, OptionError> {
}
};

// ${exec_root} resolves to Bazel's real execroot, sandbox-invariant across
// all strategies. Derived by walking up `cwd` to the first ancestor that
// contains Bazel's `DO_NOT_BUILD_HERE` sentinel file (the real output_base)
// and appending `execroot/<workspace_name>`. Used by rules_rust to set
// `CARGO_MANIFEST_DIR` / `OUT_DIR` to a sandbox-invariant absolute path so
// that `env!()` values baked into SVH are identical across pipelined
// Rustc / RustcMetadata actions and across independent invocations.
let exec_root = {
let workspace_name = std::path::Path::new(&current_dir)
let cwd_path = std::path::Path::new(&current_dir);
let workspace_name = cwd_path
.file_name()
.and_then(|n| n.to_str())
.unwrap_or("_main");
format!("{}/execroot/{}", output_base, workspace_name)
match incremental_cache::find_output_base(cwd_path) {
Some(real_ob) => format!("{}/execroot/{}", real_ob.to_string_lossy(), workspace_name),
None => format!("{}/execroot/{}", output_base, workspace_name),
}
};

let subst_mappings = subst_mapping_raw
Expand Down