Skip to content

Commit

Permalink
Auto merge of #68623 - Zoxc:lld, r=Mark-Simulacrum
Browse files Browse the repository at this point in the history
Add an option to use LLD to link the compiler on Windows platforms

Based on #68609.

Using LLD is good way to improve compile times on Windows since `link.exe` is quite slow. The time for `x.py build --stage 1 src/libtest` goes from 0:12:00 to 0:08:29. Compile time for `rustc_driver` goes from 226.34s to 18.5s. `rustc_macros` goes from 28.69s to 7.7s. The size of `rustc_driver` is also reduced from 83.3 MB to 78.7 MB.

r? @Mark-Simulacrum
  • Loading branch information
bors committed Feb 9, 2020
2 parents 6dff769 + d304cd0 commit 1ad6b5e
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 7 deletions.
10 changes: 10 additions & 0 deletions config.toml.example
Expand Up @@ -395,6 +395,15 @@
# rustc to execute.
#lld = false

# Indicates whether LLD will be used to link Rust crates during bootstrap on
# supported platforms. The LLD from the bootstrap distribution will be used
# and not the LLD compiled during the bootstrap.
#
# LLD will not be used if we're cross linking or running tests.
#
# Explicitly setting the linker for a target will override this option.
#use-lld = false

# Indicates whether some LLVM tools, like llvm-objdump, will be made available in the
# sysroot.
#llvm-tools = false
Expand Down Expand Up @@ -463,6 +472,7 @@
# Linker to be used to link Rust code. Note that the
# default value is platform specific, and if not specified it may also depend on
# what platform is crossing to what platform.
# Setting this will override the `use-lld` option for Rust code.
#linker = "cc"

# Path to the `llvm-config` binary of the installation of a custom LLVM to link
Expand Down
5 changes: 5 additions & 0 deletions src/bootstrap/bin/rustc.rs
Expand Up @@ -134,6 +134,11 @@ fn main() {
cmd.arg(format!("-Clinker={}", host_linker));
}

// Override linker flavor if necessary.
if let Ok(host_linker_flavor) = env::var("RUSTC_HOST_LINKER_FLAVOR") {
cmd.arg(format!("-Clinker-flavor={}", host_linker_flavor));
}

if let Ok(s) = env::var("RUSTC_HOST_CRT_STATIC") {
if s == "true" {
cmd.arg("-C").arg("target-feature=+crt-static");
Expand Down
27 changes: 24 additions & 3 deletions src/bootstrap/builder.rs
Expand Up @@ -692,7 +692,7 @@ impl<'a> Builder<'a> {
cmd.env_remove("MAKEFLAGS");
cmd.env_remove("MFLAGS");

if let Some(linker) = self.linker(compiler.host) {
if let Some(linker) = self.linker(compiler.host, true) {
cmd.env("RUSTC_TARGET_LINKER", linker);
}
cmd
Expand Down Expand Up @@ -952,10 +952,31 @@ impl<'a> Builder<'a> {
}
}

if let Some(host_linker) = self.linker(compiler.host) {
// FIXME: Don't use LLD if we're compiling libtest, since it fails to link it.
// See https://github.com/rust-lang/rust/issues/68647.
let can_use_lld = mode != Mode::Std;

// FIXME: The beta compiler doesn't pick the `lld-link` flavor for `*-pc-windows-msvc`
// Remove `RUSTC_HOST_LINKER_FLAVOR` when this is fixed
let lld_linker_flavor = |linker: &Path, target: Interned<String>| {
compiler.stage == 0
&& linker.file_name() == Some(OsStr::new("rust-lld"))
&& target.contains("pc-windows-msvc")
};

if let Some(host_linker) = self.linker(compiler.host, can_use_lld) {
if lld_linker_flavor(host_linker, compiler.host) {
cargo.env("RUSTC_HOST_LINKER_FLAVOR", "lld-link");
}

cargo.env("RUSTC_HOST_LINKER", host_linker);
}
if let Some(target_linker) = self.linker(target) {

if let Some(target_linker) = self.linker(target, can_use_lld) {
if lld_linker_flavor(target_linker, target) {
rustflags.arg("-Clinker-flavor=lld-link");
}

let target = crate::envify(&target);
cargo.env(&format!("CARGO_TARGET_{}_LINKER", target), target_linker);
}
Expand Down
3 changes: 3 additions & 0 deletions src/bootstrap/config.rs
Expand Up @@ -82,6 +82,7 @@ pub struct Config {
pub llvm_use_linker: Option<String>,
pub llvm_allow_old_toolchain: Option<bool>,

pub use_lld: bool,
pub lld_enabled: bool,
pub lldb_enabled: bool,
pub llvm_tools_enabled: bool,
Expand Down Expand Up @@ -321,6 +322,7 @@ struct Rust {
save_toolstates: Option<String>,
codegen_backends: Option<Vec<String>>,
lld: Option<bool>,
use_lld: Option<bool>,
llvm_tools: Option<bool>,
lldb: Option<bool>,
deny_warnings: Option<bool>,
Expand Down Expand Up @@ -565,6 +567,7 @@ impl Config {
if let Some(true) = rust.incremental {
config.incremental = true;
}
set(&mut config.use_lld, rust.use_lld);
set(&mut config.lld_enabled, rust.lld);
set(&mut config.lldb_enabled, rust.lldb);
set(&mut config.llvm_tools_enabled, rust.llvm_tools);
Expand Down
16 changes: 14 additions & 2 deletions src/bootstrap/lib.rs
Expand Up @@ -239,9 +239,10 @@ pub struct Build {
hosts: Vec<Interned<String>>,
targets: Vec<Interned<String>>,

// Stage 0 (downloaded) compiler and cargo or their local rust equivalents
// Stage 0 (downloaded) compiler, lld and cargo or their local rust equivalents
initial_rustc: PathBuf,
initial_cargo: PathBuf,
initial_lld: PathBuf,

// Runtime state filled in later on
// C/C++ compilers and archiver for all targets
Expand Down Expand Up @@ -343,9 +344,18 @@ impl Build {
// we always try to use git for LLVM builds
let in_tree_llvm_info = channel::GitInfo::new(false, &src.join("src/llvm-project"));

let initial_sysroot = config.initial_rustc.parent().unwrap().parent().unwrap();
let initial_lld = initial_sysroot
.join("lib")
.join("rustlib")
.join(config.build)
.join("bin")
.join("rust-lld");

let mut build = Build {
initial_rustc: config.initial_rustc.clone(),
initial_cargo: config.initial_cargo.clone(),
initial_lld,
local_rebuild: config.local_rebuild,
fail_fast: config.cmd.fail_fast(),
doc_tests: config.cmd.doc_tests(),
Expand Down Expand Up @@ -810,7 +820,7 @@ impl Build {
}

/// Returns the path to the linker for the given target if it needs to be overridden.
fn linker(&self, target: Interned<String>) -> Option<&Path> {
fn linker(&self, target: Interned<String>, can_use_lld: bool) -> Option<&Path> {
if let Some(linker) = self.config.target_config.get(&target).and_then(|c| c.linker.as_ref())
{
Some(linker)
Expand All @@ -819,6 +829,8 @@ impl Build {
&& !target.contains("msvc")
{
Some(self.cc(target))
} else if can_use_lld && self.config.use_lld && self.build == target {
Some(&self.initial_lld)
} else {
None
}
Expand Down
5 changes: 3 additions & 2 deletions src/bootstrap/test.rs
Expand Up @@ -596,7 +596,7 @@ impl Step for RustdocTheme {
.env("RUSTDOC_REAL", builder.rustdoc(self.compiler))
.env("RUSTDOC_CRATE_VERSION", builder.rust_version())
.env("RUSTC_BOOTSTRAP", "1");
if let Some(linker) = builder.linker(self.compiler.host) {
if let Some(linker) = builder.linker(self.compiler.host, true) {
cmd.env("RUSTC_TARGET_LINKER", linker);
}
try_run(builder, &mut cmd);
Expand Down Expand Up @@ -1035,7 +1035,8 @@ impl Step for Compiletest {
flags.push("-Zunstable-options".to_string());
flags.push(builder.config.cmd.rustc_args().join(" "));

if let Some(linker) = builder.linker(target) {
// Don't use LLD here since we want to test that rustc finds and uses a linker by itself.
if let Some(linker) = builder.linker(target, false) {
cmd.arg("--linker").arg(linker);
}

Expand Down

0 comments on commit 1ad6b5e

Please sign in to comment.