bazelbuild / bazelbuild/rules_rust

_add_native_link_flags generates both static and dynamic linking flags preventing hermetic cross-compilation

Open
#3,504 0 comments 0 reactions 0 assignees View on GitHub
needs-triage
Dominant language
Starlark
Stars
843
Forks
651
Avg merge
2d 18h
Merged PRs (30d)
15

Description

## Summary

The `_add_native_link_flags` function in `rust/private/rustc.bzl` automatically generates both static (`-lstatic=`) and dynamic (`-l`) linking flags for cc_library dependencies. This prevents hermetic cross-compilation scenarios where only static libraries are available.

## Problem Description

When cross-compiling a Rust binary that depends on cc_library targets, `_add_native_link_flags` generates linking flags like:
```
-lstatic=mylib -lmylib
```

In hermetic cross-compilation environments (e.g., macOS host targeting Linux), only static libraries (`.a`) are available, but the dynamic flags (`-lmylib`) cause linker failures:
```
error: linking with `zig` failed: exit status: 1
= note: /usr/bin/ld: cannot find -lmylib: No such file or directory
```

## Minimal Reproduction

A complete, self-contained reproduction is available at:
**https://gist.github.com/punya/a013c30ea31ca4ef0386968e7f21849d**

The reproduction demonstrates:
1. A local cc_library that builds successfully (creating both .a and .so files)
2. A rust_binary that fails during hermetic cross-compilation
3. Evidence that even linkstatic=True doesn't solve the problem
4. A working manual workaround using rustc_flags
5. Why the workaround is insufficient for real-world use

Run `./test.sh` to see all scenarios in action.

## Root Cause

The platform-specific link flag generators (e.g., `_make_link_flags_default` for Linux) in `_add_native_link_flags` are hardcoded to generate both static and dynamic flags for each cc_library dependency. There's no mechanism to generate **only** static flags.

## Proposed Solutions (Ranked by Preference)

### Option 1 (Preferred): Automatic Detection
Automatically detect when only static libraries are available and generate only static flags. The function could:
- Check if dynamic libraries (`.so`, `.dylib`, `.dll`) exist alongside static libraries
- In hermetic cross-compilation, only static libraries are typically available
- Fall back to static-only linking when dynamic libraries are missing

### Option 2: Add `static_only_linking` attribute
Add a new attribute to `rust_binary` and `rust_library` rules:
```python
rust_binary(
name = "my_binary",
static_only_linking = True, # Generate only -lstatic= flags
deps = [":mylib"],
)
```

### Option 3: Use linking modifiers
Leverage Rust's native linking modifiers (RFC 2951) when available:
```
-l static:+whole-archive=mylib
```

## Impact

This affects any project using:
- Hermetic cross-compilation with cc_library dependencies
- Static-only build environments
- Embedded targets where dynamic linking isn't available
- Container builds targeting minimal base images
- Projects currently forced to use cumbersome manual workarounds that don't scale

## Current Workarounds

A manual workaround exists but is insufficient:

**Manual rustc_flags workaround:**
```python
rust_binary(
name = "my_binary",
deps = [":mylib"],
rustc_flags = [
"-C", "link-arg=-Wl,-Bstatic",
"-C", "link-arg=-lmylib",
"-C", "link-arg=-Wl,-Bdynamic",
],
)
```

Limitations of this workaround:
- Requires manually specifying every library name
- Becomes unwieldy for complex dependency trees
- Defeats the purpose of Bazel's automatic dependency management
- Must be repeated for every rust_binary target

Other insufficient workarounds:
- Avoid cc_library dependencies in Rust targets
- Use cc_binary as the final linker instead of rust_binary
- Patch rules_rust locally
- Abandon hermetic cross-compilation

## Additional Context

- Related to ongoing work on hermetic builds (#490)
- Could benefit from RFC 2951 (native-link-modifiers) implementation
- Similar challenges exist in other cross-compilation scenarios (#2518)
- The issue manifests in the `_make_link_flags_default` function which generates both flag types

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.