Skip to content

Commit 3b5754e

Browse files
committed
Auto merge of #40018 - japaric:ld, r=alexcrichton
-Z linker-flavor (Please read the commit message first) This PR is an alternative to #36120 (internal lld linker). The main goal of this PR is to make it *possible* to use LLD as a linker to allow out of tree experimentation. Now that LLD is going to be shipped with LLVM 4.0, it should become easier to get a hold of LLD (hopefully, it will be packaged by Linux distros soon). Since LLD is a multiarch linker, it has the potential to make cross compilation easier (less tools need to be installed). Supposedly, LLD is also faster than the gold linker so LLD may improve build times where link times are significant (e.g. 100% incremental compilation reuse). The place where LLD shines is at linking Rust programs that don't depend on system libraries. For example, here's how you would link a bare metal ARM Cortex-M program: ``` $ xargo rustc --target thumbv7m-none-eabi -- -Z linker-flavor=ld -C linker=ld.lld -Z print-link-args "ld.lld" \ "-L" \ "$XARGO_HOME/lib/rustlib/thumbv7m-none-eabi/lib" \ "$PWD/target/thumbv7m-none-eabi/debug/deps/app-de1f86df314ad68c.0.o" \ "-o" \ "$PWD/target/thumbv7m-none-eabi/debug/deps/app-de1f86df314ad68c" \ "--gc-sections" \ "-L" \ "$PWD/target/thumbv7m-none-eabi/debug/deps" \ "-L" \ "$PWD/target/debug/deps" \ "-L" \ "$XARGO_HOME/lib/rustlib/thumbv7m-none-eabi/lib" \ "-Bstatic" \ "-Bdynamic" \ "$XARGO_HOME/lib/rustlib/thumbv7m-none-eabi/lib/libcore-11670d2bd4951fa7.rlib" $ file target/thumbv7m-none-eabi/debug/app app: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, not stripped, with debug_info ``` This doesn't require installing the `arm-none-eabi-gcc` toolchain. Even cooler (but I'm biased) is that you can link Rust programs that use [`steed`] (`steed` is a `std` re-implementation free of C dependencies for Linux systems) instead of `std` for a bunch of different architectures without having to install a single cross toolchain. [`steed`]: https://github.com/japaric/steed ``` $ xargo rustc --target aarch64-unknown-linux-steed --example hello --release -- -Z print-link-args "ld.lld" \ "-L" \ "$XARGO_HOME/lib/rustlib/aarch64-unknown-linux-steed/lib" \ "$PWD/target/aarch64-unknown-linux-steed/release/examples/hello-80c130ad884c0f8f.0.o" \ "-o" \ "$PWD/target/aarch64-unknown-linux-steed/release/examples/hello-80c130ad884c0f8f" \ "--gc-sections" \ "-L" \ "$PWD/target/aarch64-unknown-linux-steed/release/deps" \ "-L" \ "$PWD/target/release/deps" \ "-L" \ "$XARGO_HOME/lib/rustlib/aarch64-unknown-linux-steed/lib" \ "-Bstatic" \ "-Bdynamic" \ "/tmp/rustc.lAybk9Ltx93Q/libcompiler_builtins-589aede02de78434.rlib" $ file target/aarch64-unknown-linux-steed/release/examples/hello hello: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), statically linked, not stripped, with debug_info ``` All these targets (architectures) worked with LLD: - [aarch64-unknown-linux-steed](https://github.com/japaric/steed/blob/lld/docker/aarch64-unknown-linux-steed.json) - [arm-unknown-linux-steedeabi](https://github.com/japaric/steed/blob/lld/docker/arm-unknown-linux-steedeabi.json) - [arm-unknown-linux-steedeabihf](https://github.com/japaric/steed/blob/lld/docker/arm-unknown-linux-steedeabihf.json) - [armv7-unknown-linux-steedeabihf](https://github.com/japaric/steed/blob/lld/docker/armv7-unknown-linux-steedeabihf.json) - [i686-unknown-linux-steed](https://github.com/japaric/steed/blob/lld/docker/i686-unknown-linux-steed.json) - [mips-unknown-linux-steed](https://github.com/japaric/steed/blob/lld/docker/mips-unknown-linux-steed.json) - [mipsel-unknown-linux-steed](https://github.com/japaric/steed/blob/lld/docker/mipsel-unknown-linux-steed.json) - [powerpc-unknown-linux-steed](https://github.com/japaric/steed/blob/lld/docker/powerpc-unknown-linux-steed.json) - [powerpc64-unknown-linux-steed](https://github.com/japaric/steed/blob/lld/docker/powerpc64-unknown-linux-steed.json) - [x86_64-unknown-linux-steed](https://github.com/japaric/steed/blob/lld/docker/x86_64-unknown-linux-steed.json) --- The case where lld is unergonomic is linking binaries that depend on system libraries. Like "Hello, world" for `x86_64-unknown-linux-gnu`. Because you have to pass as linker arguments: the path to the startup objects, the path to the dynamic linker and the library search paths. And all those are system specific so they can't be encoded in the target itself. ``` $ cargo \ rustc \ --release \ -- \ -C \ linker=ld.lld \ -Z \ linker-flavor=ld \ -C \ link-args='-dynamic-linker /lib64/ld-linux-x86-64.so.2 -L/usr/lib -L/usr/lib/gcc/x86_64-pc-linux-gnu/6.3.1 /usr/lib/Scrt1.o /usr/lib/crti.o /usr/lib/gcc/x86_64-pc-linux-gnu/6.3.1/crtbeginS.o /usr/lib/gcc/x86_64-pc-linux-gnu/6.3.1/crtendS.o /usr/lib/crtn.o' ``` --- Another case where `-Z linker-flavor` may come in handy is directly calling Solaris' linker which is also a multiarch linker (or so I have heard). cc @binarycrusader cc @alexcrichton Heads up: [breaking-change] due to changes in the target specification format.
2 parents 8493dd6 + e192fb3 commit 3b5754e

File tree

92 files changed

+682
-240
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

92 files changed

+682
-240
lines changed

src/doc/unstable-book/src/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@
108108
- [link_llvm_intrinsics](link-llvm-intrinsics.md)
109109
- [linkage](linkage.md)
110110
- [linked_list_extras](linked-list-extras.md)
111+
- [linker_flavor](linker-flavor.md)
111112
- [log_syntax](log-syntax.md)
112113
- [lookup_host](lookup-host.md)
113114
- [loop_break_value](loop-break-value.md)
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# `linker-flavor`
2+
3+
The tracking issue for this feature is: None
4+
5+
------------------------
6+
7+
Every `rustc` target defaults to some linker. For example, Linux targets default
8+
to gcc. In some cases, you may want to override the default; you can do that
9+
with the unstable CLI argument: `-Z linker-flavor`.
10+
11+
Here how you would use this flag to link a Rust binary for the
12+
`thumbv7m-none-eabi` using LLD instead of GCC.
13+
14+
``` text
15+
$ xargo rustc --target thumbv7m-none-eabi -- \
16+
-C linker=ld.lld \
17+
-Z linker-flavor=ld \
18+
-Z print-link-args | tr ' ' '\n'
19+
"ld.lld"
20+
"-L"
21+
"$SYSROOT/lib/rustlib/thumbv7m-none-eabi/lib"
22+
"$PWD/target/thumbv7m-none-eabi/debug/deps/app-512e9dbf385f233c.0.o"
23+
"-o"
24+
"$PWD/target/thumbv7m-none-eabi/debug/deps/app-512e9dbf385f233c"
25+
"--gc-sections"
26+
"-L"
27+
"$PWD/target/thumbv7m-none-eabi/debug/deps"
28+
"-L"
29+
"$PWD/target/debug/deps"
30+
"-L"
31+
"$SYSROOT/lib/rustlib/thumbv7m-none-eabi/lib"
32+
"-Bstatic"
33+
"$SYSROOT/lib/rustlib/thumbv7m-none-eabi/lib/libcore-e1ccb7dfb1cb9ebb.rlib"
34+
"-Bdynamic"
35+
```
36+
37+
Whereas the default is:
38+
39+
``` text
40+
$ xargo rustc --target thumbv7m-none-eabi -- \
41+
-C link-arg=-nostartfiles \
42+
-Z print-link-args | tr ' ' '\n'
43+
"arm-none-eabi-gcc"
44+
"-L"
45+
"$SYSROOT/lib/rustlib/thumbv7m-none-eabi/lib"
46+
"$PWD/target/thumbv7m-none-eabi/debug/deps/app-961e39416baa38d9.0.o"
47+
"-o"
48+
"$PWD/target/thumbv7m-none-eabi/debug/deps/app-961e39416baa38d9"
49+
"-Wl,--gc-sections"
50+
"-nodefaultlibs"
51+
"-L"
52+
"$PWD/target/thumbv7m-none-eabi/debug/deps"
53+
"-L"
54+
"$PWD/target/debug/deps"
55+
"-L"
56+
"$SYSROOT/lib/rustlib/thumbv7m-none-eabi/lib"
57+
"-Wl,-Bstatic"
58+
"$SYSROOT/lib/rustlib/thumbv7m-none-eabi/lib/libcore-e1ccb7dfb1cb9ebb.rlib"
59+
"-nostartfiles"
60+
"-Wl,-Bdynamic"
61+
```

src/librustc/session/config.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pub use self::DebugInfoLevel::*;
1919
use session::{early_error, early_warn, Session};
2020
use session::search_paths::SearchPaths;
2121

22-
use rustc_back::PanicStrategy;
22+
use rustc_back::{LinkerFlavor, PanicStrategy};
2323
use rustc_back::target::Target;
2424
use lint;
2525
use middle::cstore;
@@ -641,12 +641,14 @@ macro_rules! options {
641641
Some("either `panic` or `abort`");
642642
pub const parse_sanitizer: Option<&'static str> =
643643
Some("one of: `address`, `leak`, `memory` or `thread`");
644+
pub const parse_linker_flavor: Option<&'static str> =
645+
Some(::rustc_back::LinkerFlavor::one_of());
644646
}
645647

646648
#[allow(dead_code)]
647649
mod $mod_set {
648650
use super::{$struct_name, Passes, SomePasses, AllPasses, Sanitizer};
649-
use rustc_back::PanicStrategy;
651+
use rustc_back::{LinkerFlavor, PanicStrategy};
650652

651653
$(
652654
pub fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool {
@@ -777,6 +779,14 @@ macro_rules! options {
777779
}
778780
true
779781
}
782+
783+
fn parse_linker_flavor(slote: &mut Option<LinkerFlavor>, v: Option<&str>) -> bool {
784+
match v.and_then(LinkerFlavor::from_str) {
785+
Some(lf) => *slote = Some(lf),
786+
_ => return false,
787+
}
788+
true
789+
}
780790
}
781791
) }
782792

@@ -979,6 +989,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
979989
"pass `-install_name @rpath/...` to the macOS linker"),
980990
sanitizer: Option<Sanitizer> = (None, parse_sanitizer, [TRACKED],
981991
"Use a sanitizer"),
992+
linker_flavor: Option<LinkerFlavor> = (None, parse_linker_flavor, [UNTRACKED],
993+
"Linker flavor"),
982994
}
983995

984996
pub fn default_lib_output() -> CrateType {

src/librustc/session/mod.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ use syntax::{ast, codemap};
3636
use syntax::feature_gate::AttributeType;
3737
use syntax_pos::{Span, MultiSpan};
3838

39-
use rustc_back::PanicStrategy;
39+
use rustc_back::{LinkerFlavor, PanicStrategy};
4040
use rustc_back::target::Target;
4141
use rustc_data_structures::flock;
4242
use llvm;
@@ -363,6 +363,9 @@ impl Session {
363363
pub fn panic_strategy(&self) -> PanicStrategy {
364364
self.opts.cg.panic.unwrap_or(self.target.target.options.panic_strategy)
365365
}
366+
pub fn linker_flavor(&self) -> LinkerFlavor {
367+
self.opts.debugging_opts.linker_flavor.unwrap_or(self.target.target.linker_flavor)
368+
}
366369
pub fn no_landing_pads(&self) -> bool {
367370
self.opts.debugging_opts.no_landing_pads || self.panic_strategy() == PanicStrategy::Abort
368371
}

src/librustc_back/lib.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,48 @@ pub mod dynamic_lib;
5252

5353
use serialize::json::{Json, ToJson};
5454

55+
macro_rules! linker_flavor {
56+
($(($variant:ident, $string:expr),)+) => {
57+
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Hash,
58+
RustcEncodable, RustcDecodable)]
59+
pub enum LinkerFlavor {
60+
$($variant,)+
61+
}
62+
63+
impl LinkerFlavor {
64+
pub const fn one_of() -> &'static str {
65+
concat!("one of: ", $($string, " ",)+)
66+
}
67+
68+
pub fn from_str(s: &str) -> Option<Self> {
69+
Some(match s {
70+
$($string => LinkerFlavor::$variant,)+
71+
_ => return None,
72+
})
73+
}
74+
75+
pub fn desc(&self) -> &str {
76+
match *self {
77+
$(LinkerFlavor::$variant => $string,)+
78+
}
79+
}
80+
}
81+
82+
impl ToJson for LinkerFlavor {
83+
fn to_json(&self) -> Json {
84+
self.desc().to_json()
85+
}
86+
}
87+
}
88+
}
89+
90+
linker_flavor! {
91+
(Em, "em"),
92+
(Gcc, "gcc"),
93+
(Ld, "ld"),
94+
(Msvc, "msvc"),
95+
}
96+
5597
#[derive(Clone, Copy, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
5698
pub enum PanicStrategy {
5799
Unwind,

src/librustc_back/target/aarch64_apple_ios.rs

Lines changed: 2 additions & 0 deletions
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 LinkerFlavor;
1112
use target::{Target, TargetOptions, TargetResult};
1213
use super::apple_ios_base::{opts, Arch};
1314

@@ -22,6 +23,7 @@ pub fn target() -> TargetResult {
2223
target_os: "ios".to_string(),
2324
target_env: "".to_string(),
2425
target_vendor: "apple".to_string(),
26+
linker_flavor: LinkerFlavor::Gcc,
2527
options: TargetOptions {
2628
features: "+neon,+fp-armv8,+cyclone".to_string(),
2729
eliminate_frame_pointer: false,

src/librustc_back/target/aarch64_linux_android.rs

Lines changed: 2 additions & 0 deletions
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 LinkerFlavor;
1112
use target::{Target, TargetOptions, TargetResult};
1213

1314
// See https://developer.android.com/ndk/guides/abis.html#arm64-v8a
@@ -28,6 +29,7 @@ pub fn target() -> TargetResult {
2829
target_os: "android".to_string(),
2930
target_env: "".to_string(),
3031
target_vendor: "unknown".to_string(),
32+
linker_flavor: LinkerFlavor::Gcc,
3133
options: TargetOptions {
3234
abi_blacklist: super::arm_base::abi_blacklist(),
3335
.. base

src/librustc_back/target/aarch64_unknown_freebsd.rs

Lines changed: 2 additions & 0 deletions
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 LinkerFlavor;
1112
use target::{Target, TargetOptions, TargetResult};
1213

1314
pub fn target() -> TargetResult {
@@ -26,6 +27,7 @@ pub fn target() -> TargetResult {
2627
target_os: "freebsd".to_string(),
2728
target_env: "".to_string(),
2829
target_vendor: "unknown".to_string(),
30+
linker_flavor: LinkerFlavor::Gcc,
2931
options: TargetOptions {
3032
abi_blacklist: super::arm_base::abi_blacklist(),
3133
.. base

src/librustc_back/target/aarch64_unknown_fuchsia.rs

Lines changed: 2 additions & 0 deletions
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 LinkerFlavor;
1112
use target::{Target, TargetOptions, TargetResult};
1213

1314
pub fn target() -> TargetResult {
@@ -23,6 +24,7 @@ pub fn target() -> TargetResult {
2324
target_os: "fuchsia".to_string(),
2425
target_env: "".to_string(),
2526
target_vendor: "unknown".to_string(),
27+
linker_flavor: LinkerFlavor::Gcc,
2628
options: TargetOptions {
2729
abi_blacklist: super::arm_base::abi_blacklist(),
2830
.. base

src/librustc_back/target/aarch64_unknown_linux_gnu.rs

Lines changed: 2 additions & 0 deletions
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 LinkerFlavor;
1112
use target::{Target, TargetOptions, TargetResult};
1213

1314
pub fn target() -> TargetResult {
@@ -26,6 +27,7 @@ pub fn target() -> TargetResult {
2627
arch: "aarch64".to_string(),
2728
target_os: "linux".to_string(),
2829
target_vendor: "unknown".to_string(),
30+
linker_flavor: LinkerFlavor::Gcc,
2931
options: TargetOptions {
3032
abi_blacklist: super::arm_base::abi_blacklist(),
3133
.. base

0 commit comments

Comments
 (0)