Skip to content

Commit f8ada0a

Browse files
committed
Remap path prefixes for canonicalized paths
1 parent a9565ff commit f8ada0a

5 files changed

Lines changed: 193 additions & 2 deletions

File tree

rust/private/rustc.bzl

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -882,6 +882,33 @@ def _will_emit_object_file(emit):
882882
def _remove_codegen_units(flag):
883883
return None if flag.startswith("-Ccodegen-units") else flag
884884

885+
def _should_add_oso_prefix(feature_configuration, ld_is_direct_driver, toolchain):
886+
"""Whether to add -oso_prefix to strip absolute paths from N_OSO entries.
887+
888+
On macOS, ld64 embeds absolute paths in N_OSO stab entries which breaks
889+
build reproducibility. The -oso_prefix flag strips a prefix from these
890+
entries. This function gates the flag on linker support.
891+
892+
Args:
893+
feature_configuration (FeatureConfiguration): Feature configuration to be queried.
894+
ld_is_direct_driver (bool): Whether the linker is invoked directly (e.g. rust-lld).
895+
toolchain (rust_toolchain): The current Rust toolchain.
896+
897+
Returns:
898+
bool: True if -oso_prefix should be added.
899+
"""
900+
if not toolchain.target_os.startswith(("mac", "darwin", "ios")):
901+
return False
902+
903+
if not ld_is_direct_driver:
904+
return feature_configuration and cc_common.is_enabled(
905+
feature_configuration = feature_configuration,
906+
feature_name = "oso_prefix_is_pwd",
907+
)
908+
909+
# lld-macho has supported -oso_prefix since LLVM 14 (2021).
910+
return True
911+
885912
def construct_arguments(
886913
*,
887914
ctx,
@@ -938,7 +965,9 @@ def construct_arguments(
938965
include_link_flags (bool, optional): Whether to include flags like `-l` that instruct the linker to search for a library.
939966
stamp (bool, optional): Whether or not workspace status stamping is enabled. For more details see
940967
https://docs.bazel.build/versions/main/user-manual.html#flag--stamp
941-
remap_path_prefix (str, optional): A value used to remap `${pwd}` to. If set to None, no prefix will be set.
968+
remap_path_prefix (str, optional): A value used to remap `${pwd}`, `${exec_root}`, and `${output_base}` to.
969+
If set to None, no remapping will be applied. On macOS, also adds `-oso_prefix` to strip absolute paths
970+
from N_OSO linker entries.
942971
use_json_output (bool): Have rustc emit json and process_wrapper parse json messages to output rendered output.
943972
build_metadata (bool): Generate CLI arguments for building *only* .rmeta files. This requires use_json_output.
944973
force_depend_on_objects (bool): Force using `.rlib` object files instead of metadata (`.rmeta`) files even if they are available.
@@ -988,6 +1017,8 @@ def construct_arguments(
9881017
# Since we cannot get the `exec_root` from starlark, we cheat a little and
9891018
# use `${pwd}` which resolves the `exec_root` at action execution time.
9901019
process_wrapper_flags.add("--subst", "pwd=${pwd}")
1020+
process_wrapper_flags.add("--subst", "exec_root=${exec_root}")
1021+
process_wrapper_flags.add("--subst", "output_base=${output_base}")
9911022

9921023
# If stamping is enabled, enable the functionality in the process wrapper
9931024
if stamp:
@@ -1075,6 +1106,8 @@ def construct_arguments(
10751106
# For determinism to help with build distribution and such
10761107
if remap_path_prefix != None:
10771108
rustc_flags.add("--remap-path-prefix=${{pwd}}={}".format(remap_path_prefix))
1109+
rustc_flags.add("--remap-path-prefix=${{exec_root}}={}".format(remap_path_prefix))
1110+
rustc_flags.add("--remap-path-prefix=${{output_base}}={}".format(remap_path_prefix))
10781111

10791112
emit_without_paths = []
10801113
for kind in emit:
@@ -1139,6 +1172,17 @@ def construct_arguments(
11391172
# Additional context: https://github.com/rust-lang/rust/pull/36574
11401173
rustc_flags.add_all(link_args, format_each = "--codegen=link-arg=%s")
11411174

1175+
if remap_path_prefix != None and _should_add_oso_prefix(
1176+
feature_configuration,
1177+
ld_is_direct_driver,
1178+
toolchain,
1179+
):
1180+
if ld_is_direct_driver:
1181+
rustc_flags.add("--codegen=link-arg=-oso_prefix")
1182+
rustc_flags.add("${output_base}/", format = "--codegen=link-arg=%s")
1183+
else:
1184+
rustc_flags.add("--codegen=link-arg=-Wl,-oso_prefix,${output_base}/")
1185+
11421186
_add_native_link_flags(
11431187
rustc_flags,
11441188
dep_info,

test/unit/remap_path_prefix/BUILD.bazel

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
load("//rust:defs.bzl", "rust_binary", "rust_library", "rust_test")
22
load(":debug_transition.bzl", "dbg_rust_binary")
3+
load(":remap_path_prefix_test.bzl", "remap_path_prefix_test_suite")
34

45
rust_library(
56
name = "dep",
@@ -35,3 +36,7 @@ rust_test(
3536
},
3637
deps = ["//rust/runfiles"],
3738
)
39+
40+
remap_path_prefix_test_suite(
41+
name = "remap_path_prefix_test_suite",
42+
)
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
"""Analysis tests verifying remap_path_prefix flags."""
2+
3+
load("@bazel_skylib//lib:unittest.bzl", "analysistest")
4+
load("@bazel_skylib//rules:write_file.bzl", "write_file")
5+
load("//rust:defs.bzl", "rust_binary", "rust_library")
6+
load(
7+
"//test/unit:common.bzl",
8+
"assert_action_mnemonic",
9+
"assert_argv_contains",
10+
"assert_list_contains_adjacent_elements",
11+
)
12+
13+
def _remap_path_prefix_test_impl(ctx):
14+
env = analysistest.begin(ctx)
15+
target = analysistest.target_under_test(env)
16+
17+
action = target.actions[0]
18+
assert_action_mnemonic(env, action, "Rustc")
19+
20+
assert_argv_contains(env, action, "--remap-path-prefix=${pwd}=.")
21+
assert_argv_contains(env, action, "--remap-path-prefix=${exec_root}=.")
22+
assert_argv_contains(env, action, "--remap-path-prefix=${output_base}=.")
23+
24+
return analysistest.end(env)
25+
26+
_remap_path_prefix_test = analysistest.make(_remap_path_prefix_test_impl)
27+
28+
def _subst_flags_test_impl(ctx):
29+
"""Verify that process wrapper --subst flags are present."""
30+
env = analysistest.begin(ctx)
31+
target = analysistest.target_under_test(env)
32+
33+
action = target.actions[0]
34+
assert_action_mnemonic(env, action, "Rustc")
35+
36+
assert_list_contains_adjacent_elements(env, action.argv, ["--subst", "pwd=${pwd}"])
37+
assert_list_contains_adjacent_elements(env, action.argv, ["--subst", "exec_root=${exec_root}"])
38+
assert_list_contains_adjacent_elements(env, action.argv, ["--subst", "output_base=${output_base}"])
39+
40+
return analysistest.end(env)
41+
42+
_subst_flags_test = analysistest.make(_subst_flags_test_impl)
43+
44+
def remap_path_prefix_test_suite(name):
45+
"""Entry-point macro called from the BUILD file.
46+
47+
Args:
48+
name (str): The name of the test suite.
49+
"""
50+
write_file(
51+
name = "remap_lib_src",
52+
out = "remap_lib.rs",
53+
content = [
54+
"pub fn hello() {}",
55+
"",
56+
],
57+
)
58+
59+
rust_library(
60+
name = "remap_lib",
61+
srcs = [":remap_lib.rs"],
62+
edition = "2021",
63+
)
64+
65+
write_file(
66+
name = "remap_bin_src",
67+
out = "remap_bin.rs",
68+
content = [
69+
"fn main() {}",
70+
"",
71+
],
72+
)
73+
74+
rust_binary(
75+
name = "remap_bin",
76+
srcs = [":remap_bin.rs"],
77+
edition = "2021",
78+
)
79+
80+
_remap_path_prefix_test(
81+
name = "remap_path_prefix_lib_test",
82+
target_under_test = ":remap_lib",
83+
)
84+
85+
_remap_path_prefix_test(
86+
name = "remap_path_prefix_bin_test",
87+
target_under_test = ":remap_bin",
88+
)
89+
90+
_subst_flags_test(
91+
name = "subst_flags_lib_test",
92+
target_under_test = ":remap_lib",
93+
)
94+
95+
_subst_flags_test(
96+
name = "subst_flags_bin_test",
97+
target_under_test = ":remap_bin",
98+
)
99+
100+
tests = [
101+
":remap_path_prefix_lib_test",
102+
":remap_path_prefix_bin_test",
103+
":subst_flags_lib_test",
104+
":subst_flags_bin_test",
105+
]
106+
107+
native.test_suite(
108+
name = name,
109+
tests = tests,
110+
)

util/process_wrapper/BUILD.bazel

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ rust_binary_without_process_wrapper(
4040
# paths embedded in this section, is stripped out.
4141
rustc_flags = select({
4242
":opt_linux": ["-Cstrip=debuginfo"],
43-
":opt_macos": ["-Cstrip=debuginfo"],
43+
":opt_macos": ["-Cstrip=symbols"],
4444
"//conditions:default": [],
4545
}),
4646
visibility = ["//visibility:public"],

util/process_wrapper/options.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,34 @@ pub(crate) fn options() -> Result<Options, OptionError> {
137137
.to_str()
138138
.ok_or_else(|| OptionError::Generic("current directory not utf-8".to_owned()))?
139139
.to_owned();
140+
let output_base = {
141+
let external = std::path::Path::new(&current_dir).join("external");
142+
match std::fs::read_link(&external) {
143+
Ok(target) => target
144+
.parent()
145+
.unwrap_or(&target)
146+
.to_str()
147+
.unwrap_or(&current_dir)
148+
.to_owned(),
149+
Err(_) => {
150+
let cwd = std::path::Path::new(&current_dir);
151+
cwd.parent()
152+
.and_then(|p| p.parent())
153+
.and_then(|p| p.to_str())
154+
.unwrap_or(&current_dir)
155+
.to_owned()
156+
}
157+
}
158+
};
159+
160+
let exec_root = {
161+
let workspace_name = std::path::Path::new(&current_dir)
162+
.file_name()
163+
.and_then(|n| n.to_str())
164+
.unwrap_or("_main");
165+
format!("{}/execroot/{}", output_base, workspace_name)
166+
};
167+
140168
let subst_mappings = subst_mapping_raw
141169
.unwrap_or_default()
142170
.into_iter()
@@ -146,6 +174,10 @@ pub(crate) fn options() -> Result<Options, OptionError> {
146174
})?;
147175
let v = if val == "${pwd}" {
148176
current_dir.as_str()
177+
} else if val == "${output_base}" {
178+
output_base.as_str()
179+
} else if val == "${exec_root}" {
180+
exec_root.as_str()
149181
} else {
150182
val
151183
}

0 commit comments

Comments
 (0)