Skip to content

Commit b30f5b4

Browse files
authored
fix: don't prefer clang for -Clinker-plugin-lto=no (#2046)
`prefer_clang` looked for the text `linker-plugin-lto` anywhere in `CARGO_ENCODED_RUSTFLAGS`, so `-Clinker-plugin-lto=no` (or `n`, `off`, `false`, or a later `=no` after an enabling flag) and unrelated flags that merely contain the text still made cc look for `clang` first when `CC` is not set. Use the parsed value from `RustcCodegenFlags` instead, the same one that decides whether `-flto=thin` is passed.
1 parent fb5eb51 commit b30f5b4

3 files changed

Lines changed: 40 additions & 2 deletions

File tree

‎src/flags.rs‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,11 @@ impl<'this> RustcCodegenFlags<'this> {
281281
}
282282
}
283283

284+
/// Whether the last `-Clinker-plugin-lto` enables linker-plugin LTO.
285+
pub(crate) fn linker_plugin_lto(&self) -> bool {
286+
self.linker_plugin_lto.unwrap_or(false)
287+
}
288+
284289
// Rust and clang/cc don't agree on what equivalent flags should look like.
285290
pub(crate) fn cc_flags(
286291
&self,
@@ -435,7 +440,7 @@ impl<'this> RustcCodegenFlags<'this> {
435440
}
436441

437442
// https://doc.rust-lang.org/rustc/linker-plugin-lto.html
438-
if self.linker_plugin_lto.unwrap_or(false) {
443+
if self.linker_plugin_lto() {
439444
// https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-flto
440445
// In order to use linker-plugin-lto to achieve cross-lang lto, cc has to use thin LTO
441446
// to compile the c/c++ libraries because llvm linker plugin/lld uses thin LTO by default.

‎src/lib.rs‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3962,9 +3962,14 @@ impl Build {
39623962
cmd
39633963
}
39643964

3965+
/// Whether to look for `clang` (or `clang++`) first when no compiler is
3966+
/// set, so that C and C++ code can take part in rustc's linker-plugin LTO.
39653967
fn prefer_clang(&self) -> bool {
39663968
if let Some(env) = self.get_cargo_env("CARGO_ENCODED_RUSTFLAGS") {
3967-
env.to_string_lossy().contains("linker-plugin-lto")
3969+
// Flags that don't parse are left for rustc and
3970+
// `add_inherited_rustflags` to report.
3971+
RustcCodegenFlags::parse(&env.to_string_lossy())
3972+
.map_or(false, |flags| flags.linker_plugin_lto())
39683973
} else {
39693974
false
39703975
}

‎tests/rustflags.rs‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,3 +128,31 @@ fn enabled_linker_plugin_lto_preserves_clang_lto() {
128128
test.cmd_for_source("foo.c").must_have("-flto=thin");
129129
}
130130
}
131+
132+
#[test]
133+
fn linker_plugin_lto_prefers_clang() {
134+
for (flags, program) in [
135+
("-Clinker-plugin-lto", "clang"),
136+
("-Clinker-plugin-lto=yes", "clang"),
137+
("-Clinker-plugin-lto=/path/to/LLVMgold.so", "clang"),
138+
("-C\u{1f}linker-plugin-lto", "clang"),
139+
("-Clinker-plugin-lto=no\u{1f}-Clinker-plugin-lto", "clang"),
140+
("-Clinker-plugin-lto=n", "cc"),
141+
("-Clinker-plugin-lto=no", "cc"),
142+
("-Clinker-plugin-lto=off", "cc"),
143+
("-Clinker-plugin-lto=false", "cc"),
144+
("--codegen\u{1f}linker-plugin-lto=no", "cc"),
145+
("-Clinker-plugin-lto\u{1f}-Clinker-plugin-lto=no", "cc"),
146+
("-L/opt/linker-plugin-lto/lib", "cc"),
147+
("", "cc"),
148+
] {
149+
let mut test = Test::gnu();
150+
test.shim("clang");
151+
// cc looks for `clang` on the inherited `PATH`, not on the one set
152+
// with `Build::env`.
153+
test.env.set("PATH", test.td.path());
154+
test.env.set("CARGO_ENCODED_RUSTFLAGS", flags);
155+
test.gcc().file("foo.c").compile("foo");
156+
test.cmd_for_source("foo.c").must_run(program);
157+
}
158+
}

0 commit comments

Comments
 (0)