Skip to content

C++ linker and sysroot paths are not rewritten by Bazel path mapping #4250

Description

@Gormo

rustc actions advertise supports-path-mapping, but the C++ linker returned by
cc_common.get_tool_for_action() is passed to rustc as an analysis-time
string:

rustc_flags.add(ld, format = "--codegen=linker=%s")

The C++ link arguments are also passed as strings:

rustc_flags.add_all(link_args, format_each = "--codegen=link-arg=%s")

Bazel only rewrites paths that retain their File identity when expanded
through an Args object. It cannot rewrite arbitrary strings containing
file.path.

When --experimental_output_paths=strip is enabled, the Rustc action executes
against the path-mapped bazel-out/cfg layout, but --codegen=linker and
linker arguments such as --sysroot can still refer to their analysis-time
bazel-out/<configuration>-exec paths.

This causes Rust linking to fail when using a hermetic C++ toolchain whose
linker or sysroot is a Bazel artifact.

Example failure

The generated Rustc command contains arguments similar to:

--codegen=linker=bazel-out/<configuration>-exec/bin/.../x86_64-linux-g++.br_real
--codegen=link-arg=--sysroot=bazel-out/<configuration>-exec/bin/.../sysroot

The action sandbox instead contains the toolchain under:

bazel-out/cfg/bin/...

Rustc therefore fails to execute the linker, or the linker fails to find its
sysroot.

Expected behavior

All artifact paths supplied to an action that advertises
supports-path-mapping should be passed through path-mapping-aware Args
entries.

In particular:

  • --codegen=linker should use the corresponding C++ toolchain File.
  • A path-bearing C++ --sysroot argument should be derived from an artifact
    that Bazel can map at action execution time.
  • Tool executables contained within directory/tree artifacts should also be
    supported.
  • Existing behavior should remain available as a fallback when the linker
    cannot be associated with a toolchain artifact.

Actual behavior

cc_common.get_tool_for_action() returns the linker path as a string.
rules_rust forwards that string directly to rustc, so Bazel cannot rewrite
its output-path prefix.

The same problem affects a --sysroot value returned as part of the C++
toolchain command line.

Reproduction outline

  1. Configure a hermetic C++ toolchain whose linker and sysroot are generated or
    external Bazel artifacts.

  2. Build a rust_binary that uses the C++ linker.

  3. Enable:

    --experimental_output_paths=strip
    
  4. Observe that the Rustc action uses bazel-out/cfg, while
    --codegen=linker or --codegen=link-arg=--sysroot=... still contains the
    analysis-time configuration path.

Disabling stripped output paths avoids the mismatch.

Related work

The current main branch still passes both the linker and link arguments as
strings, so this part of #3927 does not appear to have been incorporated by
#4011.

Suggested direction

Associate the path returned by cc_common.get_tool_for_action() with a member
of the C++ toolchain's linker/all-files artifact sets, preserving a directory
artifact plus relative suffix when necessary.

Pass that artifact through Args.add for --codegen=linker. Path-bearing
linker arguments such as --sysroot should similarly be constructed from a
typed artifact at argument-expansion time.

A regression test should use a C++ toolchain whose linker and sysroot live
under a configuration-dependent output path and build with
--experimental_output_paths=strip.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions