Skip to content

Commit

Permalink
integration-test: Set rust-lld as a linker only on macOS
Browse files Browse the repository at this point in the history
The recommendation (coming from rust-lang/rust#130062) for Linux hosts
is using C compiler driver as a linker, which is able to find
system-wide libraries. Using linker binaries directly in `-C linker`
(e.g. `-C linker=rust-lld`) often results in errors like:

```
cargo:warning=error: linking with `rust-lld` failed: exit status: 1ger, ppv-lite86, libc...
cargo:warning=  |
cargo:warning=  = note: LC_ALL="C" PATH="/home/vadorovsky/.rustup/toolchains/stable-x86_64-un
cargo:warning=  = note: rust-lld: error: unable to find library -lgcc_s
cargo:warning=          rust-lld: error: unable to find library -lc
cargo:warning=
cargo:warning=
cargo:warning=
cargo:warning=error: aborting due to 1 previous error
```

Not touching the linker settings is usually the best approach for Linux
systems. Native builds pick up the default C toolchain. Cross builds
default to GCC cross wrapper, but that's easy to supress with clang and
lld using RUSTFLAGS.

However, `-C linker=rust-lld` still works the best on macOS, where Rust
toolchains come with libc and runtime library and there is no need to
link any system libraries. Keep setting it only for macOS.

Fixes aya-rs#907
  • Loading branch information
vadorovsky committed Nov 26, 2024
1 parent 119049f commit 613aaf8
Showing 1 changed file with 51 additions and 3 deletions.
54 changes: 51 additions & 3 deletions xtask/src/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,60 @@ pub fn build<F>(target: Option<&str>, f: F) -> Result<Vec<(String, PathBuf)>>
where
F: FnOnce(&mut Command) -> &mut Command,
{
// Always use rust-lld and -Zbuild-std in case we're cross-compiling.
let mut cmd = Command::new("cargo");
cmd.args(["build", "--message-format=json"]);
if let Some(target) = target {
let config = format!("target.{target}.linker = \"rust-lld\"");
cmd.args(["--target", target, "--config", &config]);
cmd.args(["--target", target]);
// During a cross build, it's important to pick the correct linker.
//
// On Linux, C compiler driver should be always used as the linker.
// The C compiler eventually ends up calling the linker binary (e.g.
// ld, lld), but before doing that, it figures out the appropiate
// linker flags, which include the system library paths. Calling linker
// binaries directly results in them not being able to find system
// libraries (like libc or runtime library), which can manifest in
// errors like `unable to find library -lgcc_s`.
//
// The issue was discussed with the Rust maintainers[0] and the
// consensus is to always use `-C linker` to specify the C compiler
/// (e.g. `-C linker=gcc`, `-C linker=clang`). Choice of a specific
// linker (like ldd or mold) can be done with `-C link-arg=-fuse-ld=`.
//
// However, the same doesn't hold true for macOS. Cross toolchains for
// Linux targets on macOS hosts, provided by rustup, are self-contained,
// come with libc, runtime library and don't depend on any system
// libraries. Therefore, direct usage of rust-lld through
// `-C linker=rust-lld` works fine, because rust-lld is able to find
// libc and runtime in rustup's toolchain.
//
// Using system-wide compiler (clang) on macOS would take the opposite
// effect than on Linux. The system compiler would be the one not being
// able to find the Linux-compatible libc and runtime
//
// To sum it up, this is the way of determining the linker we follow:
//
// - On Linux, use a C compiler for the cross target.
// - On macOS, use rust-lld directly.
//
// The first point is already covered by the configuration in
// `.cargo/config.toml`, which uses cross GCC compilers as linkers for
// popular non-x86_64 targets (e.g. aarch64-linux-musl-gcc). People
// who want to use a different compiler (e.g. clang), can overwrite
// RUSTFLAGS. Set of flags like `-C linker=clang
// -C link-arg=--target=aarch64-unknown-linux-musl
// -C link-arg=-fuse-ld=lld` should result in the build which uses only
// LLVM and has no dependency on GCC. mold can be used with
// `-C link-arg=-fuse-ld=mold`
//
// To cover the macOS case, we explicitly set the linker to rust-lld,
// ignoring the default configuration from `.cargo/config.toml`.
//
// [0] https://github.com/rust-lang/rust/issues/130062
#[cfg(target_os = "macos")]
{
let config = format!("target.{target}.linker = \"rust-lld\"");
cmd.args(["--config", &config]);
}
}
f(&mut cmd);

Expand Down

0 comments on commit 613aaf8

Please sign in to comment.