about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/bootstrap/dist.rs6
-rw-r--r--src/bootstrap/native.rs13
-rw-r--r--src/librustc_back/lib.rs6
-rw-r--r--src/librustc_back/target/aarch64_unknown_cloudabi.rs2
-rw-r--r--src/librustc_back/target/armv7_unknown_cloudabi_eabihf.rs2
-rw-r--r--src/librustc_back/target/asmjs_unknown_emscripten.rs3
-rw-r--r--src/librustc_back/target/emscripten_base.rs17
-rw-r--r--src/librustc_back/target/haiku_base.rs1
-rw-r--r--src/librustc_back/target/i686_unknown_cloudabi.rs2
-rw-r--r--src/librustc_back/target/l4re_base.rs1
-rw-r--r--src/librustc_back/target/mod.rs9
-rw-r--r--src/librustc_back/target/msp430_none_elf.rs2
-rw-r--r--src/librustc_back/target/thumb_base.rs2
-rw-r--r--src/librustc_back/target/wasm32_experimental_emscripten.rs3
-rw-r--r--src/librustc_back/target/wasm32_unknown_emscripten.rs3
-rw-r--r--src/librustc_back/target/wasm32_unknown_unknown.rs2
-rw-r--r--src/librustc_back/target/windows_base.rs2
-rw-r--r--src/librustc_back/target/windows_msvc_base.rs1
-rw-r--r--src/librustc_back/target/x86_64_rumprun_netbsd.rs2
-rw-r--r--src/librustc_back/target/x86_64_unknown_cloudabi.rs2
-rw-r--r--src/librustc_trans/Cargo.toml4
-rw-r--r--src/librustc_trans/back/command.rs14
-rw-r--r--src/librustc_trans/back/link.rs95
-rw-r--r--src/librustc_trans/back/linker.rs4
-rw-r--r--src/librustc_trans/back/write.rs2
-rw-r--r--src/librustc_trans/lib.rs1
26 files changed, 83 insertions, 118 deletions
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index 02ef7c0e1ff..576e5078247 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -606,8 +606,10 @@ impl Step for Std {
         let mut src = builder.sysroot_libdir(compiler, target).to_path_buf();
         src.pop(); // Remove the trailing /lib folder from the sysroot_libdir
         cp_filtered(&src, &dst, &|path| {
-            path.file_name().and_then(|s| s.to_str()) !=
-                Some(build.config.rust_codegen_backends_dir.as_str())
+            let name = path.file_name().and_then(|s| s.to_str());
+            name != Some(build.config.rust_codegen_backends_dir.as_str()) &&
+                name != Some("bin")
+
         });
 
         let mut cmd = rust_installer(builder);
diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs
index 987d70fd047..7888f0b938d 100644
--- a/src/bootstrap/native.rs
+++ b/src/bootstrap/native.rs
@@ -208,7 +208,7 @@ impl Step for Llvm {
             cfg.define("LLVM_NATIVE_BUILD", build.llvm_out(build.build).join("build"));
         }
 
-        configure_cmake(build, target, &mut cfg);
+        configure_cmake(build, target, &mut cfg, false);
 
         // FIXME: we don't actually need to build all LLVM tools and all LLVM
         //        libraries here, e.g. we just want a few components and a few
@@ -241,7 +241,8 @@ fn check_llvm_version(build: &Build, llvm_config: &Path) {
 
 fn configure_cmake(build: &Build,
                    target: Interned<String>,
-                   cfg: &mut cmake::Config) {
+                   cfg: &mut cmake::Config,
+                   building_dist_binaries: bool) {
     if build.config.ninja {
         cfg.generator("Ninja");
     }
@@ -294,8 +295,10 @@ fn configure_cmake(build: &Build,
     cfg.build_arg("-j").build_arg(build.jobs().to_string());
     cfg.define("CMAKE_C_FLAGS", build.cflags(target).join(" "));
     let mut cxxflags = build.cflags(target).join(" ");
-    if build.config.llvm_static_stdcpp && !target.contains("windows") {
-        cxxflags.push_str(" -static-libstdc++");
+    if building_dist_binaries {
+        if build.config.llvm_static_stdcpp && !target.contains("windows") {
+            cxxflags.push_str(" -static-libstdc++");
+        }
     }
     cfg.define("CMAKE_CXX_FLAGS", cxxflags);
     if let Some(ar) = build.ar(target) {
@@ -350,7 +353,7 @@ impl Step for Lld {
         t!(fs::create_dir_all(&out_dir));
 
         let mut cfg = cmake::Config::new(build.src.join("src/tools/lld"));
-        configure_cmake(build, target, &mut cfg);
+        configure_cmake(build, target, &mut cfg, true);
 
         cfg.out_dir(&out_dir)
            .profile("Release")
diff --git a/src/librustc_back/lib.rs b/src/librustc_back/lib.rs
index 141c8954a33..9de56cca339 100644
--- a/src/librustc_back/lib.rs
+++ b/src/librustc_back/lib.rs
@@ -57,6 +57,9 @@ pub enum LinkerFlavor {
          RustcEncodable, RustcDecodable)]
 pub enum LldFlavor {
     Wasm,
+    Ld64,
+    Ld,
+    Link,
 }
 
 impl ToJson for LinkerFlavor {
@@ -94,6 +97,9 @@ flavor_mappings! {
     ((LinkerFlavor::Ld), "ld"),
     ((LinkerFlavor::Msvc), "msvc"),
     ((LinkerFlavor::Lld(LldFlavor::Wasm)), "wasm-ld"),
+    ((LinkerFlavor::Lld(LldFlavor::Ld64)), "ld64.lld"),
+    ((LinkerFlavor::Lld(LldFlavor::Ld)), "ld.lld"),
+    ((LinkerFlavor::Lld(LldFlavor::Link)), "lld-link"),
 }
 
 #[derive(Clone, Copy, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
diff --git a/src/librustc_back/target/aarch64_unknown_cloudabi.rs b/src/librustc_back/target/aarch64_unknown_cloudabi.rs
index 59c82e06a67..a5d0e5bf166 100644
--- a/src/librustc_back/target/aarch64_unknown_cloudabi.rs
+++ b/src/librustc_back/target/aarch64_unknown_cloudabi.rs
@@ -15,7 +15,7 @@ pub fn target() -> TargetResult {
     let mut base = super::cloudabi_base::opts();
     base.max_atomic_width = Some(128);
     base.abi_blacklist = super::arm_base::abi_blacklist();
-    base.linker = "aarch64-unknown-cloudabi-cc".to_string();
+    base.linker = Some("aarch64-unknown-cloudabi-cc".to_string());
 
     Ok(Target {
         llvm_target: "aarch64-unknown-cloudabi".to_string(),
diff --git a/src/librustc_back/target/armv7_unknown_cloudabi_eabihf.rs b/src/librustc_back/target/armv7_unknown_cloudabi_eabihf.rs
index faa2c4fdceb..fa66a35abbf 100644
--- a/src/librustc_back/target/armv7_unknown_cloudabi_eabihf.rs
+++ b/src/librustc_back/target/armv7_unknown_cloudabi_eabihf.rs
@@ -17,7 +17,7 @@ pub fn target() -> TargetResult {
     base.max_atomic_width = Some(64);
     base.features = "+v7,+vfp3,+neon".to_string();
     base.abi_blacklist = super::arm_base::abi_blacklist();
-    base.linker = "armv7-unknown-cloudabi-eabihf-cc".to_string();
+    base.linker = Some("armv7-unknown-cloudabi-eabihf-cc".to_string());
 
     Ok(Target {
         llvm_target: "armv7-unknown-cloudabi-eabihf".to_string(),
diff --git a/src/librustc_back/target/asmjs_unknown_emscripten.rs b/src/librustc_back/target/asmjs_unknown_emscripten.rs
index 5d9f0f6012b..f114926740a 100644
--- a/src/librustc_back/target/asmjs_unknown_emscripten.rs
+++ b/src/librustc_back/target/asmjs_unknown_emscripten.rs
@@ -10,7 +10,6 @@
 
 use LinkerFlavor;
 use super::{LinkArgs, Target, TargetOptions};
-use super::emscripten_base::{cmd};
 
 pub fn target() -> Result<Target, String> {
     let mut args = LinkArgs::new();
@@ -19,8 +18,6 @@ pub fn target() -> Result<Target, String> {
                      "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string()]);
 
     let opts = TargetOptions {
-        linker: cmd("emcc"),
-
         dynamic_linking: false,
         executables: true,
         exe_suffix: ".js".to_string(),
diff --git a/src/librustc_back/target/emscripten_base.rs b/src/librustc_back/target/emscripten_base.rs
deleted file mode 100644
index bacada3f5ab..00000000000
--- a/src/librustc_back/target/emscripten_base.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-pub fn cmd(name: &str) -> String {
-    if cfg!(windows) {
-        format!("{}.bat", name)
-    } else {
-        name.to_string()
-    }
-}
diff --git a/src/librustc_back/target/haiku_base.rs b/src/librustc_back/target/haiku_base.rs
index 112f424f7a8..a1ccb632cab 100644
--- a/src/librustc_back/target/haiku_base.rs
+++ b/src/librustc_back/target/haiku_base.rs
@@ -13,7 +13,6 @@ use std::default::Default;
 
 pub fn opts() -> TargetOptions {
     TargetOptions {
-        linker: "cc".to_string(),
         dynamic_linking: true,
         executables: true,
         has_rpath: false,
diff --git a/src/librustc_back/target/i686_unknown_cloudabi.rs b/src/librustc_back/target/i686_unknown_cloudabi.rs
index e244f443d3e..69c3b298cab 100644
--- a/src/librustc_back/target/i686_unknown_cloudabi.rs
+++ b/src/librustc_back/target/i686_unknown_cloudabi.rs
@@ -15,7 +15,7 @@ pub fn target() -> TargetResult {
     let mut base = super::cloudabi_base::opts();
     base.cpu = "pentium4".to_string();
     base.max_atomic_width = Some(64);
-    base.linker = "i686-unknown-cloudabi-cc".to_string();
+    base.linker = Some("i686-unknown-cloudabi-cc".to_string());
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
     base.stack_probes = true;
 
diff --git a/src/librustc_back/target/l4re_base.rs b/src/librustc_back/target/l4re_base.rs
index 31d428d2668..7cb7f8d613d 100644
--- a/src/librustc_back/target/l4re_base.rs
+++ b/src/librustc_back/target/l4re_base.rs
@@ -73,7 +73,6 @@ pub fn opts() -> Result<TargetOptions, String> {
         has_elf_tls: false,
         exe_allocation_crate: None,
         panic_strategy: PanicStrategy::Abort,
-        linker: "ld".to_string(),
         pre_link_args,
         post_link_args,
         target_family: Some("unix".to_string()),
diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs
index be69127d8f2..0a3e1826f3a 100644
--- a/src/librustc_back/target/mod.rs
+++ b/src/librustc_back/target/mod.rs
@@ -58,7 +58,6 @@ mod arm_base;
 mod bitrig_base;
 mod cloudabi_base;
 mod dragonfly_base;
-mod emscripten_base;
 mod freebsd_base;
 mod haiku_base;
 mod linux_base;
@@ -279,8 +278,8 @@ pub struct TargetOptions {
     /// Whether the target is built-in or loaded from a custom target specification.
     pub is_builtin: bool,
 
-    /// Linker to invoke. Defaults to "cc".
-    pub linker: String,
+    /// Linker to invoke
+    pub linker: Option<String>,
 
     /// Linker arguments that are unconditionally passed *before* any
     /// user-defined libraries.
@@ -482,7 +481,7 @@ impl Default for TargetOptions {
     fn default() -> TargetOptions {
         TargetOptions {
             is_builtin: false,
-            linker: option_env!("CFG_DEFAULT_LINKER").unwrap_or("cc").to_string(),
+            linker: option_env!("CFG_DEFAULT_LINKER").map(|s| s.to_string()),
             pre_link_args: LinkArgs::new(),
             post_link_args: LinkArgs::new(),
             asm_args: Vec::new(),
@@ -732,7 +731,7 @@ impl Target {
         }
 
         key!(is_builtin, bool);
-        key!(linker);
+        key!(linker, optional);
         key!(pre_link_args, link_args);
         key!(pre_link_objects_exe, list);
         key!(pre_link_objects_dll, list);
diff --git a/src/librustc_back/target/msp430_none_elf.rs b/src/librustc_back/target/msp430_none_elf.rs
index 966df897f01..d0f512ae47c 100644
--- a/src/librustc_back/target/msp430_none_elf.rs
+++ b/src/librustc_back/target/msp430_none_elf.rs
@@ -32,7 +32,7 @@ pub fn target() -> TargetResult {
             // to gcc to get object files. For this reason we have a hard
             // dependency on this specific gcc.
             asm_args: vec!["-mcpu=msp430".to_string()],
-            linker: "msp430-elf-gcc".to_string(),
+            linker: Some("msp430-elf-gcc".to_string()),
             no_integrated_as: true,
 
             // There are no atomic instructions available in the MSP430
diff --git a/src/librustc_back/target/thumb_base.rs b/src/librustc_back/target/thumb_base.rs
index 6bb496649a8..6a8f52f5093 100644
--- a/src/librustc_back/target/thumb_base.rs
+++ b/src/librustc_back/target/thumb_base.rs
@@ -45,7 +45,7 @@ pub fn opts() -> TargetOptions {
         executables: true,
         // In 99%+ of cases, we want to use the `arm-none-eabi-gcc` compiler (there aren't many
         // options around)
-        linker: "arm-none-eabi-gcc".to_string(),
+        linker: Some("arm-none-eabi-gcc".to_string()),
         // Because these devices have very little resources having an unwinder is too onerous so we
         // default to "abort" because the "unwind" strategy is very rare.
         panic_strategy: PanicStrategy::Abort,
diff --git a/src/librustc_back/target/wasm32_experimental_emscripten.rs b/src/librustc_back/target/wasm32_experimental_emscripten.rs
index a261c982b3f..13dee3a5768 100644
--- a/src/librustc_back/target/wasm32_experimental_emscripten.rs
+++ b/src/librustc_back/target/wasm32_experimental_emscripten.rs
@@ -10,7 +10,6 @@
 
 use LinkerFlavor;
 use super::{LinkArgs, Target, TargetOptions};
-use super::emscripten_base::{cmd};
 
 pub fn target() -> Result<Target, String> {
     let mut post_link_args = LinkArgs::new();
@@ -24,8 +23,6 @@ pub fn target() -> Result<Target, String> {
                                "-g3".to_string()]);
 
     let opts = TargetOptions {
-        linker: cmd("emcc"),
-
         dynamic_linking: false,
         executables: true,
         // Today emcc emits two files - a .js file to bootstrap and
diff --git a/src/librustc_back/target/wasm32_unknown_emscripten.rs b/src/librustc_back/target/wasm32_unknown_emscripten.rs
index 4823541f226..2770e67e30a 100644
--- a/src/librustc_back/target/wasm32_unknown_emscripten.rs
+++ b/src/librustc_back/target/wasm32_unknown_emscripten.rs
@@ -10,7 +10,6 @@
 
 use LinkerFlavor;
 use super::{LinkArgs, Target, TargetOptions};
-use super::emscripten_base::{cmd};
 
 pub fn target() -> Result<Target, String> {
     let mut post_link_args = LinkArgs::new();
@@ -21,8 +20,6 @@ pub fn target() -> Result<Target, String> {
                                "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string()]);
 
     let opts = TargetOptions {
-        linker: cmd("emcc"),
-
         dynamic_linking: false,
         executables: true,
         // Today emcc emits two files - a .js file to bootstrap and
diff --git a/src/librustc_back/target/wasm32_unknown_unknown.rs b/src/librustc_back/target/wasm32_unknown_unknown.rs
index c771762cfc8..1d84e137517 100644
--- a/src/librustc_back/target/wasm32_unknown_unknown.rs
+++ b/src/librustc_back/target/wasm32_unknown_unknown.rs
@@ -22,8 +22,6 @@ use super::{Target, TargetOptions, PanicStrategy};
 
 pub fn target() -> Result<Target, String> {
     let opts = TargetOptions {
-        linker: "lld".to_string(),
-
         // we allow dynamic linking, but only cdylibs. Basically we allow a
         // final library artifact that exports some symbols (a wasm module) but
         // we don't allow intermediate `dylib` crate types
diff --git a/src/librustc_back/target/windows_base.rs b/src/librustc_back/target/windows_base.rs
index 30038400f6c..05b6247c951 100644
--- a/src/librustc_back/target/windows_base.rs
+++ b/src/librustc_back/target/windows_base.rs
@@ -75,7 +75,7 @@ pub fn opts() -> TargetOptions {
     TargetOptions {
         // FIXME(#13846) this should be enabled for windows
         function_sections: false,
-        linker: "gcc".to_string(),
+        linker: Some("gcc".to_string()),
         dynamic_linking: true,
         executables: true,
         dll_prefix: "".to_string(),
diff --git a/src/librustc_back/target/windows_msvc_base.rs b/src/librustc_back/target/windows_msvc_base.rs
index e0bf36ee407..34aa17267f8 100644
--- a/src/librustc_back/target/windows_msvc_base.rs
+++ b/src/librustc_back/target/windows_msvc_base.rs
@@ -20,7 +20,6 @@ pub fn opts() -> TargetOptions {
 
     TargetOptions {
         function_sections: true,
-        linker: "link.exe".to_string(),
         dynamic_linking: true,
         executables: true,
         dll_prefix: "".to_string(),
diff --git a/src/librustc_back/target/x86_64_rumprun_netbsd.rs b/src/librustc_back/target/x86_64_rumprun_netbsd.rs
index 18f6380b6ee..3158665a2e2 100644
--- a/src/librustc_back/target/x86_64_rumprun_netbsd.rs
+++ b/src/librustc_back/target/x86_64_rumprun_netbsd.rs
@@ -15,7 +15,7 @@ pub fn target() -> TargetResult {
     let mut base = super::netbsd_base::opts();
     base.cpu = "x86-64".to_string();
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
-    base.linker = "x86_64-rumprun-netbsd-gcc".to_string();
+    base.linker = Some("x86_64-rumprun-netbsd-gcc".to_string());
     base.max_atomic_width = Some(64);
 
     base.dynamic_linking = false;
diff --git a/src/librustc_back/target/x86_64_unknown_cloudabi.rs b/src/librustc_back/target/x86_64_unknown_cloudabi.rs
index 1ce3c6444f1..d1a9cb1cd7e 100644
--- a/src/librustc_back/target/x86_64_unknown_cloudabi.rs
+++ b/src/librustc_back/target/x86_64_unknown_cloudabi.rs
@@ -15,7 +15,7 @@ pub fn target() -> TargetResult {
     let mut base = super::cloudabi_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
-    base.linker = "x86_64-unknown-cloudabi-cc".to_string();
+    base.linker = Some("x86_64-unknown-cloudabi-cc".to_string());
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
     base.stack_probes = true;
 
diff --git a/src/librustc_trans/Cargo.toml b/src/librustc_trans/Cargo.toml
index 4b9c93088a5..805d2086ee4 100644
--- a/src/librustc_trans/Cargo.toml
+++ b/src/librustc_trans/Cargo.toml
@@ -11,6 +11,7 @@ test = false
 
 [dependencies]
 bitflags = "1.0"
+cc = "1.0.1"
 flate2 = "1.0"
 jobserver = "0.1.5"
 libc = "0.2"
@@ -34,9 +35,6 @@ syntax = { path = "../libsyntax" }
 syntax_pos = { path = "../libsyntax_pos" }
 tempdir = "0.3"
 
-[target."cfg(windows)".dependencies]
-cc = "1.0.1"
-
 [features]
 # Used to communicate the feature to `rustc_back` in the same manner that the
 # `rustc` driver script communicate this.
diff --git a/src/librustc_trans/back/command.rs b/src/librustc_trans/back/command.rs
index e5e0a4e3ba0..ecf7bf5036e 100644
--- a/src/librustc_trans/back/command.rs
+++ b/src/librustc_trans/back/command.rs
@@ -81,17 +81,6 @@ impl Command {
         self
     }
 
-    pub fn envs<I, K, V>(&mut self, envs: I) -> &mut Command
-        where I: IntoIterator<Item=(K, V)>,
-              K: AsRef<OsStr>,
-              V: AsRef<OsStr>
-    {
-        for (key, value) in envs {
-            self._env(key.as_ref(), value.as_ref());
-        }
-        self
-    }
-
     fn _env(&mut self, key: &OsStr, value: &OsStr) {
         self.env.push((key.to_owned(), value.to_owned()));
     }
@@ -112,6 +101,9 @@ impl Command {
                 let mut c = process::Command::new(p);
                 c.arg("-flavor").arg(match flavor {
                     LldFlavor::Wasm => "wasm",
+                    LldFlavor::Ld => "gnu",
+                    LldFlavor::Link => "link",
+                    LldFlavor::Ld64 => "darwin",
                 });
                 c
             }
diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs
index c134203a773..636b3984117 100644
--- a/src/librustc_trans/back/link.rs
+++ b/src/librustc_trans/back/link.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use cc::windows_registry;
 use super::archive::{ArchiveBuilder, ArchiveConfig};
 use super::bytecode::RLIB_BYTECODE_EXTENSION;
 use super::linker::Linker;
@@ -35,7 +36,6 @@ use llvm;
 use std::ascii;
 use std::char;
 use std::env;
-use std::ffi::OsString;
 use std::fmt;
 use std::fs;
 use std::io;
@@ -58,9 +58,7 @@ pub use rustc_trans_utils::link::{find_crate_name, filename_for_input, default_o
 // 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, Vec<(OsString, OsString)>) {
-    let envs = vec![("PATH".into(), command_path(sess))];
-
+pub fn get_linker(sess: &Session) -> (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
@@ -75,60 +73,57 @@ pub fn get_linker(sess: &Session) -> (PathBuf, Command, Vec<(OsString, OsString)
                 return Command::bat_script(linker)
             }
         }
-        Command::new(linker)
-    };
-
-    if let Some(ref linker) = sess.opts.cg.linker {
-        (linker.clone(), cmd(linker), envs)
-    } else if sess.target.target.options.is_like_msvc {
-        let (cmd, envs) = msvc_link_exe_cmd(sess);
-        (PathBuf::from("link.exe"), cmd, envs)
-    } else if let LinkerFlavor::Lld(f) = sess.linker_flavor() {
-        let linker = PathBuf::from(&sess.target.target.options.linker);
-        let cmd = Command::lld(&linker, f);
-        (linker, cmd, envs)
-    } else {
-        let linker = PathBuf::from(&sess.target.target.options.linker);
-        let cmd = cmd(&linker);
-        (linker, cmd, envs)
-    }
-}
+        match sess.linker_flavor() {
+            LinkerFlavor::Lld(f) => Command::lld(linker, f),
+            _ => Command::new(linker),
 
-#[cfg(windows)]
-pub fn msvc_link_exe_cmd(sess: &Session) -> (Command, Vec<(OsString, OsString)>) {
-    use cc::windows_registry;
+        }
+    };
 
-    let target = &sess.opts.target_triple;
-    let tool = windows_registry::find_tool(target, "link.exe");
+    let msvc_tool = windows_registry::find_tool(&sess.opts.target_triple, "link.exe");
 
-    if let Some(tool) = tool {
-        let mut cmd = Command::new(tool.path());
-        cmd.args(tool.args());
-        for &(ref k, ref v) in tool.env() {
-            cmd.env(k, v);
-        }
-        let envs = tool.env().to_vec();
-        (cmd, envs)
-    } else {
-        debug!("Failed to locate linker.");
-        (Command::new("link.exe"), vec![])
-    }
-}
+    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(),
+        });
 
-#[cfg(not(windows))]
-pub fn msvc_link_exe_cmd(_sess: &Session) -> (Command, Vec<(OsString, OsString)>) {
-    (Command::new("link.exe"), vec![])
-}
+    let mut cmd = cmd(linker_path);
 
-fn command_path(sess: &Session) -> OsString {
     // 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)
                            .get_tools_search_paths();
-    if let Some(path) = env::var_os("PATH") {
-        new_path.extend(env::split_paths(&path));
+    let mut msvc_changed_path = false;
+    if sess.target.target.options.is_like_msvc {
+        if let Some(ref tool) = msvc_tool {
+            cmd.args(tool.args());
+            for &(ref k, ref v) in tool.env() {
+                if k == "PATH" {
+                    new_path.extend(env::split_paths(v));
+                    msvc_changed_path = true;
+                } else {
+                    cmd.env(k, v);
+                }
+            }
+        }
     }
-    env::join_paths(new_path).unwrap()
+
+    if !msvc_changed_path {
+        if let Some(path) = env::var_os("PATH") {
+            new_path.extend(env::split_paths(&path));
+        }
+    }
+    cmd.env("PATH", env::join_paths(new_path).unwrap());
+
+    (linker_path.to_path_buf(), cmd)
 }
 
 pub fn remove(sess: &Session, path: &Path) {
@@ -618,9 +613,7 @@ fn link_natively(sess: &Session,
     let flavor = sess.linker_flavor();
 
     // The invocations of cc share some flags across platforms
-    let (pname, mut cmd, envs) = get_linker(sess);
-    // This will set PATH on windows
-    cmd.envs(envs);
+    let (pname, mut cmd) = get_linker(sess);
 
     let root = sess.target_filesearch(PathKind::Native).get_lib_path();
     if let Some(args) = sess.target.target.options.pre_link_args.get(&flavor) {
diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs
index a82270c5272..a3ff39a47a2 100644
--- a/src/librustc_trans/back/linker.rs
+++ b/src/librustc_trans/back/linker.rs
@@ -45,6 +45,7 @@ impl LinkerInfo {
                          cmd: Command,
                          sess: &'a Session) -> Box<Linker+'a> {
         match sess.linker_flavor() {
+            LinkerFlavor::Lld(LldFlavor::Link) |
             LinkerFlavor::Msvc => {
                 Box::new(MsvcLinker {
                     cmd,
@@ -68,6 +69,9 @@ impl LinkerInfo {
                     is_ld: false,
                 }) as Box<Linker>
             }
+
+            LinkerFlavor::Lld(LldFlavor::Ld) |
+            LinkerFlavor::Lld(LldFlavor::Ld64) |
             LinkerFlavor::Ld => {
                 Box::new(GccLinker {
                     cmd,
diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs
index 1664aa9d0b3..78b26a37485 100644
--- a/src/librustc_trans/back/write.rs
+++ b/src/librustc_trans/back/write.rs
@@ -1369,7 +1369,7 @@ 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);
+        let (name, mut cmd) = get_linker(sess);
         cmd.args(&sess.target.target.options.asm_args);
         Some(Arc::new(AssemblerCommand {
             name,
diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs
index 51ad17fe205..0b8da10b78e 100644
--- a/src/librustc_trans/lib.rs
+++ b/src/librustc_trans/lib.rs
@@ -62,7 +62,6 @@ extern crate rustc_trans_utils;
 extern crate syntax_pos;
 extern crate rustc_errors as errors;
 extern crate serialize;
-#[cfg(windows)]
 extern crate cc; // Used to locate MSVC
 extern crate tempdir;