integration-test: Set `rust-lld` as a linker only on macOS

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 #907
reviewable/pr908/r5
Michal Rostecki 10 months ago
parent 119049f2a2
commit 613aaf8d7a

@ -54,12 +54,60 @@ pub fn build<F>(target: Option<&str>, f: F) -> Result<Vec<(String, PathBuf)>>
where where
F: FnOnce(&mut Command) -> &mut Command, 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"); let mut cmd = Command::new("cargo");
cmd.args(["build", "--message-format=json"]); cmd.args(["build", "--message-format=json"]);
if let Some(target) = target { if let Some(target) = target {
let config = format!("target.{target}.linker = \"rust-lld\""); cmd.args(["--target", target]);
cmd.args(["--target", target, "--config", &config]); // 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); f(&mut cmd);

Loading…
Cancel
Save