bazelbuild / bazelbuild/rules_rust

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

Open
#4,250 1 comment 0 reactions 0 assignees View on GitHub
help wanted
Dominant language
Starlark
Stars
843
Forks
651
Avg merge
2d 18h
Merged PRs (30d)
15

Description

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:

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

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

```starlark
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/-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:

```text
--codegen=linker=bazel-out/-exec/bin/.../x86_64-linux-g++.br_real
--codegen=link-arg=--sysroot=bazel-out/-exec/bin/.../sysroot
```

The action sandbox instead contains the toolchain under:

```text
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:

```text
--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

- #4011 added general support for `experimental_output_paths`.
- #3927 included a change to pass `--codegen=linker` using a `File`, but it was
closed after #4011 was believed to cover the same 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`.
```

Contributor guide

Open the contributing guide

Research direction

Start at the cc_common.get_tool_for_action() call and the rustc_flags Args construction described in the issue. Inspect the C++ toolchain linker/all-files artifact sets and how path-bearing --sysroot arguments are represented. Add a regression test using configuration-dependent linker and sysroot artifacts with --experimental_output_paths=strip; done means Bazel rewrites these paths while preserving the fallback behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp, rust
Domain
build-system
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.