Skip to content

Commit eb74f21

Browse files
committed
try to infer linker flavor from linker name and vice versa
1 parent b73535f commit eb74f21

File tree

4 files changed

+97
-42
lines changed

4 files changed

+97
-42
lines changed

src/librustc/session/mod.rs

+1-8
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ use syntax::feature_gate::AttributeType;
4242
use syntax_pos::{MultiSpan, Span};
4343
use util::profiling::SelfProfiler;
4444

45-
use rustc_target::spec::{LinkerFlavor, PanicStrategy};
45+
use rustc_target::spec::PanicStrategy;
4646
use rustc_target::spec::{Target, TargetTriple};
4747
use rustc_data_structures::flock;
4848
use jobserver::Client;
@@ -607,13 +607,6 @@ impl Session {
607607
.panic
608608
.unwrap_or(self.target.target.options.panic_strategy)
609609
}
610-
pub fn linker_flavor(&self) -> LinkerFlavor {
611-
self.opts
612-
.debugging_opts
613-
.linker_flavor
614-
.unwrap_or(self.target.target.linker_flavor)
615-
}
616-
617610
pub fn fewer_names(&self) -> bool {
618611
let more_names = self.opts
619612
.output_types

src/librustc_codegen_llvm/back/link.rs

+82-26
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ pub use rustc_codegen_utils::link::{find_crate_name, filename_for_input, default
6060
// The third parameter is for env vars, used on windows to set up the
6161
// path for MSVC to find its DLLs, and gcc to find its bundled
6262
// toolchain
63-
pub fn get_linker(sess: &Session) -> (PathBuf, Command) {
63+
pub fn get_linker(sess: &Session, linker: &Path, flavor: LinkerFlavor) -> (PathBuf, Command) {
6464
// If our linker looks like a batch script on Windows then to execute this
6565
// we'll need to spawn `cmd` explicitly. This is primarily done to handle
6666
// 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) {
6969
// This worked historically but is needed manually since #42436 (regression
7070
// was tagged as #42791) and some more info can be found on #44443 for
7171
// emscripten itself.
72-
let cmd = |linker: &Path| {
72+
let mut cmd = (|| {
7373
if let Some(linker) = linker.to_str() {
7474
if cfg!(windows) && linker.ends_with(".bat") {
7575
return Command::bat_script(linker)
7676
}
7777
}
78-
match sess.linker_flavor() {
78+
match flavor {
7979
LinkerFlavor::Lld(f) => Command::lld(linker, f),
8080
_ => Command::new(linker),
8181

8282
}
83-
};
83+
})();
8484

8585
let msvc_tool = windows_registry::find_tool(&sess.opts.target_triple.triple(), "link.exe");
8686

87-
let linker_path = sess.opts.cg.linker.as_ref().map(|s| &**s)
88-
.or(sess.target.target.options.linker.as_ref().map(|s| s.as_ref()))
89-
.unwrap_or(match sess.linker_flavor() {
90-
LinkerFlavor::Msvc => {
91-
msvc_tool.as_ref().map(|t| t.path()).unwrap_or("link.exe".as_ref())
92-
}
93-
LinkerFlavor::Em if cfg!(windows) => "emcc.bat".as_ref(),
94-
LinkerFlavor::Em => "emcc".as_ref(),
95-
LinkerFlavor::Gcc => "cc".as_ref(),
96-
LinkerFlavor::Ld => "ld".as_ref(),
97-
LinkerFlavor::Lld(_) => "lld".as_ref(),
98-
});
99-
100-
let mut cmd = cmd(linker_path);
101-
10287
// The compiler's sysroot often has some bundled tools, so add it to the
10388
// PATH for the child.
10489
let mut new_path = sess.host_filesearch(PathKind::All)
@@ -125,7 +110,7 @@ pub fn get_linker(sess: &Session) -> (PathBuf, Command) {
125110
}
126111
cmd.env("PATH", env::join_paths(new_path).unwrap());
127112

128-
(linker_path.to_path_buf(), cmd)
113+
(linker.to_path_buf(), cmd)
129114
}
130115

131116
pub fn remove(sess: &Session, path: &Path) {
@@ -615,6 +600,71 @@ fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLibrary]) {
615600
}
616601
}
617602

603+
pub fn linker_and_flavor(sess: &Session) -> Result<(PathBuf, LinkerFlavor), ()> {
604+
fn from<F>(
605+
sess: &Session,
606+
linker: Option<PathBuf>,
607+
flavor: Option<LinkerFlavor>,
608+
otherwise: F,
609+
) -> Result<(PathBuf, LinkerFlavor), ()>
610+
where
611+
F: FnOnce() -> Result<(PathBuf, LinkerFlavor), ()>
612+
{
613+
match (linker, flavor) {
614+
(Some(linker), Some(flavor)) => Ok((linker, flavor)),
615+
// only the linker flavor is known; use the default linker for the selected flavor
616+
(None, Some(flavor)) => Ok((PathBuf::from(match flavor {
617+
LinkerFlavor::Em => "emcc",
618+
LinkerFlavor::Gcc => "gcc",
619+
LinkerFlavor::Ld => "ld",
620+
LinkerFlavor::Msvc => "link.exe",
621+
LinkerFlavor::Lld(_) => "lld",
622+
}), flavor)),
623+
// infer the linker flavor from the linker name
624+
(Some(linker), None) => {
625+
let stem = linker.file_stem().and_then(|stem| stem.to_str()).ok_or_else(|| {
626+
sess
627+
.struct_err(&format!("couldn't extract file stem from specified linker"))
628+
.emit();
629+
})?.to_owned();
630+
631+
let flavor = if stem == "emcc" {
632+
LinkerFlavor::Em
633+
} else if stem == "gcc" || stem.ends_with("-gcc") {
634+
LinkerFlavor::Gcc
635+
} else if stem == "ld" || stem == "ld.lld" || stem.ends_with("-ld") {
636+
LinkerFlavor::Ld
637+
} else if stem == "link" || stem == "lld-link" {
638+
LinkerFlavor::Msvc
639+
} else {
640+
sess
641+
.struct_err(&format!("couldn't infer linker flavor from specified linker"))
642+
.emit();
643+
return Err(());
644+
};
645+
646+
Ok((linker, flavor))
647+
},
648+
(None, None) => otherwise(),
649+
}
650+
}
651+
652+
// linker and linker flavor specified via command line have precedence over what the target
653+
// specification specifies
654+
from(sess, sess.opts.cg.linker.clone(), sess.opts.debugging_opts.linker_flavor, || {
655+
from(
656+
sess,
657+
sess.target.target.options.linker.clone().map(PathBuf::from),
658+
Some(sess.target.target.linker_flavor),
659+
|| {
660+
sess
661+
.struct_err(&format!("no linker or linker flavor information provided"))
662+
.emit();
663+
Err(())
664+
})
665+
})
666+
}
667+
618668
// Create a dynamic library or executable
619669
//
620670
// This will invoke the system linker/cc to create the resulting file. This
@@ -625,10 +675,15 @@ fn link_natively(sess: &Session,
625675
codegen_results: &CodegenResults,
626676
tmpdir: &Path) {
627677
info!("preparing {:?} to {:?}", crate_type, out_filename);
628-
let flavor = sess.linker_flavor();
678+
let (linker, flavor) = if let Ok((linker, flavor)) = linker_and_flavor(sess) {
679+
(linker, flavor)
680+
} else {
681+
sess.abort_if_errors();
682+
return;
683+
};
629684

630685
// The invocations of cc share some flags across platforms
631-
let (pname, mut cmd) = get_linker(sess);
686+
let (pname, mut cmd) = get_linker(sess, &linker, flavor);
632687

633688
let root = sess.target_filesearch(PathKind::Native).get_lib_path();
634689
if let Some(args) = sess.target.target.options.pre_link_args.get(&flavor) {
@@ -669,8 +724,8 @@ fn link_natively(sess: &Session,
669724
}
670725

671726
{
672-
let mut linker = codegen_results.linker_info.to_linker(cmd, &sess);
673-
link_args(&mut *linker, sess, crate_type, tmpdir,
727+
let mut linker = codegen_results.linker_info.to_linker(cmd, &sess, flavor);
728+
link_args(&mut *linker, flavor, sess, crate_type, tmpdir,
674729
out_filename, codegen_results);
675730
cmd = linker.finalize();
676731
}
@@ -742,7 +797,7 @@ fn link_natively(sess: &Session,
742797
// linking executables as pie. Different versions of gcc seem to use
743798
// different quotes in the error message so don't check for them.
744799
if sess.target.target.options.linker_is_gnu &&
745-
sess.linker_flavor() != LinkerFlavor::Ld &&
800+
flavor != LinkerFlavor::Ld &&
746801
(out.contains("unrecognized command line option") ||
747802
out.contains("unknown argument")) &&
748803
out.contains("-no-pie") &&
@@ -991,6 +1046,7 @@ fn exec_linker(sess: &Session, cmd: &mut Command, out_filename: &Path, tmpdir: &
9911046
}
9921047

9931048
fn link_args(cmd: &mut dyn Linker,
1049+
flavor: LinkerFlavor,
9941050
sess: &Session,
9951051
crate_type: config::CrateType,
9961052
tmpdir: &Path,
@@ -1075,7 +1131,7 @@ fn link_args(cmd: &mut dyn Linker,
10751131
// independent executables by default. We have to pass -no-pie to
10761132
// explicitly turn that off. Not applicable to ld.
10771133
if sess.target.target.options.linker_is_gnu
1078-
&& sess.linker_flavor() != LinkerFlavor::Ld {
1134+
&& flavor != LinkerFlavor::Ld {
10791135
cmd.no_position_independent_executable();
10801136
}
10811137
}

src/librustc_codegen_llvm/back/linker.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,9 @@ impl LinkerInfo {
4444

4545
pub fn to_linker<'a>(&'a self,
4646
cmd: Command,
47-
sess: &'a Session) -> Box<dyn Linker+'a> {
48-
match sess.linker_flavor() {
47+
sess: &'a Session,
48+
flavor: LinkerFlavor) -> Box<dyn Linker+'a> {
49+
match flavor {
4950
LinkerFlavor::Lld(LldFlavor::Link) |
5051
LinkerFlavor::Msvc => {
5152
Box::new(MsvcLinker {

src/librustc_codegen_llvm/back/write.rs

+11-6
Original file line numberDiff line numberDiff line change
@@ -1503,12 +1503,17 @@ fn start_executing_work(tcx: TyCtxt,
15031503

15041504
let assembler_cmd = if modules_config.no_integrated_as {
15051505
// HACK: currently we use linker (gcc) as our assembler
1506-
let (name, mut cmd) = get_linker(sess);
1507-
cmd.args(&sess.target.target.options.asm_args);
1508-
Some(Arc::new(AssemblerCommand {
1509-
name,
1510-
cmd,
1511-
}))
1506+
if let Ok((linker, flavor)) = link::linker_and_flavor(sess) {
1507+
let (name, mut cmd) = get_linker(sess, &linker, flavor);
1508+
cmd.args(&sess.target.target.options.asm_args);
1509+
Some(Arc::new(AssemblerCommand {
1510+
name,
1511+
cmd,
1512+
}))
1513+
} else {
1514+
sess.abort_if_errors();
1515+
None
1516+
}
15121517
} else {
15131518
None
15141519
};

0 commit comments

Comments
 (0)