Skip to content

Commit 2013ccc

Browse files
committed
rustc_target: Refactor linker flavor inference
Go through an intermediate pair of `cc`and `lld` hints instead of mapping CLI options to `LinkerFlavor` directly, and use the target's default linker flavor as a reference.
1 parent 498553f commit 2013ccc

File tree

2 files changed

+76
-56
lines changed
  • compiler

2 files changed

+76
-56
lines changed

compiler/rustc_codegen_ssa/src/back/link.rs

Lines changed: 3 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use rustc_session::utils::NativeLibKind;
2323
use rustc_session::{filesearch, Session};
2424
use rustc_span::symbol::Symbol;
2525
use rustc_target::spec::crt_objects::{CrtObjects, LinkSelfContainedDefault};
26-
use rustc_target::spec::{Cc, LinkOutputKind, LinkerFlavor, LinkerFlavorCli, Lld, PanicStrategy};
26+
use rustc_target::spec::{Cc, LinkOutputKind, LinkerFlavor, Lld, PanicStrategy};
2727
use rustc_target::spec::{RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo};
2828

2929
use super::archive::{ArchiveBuilder, ArchiveBuilderBuilder};
@@ -1302,44 +1302,7 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
13021302
let stem = linker.file_stem().and_then(|stem| stem.to_str()).unwrap_or_else(|| {
13031303
sess.emit_fatal(errors::LinkerFileStem);
13041304
});
1305-
1306-
// Remove any version postfix.
1307-
let stem = stem
1308-
.rsplit_once('-')
1309-
.and_then(|(lhs, rhs)| rhs.chars().all(char::is_numeric).then_some(lhs))
1310-
.unwrap_or(stem);
1311-
1312-
// GCC/Clang can have an optional target prefix.
1313-
let flavor = if stem == "emcc" {
1314-
LinkerFlavor::EmCc
1315-
} else if stem == "gcc"
1316-
|| stem.ends_with("-gcc")
1317-
|| stem == "g++"
1318-
|| stem.ends_with("-g++")
1319-
|| stem == "clang"
1320-
|| stem.ends_with("-clang")
1321-
|| stem == "clang++"
1322-
|| stem.ends_with("-clang++")
1323-
{
1324-
LinkerFlavor::from_cli(LinkerFlavorCli::Gcc, &sess.target)
1325-
} else if stem == "wasm-ld" || stem.ends_with("-wasm-ld") {
1326-
LinkerFlavor::WasmLld(Cc::No)
1327-
} else if stem == "ld" || stem.ends_with("-ld") {
1328-
LinkerFlavor::from_cli(LinkerFlavorCli::Ld, &sess.target)
1329-
} else if stem == "ld.lld" {
1330-
LinkerFlavor::Gnu(Cc::No, Lld::Yes)
1331-
} else if stem == "link" {
1332-
LinkerFlavor::Msvc(Lld::No)
1333-
} else if stem == "lld-link" {
1334-
LinkerFlavor::Msvc(Lld::Yes)
1335-
} else if stem == "lld" || stem == "rust-lld" {
1336-
let lld_flavor = sess.target.linker_flavor.lld_flavor();
1337-
LinkerFlavor::from_cli(LinkerFlavorCli::Lld(lld_flavor), &sess.target)
1338-
} else {
1339-
// fall back to the value in the target spec
1340-
sess.target.linker_flavor
1341-
};
1342-
1305+
let flavor = sess.target.linker_flavor.with_linker_hints(stem);
13431306
Some((linker, flavor))
13441307
}
13451308
(None, None) => None,
@@ -1349,7 +1312,7 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
13491312
// linker and linker flavor specified via command line have precedence over what the target
13501313
// specification specifies
13511314
let linker_flavor =
1352-
sess.opts.cg.linker_flavor.map(|flavor| LinkerFlavor::from_cli(flavor, &sess.target));
1315+
sess.opts.cg.linker_flavor.map(|flavor| sess.target.linker_flavor.with_cli_hints(flavor));
13531316
if let Some(ret) = infer_from(sess, sess.opts.cg.linker.clone(), linker_flavor) {
13541317
return ret;
13551318
}

compiler/rustc_target/src/spec/mod.rs

Lines changed: 73 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -205,15 +205,11 @@ impl ToJson for LldFlavor {
205205
}
206206

207207
impl LinkerFlavor {
208-
pub fn from_cli(cli: LinkerFlavorCli, target: &TargetOptions) -> LinkerFlavor {
209-
Self::from_cli_impl(cli, target.linker_flavor.lld_flavor(), target.linker_flavor.is_gnu())
210-
}
211-
212-
/// The passed CLI flavor is preferred over other args coming from the default target spec,
213-
/// so this function can produce a flavor that is incompatible with the current target.
214-
/// FIXME: Produce errors when `-Clinker-flavor` is set to something incompatible
215-
/// with the current target.
216-
fn from_cli_impl(cli: LinkerFlavorCli, lld_flavor: LldFlavor, is_gnu: bool) -> LinkerFlavor {
208+
/// At this point the target's reference linker flavor doesn't yet exist and we need to infer
209+
/// it. The inference always succeds and gives some result, and we don't report any flavor
210+
/// incompatibility errors for json target specs. The CLI flavor is used as the main source
211+
/// of truth, other flags are used in case of ambiguities.
212+
fn from_cli_json(cli: LinkerFlavorCli, lld_flavor: LldFlavor, is_gnu: bool) -> LinkerFlavor {
217213
match cli {
218214
LinkerFlavorCli::Gcc => match lld_flavor {
219215
LldFlavor::Ld if is_gnu => LinkerFlavor::Gnu(Cc::Yes, Lld::No),
@@ -257,6 +253,72 @@ impl LinkerFlavor {
257253
}
258254
}
259255

256+
fn infer_cli_hints(cli: LinkerFlavorCli) -> (Option<Cc>, Option<Lld>) {
257+
match cli {
258+
LinkerFlavorCli::Gcc | LinkerFlavorCli::Em => (Some(Cc::Yes), None),
259+
LinkerFlavorCli::Lld(_) => (Some(Cc::No), Some(Lld::Yes)),
260+
LinkerFlavorCli::Ld | LinkerFlavorCli::Msvc => (Some(Cc::No), Some(Lld::No)),
261+
LinkerFlavorCli::BpfLinker | LinkerFlavorCli::PtxLinker => (None, None),
262+
}
263+
}
264+
265+
fn infer_linker_hints(linker_stem: &str) -> (Option<Cc>, Option<Lld>) {
266+
// Remove any version postfix.
267+
let stem = linker_stem
268+
.rsplit_once('-')
269+
.and_then(|(lhs, rhs)| rhs.chars().all(char::is_numeric).then_some(lhs))
270+
.unwrap_or(linker_stem);
271+
272+
// GCC/Clang can have an optional target prefix.
273+
if stem == "emcc"
274+
|| stem == "gcc"
275+
|| stem.ends_with("-gcc")
276+
|| stem == "g++"
277+
|| stem.ends_with("-g++")
278+
|| stem == "clang"
279+
|| stem.ends_with("-clang")
280+
|| stem == "clang++"
281+
|| stem.ends_with("-clang++")
282+
{
283+
(Some(Cc::Yes), None)
284+
} else if stem == "wasm-ld"
285+
|| stem.ends_with("-wasm-ld")
286+
|| stem == "ld.lld"
287+
|| stem == "lld"
288+
|| stem == "rust-lld"
289+
|| stem == "lld-link"
290+
{
291+
(Some(Cc::No), Some(Lld::Yes))
292+
} else if stem == "ld" || stem.ends_with("-ld") || stem == "link" {
293+
(Some(Cc::No), Some(Lld::No))
294+
} else {
295+
(None, None)
296+
}
297+
}
298+
299+
fn with_hints(self, (cc_hint, lld_hint): (Option<Cc>, Option<Lld>)) -> LinkerFlavor {
300+
match self {
301+
LinkerFlavor::Gnu(cc, lld) => {
302+
LinkerFlavor::Gnu(cc_hint.unwrap_or(cc), lld_hint.unwrap_or(lld))
303+
}
304+
LinkerFlavor::Darwin(cc, lld) => {
305+
LinkerFlavor::Darwin(cc_hint.unwrap_or(cc), lld_hint.unwrap_or(lld))
306+
}
307+
LinkerFlavor::WasmLld(cc) => LinkerFlavor::WasmLld(cc_hint.unwrap_or(cc)),
308+
LinkerFlavor::Unix(cc) => LinkerFlavor::Unix(cc_hint.unwrap_or(cc)),
309+
LinkerFlavor::Msvc(lld) => LinkerFlavor::Msvc(lld_hint.unwrap_or(lld)),
310+
LinkerFlavor::EmCc | LinkerFlavor::Bpf | LinkerFlavor::Ptx => self,
311+
}
312+
}
313+
314+
pub fn with_cli_hints(self, cli: LinkerFlavorCli) -> LinkerFlavor {
315+
self.with_hints(LinkerFlavor::infer_cli_hints(cli))
316+
}
317+
318+
pub fn with_linker_hints(self, linker_stem: &str) -> LinkerFlavor {
319+
self.with_hints(LinkerFlavor::infer_linker_hints(linker_stem))
320+
}
321+
260322
pub fn lld_flavor(self) -> LldFlavor {
261323
match self {
262324
LinkerFlavor::Gnu(..)
@@ -1801,7 +1863,7 @@ impl TargetOptions {
18011863
}
18021864

18031865
fn update_from_cli(&mut self) {
1804-
self.linker_flavor = LinkerFlavor::from_cli_impl(
1866+
self.linker_flavor = LinkerFlavor::from_cli_json(
18051867
self.linker_flavor_json,
18061868
self.lld_flavor_json,
18071869
self.linker_is_gnu_json,
@@ -1815,12 +1877,7 @@ impl TargetOptions {
18151877
] {
18161878
args.clear();
18171879
for (flavor, args_json) in args_json {
1818-
// Cannot use `from_cli` due to borrow checker.
1819-
let linker_flavor = LinkerFlavor::from_cli_impl(
1820-
*flavor,
1821-
self.lld_flavor_json,
1822-
self.linker_is_gnu_json,
1823-
);
1880+
let linker_flavor = self.linker_flavor.with_cli_hints(*flavor);
18241881
// Normalize to no lld to avoid asserts.
18251882
let linker_flavor = match linker_flavor {
18261883
LinkerFlavor::Gnu(cc, _) => LinkerFlavor::Gnu(cc, Lld::No),

0 commit comments

Comments
 (0)