Skip to content

bazel coverage fails for Rust targets: -u linker flag incorrectly parsed as filename #243

@electronjoe

Description

@electronjoe

When using hermetic_cc_toolchain with rules_rust, running bazel coverage on Rust targets fails with:

ld.lld: error: cannot open __llvm_profile_runtime: No such file or directory

This is caused by Zig's clang driver misinterpreting the -u SYMBOL linker flag format.

Environment

  • hermetic_cc_toolchain: 4.1.0
  • rules_rust: 0.68.1
  • Zig: 0.12.0 (bundled with hermetic_cc_toolchain)
  • Bazel: 8.x
  • OS: Linux x86_64

Steps to Reproduce

Open GitHub codespace from my minimal reproduction repo: https://github.com/anthropics/bazel-cpp-rust-codecov

bazel coverage //rust:greeter_test
<succeeds as patch has been applied>
git rebase to remove single git commit patch
bazel coverage //rust:greeter_test
<fails>: ld.lld: error: cannot open __llvm_profile_runtime: No such file or directory

Expected Behavior

Coverage builds and tests run successfully, generating LCOV coverage data.

Actual Behavior

Build fails during linking with:

error: linking with `external/hermetic_cc_toolchain~~toolchains~zig_config/tools/x86_64-linux-gnu.2.17/c++` failed: exit status: 1
  |
  = note: ld.lld: error: cannot open __llvm_profile_runtime: No such file or directory

Root Cause

When bazel coverage runs, rustc passes coverage instrumentation flags to the linker:

-u __llvm_profile_runtime -fprofile-instr-generate

The -u SYMBOL flag tells the linker to force a symbol to be undefined (ensuring it gets linked in). However, Zig's clang driver incorrectly parses this:

  1. It matches -u against the Windows /u CLFlag (undefine macro) instead of the Unix linker -u flag
  2. This consumes -u as a standalone flag
  3. __llvm_profile_runtime is then treated as a positional argument (input filename)
  4. Zig tries to open it as a file → FileNotFound / No such file or directory

This can be verified by testing directly with Zig:

# Fails - Zig misparses -u
echo 'int main(){}' | zig c++ -x c - -u __test_symbol -target x86_64-linux-gnu -o /dev/null
# __test_symbol:1:1: error: FileNotFound

# Works - using -Wl to bypass Zig's argument parsing
echo 'int main(){}' | zig c++ -x c - -Wl,-u,__test_symbol -target x86_64-linux-gnu -o /dev/null
# Success

Upstream Zig Bug

This is a known bug in Zig, tracked at:

The fix modifies src/clang_options_data.zig to prevent the Windows /u CLFlag from matching when using a dash prefix (-u).

Workaround

Until the Zig fix is released, the issue can be worked around by patching zig-wrapper.zig to transform -u SYMBOL into -Wl,-u,SYMBOL.

I have posted #242 for consideration with this workaround.

Suggested Resolution

  1. Short-term: Consider including this patch in hermetic_cc_toolchain until Zig releases a fix
  2. Long-term: Remove the patch once a fixed Zig version is bundled

Related Issues

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions