Skip to content

Commit 8af67ba

Browse files
committed
Auto merge of #124129 - lqd:enable-lld, r=Mark-Simulacrum
Enable `rust-lld` on nightly `x86_64-unknown-linux-gnu` We believe we have done virtually all the internal work and tests we could to prepare for using `lld` as the default linker (at least on Linux). We're IMHO at a point where we'd need to expand testing and coverage in order to make progress on this effort. Therefore, for further testing and gathering real-world feedback, unexpected issues and use-cases, this PR enables `rust-lld` as the default linker: - on nightly only (and dev channel) - on `x86_64-unknown-linux-gnu` only - when not using an external LLVM (except `download-ci-llvm`), so that distros are not impacted as described in more detail in this [zulip thread](https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/Enabling.20.60rust-lld.60.20on.20nightly.20.60x86_64-unknown-linux-gnu.60/near/433709343). In case any issues happen to users, as e.g. lld is not bug-for-bug compatible with GNU ld, it's easy to disable with `-Zlinker-features=-lld` to revert to using the system's default linker. --- I don't know who should review this kind of things, as it's somewhat of a crosscutting effort. Compiler contributor, compiler performance WG and infra member sounds perfect, so r? `@Mark-Simulacrum.` The last crater run encountered a low number (44) of mainly avoidable issues, like small incompatibilities, user errors, and a difference between the two linkers about which default to use with `--gc-sections`. [Here's the triage report](https://hackmd.io/OAJxlxc6Te6YUot9ftYSKQ?view), categorizing the issues, with some analyses and workarounds. I'd appreciate another set of eyes looking at these results. The changes in this PR have been test-driven for CI changes, try builds with tests enabled, rustc-perf with bootstrapping, in PR #113382. For infra, about the CI change: this PR forces `rust.lld` to false on vanilla LLVM builders, just to make sure we have coverage without `rust-lld`. Though to be clear, just using an external LLVM is already enough to keep `rust.lld` to false, in turn reverting everything to using the system's default linker. cc `@rust-lang/bootstrap` for the bootstrap and config change cc `@petrochenkov` for the small compiler change cc `@rust-lang/wg-compiler-performance` The blog post announcing the change, that we expect to merge around the same time as we merge this PR, is open [on the blog repo](rust-lang/blog.rust-lang.org#1319). Bootstrap change history: this PR changes the default of a config option on `x86_64-unknown-linux-gnu`. It's, however, not expected to cause issues, or require any changes to existing configurations. It's a big enough change that people should at least know about it, in case it causes unexpected problems. If that happens, set `rust.lld = false` in your `config.toml` (and open an issue).
2 parents fa37db5 + 3a90967 commit 8af67ba

File tree

8 files changed

+117
-14
lines changed

8 files changed

+117
-14
lines changed

compiler/rustc_target/src/spec/mod.rs

+6
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,12 @@ impl LinkSelfContainedDefault {
612612
_ => "crt-objects-fallback",
613613
}
614614
}
615+
616+
/// Creates a `LinkSelfContainedDefault` enabling the self-contained linker for target specs
617+
/// (the equivalent of `-Clink-self-contained=+linker` on the CLI).
618+
pub fn with_linker() -> LinkSelfContainedDefault {
619+
LinkSelfContainedDefault::WithComponents(LinkSelfContainedComponents::LINKER)
620+
}
615621
}
616622

617623
bitflags::bitflags! {

compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs

+7
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@ pub fn target() -> Target {
1818
| SanitizerSet::THREAD;
1919
base.supports_xray = true;
2020

21+
// When we're asked to use the `rust-lld` linker by default, set the appropriate lld-using
22+
// linker flavor, and self-contained linker component.
23+
if option_env!("CFG_USE_SELF_CONTAINED_LINKER").is_some() {
24+
base.linker_flavor = LinkerFlavor::Gnu(Cc::Yes, Lld::Yes);
25+
base.link_self_contained = crate::spec::LinkSelfContainedDefault::with_linker();
26+
}
27+
2128
Target {
2229
llvm_target: "x86_64-unknown-linux-gnu".into(),
2330
metadata: crate::spec::TargetMetadata {

config.example.toml

+6-3
Original file line numberDiff line numberDiff line change
@@ -653,9 +653,12 @@
653653
# when no explicit backend is specified.
654654
#codegen-backends = ["llvm"]
655655

656-
# Indicates whether LLD will be compiled and made available in the sysroot for
657-
# rustc to execute.
658-
#lld = false
656+
# Indicates whether LLD will be compiled and made available in the sysroot for rustc to execute, and
657+
# whether to set it as rustc's default linker on `x86_64-unknown-linux-gnu`. This will also only be
658+
# when *not* building an external LLVM (so only when using `download-ci-llvm` or building LLVM from
659+
# the in-tree source): setting `llvm-config` in the `[target.x86_64-unknown-linux-gnu]` section will
660+
# make this default to false.
661+
#lld = false in all cases, except on `x86_64-unknown-linux-gnu` as described above, where it is true
659662

660663
# Indicates whether LLD will be used to link Rust crates during bootstrap on
661664
# supported platforms.

src/bootstrap/src/core/build_steps/compile.rs

+5
Original file line numberDiff line numberDiff line change
@@ -1136,6 +1136,11 @@ pub fn rustc_cargo_env(
11361136
cargo.env("CFG_DEFAULT_LINKER", s);
11371137
}
11381138

1139+
// Enable rustc's env var for `rust-lld` when requested.
1140+
if builder.config.lld_enabled {
1141+
cargo.env("CFG_USE_SELF_CONTAINED_LINKER", "1");
1142+
}
1143+
11391144
if builder.config.rust_verify_llvm_ir {
11401145
cargo.env("RUSTC_VERIFY_LLVM_IR", "1");
11411146
}

src/bootstrap/src/core/config/config.rs

+40-11
Original file line numberDiff line numberDiff line change
@@ -1532,6 +1532,7 @@ impl Config {
15321532
let mut debuginfo_level_tests = None;
15331533
let mut optimize = None;
15341534
let mut omit_git_hash = None;
1535+
let mut lld_enabled = None;
15351536

15361537
if let Some(rust) = toml.rust {
15371538
let Rust {
@@ -1565,7 +1566,7 @@ impl Config {
15651566
dist_src,
15661567
save_toolstates,
15671568
codegen_backends,
1568-
lld,
1569+
lld: lld_enabled_toml,
15691570
llvm_tools,
15701571
llvm_bitcode_linker,
15711572
deny_warnings,
@@ -1620,6 +1621,7 @@ impl Config {
16201621
debuginfo_level_std = debuginfo_level_std_toml;
16211622
debuginfo_level_tools = debuginfo_level_tools_toml;
16221623
debuginfo_level_tests = debuginfo_level_tests_toml;
1624+
lld_enabled = lld_enabled_toml;
16231625

16241626
config.rust_split_debuginfo_for_build_triple = split_debuginfo
16251627
.as_deref()
@@ -1653,18 +1655,8 @@ impl Config {
16531655
config.incremental = true;
16541656
}
16551657
set(&mut config.lld_mode, lld_mode);
1656-
set(&mut config.lld_enabled, lld);
16571658
set(&mut config.llvm_bitcode_linker_enabled, llvm_bitcode_linker);
16581659

1659-
if matches!(config.lld_mode, LldMode::SelfContained)
1660-
&& !config.lld_enabled
1661-
&& flags.stage.unwrap_or(0) > 0
1662-
{
1663-
panic!(
1664-
"Trying to use self-contained lld as a linker, but LLD is not being added to the sysroot. Enable it with rust.lld = true."
1665-
);
1666-
}
1667-
16681660
config.llvm_tools_enabled = llvm_tools.unwrap_or(true);
16691661
config.rustc_parallel =
16701662
parallel_compiler.unwrap_or(config.channel == "dev" || config.channel == "nightly");
@@ -1954,6 +1946,43 @@ impl Config {
19541946
config.llvm_plugins = llvm_plugins.unwrap_or(false);
19551947
config.rust_optimize = optimize.unwrap_or(RustOptimize::Bool(true));
19561948

1949+
// We make `x86_64-unknown-linux-gnu` use the self-contained linker by default, so we will
1950+
// build our internal lld and use it as the default linker, by setting the `rust.lld` config
1951+
// to true by default:
1952+
// - on the `x86_64-unknown-linux-gnu` target
1953+
// - on the `dev` and `nightly` channels
1954+
// - when building our in-tree llvm (i.e. the target has not set an `llvm-config`), so that
1955+
// we're also able to build the corresponding lld
1956+
// - or when using an external llvm that's downloaded from CI, which also contains our prebuilt
1957+
// lld
1958+
// - otherwise, we'd be using an external llvm, and lld would not necessarily available and
1959+
// thus, disabled
1960+
// - similarly, lld will not be built nor used by default when explicitly asked not to, e.g.
1961+
// when the config sets `rust.lld = false`
1962+
if config.build.triple == "x86_64-unknown-linux-gnu"
1963+
&& config.hosts == [config.build]
1964+
&& (config.channel == "dev" || config.channel == "nightly")
1965+
{
1966+
let no_llvm_config = config
1967+
.target_config
1968+
.get(&config.build)
1969+
.is_some_and(|target_config| target_config.llvm_config.is_none());
1970+
let enable_lld = config.llvm_from_ci || no_llvm_config;
1971+
// Prefer the config setting in case an explicit opt-out is needed.
1972+
config.lld_enabled = lld_enabled.unwrap_or(enable_lld);
1973+
} else {
1974+
set(&mut config.lld_enabled, lld_enabled);
1975+
}
1976+
1977+
if matches!(config.lld_mode, LldMode::SelfContained)
1978+
&& !config.lld_enabled
1979+
&& flags.stage.unwrap_or(0) > 0
1980+
{
1981+
panic!(
1982+
"Trying to use self-contained lld as a linker, but LLD is not being added to the sysroot. Enable it with rust.lld = true."
1983+
);
1984+
}
1985+
19571986
let default = debug == Some(true);
19581987
config.rust_debug_assertions = debug_assertions.unwrap_or(default);
19591988
config.rust_debug_assertions_std =

src/bootstrap/src/utils/change_tracker.rs

+5
Original file line numberDiff line numberDiff line change
@@ -185,4 +185,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
185185
severity: ChangeSeverity::Info,
186186
summary: r#"The compiler profile now defaults to rust.debuginfo-level = "line-tables-only""#,
187187
},
188+
ChangeInfo {
189+
change_id: 124129,
190+
severity: ChangeSeverity::Warning,
191+
summary: "`rust.lld` has a new default value of `true` on `x86_64-unknown-linux-gnu`. Starting at stage1, `rust-lld` will thus be this target's default linker. No config changes should be necessary.",
192+
},
188193
];
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// Test linking using `cc` with `rust-lld`, which is on by default on the x86_64-unknown-linux-gnu
2+
// target.
3+
// See https://github.com/rust-lang/compiler-team/issues/510 for more info
4+
5+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Ensure that rust-lld is used as the default linker on `x86_64-unknown-linux-gnu`, and that it can
2+
// also be turned off with a CLI flag.
3+
4+
//@ needs-rust-lld
5+
//@ only-x86_64-unknown-linux-gnu
6+
7+
extern crate run_make_support;
8+
9+
use run_make_support::regex::Regex;
10+
use run_make_support::rustc;
11+
use std::process::Output;
12+
13+
fn main() {
14+
// A regular compilation should use rust-lld by default. We'll check that by asking the linker
15+
// to display its version number with a link-arg.
16+
let output = rustc()
17+
.env("RUSTC_LOG", "rustc_codegen_ssa::back::link=info")
18+
.link_arg("-Wl,-v")
19+
.input("main.rs")
20+
.run();
21+
assert!(
22+
find_lld_version_in_logs(output),
23+
"the LLD version string should be present in the output logs"
24+
);
25+
26+
// But it can still be disabled by turning the linker feature off.
27+
let output = rustc()
28+
.env("RUSTC_LOG", "rustc_codegen_ssa::back::link=info")
29+
.link_arg("-Wl,-v")
30+
.arg("-Zlinker-features=-lld")
31+
.input("main.rs")
32+
.run();
33+
assert!(
34+
!find_lld_version_in_logs(output),
35+
"the LLD version string should not be present in the output logs"
36+
);
37+
}
38+
39+
fn find_lld_version_in_logs(output: Output) -> bool {
40+
let lld_version_re = Regex::new(r"^LLD [0-9]+\.[0-9]+\.[0-9]+").unwrap();
41+
let stderr = std::str::from_utf8(&output.stderr).unwrap();
42+
stderr.lines().any(|line| lld_version_re.is_match(line))
43+
}

0 commit comments

Comments
 (0)