try to infer linker flavor from linker name and vice versa
This commit is contained in:
parent
b73535f1e9
commit
eb74f21f5a
4 changed files with 97 additions and 42 deletions
|
@ -42,7 +42,7 @@ use syntax::feature_gate::AttributeType;
|
|||
use syntax_pos::{MultiSpan, Span};
|
||||
use util::profiling::SelfProfiler;
|
||||
|
||||
use rustc_target::spec::{LinkerFlavor, PanicStrategy};
|
||||
use rustc_target::spec::PanicStrategy;
|
||||
use rustc_target::spec::{Target, TargetTriple};
|
||||
use rustc_data_structures::flock;
|
||||
use jobserver::Client;
|
||||
|
@ -607,13 +607,6 @@ impl Session {
|
|||
.panic
|
||||
.unwrap_or(self.target.target.options.panic_strategy)
|
||||
}
|
||||
pub fn linker_flavor(&self) -> LinkerFlavor {
|
||||
self.opts
|
||||
.debugging_opts
|
||||
.linker_flavor
|
||||
.unwrap_or(self.target.target.linker_flavor)
|
||||
}
|
||||
|
||||
pub fn fewer_names(&self) -> bool {
|
||||
let more_names = self.opts
|
||||
.output_types
|
||||
|
|
|
@ -60,7 +60,7 @@ pub use rustc_codegen_utils::link::{find_crate_name, filename_for_input, default
|
|||
// The third parameter is for env vars, used on windows to set up the
|
||||
// path for MSVC to find its DLLs, and gcc to find its bundled
|
||||
// toolchain
|
||||
pub fn get_linker(sess: &Session) -> (PathBuf, Command) {
|
||||
pub fn get_linker(sess: &Session, linker: &Path, flavor: LinkerFlavor) -> (PathBuf, Command) {
|
||||
// If our linker looks like a batch script on Windows then to execute this
|
||||
// we'll need to spawn `cmd` explicitly. This is primarily done to handle
|
||||
// emscripten where the linker is `emcc.bat` and needs to be spawned as
|
||||
|
@ -69,36 +69,21 @@ pub fn get_linker(sess: &Session) -> (PathBuf, Command) {
|
|||
// This worked historically but is needed manually since #42436 (regression
|
||||
// was tagged as #42791) and some more info can be found on #44443 for
|
||||
// emscripten itself.
|
||||
let cmd = |linker: &Path| {
|
||||
let mut cmd = (|| {
|
||||
if let Some(linker) = linker.to_str() {
|
||||
if cfg!(windows) && linker.ends_with(".bat") {
|
||||
return Command::bat_script(linker)
|
||||
}
|
||||
}
|
||||
match sess.linker_flavor() {
|
||||
match flavor {
|
||||
LinkerFlavor::Lld(f) => Command::lld(linker, f),
|
||||
_ => Command::new(linker),
|
||||
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
let msvc_tool = windows_registry::find_tool(&sess.opts.target_triple.triple(), "link.exe");
|
||||
|
||||
let linker_path = sess.opts.cg.linker.as_ref().map(|s| &**s)
|
||||
.or(sess.target.target.options.linker.as_ref().map(|s| s.as_ref()))
|
||||
.unwrap_or(match sess.linker_flavor() {
|
||||
LinkerFlavor::Msvc => {
|
||||
msvc_tool.as_ref().map(|t| t.path()).unwrap_or("link.exe".as_ref())
|
||||
}
|
||||
LinkerFlavor::Em if cfg!(windows) => "emcc.bat".as_ref(),
|
||||
LinkerFlavor::Em => "emcc".as_ref(),
|
||||
LinkerFlavor::Gcc => "cc".as_ref(),
|
||||
LinkerFlavor::Ld => "ld".as_ref(),
|
||||
LinkerFlavor::Lld(_) => "lld".as_ref(),
|
||||
});
|
||||
|
||||
let mut cmd = cmd(linker_path);
|
||||
|
||||
// The compiler's sysroot often has some bundled tools, so add it to the
|
||||
// PATH for the child.
|
||||
let mut new_path = sess.host_filesearch(PathKind::All)
|
||||
|
@ -125,7 +110,7 @@ pub fn get_linker(sess: &Session) -> (PathBuf, Command) {
|
|||
}
|
||||
cmd.env("PATH", env::join_paths(new_path).unwrap());
|
||||
|
||||
(linker_path.to_path_buf(), cmd)
|
||||
(linker.to_path_buf(), cmd)
|
||||
}
|
||||
|
||||
pub fn remove(sess: &Session, path: &Path) {
|
||||
|
@ -615,6 +600,71 @@ fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLibrary]) {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn linker_and_flavor(sess: &Session) -> Result<(PathBuf, LinkerFlavor), ()> {
|
||||
fn from<F>(
|
||||
sess: &Session,
|
||||
linker: Option<PathBuf>,
|
||||
flavor: Option<LinkerFlavor>,
|
||||
otherwise: F,
|
||||
) -> Result<(PathBuf, LinkerFlavor), ()>
|
||||
where
|
||||
F: FnOnce() -> Result<(PathBuf, LinkerFlavor), ()>
|
||||
{
|
||||
match (linker, flavor) {
|
||||
(Some(linker), Some(flavor)) => Ok((linker, flavor)),
|
||||
// only the linker flavor is known; use the default linker for the selected flavor
|
||||
(None, Some(flavor)) => Ok((PathBuf::from(match flavor {
|
||||
LinkerFlavor::Em => "emcc",
|
||||
LinkerFlavor::Gcc => "gcc",
|
||||
LinkerFlavor::Ld => "ld",
|
||||
LinkerFlavor::Msvc => "link.exe",
|
||||
LinkerFlavor::Lld(_) => "lld",
|
||||
}), flavor)),
|
||||
// infer the linker flavor from the linker name
|
||||
(Some(linker), None) => {
|
||||
let stem = linker.file_stem().and_then(|stem| stem.to_str()).ok_or_else(|| {
|
||||
sess
|
||||
.struct_err(&format!("couldn't extract file stem from specified linker"))
|
||||
.emit();
|
||||
})?.to_owned();
|
||||
|
||||
let flavor = if stem == "emcc" {
|
||||
LinkerFlavor::Em
|
||||
} else if stem == "gcc" || stem.ends_with("-gcc") {
|
||||
LinkerFlavor::Gcc
|
||||
} else if stem == "ld" || stem == "ld.lld" || stem.ends_with("-ld") {
|
||||
LinkerFlavor::Ld
|
||||
} else if stem == "link" || stem == "lld-link" {
|
||||
LinkerFlavor::Msvc
|
||||
} else {
|
||||
sess
|
||||
.struct_err(&format!("couldn't infer linker flavor from specified linker"))
|
||||
.emit();
|
||||
return Err(());
|
||||
};
|
||||
|
||||
Ok((linker, flavor))
|
||||
},
|
||||
(None, None) => otherwise(),
|
||||
}
|
||||
}
|
||||
|
||||
// linker and linker flavor specified via command line have precedence over what the target
|
||||
// specification specifies
|
||||
from(sess, sess.opts.cg.linker.clone(), sess.opts.debugging_opts.linker_flavor, || {
|
||||
from(
|
||||
sess,
|
||||
sess.target.target.options.linker.clone().map(PathBuf::from),
|
||||
Some(sess.target.target.linker_flavor),
|
||||
|| {
|
||||
sess
|
||||
.struct_err(&format!("no linker or linker flavor information provided"))
|
||||
.emit();
|
||||
Err(())
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// Create a dynamic library or executable
|
||||
//
|
||||
// This will invoke the system linker/cc to create the resulting file. This
|
||||
|
@ -625,10 +675,15 @@ fn link_natively(sess: &Session,
|
|||
codegen_results: &CodegenResults,
|
||||
tmpdir: &Path) {
|
||||
info!("preparing {:?} to {:?}", crate_type, out_filename);
|
||||
let flavor = sess.linker_flavor();
|
||||
let (linker, flavor) = if let Ok((linker, flavor)) = linker_and_flavor(sess) {
|
||||
(linker, flavor)
|
||||
} else {
|
||||
sess.abort_if_errors();
|
||||
return;
|
||||
};
|
||||
|
||||
// The invocations of cc share some flags across platforms
|
||||
let (pname, mut cmd) = get_linker(sess);
|
||||
let (pname, mut cmd) = get_linker(sess, &linker, flavor);
|
||||
|
||||
let root = sess.target_filesearch(PathKind::Native).get_lib_path();
|
||||
if let Some(args) = sess.target.target.options.pre_link_args.get(&flavor) {
|
||||
|
@ -669,8 +724,8 @@ fn link_natively(sess: &Session,
|
|||
}
|
||||
|
||||
{
|
||||
let mut linker = codegen_results.linker_info.to_linker(cmd, &sess);
|
||||
link_args(&mut *linker, sess, crate_type, tmpdir,
|
||||
let mut linker = codegen_results.linker_info.to_linker(cmd, &sess, flavor);
|
||||
link_args(&mut *linker, flavor, sess, crate_type, tmpdir,
|
||||
out_filename, codegen_results);
|
||||
cmd = linker.finalize();
|
||||
}
|
||||
|
@ -742,7 +797,7 @@ fn link_natively(sess: &Session,
|
|||
// linking executables as pie. Different versions of gcc seem to use
|
||||
// different quotes in the error message so don't check for them.
|
||||
if sess.target.target.options.linker_is_gnu &&
|
||||
sess.linker_flavor() != LinkerFlavor::Ld &&
|
||||
flavor != LinkerFlavor::Ld &&
|
||||
(out.contains("unrecognized command line option") ||
|
||||
out.contains("unknown argument")) &&
|
||||
out.contains("-no-pie") &&
|
||||
|
@ -991,6 +1046,7 @@ fn exec_linker(sess: &Session, cmd: &mut Command, out_filename: &Path, tmpdir: &
|
|||
}
|
||||
|
||||
fn link_args(cmd: &mut dyn Linker,
|
||||
flavor: LinkerFlavor,
|
||||
sess: &Session,
|
||||
crate_type: config::CrateType,
|
||||
tmpdir: &Path,
|
||||
|
@ -1075,7 +1131,7 @@ fn link_args(cmd: &mut dyn Linker,
|
|||
// independent executables by default. We have to pass -no-pie to
|
||||
// explicitly turn that off. Not applicable to ld.
|
||||
if sess.target.target.options.linker_is_gnu
|
||||
&& sess.linker_flavor() != LinkerFlavor::Ld {
|
||||
&& flavor != LinkerFlavor::Ld {
|
||||
cmd.no_position_independent_executable();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,8 +44,9 @@ impl LinkerInfo {
|
|||
|
||||
pub fn to_linker<'a>(&'a self,
|
||||
cmd: Command,
|
||||
sess: &'a Session) -> Box<dyn Linker+'a> {
|
||||
match sess.linker_flavor() {
|
||||
sess: &'a Session,
|
||||
flavor: LinkerFlavor) -> Box<dyn Linker+'a> {
|
||||
match flavor {
|
||||
LinkerFlavor::Lld(LldFlavor::Link) |
|
||||
LinkerFlavor::Msvc => {
|
||||
Box::new(MsvcLinker {
|
||||
|
|
|
@ -1503,12 +1503,17 @@ fn start_executing_work(tcx: TyCtxt,
|
|||
|
||||
let assembler_cmd = if modules_config.no_integrated_as {
|
||||
// HACK: currently we use linker (gcc) as our assembler
|
||||
let (name, mut cmd) = get_linker(sess);
|
||||
cmd.args(&sess.target.target.options.asm_args);
|
||||
Some(Arc::new(AssemblerCommand {
|
||||
name,
|
||||
cmd,
|
||||
}))
|
||||
if let Ok((linker, flavor)) = link::linker_and_flavor(sess) {
|
||||
let (name, mut cmd) = get_linker(sess, &linker, flavor);
|
||||
cmd.args(&sess.target.target.options.asm_args);
|
||||
Some(Arc::new(AssemblerCommand {
|
||||
name,
|
||||
cmd,
|
||||
}))
|
||||
} else {
|
||||
sess.abort_if_errors();
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue