From 4b72474342c3d75d5122f7fec446018adf25e5e0 Mon Sep 17 00:00:00 2001 From: Mahmoud Al-Qudsi Date: Tue, 4 Feb 2020 13:55:01 -0600 Subject: [PATCH] Detect and use sccache by introspecting RUSTC_WRAPPER (#475) * Detect and use `sccache` via `RUSTC_WRAPPER` If no other C/C++ caching tool is found by inspecting `CC` and `CXX`, `RUSTC_WRAPPER` is tested to see if an output-caching wrapper for `rustc` is in use. If that is the case and it is a wrapper known to also support C/C++ caching, use it. (Also correct/clarify a misnamed variable that caused me some confusion looking over the code.) * Support RUSTC_WRAPPER on Windows and with absolute paths When checking for possible `RUSTC_WRAPPER`s that we can use to cache C/C++ output, allow for filename extensions (e.g. `sccache.exe`) and absolute paths (e.g. `/usr/local/bin/sccache`). Closes #473 --- src/lib.rs | 35 +++++++++++++++++++++++++++++------ tests/support/mod.rs | 12 ++++++++++++ 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index ded082e..738714f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1867,7 +1867,7 @@ impl Build { cmd.args.push(sdk_path.trim().into()); cmd.args.push("-fembed-bitcode".into()); /* - * TODO we probably ultimatedly want the -fembed-bitcode-marker flag + * TODO we probably ultimately want the -fembed-bitcode-marker flag * but can't have it now because of an issue in LLVM: * https://github.com/alexcrichton/cc-rs/issues/301 * https://github.com/rust-lang/rust/pull/48896#comment-372192660 @@ -1919,13 +1919,13 @@ impl Build { .iter() .find(|a| a.starts_with(DRIVER_MODE)) .map(|a| &a[DRIVER_MODE.len()..]); - // chop off leading/trailing whitespace to work around + // Chop off leading/trailing whitespace to work around // semi-buggy build scripts which are shared in // makefiles/configure scripts (where spaces are far more // lenient) let mut t = Tool::with_clang_driver(PathBuf::from(tool.trim()), driver_mode); - if let Some(cc) = wrapper { - t.cc_wrapper_path = Some(PathBuf::from(cc)); + if let Some(cc_wrapper) = wrapper { + t.cc_wrapper_path = Some(PathBuf::from(cc_wrapper)); } for arg in args { t.cc_wrapper_args.push(arg.into()); @@ -2065,7 +2065,12 @@ impl Build { } else { default.to_string() }; - Tool::new(PathBuf::from(compiler)) + + let mut t = Tool::new(PathBuf::from(compiler)); + if let Some(cc_wrapper) = Self::rustc_wrapper_fallback() { + t.cc_wrapper_path = Some(PathBuf::from(cc_wrapper)); + } + t } }; @@ -2141,6 +2146,24 @@ impl Build { .collect() } + /// Returns a fallback `cc_compiler_wrapper` by introspecting `RUSTC_WRAPPER` + fn rustc_wrapper_fallback() -> Option { + // No explicit CC wrapper was detected, but check if RUSTC_WRAPPER + // is defined and is a build accelerator that is compatible with + // C/C++ compilers (e.g. sccache) + let valid_wrappers = ["sccache"]; + + let rustc_wrapper = std::env::var_os("RUSTC_WRAPPER")?; + let wrapper_path = Path::new(&rustc_wrapper); + let wrapper_stem = wrapper_path.file_stem()?; + + if valid_wrappers.contains(&wrapper_stem.to_str()?) { + Some(rustc_wrapper.to_str()?.to_owned()) + } else { + None + } + } + /// Returns compiler path, optional modifier name from whitelist, and arguments vec fn env_tool(&self, name: &str) -> Option<(String, Option, Vec)> { let tool = match self.get_var(name) { @@ -2200,7 +2223,7 @@ impl Build { Some(( maybe_wrapper.to_string(), - None, + Self::rustc_wrapper_fallback(), parts.map(|s| s.to_string()).collect(), )) } diff --git a/tests/support/mod.rs b/tests/support/mod.rs index fe8acde..cde930e 100644 --- a/tests/support/mod.rs +++ b/tests/support/mod.rs @@ -22,6 +22,18 @@ pub struct Execution { impl Test { pub fn new() -> Test { + // This is ugly: `sccache` needs to introspect the compiler it is + // executing, as it adjusts its behavior depending on the + // language/compiler. This crate's test driver uses mock compilers that + // are obviously not supported by sccache, so the tests fail if + // RUSTC_WRAPPER is set. rust doesn't build test dependencies with + // the `test` feature enabled, so we can't conditionally disable the + // usage of `sccache` if running in a test environment, at least not + // without setting an environment variable here and testing for it + // there. Explicitly deasserting RUSTC_WRAPPER here seems to be the + // lesser of the two evils. + env::remove_var("RUSTC_WRAPPER"); + let mut gcc = PathBuf::from(env::current_exe().unwrap()); gcc.pop(); if gcc.ends_with("deps") {