Skip to content

Commit ce52e0e

Browse files
committed
rustc: Tweak default linker selection
This commit refactors how the path to the linker that we're going to invoke is selected. Previously all targets listed *both* a `LinkerFlavor` and a `linker` (path) option, but this meant that whenever you changed one you had to change the other. The purpose of this commit is to avoid coupling these where possible. Target specifications now only unconditionally define the *flavor* of the linker that they're using by default. If not otherwise specified each flavor now implies a particular default linker to run. As a result, this means that if you'd like to test out `ld` for example you should be able to do: rustc -Z linker-flavor=ld foo.rs whereas previously you had to do rustc -Z linker-flavor=ld -C linker=ld foo.rs This will hopefully make it a bit easier to tinker around with variants that should otherwise be well known to work, for example with LLD, `ld` on OSX, etc.
1 parent 50642c8 commit ce52e0e

24 files changed

+56
-101
lines changed

src/librustc_back/lib.rs

+6
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ pub enum LinkerFlavor {
5757
RustcEncodable, RustcDecodable)]
5858
pub enum LldFlavor {
5959
Wasm,
60+
Ld64,
61+
Ld,
62+
Link,
6063
}
6164

6265
impl ToJson for LinkerFlavor {
@@ -94,6 +97,9 @@ flavor_mappings! {
9497
((LinkerFlavor::Ld), "ld"),
9598
((LinkerFlavor::Msvc), "msvc"),
9699
((LinkerFlavor::Lld(LldFlavor::Wasm)), "wasm-ld"),
100+
((LinkerFlavor::Lld(LldFlavor::Ld64)), "ld64.lld"),
101+
((LinkerFlavor::Lld(LldFlavor::Ld)), "ld.lld"),
102+
((LinkerFlavor::Lld(LldFlavor::Link)), "lld-link"),
97103
}
98104

99105
#[derive(Clone, Copy, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]

src/librustc_back/target/aarch64_unknown_cloudabi.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ pub fn target() -> TargetResult {
1515
let mut base = super::cloudabi_base::opts();
1616
base.max_atomic_width = Some(128);
1717
base.abi_blacklist = super::arm_base::abi_blacklist();
18-
base.linker = "aarch64-unknown-cloudabi-cc".to_string();
18+
base.linker = Some("aarch64-unknown-cloudabi-cc".to_string());
1919

2020
Ok(Target {
2121
llvm_target: "aarch64-unknown-cloudabi".to_string(),

src/librustc_back/target/armv7_unknown_cloudabi_eabihf.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pub fn target() -> TargetResult {
1717
base.max_atomic_width = Some(64);
1818
base.features = "+v7,+vfp3,+neon".to_string();
1919
base.abi_blacklist = super::arm_base::abi_blacklist();
20-
base.linker = "armv7-unknown-cloudabi-eabihf-cc".to_string();
20+
base.linker = Some("armv7-unknown-cloudabi-eabihf-cc".to_string());
2121

2222
Ok(Target {
2323
llvm_target: "armv7-unknown-cloudabi-eabihf".to_string(),

src/librustc_back/target/asmjs_unknown_emscripten.rs

-3
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010

1111
use LinkerFlavor;
1212
use super::{LinkArgs, Target, TargetOptions};
13-
use super::emscripten_base::{cmd};
1413

1514
pub fn target() -> Result<Target, String> {
1615
let mut args = LinkArgs::new();
@@ -19,8 +18,6 @@ pub fn target() -> Result<Target, String> {
1918
"ERROR_ON_UNDEFINED_SYMBOLS=1".to_string()]);
2019

2120
let opts = TargetOptions {
22-
linker: cmd("emcc"),
23-
2421
dynamic_linking: false,
2522
executables: true,
2623
exe_suffix: ".js".to_string(),

src/librustc_back/target/emscripten_base.rs

-17
This file was deleted.

src/librustc_back/target/haiku_base.rs

-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ use std::default::Default;
1313

1414
pub fn opts() -> TargetOptions {
1515
TargetOptions {
16-
linker: "cc".to_string(),
1716
dynamic_linking: true,
1817
executables: true,
1918
has_rpath: false,

src/librustc_back/target/i686_unknown_cloudabi.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ pub fn target() -> TargetResult {
1515
let mut base = super::cloudabi_base::opts();
1616
base.cpu = "pentium4".to_string();
1717
base.max_atomic_width = Some(64);
18-
base.linker = "i686-unknown-cloudabi-cc".to_string();
18+
base.linker = Some("i686-unknown-cloudabi-cc".to_string());
1919
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
2020
base.stack_probes = true;
2121

src/librustc_back/target/l4re_base.rs

-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,6 @@ pub fn opts() -> Result<TargetOptions, String> {
7373
has_elf_tls: false,
7474
exe_allocation_crate: None,
7575
panic_strategy: PanicStrategy::Abort,
76-
linker: "ld".to_string(),
7776
pre_link_args,
7877
post_link_args,
7978
target_family: Some("unix".to_string()),

src/librustc_back/target/mod.rs

+4-5
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@ mod arm_base;
5858
mod bitrig_base;
5959
mod cloudabi_base;
6060
mod dragonfly_base;
61-
mod emscripten_base;
6261
mod freebsd_base;
6362
mod haiku_base;
6463
mod linux_base;
@@ -276,8 +275,8 @@ pub struct TargetOptions {
276275
/// Whether the target is built-in or loaded from a custom target specification.
277276
pub is_builtin: bool,
278277

279-
/// Linker to invoke. Defaults to "cc".
280-
pub linker: String,
278+
/// Linker to invoke
279+
pub linker: Option<String>,
281280

282281
/// Linker arguments that are unconditionally passed *before* any
283282
/// user-defined libraries.
@@ -480,7 +479,7 @@ impl Default for TargetOptions {
480479
fn default() -> TargetOptions {
481480
TargetOptions {
482481
is_builtin: false,
483-
linker: option_env!("CFG_DEFAULT_LINKER").unwrap_or("cc").to_string(),
482+
linker: option_env!("CFG_DEFAULT_LINKER").map(|s| s.to_string()),
484483
pre_link_args: LinkArgs::new(),
485484
post_link_args: LinkArgs::new(),
486485
asm_args: Vec::new(),
@@ -730,7 +729,7 @@ impl Target {
730729
}
731730

732731
key!(is_builtin, bool);
733-
key!(linker);
732+
key!(linker, optional);
734733
key!(pre_link_args, link_args);
735734
key!(pre_link_objects_exe, list);
736735
key!(pre_link_objects_dll, list);

src/librustc_back/target/msp430_none_elf.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ pub fn target() -> TargetResult {
3232
// to gcc to get object files. For this reason we have a hard
3333
// dependency on this specific gcc.
3434
asm_args: vec!["-mcpu=msp430".to_string()],
35-
linker: "msp430-elf-gcc".to_string(),
35+
linker: Some("msp430-elf-gcc".to_string()),
3636
no_integrated_as: true,
3737

3838
// There are no atomic instructions available in the MSP430

src/librustc_back/target/thumb_base.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ pub fn opts() -> TargetOptions {
4545
executables: true,
4646
// In 99%+ of cases, we want to use the `arm-none-eabi-gcc` compiler (there aren't many
4747
// options around)
48-
linker: "arm-none-eabi-gcc".to_string(),
48+
linker: Some("arm-none-eabi-gcc".to_string()),
4949
// Because these devices have very little resources having an unwinder is too onerous so we
5050
// default to "abort" because the "unwind" strategy is very rare.
5151
panic_strategy: PanicStrategy::Abort,

src/librustc_back/target/wasm32_experimental_emscripten.rs

-3
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010

1111
use LinkerFlavor;
1212
use super::{LinkArgs, Target, TargetOptions};
13-
use super::emscripten_base::{cmd};
1413

1514
pub fn target() -> Result<Target, String> {
1615
let mut post_link_args = LinkArgs::new();
@@ -24,8 +23,6 @@ pub fn target() -> Result<Target, String> {
2423
"-g3".to_string()]);
2524

2625
let opts = TargetOptions {
27-
linker: cmd("emcc"),
28-
2926
dynamic_linking: false,
3027
executables: true,
3128
// Today emcc emits two files - a .js file to bootstrap and

src/librustc_back/target/wasm32_unknown_emscripten.rs

-3
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010

1111
use LinkerFlavor;
1212
use super::{LinkArgs, Target, TargetOptions};
13-
use super::emscripten_base::{cmd};
1413

1514
pub fn target() -> Result<Target, String> {
1615
let mut post_link_args = LinkArgs::new();
@@ -21,8 +20,6 @@ pub fn target() -> Result<Target, String> {
2120
"ERROR_ON_UNDEFINED_SYMBOLS=1".to_string()]);
2221

2322
let opts = TargetOptions {
24-
linker: cmd("emcc"),
25-
2623
dynamic_linking: false,
2724
executables: true,
2825
// Today emcc emits two files - a .js file to bootstrap and

src/librustc_back/target/wasm32_unknown_unknown.rs

-2
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@ use super::{Target, TargetOptions, PanicStrategy};
2222

2323
pub fn target() -> Result<Target, String> {
2424
let opts = TargetOptions {
25-
linker: "lld".to_string(),
26-
2725
// we allow dynamic linking, but only cdylibs. Basically we allow a
2826
// final library artifact that exports some symbols (a wasm module) but
2927
// we don't allow intermediate `dylib` crate types

src/librustc_back/target/windows_base.rs

-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,6 @@ pub fn opts() -> TargetOptions {
7575
TargetOptions {
7676
// FIXME(#13846) this should be enabled for windows
7777
function_sections: false,
78-
linker: "gcc".to_string(),
7978
dynamic_linking: true,
8079
executables: true,
8180
dll_prefix: "".to_string(),

src/librustc_back/target/windows_msvc_base.rs

-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ pub fn opts() -> TargetOptions {
2020

2121
TargetOptions {
2222
function_sections: true,
23-
linker: "link.exe".to_string(),
2423
dynamic_linking: true,
2524
executables: true,
2625
dll_prefix: "".to_string(),

src/librustc_back/target/x86_64_rumprun_netbsd.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ pub fn target() -> TargetResult {
1515
let mut base = super::netbsd_base::opts();
1616
base.cpu = "x86-64".to_string();
1717
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
18-
base.linker = "x86_64-rumprun-netbsd-gcc".to_string();
18+
base.linker = Some("x86_64-rumprun-netbsd-gcc".to_string());
1919
base.max_atomic_width = Some(64);
2020

2121
base.dynamic_linking = false;

src/librustc_back/target/x86_64_unknown_cloudabi.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ pub fn target() -> TargetResult {
1515
let mut base = super::cloudabi_base::opts();
1616
base.cpu = "x86-64".to_string();
1717
base.max_atomic_width = Some(64);
18-
base.linker = "x86_64-unknown-cloudabi-cc".to_string();
18+
base.linker = Some("x86_64-unknown-cloudabi-cc".to_string());
1919
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
2020
base.stack_probes = true;
2121

src/librustc_trans/Cargo.toml

+1-3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ test = false
1111

1212
[dependencies]
1313
bitflags = "1.0"
14+
cc = "1.0.1"
1415
flate2 = "1.0"
1516
jobserver = "0.1.5"
1617
libc = "0.2"
@@ -34,9 +35,6 @@ syntax = { path = "../libsyntax" }
3435
syntax_pos = { path = "../libsyntax_pos" }
3536
tempdir = "0.3"
3637

37-
[target."cfg(windows)".dependencies]
38-
cc = "1.0.1"
39-
4038
[features]
4139
# Used to communicate the feature to `rustc_back` in the same manner that the
4240
# `rustc` driver script communicate this.

src/librustc_trans/back/command.rs

+3-11
Original file line numberDiff line numberDiff line change
@@ -81,17 +81,6 @@ impl Command {
8181
self
8282
}
8383

84-
pub fn envs<I, K, V>(&mut self, envs: I) -> &mut Command
85-
where I: IntoIterator<Item=(K, V)>,
86-
K: AsRef<OsStr>,
87-
V: AsRef<OsStr>
88-
{
89-
for (key, value) in envs {
90-
self._env(key.as_ref(), value.as_ref());
91-
}
92-
self
93-
}
94-
9584
fn _env(&mut self, key: &OsStr, value: &OsStr) {
9685
self.env.push((key.to_owned(), value.to_owned()));
9786
}
@@ -112,6 +101,9 @@ impl Command {
112101
let mut c = process::Command::new(p);
113102
c.arg("-flavor").arg(match flavor {
114103
LldFlavor::Wasm => "wasm",
104+
LldFlavor::Ld => "gnu",
105+
LldFlavor::Link => "link",
106+
LldFlavor::Ld64 => "darwin",
115107
});
116108
c
117109
}

src/librustc_trans/back/link.rs

+30-41
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
use cc::windows_registry;
1112
use super::archive::{ArchiveBuilder, ArchiveConfig};
1213
use super::bytecode::RLIB_BYTECODE_EXTENSION;
1314
use super::linker::Linker;
@@ -58,9 +59,7 @@ pub use rustc_trans_utils::link::{find_crate_name, filename_for_input, default_o
5859
// The third parameter is for env vars, used on windows to set up the
5960
// path for MSVC to find its DLLs, and gcc to find its bundled
6061
// toolchain
61-
pub fn get_linker(sess: &Session) -> (PathBuf, Command, Vec<(OsString, OsString)>) {
62-
let envs = vec![("PATH".into(), command_path(sess))];
63-
62+
pub fn get_linker(sess: &Session) -> (PathBuf, Command) {
6463
// If our linker looks like a batch script on Windows then to execute this
6564
// we'll need to spawn `cmd` explicitly. This is primarily done to handle
6665
// emscripten where the linker is `emcc.bat` and needs to be spawned as
@@ -75,49 +74,41 @@ pub fn get_linker(sess: &Session) -> (PathBuf, Command, Vec<(OsString, OsString)
7574
return Command::bat_script(linker)
7675
}
7776
}
78-
Command::new(linker)
77+
match sess.linker_flavor() {
78+
LinkerFlavor::Lld(f) => Command::lld(linker, f),
79+
_ => Command::new(linker),
80+
81+
}
7982
};
8083

81-
if let Some(ref linker) = sess.opts.cg.linker {
82-
(linker.clone(), cmd(linker), envs)
83-
} else if sess.target.target.options.is_like_msvc {
84-
let (cmd, envs) = msvc_link_exe_cmd(sess);
85-
(PathBuf::from("link.exe"), cmd, envs)
86-
} else if let LinkerFlavor::Lld(f) = sess.linker_flavor() {
87-
let linker = PathBuf::from(&sess.target.target.options.linker);
88-
let cmd = Command::lld(&linker, f);
89-
(linker, cmd, envs)
90-
} else {
91-
let linker = PathBuf::from(&sess.target.target.options.linker);
92-
let cmd = cmd(&linker);
93-
(linker, cmd, envs)
94-
}
95-
}
84+
let msvc_tool = windows_registry::find_tool(&sess.opts.target_triple, "link.exe");
9685

97-
#[cfg(windows)]
98-
pub fn msvc_link_exe_cmd(sess: &Session) -> (Command, Vec<(OsString, OsString)>) {
99-
use cc::windows_registry;
86+
let linker_path = sess.opts.cg.linker.as_ref().map(|s| &**s)
87+
.or(sess.target.target.options.linker.as_ref().map(|s| s.as_ref()))
88+
.unwrap_or(match sess.linker_flavor() {
89+
LinkerFlavor::Msvc => {
90+
msvc_tool.as_ref().map(|t| t.path()).unwrap_or("link.exe".as_ref())
91+
}
92+
LinkerFlavor::Em if cfg!(windows) => "emcc.bat".as_ref(),
93+
LinkerFlavor::Em => "emcc".as_ref(),
94+
LinkerFlavor::Gcc => "gcc".as_ref(),
95+
LinkerFlavor::Ld => "ld".as_ref(),
96+
LinkerFlavor::Lld(_) => "lld".as_ref(),
97+
});
10098

101-
let target = &sess.opts.target_triple;
102-
let tool = windows_registry::find_tool(target, "link.exe");
99+
let mut cmd = cmd(linker_path);
103100

104-
if let Some(tool) = tool {
105-
let mut cmd = Command::new(tool.path());
106-
cmd.args(tool.args());
107-
for &(ref k, ref v) in tool.env() {
108-
cmd.env(k, v);
101+
if sess.target.target.options.is_like_msvc {
102+
if let Some(ref tool) = msvc_tool {
103+
cmd.args(tool.args());
104+
for &(ref k, ref v) in tool.env() {
105+
cmd.env(k, v);
106+
}
109107
}
110-
let envs = tool.env().to_vec();
111-
(cmd, envs)
112-
} else {
113-
debug!("Failed to locate linker.");
114-
(Command::new("link.exe"), vec![])
115108
}
116-
}
109+
cmd.env("PATH", command_path(sess));
117110

118-
#[cfg(not(windows))]
119-
pub fn msvc_link_exe_cmd(_sess: &Session) -> (Command, Vec<(OsString, OsString)>) {
120-
(Command::new("link.exe"), vec![])
111+
(linker_path.to_path_buf(), cmd)
121112
}
122113

123114
fn command_path(sess: &Session) -> OsString {
@@ -570,9 +561,7 @@ fn link_natively(sess: &Session,
570561
let flavor = sess.linker_flavor();
571562

572563
// The invocations of cc share some flags across platforms
573-
let (pname, mut cmd, envs) = get_linker(sess);
574-
// This will set PATH on windows
575-
cmd.envs(envs);
564+
let (pname, mut cmd) = get_linker(sess);
576565

577566
let root = sess.target_filesearch(PathKind::Native).get_lib_path();
578567
if let Some(args) = sess.target.target.options.pre_link_args.get(&flavor) {

0 commit comments

Comments
 (0)