diff options
| author | Vadim Petrochenkov <vadim.petrochenkov@gmail.com> | 2023-04-19 18:53:23 +0300 |
|---|---|---|
| committer | Vadim Petrochenkov <vadim.petrochenkov@gmail.com> | 2023-05-29 19:58:11 +0300 |
| commit | 2013ccc218a488768ad6b647dd8ecc293e7847b4 (patch) | |
| tree | de9f89b74756ea587499918c6dc0e3b8ca80b01f | |
| parent | 498553fc04f6a3fdc53412320f4e913bc53bc267 (diff) | |
| download | rust-2013ccc218a488768ad6b647dd8ecc293e7847b4.tar.gz rust-2013ccc218a488768ad6b647dd8ecc293e7847b4.zip | |
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.
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/back/link.rs | 43 | ||||
| -rw-r--r-- | compiler/rustc_target/src/spec/mod.rs | 89 |
2 files changed, 76 insertions, 56 deletions
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index bdbd10f8260..f8bb9bf2bb5 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -23,7 +23,7 @@ use rustc_session::utils::NativeLibKind; use rustc_session::{filesearch, Session}; use rustc_span::symbol::Symbol; use rustc_target::spec::crt_objects::{CrtObjects, LinkSelfContainedDefault}; -use rustc_target::spec::{Cc, LinkOutputKind, LinkerFlavor, LinkerFlavorCli, Lld, PanicStrategy}; +use rustc_target::spec::{Cc, LinkOutputKind, LinkerFlavor, Lld, PanicStrategy}; use rustc_target::spec::{RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo}; use super::archive::{ArchiveBuilder, ArchiveBuilderBuilder}; @@ -1302,44 +1302,7 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) { let stem = linker.file_stem().and_then(|stem| stem.to_str()).unwrap_or_else(|| { sess.emit_fatal(errors::LinkerFileStem); }); - - // Remove any version postfix. - let stem = stem - .rsplit_once('-') - .and_then(|(lhs, rhs)| rhs.chars().all(char::is_numeric).then_some(lhs)) - .unwrap_or(stem); - - // GCC/Clang can have an optional target prefix. - let flavor = if stem == "emcc" { - LinkerFlavor::EmCc - } else if stem == "gcc" - || stem.ends_with("-gcc") - || stem == "g++" - || stem.ends_with("-g++") - || stem == "clang" - || stem.ends_with("-clang") - || stem == "clang++" - || stem.ends_with("-clang++") - { - LinkerFlavor::from_cli(LinkerFlavorCli::Gcc, &sess.target) - } else if stem == "wasm-ld" || stem.ends_with("-wasm-ld") { - LinkerFlavor::WasmLld(Cc::No) - } else if stem == "ld" || stem.ends_with("-ld") { - LinkerFlavor::from_cli(LinkerFlavorCli::Ld, &sess.target) - } else if stem == "ld.lld" { - LinkerFlavor::Gnu(Cc::No, Lld::Yes) - } else if stem == "link" { - LinkerFlavor::Msvc(Lld::No) - } else if stem == "lld-link" { - LinkerFlavor::Msvc(Lld::Yes) - } else if stem == "lld" || stem == "rust-lld" { - let lld_flavor = sess.target.linker_flavor.lld_flavor(); - LinkerFlavor::from_cli(LinkerFlavorCli::Lld(lld_flavor), &sess.target) - } else { - // fall back to the value in the target spec - sess.target.linker_flavor - }; - + let flavor = sess.target.linker_flavor.with_linker_hints(stem); Some((linker, flavor)) } (None, None) => None, @@ -1349,7 +1312,7 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) { // linker and linker flavor specified via command line have precedence over what the target // specification specifies let linker_flavor = - sess.opts.cg.linker_flavor.map(|flavor| LinkerFlavor::from_cli(flavor, &sess.target)); + sess.opts.cg.linker_flavor.map(|flavor| sess.target.linker_flavor.with_cli_hints(flavor)); if let Some(ret) = infer_from(sess, sess.opts.cg.linker.clone(), linker_flavor) { return ret; } diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 62f94209cf0..6a3eea1427f 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -205,15 +205,11 @@ impl ToJson for LldFlavor { } impl LinkerFlavor { - pub fn from_cli(cli: LinkerFlavorCli, target: &TargetOptions) -> LinkerFlavor { - Self::from_cli_impl(cli, target.linker_flavor.lld_flavor(), target.linker_flavor.is_gnu()) - } - - /// The passed CLI flavor is preferred over other args coming from the default target spec, - /// so this function can produce a flavor that is incompatible with the current target. - /// FIXME: Produce errors when `-Clinker-flavor` is set to something incompatible - /// with the current target. - fn from_cli_impl(cli: LinkerFlavorCli, lld_flavor: LldFlavor, is_gnu: bool) -> LinkerFlavor { + /// At this point the target's reference linker flavor doesn't yet exist and we need to infer + /// it. The inference always succeds and gives some result, and we don't report any flavor + /// incompatibility errors for json target specs. The CLI flavor is used as the main source + /// of truth, other flags are used in case of ambiguities. + fn from_cli_json(cli: LinkerFlavorCli, lld_flavor: LldFlavor, is_gnu: bool) -> LinkerFlavor { match cli { LinkerFlavorCli::Gcc => match lld_flavor { LldFlavor::Ld if is_gnu => LinkerFlavor::Gnu(Cc::Yes, Lld::No), @@ -257,6 +253,72 @@ impl LinkerFlavor { } } + fn infer_cli_hints(cli: LinkerFlavorCli) -> (Option<Cc>, Option<Lld>) { + match cli { + LinkerFlavorCli::Gcc | LinkerFlavorCli::Em => (Some(Cc::Yes), None), + LinkerFlavorCli::Lld(_) => (Some(Cc::No), Some(Lld::Yes)), + LinkerFlavorCli::Ld | LinkerFlavorCli::Msvc => (Some(Cc::No), Some(Lld::No)), + LinkerFlavorCli::BpfLinker | LinkerFlavorCli::PtxLinker => (None, None), + } + } + + fn infer_linker_hints(linker_stem: &str) -> (Option<Cc>, Option<Lld>) { + // Remove any version postfix. + let stem = linker_stem + .rsplit_once('-') + .and_then(|(lhs, rhs)| rhs.chars().all(char::is_numeric).then_some(lhs)) + .unwrap_or(linker_stem); + + // GCC/Clang can have an optional target prefix. + if stem == "emcc" + || stem == "gcc" + || stem.ends_with("-gcc") + || stem == "g++" + || stem.ends_with("-g++") + || stem == "clang" + || stem.ends_with("-clang") + || stem == "clang++" + || stem.ends_with("-clang++") + { + (Some(Cc::Yes), None) + } else if stem == "wasm-ld" + || stem.ends_with("-wasm-ld") + || stem == "ld.lld" + || stem == "lld" + || stem == "rust-lld" + || stem == "lld-link" + { + (Some(Cc::No), Some(Lld::Yes)) + } else if stem == "ld" || stem.ends_with("-ld") || stem == "link" { + (Some(Cc::No), Some(Lld::No)) + } else { + (None, None) + } + } + + fn with_hints(self, (cc_hint, lld_hint): (Option<Cc>, Option<Lld>)) -> LinkerFlavor { + match self { + LinkerFlavor::Gnu(cc, lld) => { + LinkerFlavor::Gnu(cc_hint.unwrap_or(cc), lld_hint.unwrap_or(lld)) + } + LinkerFlavor::Darwin(cc, lld) => { + LinkerFlavor::Darwin(cc_hint.unwrap_or(cc), lld_hint.unwrap_or(lld)) + } + LinkerFlavor::WasmLld(cc) => LinkerFlavor::WasmLld(cc_hint.unwrap_or(cc)), + LinkerFlavor::Unix(cc) => LinkerFlavor::Unix(cc_hint.unwrap_or(cc)), + LinkerFlavor::Msvc(lld) => LinkerFlavor::Msvc(lld_hint.unwrap_or(lld)), + LinkerFlavor::EmCc | LinkerFlavor::Bpf | LinkerFlavor::Ptx => self, + } + } + + pub fn with_cli_hints(self, cli: LinkerFlavorCli) -> LinkerFlavor { + self.with_hints(LinkerFlavor::infer_cli_hints(cli)) + } + + pub fn with_linker_hints(self, linker_stem: &str) -> LinkerFlavor { + self.with_hints(LinkerFlavor::infer_linker_hints(linker_stem)) + } + pub fn lld_flavor(self) -> LldFlavor { match self { LinkerFlavor::Gnu(..) @@ -1801,7 +1863,7 @@ impl TargetOptions { } fn update_from_cli(&mut self) { - self.linker_flavor = LinkerFlavor::from_cli_impl( + self.linker_flavor = LinkerFlavor::from_cli_json( self.linker_flavor_json, self.lld_flavor_json, self.linker_is_gnu_json, @@ -1815,12 +1877,7 @@ impl TargetOptions { ] { args.clear(); for (flavor, args_json) in args_json { - // Cannot use `from_cli` due to borrow checker. - let linker_flavor = LinkerFlavor::from_cli_impl( - *flavor, - self.lld_flavor_json, - self.linker_is_gnu_json, - ); + let linker_flavor = self.linker_flavor.with_cli_hints(*flavor); // Normalize to no lld to avoid asserts. let linker_flavor = match linker_flavor { LinkerFlavor::Gnu(cc, _) => LinkerFlavor::Gnu(cc, Lld::No), |
