1
Fork 0

rustc_target: Refactor internal linker flavors

In accordance with the design from https://github.com/rust-lang/rust/pull/96827#issuecomment-1208441595
This commit is contained in:
Vadim Petrochenkov 2022-08-06 21:08:46 +03:00
parent 4bd30785eb
commit 572b6a9c60
104 changed files with 569 additions and 438 deletions

View file

@ -16,7 +16,7 @@ use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo, S
use rustc_middle::ty::TyCtxt;
use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip};
use rustc_session::Session;
use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor};
use rustc_target::spec::{Cc, LinkOutputKind, LinkerFlavor, Lld};
use cc::windows_registry;
@ -56,8 +56,13 @@ pub fn get_linker<'a>(
let mut cmd = match linker.to_str() {
Some(linker) if cfg!(windows) && linker.ends_with(".bat") => Command::bat_script(linker),
_ => match flavor {
LinkerFlavor::Lld(f) => Command::lld(linker, f),
LinkerFlavor::Msvc if sess.opts.cg.linker.is_none() && sess.target.linker.is_none() => {
LinkerFlavor::Gnu(Cc::No, Lld::Yes)
| LinkerFlavor::Darwin(Cc::No, Lld::Yes)
| LinkerFlavor::WasmLld(Cc::No)
| LinkerFlavor::Msvc(Lld::Yes) => Command::lld(linker, flavor.lld_flavor()),
LinkerFlavor::Msvc(Lld::No)
if sess.opts.cg.linker.is_none() && sess.target.linker.is_none() =>
{
Command::new(msvc_tool.as_ref().map_or(linker, |t| t.path()))
}
_ => Command::new(linker),
@ -68,9 +73,7 @@ pub fn get_linker<'a>(
// To comply with the Windows App Certification Kit,
// MSVC needs to link with the Store versions of the runtime libraries (vcruntime, msvcrt, etc).
let t = &sess.target;
if (flavor == LinkerFlavor::Msvc || flavor == LinkerFlavor::Lld(LldFlavor::Link))
&& t.vendor == "uwp"
{
if matches!(flavor, LinkerFlavor::Msvc(..)) && t.vendor == "uwp" {
if let Some(ref tool) = msvc_tool {
let original_path = tool.path();
if let Some(ref root_lib_path) = original_path.ancestors().nth(4) {
@ -126,23 +129,22 @@ pub fn get_linker<'a>(
// to the linker args construction.
assert!(cmd.get_args().is_empty() || sess.target.vendor == "uwp");
match flavor {
LinkerFlavor::Gcc => {
Box::new(GccLinker { cmd, sess, target_cpu, hinted_static: false, is_ld: false })
as Box<dyn Linker>
}
LinkerFlavor::Ld if sess.target.os == "l4re" => {
LinkerFlavor::Unix(Cc::No) if sess.target.os == "l4re" => {
Box::new(L4Bender::new(cmd, sess)) as Box<dyn Linker>
}
LinkerFlavor::Lld(LldFlavor::Ld)
| LinkerFlavor::Lld(LldFlavor::Ld64)
| LinkerFlavor::Ld => {
Box::new(GccLinker { cmd, sess, target_cpu, hinted_static: false, is_ld: true })
as Box<dyn Linker>
}
LinkerFlavor::Lld(LldFlavor::Link) | LinkerFlavor::Msvc => {
Box::new(MsvcLinker { cmd, sess }) as Box<dyn Linker>
}
LinkerFlavor::Lld(LldFlavor::Wasm) => Box::new(WasmLd::new(cmd, sess)) as Box<dyn Linker>,
LinkerFlavor::WasmLld(Cc::No) => Box::new(WasmLd::new(cmd, sess)) as Box<dyn Linker>,
LinkerFlavor::Gnu(cc, _)
| LinkerFlavor::Darwin(cc, _)
| LinkerFlavor::WasmLld(cc)
| LinkerFlavor::Unix(cc) => Box::new(GccLinker {
cmd,
sess,
target_cpu,
hinted_static: false,
is_ld: cc == Cc::No,
is_gnu: flavor.is_gnu(),
}) as Box<dyn Linker>,
LinkerFlavor::Msvc(..) => Box::new(MsvcLinker { cmd, sess }) as Box<dyn Linker>,
LinkerFlavor::EmCc => Box::new(EmLinker { cmd, sess }) as Box<dyn Linker>,
LinkerFlavor::Bpf => Box::new(BpfLinker { cmd, sess }) as Box<dyn Linker>,
LinkerFlavor::Ptx => Box::new(PtxLinker { cmd, sess }) as Box<dyn Linker>,
@ -211,6 +213,7 @@ pub struct GccLinker<'a> {
hinted_static: bool, // Keeps track of the current hinting mode.
// Link as ld
is_ld: bool,
is_gnu: bool,
}
impl<'a> GccLinker<'a> {
@ -359,7 +362,7 @@ impl<'a> Linker for GccLinker<'a> {
fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) {
match output_kind {
LinkOutputKind::DynamicNoPicExe => {
if !self.is_ld && self.sess.target.linker_is_gnu {
if !self.is_ld && self.is_gnu {
self.cmd.arg("-no-pie");
}
}
@ -373,7 +376,7 @@ impl<'a> Linker for GccLinker<'a> {
LinkOutputKind::StaticNoPicExe => {
// `-static` works for both gcc wrapper and ld.
self.cmd.arg("-static");
if !self.is_ld && self.sess.target.linker_is_gnu {
if !self.is_ld && self.is_gnu {
self.cmd.arg("-no-pie");
}
}
@ -432,31 +435,25 @@ impl<'a> Linker for GccLinker<'a> {
// has -needed-l{} / -needed_library {}
// but we have no way to detect that here.
self.sess.warn("`as-needed` modifier not implemented yet for ld64");
} else if self.sess.target.linker_is_gnu && !self.sess.target.is_like_windows {
} else if self.is_gnu && !self.sess.target.is_like_windows {
self.linker_arg("--no-as-needed");
} else {
self.sess.warn("`as-needed` modifier not supported for current linker");
}
}
self.hint_dynamic();
self.cmd.arg(format!(
"-l{}{lib}",
if verbatim && self.sess.target.linker_is_gnu { ":" } else { "" },
));
self.cmd.arg(format!("-l{}{lib}", if verbatim && self.is_gnu { ":" } else { "" },));
if !as_needed {
if self.sess.target.is_like_osx {
// See above FIXME comment
} else if self.sess.target.linker_is_gnu && !self.sess.target.is_like_windows {
} else if self.is_gnu && !self.sess.target.is_like_windows {
self.linker_arg("--as-needed");
}
}
}
fn link_staticlib(&mut self, lib: &str, verbatim: bool) {
self.hint_static();
self.cmd.arg(format!(
"-l{}{lib}",
if verbatim && self.sess.target.linker_is_gnu { ":" } else { "" },
));
self.cmd.arg(format!("-l{}{lib}", if verbatim && self.is_gnu { ":" } else { "" },));
}
fn link_rlib(&mut self, lib: &Path) {
self.hint_static();
@ -511,10 +508,7 @@ impl<'a> Linker for GccLinker<'a> {
let target = &self.sess.target;
if !target.is_like_osx {
self.linker_arg("--whole-archive");
self.cmd.arg(format!(
"-l{}{lib}",
if verbatim && self.sess.target.linker_is_gnu { ":" } else { "" },
));
self.cmd.arg(format!("-l{}{lib}", if verbatim && self.is_gnu { ":" } else { "" },));
self.linker_arg("--no-whole-archive");
} else {
// -force_load is the macOS equivalent of --whole-archive, but it
@ -559,21 +553,19 @@ impl<'a> Linker for GccLinker<'a> {
// eliminate the metadata. If we're building an executable, however,
// --gc-sections drops the size of hello world from 1.8MB to 597K, a 67%
// reduction.
} else if (self.sess.target.linker_is_gnu || self.sess.target.is_like_wasm)
&& !keep_metadata
{
} else if (self.is_gnu || self.sess.target.is_like_wasm) && !keep_metadata {
self.linker_arg("--gc-sections");
}
}
fn no_gc_sections(&mut self) {
if self.sess.target.linker_is_gnu || self.sess.target.is_like_wasm {
if self.is_gnu || self.sess.target.is_like_wasm {
self.linker_arg("--no-gc-sections");
}
}
fn optimize(&mut self) {
if !self.sess.target.linker_is_gnu && !self.sess.target.is_like_wasm {
if !self.is_gnu && !self.sess.target.is_like_wasm {
return;
}
@ -587,7 +579,7 @@ impl<'a> Linker for GccLinker<'a> {
}
fn pgo_gen(&mut self) {
if !self.sess.target.linker_is_gnu {
if !self.is_gnu {
return;
}
@ -758,13 +750,13 @@ impl<'a> Linker for GccLinker<'a> {
fn add_no_exec(&mut self) {
if self.sess.target.is_like_windows {
self.linker_arg("--nxcompat");
} else if self.sess.target.linker_is_gnu {
} else if self.is_gnu {
self.linker_arg("-znoexecstack");
}
}
fn add_as_needed(&mut self) {
if self.sess.target.linker_is_gnu && !self.sess.target.is_like_windows {
if self.is_gnu && !self.sess.target.is_like_windows {
self.linker_arg("--as-needed");
} else if self.sess.target.is_like_solaris {
// -z ignore is the Solaris equivalent to the GNU ld --as-needed option