about summary refs log tree commit diff
path: root/src/bootstrap
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-05-10 10:30:02 +0000
committerbors <bors@rust-lang.org>2018-05-10 10:30:02 +0000
commit57dc98434eb818733dbc941405fdee59e5c3a023 (patch)
tree4b76049ca5ef8fb2e8f600599f407121e49676d0 /src/bootstrap
parentc8a3ec1ce6dc12f86de39bf5ac55fc2fa38358f8 (diff)
parent7e5b9ac41e36b29d5208f4e5455aade07d4d107d (diff)
downloadrust-57dc98434eb818733dbc941405fdee59e5c3a023.tar.gz
rust-57dc98434eb818733dbc941405fdee59e5c3a023.zip
Auto merge of #50200 - alexcrichton:compile-with-clang, r=kennytm
Compile LLVM with Clang on release builders

Attempting to cache in on some rustc compile time wins mentioned in https://github.com/rust-lang/rust/issues/49879#issuecomment-383602941
Diffstat (limited to 'src/bootstrap')
-rw-r--r--src/bootstrap/Cargo.toml5
-rw-r--r--src/bootstrap/bin/llvm-config-wrapper.rs27
-rw-r--r--src/bootstrap/bin/sccache-plus-cl.rs10
-rw-r--r--src/bootstrap/builder.rs6
-rw-r--r--src/bootstrap/config.rs3
-rw-r--r--src/bootstrap/native.rs68
6 files changed, 107 insertions, 12 deletions
diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml
index 2f9c4e148a6..af33ebf3c42 100644
--- a/src/bootstrap/Cargo.toml
+++ b/src/bootstrap/Cargo.toml
@@ -28,6 +28,11 @@ name = "sccache-plus-cl"
 path = "bin/sccache-plus-cl.rs"
 test = false
 
+[[bin]]
+name = "llvm-config-wrapper"
+path = "bin/llvm-config-wrapper.rs"
+test = false
+
 [dependencies]
 build_helper = { path = "../build_helper" }
 cmake = "0.1.23"
diff --git a/src/bootstrap/bin/llvm-config-wrapper.rs b/src/bootstrap/bin/llvm-config-wrapper.rs
new file mode 100644
index 00000000000..b1703f8c728
--- /dev/null
+++ b/src/bootstrap/bin/llvm-config-wrapper.rs
@@ -0,0 +1,27 @@
+// Copyright 2018 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.
+
+// The sheer existence of this file is an awful hack. See the comments in
+// `src/bootstrap/native.rs` for why this is needed when compiling LLD.
+
+use std::env;
+use std::process::{self, Stdio, Command};
+use std::io::{self, Write};
+
+fn main() {
+    let real_llvm_config = env::var_os("LLVM_CONFIG_REAL").unwrap();
+    let mut cmd = Command::new(real_llvm_config);
+    cmd.args(env::args().skip(1)).stderr(Stdio::piped());
+    let output = cmd.output().expect("failed to spawn llvm-config");
+    let stdout = String::from_utf8_lossy(&output.stdout);
+    print!("{}", stdout.replace("\\", "/"));
+    io::stdout().flush().unwrap();
+    process::exit(output.status.code().unwrap_or(1));
+}
diff --git a/src/bootstrap/bin/sccache-plus-cl.rs b/src/bootstrap/bin/sccache-plus-cl.rs
index 8584014d48d..0a20ac7e492 100644
--- a/src/bootstrap/bin/sccache-plus-cl.rs
+++ b/src/bootstrap/bin/sccache-plus-cl.rs
@@ -16,8 +16,8 @@ use std::process::{self, Command};
 fn main() {
     let target = env::var("SCCACHE_TARGET").unwrap();
     // Locate the actual compiler that we're invoking
-    env::remove_var("CC");
-    env::remove_var("CXX");
+    env::set_var("CC", env::var_os("SCCACHE_CC").unwrap());
+    env::set_var("CXX", env::var_os("SCCACHE_CXX").unwrap());
     let mut cfg = cc::Build::new();
     cfg.cargo_metadata(false)
        .out_dir("/")
@@ -39,6 +39,12 @@ fn main() {
         cmd.arg(arg);
     }
 
+    if let Ok(s) = env::var("SCCACHE_EXTRA_ARGS") {
+        for s in s.split_whitespace() {
+            cmd.arg(s);
+        }
+    }
+
     let status = cmd.status().expect("failed to spawn");
     process::exit(status.code().unwrap_or(2))
 }
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index 701313d8082..f87436504c6 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -751,7 +751,11 @@ impl<'a> Builder<'a> {
         // the options through environment variables that are fetched and understood by both.
         //
         // FIXME: the guard against msvc shouldn't need to be here
-        if !target.contains("msvc") {
+        if target.contains("msvc") {
+            if let Some(ref cl) = self.config.llvm_clang_cl {
+                cargo.env("CC", cl).env("CXX", cl);
+            }
+        } else {
             let ccache = self.config.ccache.as_ref();
             let ccacheify = |s: &Path| {
                 let ccache = match ccache {
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index 6dd6291be23..9840682d137 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -82,6 +82,7 @@ pub struct Config {
     pub llvm_version_check: bool,
     pub llvm_static_stdcpp: bool,
     pub llvm_link_shared: bool,
+    pub llvm_clang_cl: Option<String>,
     pub llvm_targets: Option<String>,
     pub llvm_experimental_targets: String,
     pub llvm_link_jobs: Option<u32>,
@@ -250,6 +251,7 @@ struct Llvm {
     experimental_targets: Option<String>,
     link_jobs: Option<u32>,
     link_shared: Option<bool>,
+    clang_cl: Option<String>
 }
 
 #[derive(Deserialize, Default, Clone)]
@@ -504,6 +506,7 @@ impl Config {
             config.llvm_experimental_targets = llvm.experimental_targets.clone()
                 .unwrap_or("WebAssembly".to_string());
             config.llvm_link_jobs = llvm.link_jobs;
+            config.llvm_clang_cl = llvm.clang_cl.clone();
         }
 
         if let Some(ref rust) = toml.rust {
diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs
index d952cb5bfc4..002044050f3 100644
--- a/src/bootstrap/native.rs
+++ b/src/bootstrap/native.rs
@@ -275,21 +275,53 @@ fn configure_cmake(builder: &Builder,
         return
     }
 
-    let cc = builder.cc(target);
-    let cxx = builder.cxx(target).unwrap();
+    let (cc, cxx) = match builder.config.llvm_clang_cl {
+        Some(ref cl) => (cl.as_ref(), cl.as_ref()),
+        None => (builder.cc(target), builder.cxx(target).unwrap()),
+    };
 
     // Handle msvc + ninja + ccache specially (this is what the bots use)
     if target.contains("msvc") &&
        builder.config.ninja &&
-       builder.config.ccache.is_some() {
-        let mut cc = env::current_exe().expect("failed to get cwd");
-        cc.set_file_name("sccache-plus-cl.exe");
+       builder.config.ccache.is_some()
+    {
+       let mut wrap_cc = env::current_exe().expect("failed to get cwd");
+       wrap_cc.set_file_name("sccache-plus-cl.exe");
 
-       cfg.define("CMAKE_C_COMPILER", sanitize_cc(&cc))
-          .define("CMAKE_CXX_COMPILER", sanitize_cc(&cc));
+       cfg.define("CMAKE_C_COMPILER", sanitize_cc(&wrap_cc))
+          .define("CMAKE_CXX_COMPILER", sanitize_cc(&wrap_cc));
        cfg.env("SCCACHE_PATH",
                builder.config.ccache.as_ref().unwrap())
-          .env("SCCACHE_TARGET", target);
+          .env("SCCACHE_TARGET", target)
+          .env("SCCACHE_CC", &cc)
+          .env("SCCACHE_CXX", &cxx);
+
+       // Building LLVM on MSVC can be a little ludicrous at times. We're so far
+       // off the beaten path here that I'm not really sure this is even half
+       // supported any more. Here we're trying to:
+       //
+       // * Build LLVM on MSVC
+       // * Build LLVM with `clang-cl` instead of `cl.exe`
+       // * Build a project with `sccache`
+       // * Build for 32-bit as well
+       // * Build with Ninja
+       //
+       // For `cl.exe` there are different binaries to compile 32/64 bit which
+       // we use but for `clang-cl` there's only one which internally
+       // multiplexes via flags. As a result it appears that CMake's detection
+       // of a compiler's architecture and such on MSVC **doesn't** pass any
+       // custom flags we pass in CMAKE_CXX_FLAGS below. This means that if we
+       // use `clang-cl.exe` it's always diagnosed as a 64-bit compiler which
+       // definitely causes problems since all the env vars are pointing to
+       // 32-bit libraries.
+       //
+       // To hack aroudn this... again... we pass an argument that's
+       // unconditionally passed in the sccache shim. This'll get CMake to
+       // correctly diagnose it's doing a 32-bit compilation and LLVM will
+       // internally configure itself appropriately.
+       if builder.config.llvm_clang_cl.is_some() && target.contains("i686") {
+           cfg.env("SCCACHE_EXTRA_ARGS", "-m32");
+       }
 
     // If ccache is configured we inform the build a little differently hwo
     // to invoke ccache while also invoking our compilers.
@@ -368,9 +400,27 @@ impl Step for Lld {
         let mut cfg = cmake::Config::new(builder.src.join("src/tools/lld"));
         configure_cmake(builder, target, &mut cfg, true);
 
+        // This is an awful, awful hack. Discovered when we migrated to using
+        // clang-cl to compile LLVM/LLD it turns out that LLD, when built out of
+        // tree, will execute `llvm-config --cmakedir` and then tell CMake about
+        // that directory for later processing. Unfortunately if this path has
+        // forward slashes in it (which it basically always does on Windows)
+        // then CMake will hit a syntax error later on as... something isn't
+        // escaped it seems?
+        //
+        // Instead of attempting to fix this problem in upstream CMake and/or
+        // LLVM/LLD we just hack around it here. This thin wrapper will take the
+        // output from llvm-config and replace all instances of `\` with `/` to
+        // ensure we don't hit the same bugs with escaping. It means that you
+        // can't build on a system where your paths require `\` on Windows, but
+        // there's probably a lot of reasons you can't do that other than this.
+        let llvm_config_shim = env::current_exe()
+            .unwrap()
+            .with_file_name("llvm-config-wrapper");
         cfg.out_dir(&out_dir)
            .profile("Release")
-           .define("LLVM_CONFIG_PATH", llvm_config)
+           .env("LLVM_CONFIG_REAL", llvm_config)
+           .define("LLVM_CONFIG_PATH", llvm_config_shim)
            .define("LLVM_INCLUDE_TESTS", "OFF");
 
         cfg.build();