Skip to content
Draft
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
46 changes: 45 additions & 1 deletion rust/private/rustc.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -882,6 +882,33 @@ def _will_emit_object_file(emit):
def _remove_codegen_units(flag):
return None if flag.startswith("-Ccodegen-units") else flag

def _should_add_oso_prefix(feature_configuration, ld_is_direct_driver, toolchain):
"""Whether to add -oso_prefix to strip absolute paths from N_OSO entries.

On macOS, ld64 embeds absolute paths in N_OSO stab entries which breaks
build reproducibility. The -oso_prefix flag strips a prefix from these
entries. This function gates the flag on linker support.

Args:
feature_configuration (FeatureConfiguration): Feature configuration to be queried.
ld_is_direct_driver (bool): Whether the linker is invoked directly (e.g. rust-lld).
toolchain (rust_toolchain): The current Rust toolchain.

Returns:
bool: True if -oso_prefix should be added.
"""
if not toolchain.target_os.startswith(("mac", "darwin", "ios")):
return False

if not ld_is_direct_driver:
return feature_configuration and cc_common.is_enabled(
feature_configuration = feature_configuration,
feature_name = "oso_prefix_is_pwd",
)

# lld-macho has supported -oso_prefix since LLVM 14 (2021).
return True

def construct_arguments(
*,
ctx,
Expand Down Expand Up @@ -938,7 +965,9 @@ def construct_arguments(
include_link_flags (bool, optional): Whether to include flags like `-l` that instruct the linker to search for a library.
stamp (bool, optional): Whether or not workspace status stamping is enabled. For more details see
https://docs.bazel.build/versions/main/user-manual.html#flag--stamp
remap_path_prefix (str, optional): A value used to remap `${pwd}` to. If set to None, no prefix will be set.
remap_path_prefix (str, optional): A value used to remap `${pwd}`, `${exec_root}`, and `${output_base}` to.
If set to None, no remapping will be applied. On macOS, also adds `-oso_prefix` to strip absolute paths
from N_OSO linker entries.
use_json_output (bool): Have rustc emit json and process_wrapper parse json messages to output rendered output.
build_metadata (bool): Generate CLI arguments for building *only* .rmeta files. This requires use_json_output.
force_depend_on_objects (bool): Force using `.rlib` object files instead of metadata (`.rmeta`) files even if they are available.
Expand Down Expand Up @@ -988,6 +1017,8 @@ def construct_arguments(
# Since we cannot get the `exec_root` from starlark, we cheat a little and
# use `${pwd}` which resolves the `exec_root` at action execution time.
process_wrapper_flags.add("--subst", "pwd=${pwd}")
process_wrapper_flags.add("--subst", "exec_root=${exec_root}")
process_wrapper_flags.add("--subst", "output_base=${output_base}")

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

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

if remap_path_prefix != None and _should_add_oso_prefix(
feature_configuration,
ld_is_direct_driver,
toolchain,
):
if ld_is_direct_driver:
rustc_flags.add("--codegen=link-arg=-oso_prefix")
rustc_flags.add("${output_base}/", format = "--codegen=link-arg=%s")
else:
rustc_flags.add("--codegen=link-arg=-Wl,-oso_prefix,${output_base}/")

_add_native_link_flags(
rustc_flags,
dep_info,
Expand Down
5 changes: 5 additions & 0 deletions test/unit/remap_path_prefix/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
load("//rust:defs.bzl", "rust_binary", "rust_library", "rust_test")
load(":debug_transition.bzl", "dbg_rust_binary")
load(":remap_path_prefix_test.bzl", "remap_path_prefix_test_suite")

rust_library(
name = "dep",
Expand Down Expand Up @@ -35,3 +36,7 @@ rust_test(
},
deps = ["//rust/runfiles"],
)

remap_path_prefix_test_suite(
name = "remap_path_prefix_test_suite",
)
110 changes: 110 additions & 0 deletions test/unit/remap_path_prefix/remap_path_prefix_test.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
"""Analysis tests verifying remap_path_prefix flags."""

load("@bazel_skylib//lib:unittest.bzl", "analysistest")
load("@bazel_skylib//rules:write_file.bzl", "write_file")
load("//rust:defs.bzl", "rust_binary", "rust_library")
load(
"//test/unit:common.bzl",
"assert_action_mnemonic",
"assert_argv_contains",
"assert_list_contains_adjacent_elements",
)

def _remap_path_prefix_test_impl(ctx):
env = analysistest.begin(ctx)
target = analysistest.target_under_test(env)

action = target.actions[0]
assert_action_mnemonic(env, action, "Rustc")

assert_argv_contains(env, action, "--remap-path-prefix=${pwd}=.")
assert_argv_contains(env, action, "--remap-path-prefix=${exec_root}=.")
assert_argv_contains(env, action, "--remap-path-prefix=${output_base}=.")

return analysistest.end(env)

_remap_path_prefix_test = analysistest.make(_remap_path_prefix_test_impl)

def _subst_flags_test_impl(ctx):
"""Verify that process wrapper --subst flags are present."""
env = analysistest.begin(ctx)
target = analysistest.target_under_test(env)

action = target.actions[0]
assert_action_mnemonic(env, action, "Rustc")

assert_list_contains_adjacent_elements(env, action.argv, ["--subst", "pwd=${pwd}"])
assert_list_contains_adjacent_elements(env, action.argv, ["--subst", "exec_root=${exec_root}"])
assert_list_contains_adjacent_elements(env, action.argv, ["--subst", "output_base=${output_base}"])

return analysistest.end(env)

_subst_flags_test = analysistest.make(_subst_flags_test_impl)

def remap_path_prefix_test_suite(name):
"""Entry-point macro called from the BUILD file.

Args:
name (str): The name of the test suite.
"""
write_file(
name = "remap_lib_src",
out = "remap_lib.rs",
content = [
"pub fn hello() {}",
"",
],
)

rust_library(
name = "remap_lib",
srcs = [":remap_lib.rs"],
edition = "2021",
)

write_file(
name = "remap_bin_src",
out = "remap_bin.rs",
content = [
"fn main() {}",
"",
],
)

rust_binary(
name = "remap_bin",
srcs = [":remap_bin.rs"],
edition = "2021",
)

_remap_path_prefix_test(
name = "remap_path_prefix_lib_test",
target_under_test = ":remap_lib",
)

_remap_path_prefix_test(
name = "remap_path_prefix_bin_test",
target_under_test = ":remap_bin",
)

_subst_flags_test(
name = "subst_flags_lib_test",
target_under_test = ":remap_lib",
)

_subst_flags_test(
name = "subst_flags_bin_test",
target_under_test = ":remap_bin",
)

tests = [
":remap_path_prefix_lib_test",
":remap_path_prefix_bin_test",
":subst_flags_lib_test",
":subst_flags_bin_test",
]

native.test_suite(
name = name,
tests = tests,
)
2 changes: 1 addition & 1 deletion util/process_wrapper/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ rust_binary_without_process_wrapper(
# paths embedded in this section, is stripped out.
rustc_flags = select({
":opt_linux": ["-Cstrip=debuginfo"],
":opt_macos": ["-Cstrip=debuginfo"],
":opt_macos": ["-Cstrip=symbols"],
"//conditions:default": [],
}),
visibility = ["//visibility:public"],
Expand Down
32 changes: 32 additions & 0 deletions util/process_wrapper/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,34 @@ pub(crate) fn options() -> Result<Options, OptionError> {
.to_str()
.ok_or_else(|| OptionError::Generic("current directory not utf-8".to_owned()))?
.to_owned();
let output_base = {
let external = std::path::Path::new(&current_dir).join("external");
match std::fs::read_link(&external) {
Ok(target) => target
.parent()
.unwrap_or(&target)
.to_str()
.unwrap_or(&current_dir)
.to_owned(),
Err(_) => {
let cwd = std::path::Path::new(&current_dir);
cwd.parent()
.and_then(|p| p.parent())
.and_then(|p| p.to_str())
.unwrap_or(&current_dir)
.to_owned()
}
}
};

let exec_root = {
let workspace_name = std::path::Path::new(&current_dir)
.file_name()
.and_then(|n| n.to_str())
.unwrap_or("_main");
format!("{}/execroot/{}", output_base, workspace_name)
};

let subst_mappings = subst_mapping_raw
.unwrap_or_default()
.into_iter()
Expand All @@ -146,6 +174,10 @@ pub(crate) fn options() -> Result<Options, OptionError> {
})?;
let v = if val == "${pwd}" {
current_dir.as_str()
} else if val == "${output_base}" {
output_base.as_str()
} else if val == "${exec_root}" {
exec_root.as_str()
} else {
val
}
Expand Down
Loading