diff --git a/rust/private/rustc.bzl b/rust/private/rustc.bzl index ad84f1066f..dfd767c738 100644 --- a/rust/private/rustc.bzl +++ b/rust/private/rustc.bzl @@ -1193,6 +1193,18 @@ def construct_arguments( rustc_flags.add("--remap-path-prefix=${{output_base}}={}".format(remap_path_prefix)) rustc_flags.add("--remap-path-prefix=${{pwd}}={}".format(remap_path_prefix)) rustc_flags.add("--remap-path-prefix=${{exec_root}}={}".format(remap_path_prefix)) + if not crate_info.root.is_source: + # Also remap the relative bazel-out//bin/ prefix. + # file!(), Location::caller(), and tracing/log macros embed + # the literal relative path that rustc received on the command + # line. The ${pwd} remap above only matches absolute paths in + # debug info, so a second remap without ${pwd} is needed to + # strip the bin-dir prefix from these compile-time paths. + # + # Use add_all with the crate root File and a map_each callback + # so Bazel's path mapping (--experimental_output_paths=strip) + # can rewrite the config portion of the bin-dir prefix. + rustc_flags.add_all([crate_info.root], map_each = _get_bin_dir_remap_prefix) emit_without_paths = [] for kind in emit: @@ -2706,6 +2718,25 @@ def _add_native_link_flags( format_each = "-lstatic=%s", ) +def _get_bin_dir_remap_prefix(file): + """Derives a --remap-path-prefix flag that strips the bin-dir prefix. + + For a generated file, file.path is "bazel-out//bin//" + and file.short_path is "/". The difference is the bin-dir + prefix that needs to be stripped from file!() and similar macros. + + Using the File object with add_all/map_each lets Bazel apply path mapping + (--experimental_output_paths=strip) to the config portion of the path. + + Args: + file (File): The crate root file (must be a generated file). + + Returns: + str: A --remap-path-prefix flag that maps the bin-dir prefix to empty. + """ + prefix = file.path[:len(file.path) - len(file.short_path)] + return "--remap-path-prefix={}=".format(prefix) + def _get_dirname(file): """A helper function for `_add_native_link_flags`. diff --git a/test/unit/remap_path_prefix/BUILD.bazel b/test/unit/remap_path_prefix/BUILD.bazel index fa77ac8256..bbdb4e9fb5 100644 --- a/test/unit/remap_path_prefix/BUILD.bazel +++ b/test/unit/remap_path_prefix/BUILD.bazel @@ -1,3 +1,4 @@ +load("@bazel_skylib//rules:write_file.bzl", "write_file") 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") @@ -37,6 +38,32 @@ rust_test( deps = ["//rust/runfiles"], ) +# Library with generated source to trigger transform_sources(). +# Exposes file!() so a runtime test can verify the path is clean. +write_file( + name = "remap_file_macro_lib_src", + out = "remap_file_macro_lib.rs", + content = [ + "pub fn get_file_path() -> &'static str {", + " file!()", + "}", + "", + ], +) + +rust_library( + name = "remap_file_macro_lib", + srcs = [":remap_file_macro_lib.rs"], + edition = "2021", +) + +rust_test( + name = "file_macro_test", + srcs = ["file_macro_test.rs"], + edition = "2021", + deps = [":remap_file_macro_lib"], +) + remap_path_prefix_test_suite( name = "remap_path_prefix_test_suite", ) diff --git a/test/unit/remap_path_prefix/file_macro_test.rs b/test/unit/remap_path_prefix/file_macro_test.rs new file mode 100644 index 0000000000..b79cb6c0a4 --- /dev/null +++ b/test/unit/remap_path_prefix/file_macro_test.rs @@ -0,0 +1,8 @@ +#[test] +fn file_macro_has_no_bazel_out_prefix() { + let path = remap_file_macro_lib::get_file_path(); + assert!( + !path.contains("bazel-out"), + "file!() should not contain 'bazel-out' prefix, got: {path}", + ); +} diff --git a/test/unit/remap_path_prefix/remap_path_prefix_test.bzl b/test/unit/remap_path_prefix/remap_path_prefix_test.bzl index a5e4d6728c..a0b4919e89 100644 --- a/test/unit/remap_path_prefix/remap_path_prefix_test.bzl +++ b/test/unit/remap_path_prefix/remap_path_prefix_test.bzl @@ -6,6 +6,9 @@ load("//rust:defs.bzl", "rust_binary", "rust_library") load( "//test/unit:common.bzl", "assert_action_mnemonic", + "assert_argv_contains", + "assert_argv_contains_prefix_not", + "assert_argv_contains_prefix_suffix", "assert_list_contains_adjacent_elements", ) @@ -26,6 +29,38 @@ def _remap_path_prefix_test_impl(ctx): _remap_path_prefix_test = analysistest.make(_remap_path_prefix_test_impl) +def _remap_path_prefix_source_test_impl(ctx): + """Verify that source targets do NOT get the relative bin-dir remap.""" + 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}=.") + assert_argv_contains_prefix_not(env, action, "--remap-path-prefix=bazel-out/") + + return analysistest.end(env) + +_remap_path_prefix_source_test = analysistest.make(_remap_path_prefix_source_test_impl) + +def _remap_file_macro_generated_test_impl(ctx): + """Verify that generated-source targets get a relative bin-dir remap for file!().""" + env = analysistest.begin(ctx) + target = analysistest.target_under_test(env) + + action = target.actions[0] + assert_action_mnemonic(env, action, "Rustc") + + # Should have the relative bin-dir remap (e.g. --remap-path-prefix=bazel-out/k8-fastbuild/bin/=) + assert_argv_contains_prefix_suffix(env, action, "--remap-path-prefix=bazel-out/", "/bin/=") + + return analysistest.end(env) + +_remap_file_macro_generated_test = analysistest.make(_remap_file_macro_generated_test_impl) + def _subst_flags_test_impl(ctx): """Verify that process wrapper --subst flags are present.""" env = analysistest.begin(ctx) @@ -88,6 +123,23 @@ def remap_path_prefix_test_suite(name): target_under_test = ":remap_bin", ) + # Verify source targets do NOT get the relative bin-dir remap. + _remap_path_prefix_source_test( + name = "remap_path_prefix_source_lib_test", + target_under_test = ":dep", + ) + + # Verify generated-source targets get the relative bin-dir remap for file!(). + _remap_file_macro_generated_test( + name = "remap_file_macro_generated_lib_test", + target_under_test = ":remap_lib", + ) + + _remap_file_macro_generated_test( + name = "remap_file_macro_generated_bin_test", + target_under_test = ":remap_bin", + ) + _subst_flags_test( name = "subst_flags_lib_test", target_under_test = ":remap_lib", @@ -101,6 +153,9 @@ def remap_path_prefix_test_suite(name): tests = [ ":remap_path_prefix_lib_test", ":remap_path_prefix_bin_test", + ":remap_path_prefix_source_lib_test", + ":remap_file_macro_generated_lib_test", + ":remap_file_macro_generated_bin_test", ":subst_flags_lib_test", ":subst_flags_bin_test", ]