From dc8754c12f8852fafbf77ca95760a8c3e8bc68fe Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Tue, 5 May 2026 08:00:54 +0000 Subject: [PATCH 1/4] Fix --remap-path-prefix for targets with generated sources When transform_sources() symlinks source files into bazel-out//bin (due to mixed generated and non-generated sources), the crate root path starts with ctx.bin_dir.path. The existing --remap-path-prefix=${pwd}=. only strips the exec root, leaving bazel-out/.../bin/ in diagnostics, file!(), panic locations, and backtraces. Use crate_info.root.is_source to detect symlinked sources and remap ${pwd}/ instead, producing clean workspace-relative paths. Apply the same fix to ${exec_root} and macOS -oso_prefix. Update analysis tests to cover both source and generated-source cases. --- rust/private/rustc.bzl | 28 ++++++-- .../remap_path_prefix_test.bzl | 68 +++++++++++++------ 2 files changed, 72 insertions(+), 24 deletions(-) diff --git a/rust/private/rustc.bzl b/rust/private/rustc.bzl index ad84f1066f..8bce8a94bc 100644 --- a/rust/private/rustc.bzl +++ b/rust/private/rustc.bzl @@ -1185,14 +1185,33 @@ def construct_arguments( rustc_flags.add(compilation_mode.strip_level, format = "--codegen=strip=%s") # For determinism to help with build distribution and such + # + # --remap-path-prefix tells rustc to replace a path prefix in all output + # (diagnostics, file!(), panic locations, backtraces) so that absolute + # sandbox paths never leak into binaries or logs. + # + # When all sources are plain workspace files, remapping ${pwd} (the exec + # root) to remap_path_prefix (default ".") is enough. + # + # However, when a target mixes generated and non-generated sources (e.g. + # proto compile_data), transform_sources() symlinks every source file into + # bazel-out//bin/... so they sit next to the generated files. In + # that case the crate root is no longer a source file and its path starts + # with ctx.bin_dir.path (e.g. "bazel-out/k8-fastbuild/bin"). We detect + # this via crate_info.root.is_source and add a more specific remap that + # also strips the bin-dir component, giving clean workspace-relative paths. if remap_path_prefix != None: # `--remap-path-prefix` flags are applied in reverse order. We need to # specify the outermost directory (output_base) first, so that it's # remapped last. Otherwise we can end up with a partial rewrite where # "/path/to/output_base/execroot" becomes "./execroot" rather than ".". 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 crate_info.root.is_source: + rustc_flags.add("--remap-path-prefix=${{pwd}}={}".format(remap_path_prefix)) + rustc_flags.add("--remap-path-prefix=${{exec_root}}={}".format(remap_path_prefix)) + else: + rustc_flags.add("--remap-path-prefix=${{pwd}}/{}={}".format(ctx.bin_dir.path, remap_path_prefix)) + rustc_flags.add("--remap-path-prefix=${{exec_root}}/{}={}".format(ctx.bin_dir.path, remap_path_prefix)) emit_without_paths = [] for kind in emit: @@ -1288,11 +1307,12 @@ def construct_arguments( if remap_path_prefix != None and _should_add_oso_prefix( toolchain, ): + oso_prefix = "${pwd}/" if crate_info.root.is_source else "${pwd}/" + ctx.bin_dir.path + "/" if ld_is_direct_driver: rustc_flags.add("--codegen=link-arg=-oso_prefix") - rustc_flags.add("${pwd}/", format = "--codegen=link-arg=%s") + rustc_flags.add(oso_prefix, format = "--codegen=link-arg=%s") else: - rustc_flags.add("--codegen=link-arg=-Wl,-oso_prefix,${pwd}/") + rustc_flags.add("--codegen=link-arg=-Wl,-oso_prefix," + oso_prefix) _add_native_link_flags( rustc_flags, 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..c7a312a02f 100644 --- a/test/unit/remap_path_prefix/remap_path_prefix_test.bzl +++ b/test/unit/remap_path_prefix/remap_path_prefix_test.bzl @@ -9,7 +9,8 @@ load( "assert_list_contains_adjacent_elements", ) -def _remap_path_prefix_test_impl(ctx): +def _remap_path_prefix_source_test_impl(ctx): + """Verify remap flags for targets with plain source files.""" env = analysistest.begin(ctx) target = analysistest.target_under_test(env) @@ -24,7 +25,23 @@ def _remap_path_prefix_test_impl(ctx): return analysistest.end(env) -_remap_path_prefix_test = analysistest.make(_remap_path_prefix_test_impl) +_remap_path_prefix_source_test = analysistest.make(_remap_path_prefix_source_test_impl) + +def _remap_path_prefix_generated_test_impl(ctx): + """Verify remap flags for targets with generated sources (symlinked into bin dir).""" + 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}/bazel-out/k8-fastbuild/bin=.") + assert_argv_contains(env, action, "--remap-path-prefix=${exec_root}/bazel-out/k8-fastbuild/bin=.") + assert_argv_contains(env, action, "--remap-path-prefix=${output_base}=.") + + return analysistest.end(env) + +_remap_path_prefix_generated_test = analysistest.make(_remap_path_prefix_generated_test_impl) def _subst_flags_test_impl(ctx): """Verify that process wrapper --subst flags are present.""" @@ -48,9 +65,12 @@ def remap_path_prefix_test_suite(name): Args: name (str): The name of the test suite. """ + + # Targets with generated sources (write_file produces non-source files, + # triggering transform_sources which symlinks into bin dir). write_file( - name = "remap_lib_src", - out = "remap_lib.rs", + name = "remap_lib_generated_src", + out = "remap_lib_generated.rs", content = [ "pub fn hello() {}", "", @@ -58,14 +78,14 @@ def remap_path_prefix_test_suite(name): ) rust_library( - name = "remap_lib", - srcs = [":remap_lib.rs"], + name = "remap_lib_generated", + srcs = [":remap_lib_generated.rs"], edition = "2021", ) write_file( - name = "remap_bin_src", - out = "remap_bin.rs", + name = "remap_bin_generated_src", + out = "remap_bin_generated.rs", content = [ "fn main() {}", "", @@ -73,34 +93,42 @@ def remap_path_prefix_test_suite(name): ) rust_binary( - name = "remap_bin", - srcs = [":remap_bin.rs"], + name = "remap_bin_generated", + srcs = [":remap_bin_generated.rs"], edition = "2021", ) - _remap_path_prefix_test( - name = "remap_path_prefix_lib_test", - target_under_test = ":remap_lib", + # Tests for plain source files (using existing dep.rs from the package). + _remap_path_prefix_source_test( + name = "remap_path_prefix_source_lib_test", + target_under_test = ":dep", + ) + + # Tests for generated sources (symlinked into bin dir). + _remap_path_prefix_generated_test( + name = "remap_path_prefix_generated_lib_test", + target_under_test = ":remap_lib_generated", ) - _remap_path_prefix_test( - name = "remap_path_prefix_bin_test", - target_under_test = ":remap_bin", + _remap_path_prefix_generated_test( + name = "remap_path_prefix_generated_bin_test", + target_under_test = ":remap_bin_generated", ) _subst_flags_test( name = "subst_flags_lib_test", - target_under_test = ":remap_lib", + target_under_test = ":remap_lib_generated", ) _subst_flags_test( name = "subst_flags_bin_test", - target_under_test = ":remap_bin", + target_under_test = ":remap_bin_generated", ) tests = [ - ":remap_path_prefix_lib_test", - ":remap_path_prefix_bin_test", + ":remap_path_prefix_source_lib_test", + ":remap_path_prefix_generated_lib_test", + ":remap_path_prefix_generated_bin_test", ":subst_flags_lib_test", ":subst_flags_bin_test", ] From b160dcde33aa5e886598dfb1f35be5ee7e3e2db9 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Tue, 5 May 2026 08:11:51 +0000 Subject: [PATCH 2/4] Fix remap tests to be platform-independent Use prefix/suffix matching instead of hardcoding k8-fastbuild in the bin dir path, so tests pass on macOS (darwin_arm64-fastbuild) too. --- test/unit/remap_path_prefix/remap_path_prefix_test.bzl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) 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 c7a312a02f..9a6a9d64e4 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,8 @@ load("//rust:defs.bzl", "rust_binary", "rust_library") load( "//test/unit:common.bzl", "assert_action_mnemonic", + "assert_argv_contains", + "assert_argv_contains_prefix_suffix", "assert_list_contains_adjacent_elements", ) @@ -35,8 +37,8 @@ def _remap_path_prefix_generated_test_impl(ctx): action = target.actions[0] assert_action_mnemonic(env, action, "Rustc") - assert_argv_contains(env, action, "--remap-path-prefix=${pwd}/bazel-out/k8-fastbuild/bin=.") - assert_argv_contains(env, action, "--remap-path-prefix=${exec_root}/bazel-out/k8-fastbuild/bin=.") + assert_argv_contains_prefix_suffix(env, action, "--remap-path-prefix=${pwd}/bazel-out/", "/bin=.") + assert_argv_contains_prefix_suffix(env, action, "--remap-path-prefix=${exec_root}/bazel-out/", "/bin=.") assert_argv_contains(env, action, "--remap-path-prefix=${output_base}=.") return analysistest.end(env) From 494132673bd5e942938ea027317ced82a61027eb Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Tue, 5 May 2026 08:45:13 +0000 Subject: [PATCH 3/4] Fix comment: remap-path-prefix does not affect file!() Update the comment to accurately list what --remap-path-prefix affects: debug info, dep-info, panic locations, and backtraces. --- rust/private/rustc.bzl | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/rust/private/rustc.bzl b/rust/private/rustc.bzl index 8bce8a94bc..d244070438 100644 --- a/rust/private/rustc.bzl +++ b/rust/private/rustc.bzl @@ -1186,9 +1186,9 @@ def construct_arguments( # For determinism to help with build distribution and such # - # --remap-path-prefix tells rustc to replace a path prefix in all output - # (diagnostics, file!(), panic locations, backtraces) so that absolute - # sandbox paths never leak into binaries or logs. + # --remap-path-prefix tells rustc to replace a path prefix in all + # embedded paths (debug info, dep-info, panic locations, backtraces) + # so that absolute sandbox paths never leak into binaries or logs. # # When all sources are plain workspace files, remapping ${pwd} (the exec # root) to remap_path_prefix (default ".") is enough. @@ -1198,8 +1198,9 @@ def construct_arguments( # bazel-out//bin/... so they sit next to the generated files. In # that case the crate root is no longer a source file and its path starts # with ctx.bin_dir.path (e.g. "bazel-out/k8-fastbuild/bin"). We detect - # this via crate_info.root.is_source and add a more specific remap that - # also strips the bin-dir component, giving clean workspace-relative paths. + # this via crate_info.root.is_source and use a more specific remap that + # also strips the bin-dir component, giving clean workspace-relative paths + # in panic messages and backtraces. if remap_path_prefix != None: # `--remap-path-prefix` flags are applied in reverse order. We need to # specify the outermost directory (output_base) first, so that it's From a2b653fd00c24de8f30553ed80e590fbf957c050 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Fri, 8 May 2026 08:26:51 +0000 Subject: [PATCH 4/4] Fix bin-dir remap to work with --experimental_output_paths=strip Use add_all with the crate root File and a map_each callback instead of hardcoding ctx.bin_dir.path in remap flag strings. This lets Bazel's path mapping rewrite the config portion of the bin-dir prefix (e.g. k8-fastbuild -> cfg), so the remap flags match the actual source file paths at execution time. --- rust/private/rustc.bzl | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/rust/private/rustc.bzl b/rust/private/rustc.bzl index d244070438..5a70b8cd4f 100644 --- a/rust/private/rustc.bzl +++ b/rust/private/rustc.bzl @@ -1211,8 +1211,19 @@ def construct_arguments( rustc_flags.add("--remap-path-prefix=${{pwd}}={}".format(remap_path_prefix)) rustc_flags.add("--remap-path-prefix=${{exec_root}}={}".format(remap_path_prefix)) else: - rustc_flags.add("--remap-path-prefix=${{pwd}}/{}={}".format(ctx.bin_dir.path, remap_path_prefix)) - rustc_flags.add("--remap-path-prefix=${{exec_root}}/{}={}".format(ctx.bin_dir.path, remap_path_prefix)) + # 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_prefix, + format_each = "--remap-path-prefix=${pwd}/%s=" + remap_path_prefix, + ) + rustc_flags.add_all( + [crate_info.root], + map_each = _get_bin_dir_prefix, + format_each = "--remap-path-prefix=${exec_root}/%s=" + remap_path_prefix, + ) emit_without_paths = [] for kind in emit: @@ -2727,6 +2738,22 @@ def _add_native_link_flags( format_each = "-lstatic=%s", ) +def _get_bin_dir_prefix(file): + """Returns the bin-dir prefix (without trailing slash) from a generated file. + + For a generated file, file.path is "bazel-out//bin//" + and file.short_path is "/". The difference is the bin-dir + prefix. Using the File object with add_all/map_each lets Bazel apply + path mapping (--experimental_output_paths=strip) to the config portion. + + Args: + file (File): A generated file (e.g. the crate root). + + Returns: + str: The bin-dir prefix, e.g. "bazel-out/k8-fastbuild/bin". + """ + return file.path[:len(file.path) - len(file.short_path)].rstrip("/") + def _get_dirname(file): """A helper function for `_add_native_link_flags`.