summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Deutschmann <whissi@gentoo.org>2018-10-04 15:35:23 +0200
committerThomas Deutschmann <whissi@gentoo.org>2018-10-04 15:35:39 +0200
commit87ee38a17afd372982e6411cc9c22bbf3229ed0c (patch)
treed4429ed9bf2c71bda25b827ed500922f0f9043f1 /www-client/firefox/files
parentdev-ros/pr2_description: remove patch merged upstream (diff)
downloadgentoo-87ee38a17afd372982e6411cc9c22bbf3229ed0c.tar.gz
gentoo-87ee38a17afd372982e6411cc9c22bbf3229ed0c.tar.bz2
gentoo-87ee38a17afd372982e6411cc9c22bbf3229ed0c.zip
www-client/firefox: make rust cc honor CC env variable
Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1496270 Package-Manager: Portage-2.3.50, Repoman-2.3.11 Signed-off-by: Thomas Deutschmann <whissi@gentoo.org>
Diffstat (limited to 'www-client/firefox/files')
-rw-r--r--www-client/firefox/files/firefox-60.0-update-cc-to-honor-CC.patch745
1 files changed, 745 insertions, 0 deletions
diff --git a/www-client/firefox/files/firefox-60.0-update-cc-to-honor-CC.patch b/www-client/firefox/files/firefox-60.0-update-cc-to-honor-CC.patch
new file mode 100644
index 000000000000..9bca3f57a0ab
--- /dev/null
+++ b/www-client/firefox/files/firefox-60.0-update-cc-to-honor-CC.patch
@@ -0,0 +1,745 @@
+https://bugzilla.mozilla.org/show_bug.cgi?id=1496270
+https://bugzilla.mozilla.org/show_bug.cgi?id=1445528
+
+--- a/third_party/rust/cc/.cargo-checksum.json
++++ b/third_party/rust/cc/.cargo-checksum.json
+@@ -1 +1 @@
+-{"files":{".travis.yml":"1a4a3f7f90349924378e93acbb524b9127e37c02cfbc6dc59fd904bbdc1c8d0b","Cargo.toml":"623dd06a83bcbf2f292ab51af93e9b79b689e3be06a62968b79f4e36f1bb769f","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"186c5c8a62520cb7a3d90d77161c954b52ae8456fca0e0669bc3a5b889592a43","appveyor.yml":"ab45bfdcf2596f357225a54e730c34d518a8f3ad56c2ed33af682cfd45bddc02","src/bin/gcc-shim.rs":"d6be9137cb48b86891e7b263adbf492e1193ffe682db9ba4a88eb1079b874b58","src/com.rs":"0cb06f5db0fb70d27db0e5917ca337de6e7032119e6aabfea1bad9c719f5f34b","src/lib.rs":"996b650e19d5ccd6e64e741789427017c913644e980862a7286ec4ed53c14a17","src/registry.rs":"3876ef9573e3bbc050aef41a684b9a510cc1a91b15ae874fe032cf4377b4d116","src/setup_config.rs":"1a3eeb11c6847c31f2a4685b62ab35c76f0b6d5a17f7ed99e9df164283a771f7","src/winapi.rs":"cb5e6cab3eb570b0f97c660ca448ccfb5024262c0c7b245c181daad91a79f211","src/windows_registry.rs":"6de548aa94215e449f0e58e9a3b1702939d7c2f7b63a9040901c948bf138201d","tests/cc_env.rs":"7402315eea7ffa23b29b393c1de8e236294ede9de562ff0a562704a157135341","tests/support/mod.rs":"092551f9f6e3a999fa0aa02f93314aac0bda2b09268f948c423df56a43575e0b","tests/test.rs":"b1164258714e13173f3861126e97bedf1e29aa24618993c4eb0edd57c431dcc7"},"package":"deaf9ec656256bb25b404c51ef50097207b9cbb29c933d31f92cae5a8a0ffee0"}
+\ No newline at end of file
++{"files":{".travis.yml":"1a4a3f7f90349924378e93acbb524b9127e37c02cfbc6dc59fd904bbdc1c8d0b","Cargo.toml":"623dd06a83bcbf2f292ab51af93e9b79b689e3be06a62968b79f4e36f1bb769f","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"186c5c8a62520cb7a3d90d77161c954b52ae8456fca0e0669bc3a5b889592a43","appveyor.yml":"ab45bfdcf2596f357225a54e730c34d518a8f3ad56c2ed33af682cfd45bddc02","src/bin/gcc-shim.rs":"d6be9137cb48b86891e7b263adbf492e1193ffe682db9ba4a88eb1079b874b58","src/com.rs":"0cb06f5db0fb70d27db0e5917ca337de6e7032119e6aabfea1bad9c719f5f34b","src/lib.rs":"6e8cea99f5fc8e5982b1ea9a336ee2f9a6158a9498c8f0c36f1e8cee8c99716e","src/registry.rs":"3876ef9573e3bbc050aef41a684b9a510cc1a91b15ae874fe032cf4377b4d116","src/setup_config.rs":"1a3eeb11c6847c31f2a4685b62ab35c76f0b6d5a17f7ed99e9df164283a771f7","src/winapi.rs":"cb5e6cab3eb570b0f97c660ca448ccfb5024262c0c7b245c181daad91a79f211","src/windows_registry.rs":"6de548aa94215e449f0e58e9a3b1702939d7c2f7b63a9040901c948bf138201d","tests/cc_env.rs":"7402315eea7ffa23b29b393c1de8e236294ede9de562ff0a562704a157135341","tests/support/mod.rs":"092551f9f6e3a999fa0aa02f93314aac0bda2b09268f948c423df56a43575e0b","tests/test.rs":"b1164258714e13173f3861126e97bedf1e29aa24618993c4eb0edd57c431dcc7"},"package":"deaf9ec656256bb25b404c51ef50097207b9cbb29c933d31f92cae5a8a0ffee0"}
+\ No newline at end of file
+--- a/third_party/rust/cc/src/lib.rs
++++ b/third_party/rust/cc/src/lib.rs
+@@ -61,15 +61,14 @@
+ extern crate rayon;
+
+ use std::env;
+-use std::ffi::{OsString, OsStr};
++use std::ffi::{OsStr, OsString};
+ use std::fs;
+-use std::path::{PathBuf, Path};
+-use std::process::{Command, Stdio, Child};
+-use std::io::{self, BufReader, BufRead, Read, Write};
++use std::path::{Path, PathBuf};
++use std::process::{Child, Command, Stdio};
++use std::io::{self, BufRead, BufReader, Read, Write};
+ use std::thread::{self, JoinHandle};
+-
+-#[cfg(feature = "parallel")]
+-use std::sync::Mutex;
++use std::collections::HashMap;
++use std::sync::{Arc, Mutex};
+
+ // These modules are all glue to support reading the MSVC version from
+ // the registry and from COM interfaces
+@@ -97,6 +96,7 @@ pub struct Build {
+ objects: Vec<PathBuf>,
+ flags: Vec<String>,
+ flags_supported: Vec<String>,
++ known_flag_support_status: Arc<Mutex<HashMap<String, bool>>>,
+ files: Vec<PathBuf>,
+ cpp: bool,
+ cpp_link_stdlib: Option<Option<String>>,
+@@ -241,8 +241,7 @@ impl ToolFamily {
+ fn nvcc_debug_flag(&self) -> &'static str {
+ match *self {
+ ToolFamily::Msvc => unimplemented!(),
+- ToolFamily::Gnu |
+- ToolFamily::Clang => "-G",
++ ToolFamily::Gnu | ToolFamily::Clang => "-G",
+ }
+ }
+
+@@ -251,8 +250,7 @@ impl ToolFamily {
+ fn nvcc_redirect_flag(&self) -> &'static str {
+ match *self {
+ ToolFamily::Msvc => unimplemented!(),
+- ToolFamily::Gnu |
+- ToolFamily::Clang => "-Xcompiler",
++ ToolFamily::Gnu | ToolFamily::Clang => "-Xcompiler",
+ }
+ }
+ }
+@@ -269,10 +267,7 @@ struct Object {
+ impl Object {
+ /// Create a new source file -> object file pair.
+ fn new(src: PathBuf, dst: PathBuf) -> Object {
+- Object {
+- src: src,
+- dst: dst,
+- }
++ Object { src: src, dst: dst }
+ }
+ }
+
+@@ -289,6 +284,7 @@ impl Build {
+ objects: Vec::new(),
+ flags: Vec::new(),
+ flags_supported: Vec::new(),
++ known_flag_support_status: Arc::new(Mutex::new(HashMap::new())),
+ files: Vec::new(),
+ shared_flag: None,
+ static_flag: None,
+@@ -344,10 +340,8 @@ impl Build {
+ /// .compile("foo");
+ /// ```
+ pub fn define<'a, V: Into<Option<&'a str>>>(&mut self, var: &str, val: V) -> &mut Build {
+- self.definitions.push((
+- var.to_string(),
+- val.into().map(|s| s.to_string()),
+- ));
++ self.definitions
++ .push((var.to_string(), val.into().map(|s| s.to_string())));
+ self
+ }
+
+@@ -398,7 +392,16 @@ impl Build {
+ ///
+ /// It may return error if it's unable to run the compilier with a test file
+ /// (e.g. the compiler is missing or a write to the `out_dir` failed).
++ ///
++ /// Note: Once computed, the result of this call is stored in the
++ /// `known_flag_support` field. If `is_flag_supported(flag)`
++ /// is called again, the result will be read from the hash table.
+ pub fn is_flag_supported(&self, flag: &str) -> Result<bool, Error> {
++ let mut known_status = self.known_flag_support_status.lock().unwrap();
++ if let Some(is_supported) = known_status.get(flag).cloned() {
++ return Ok(is_supported);
++ }
++
+ let out_dir = self.get_out_dir()?;
+ let src = self.ensure_check_file()?;
+ let obj = out_dir.join("flag_check");
+@@ -413,7 +416,8 @@ impl Build {
+ .cuda(self.cuda);
+ let compiler = cfg.try_get_compiler()?;
+ let mut cmd = compiler.to_command();
+- command_add_output_file(&mut cmd, &obj, target.contains("msvc"), false);
++ let is_arm = target.contains("aarch64") || target.contains("arm");
++ command_add_output_file(&mut cmd, &obj, target.contains("msvc"), false, is_arm);
+
+ // We need to explicitly tell msvc not to link and create an exe
+ // in the root directory of the crate
+@@ -424,7 +428,10 @@ impl Build {
+ cmd.arg(&src);
+
+ let output = cmd.output()?;
+- Ok(output.stderr.is_empty())
++ let is_supported = output.stderr.is_empty();
++
++ known_status.insert(flag.to_owned(), is_supported);
++ Ok(is_supported)
+ }
+
+ /// Add an arbitrary flag to the invocation of the compiler if it supports it
+@@ -777,9 +784,8 @@ impl Build {
+ A: AsRef<OsStr>,
+ B: AsRef<OsStr>,
+ {
+- self.env.push(
+- (a.as_ref().to_owned(), b.as_ref().to_owned()),
+- );
++ self.env
++ .push((a.as_ref().to_owned(), b.as_ref().to_owned()));
+ self
+ }
+
+@@ -880,31 +886,19 @@ impl Build {
+ fn compile_objects(&self, objs: &[Object]) -> Result<(), Error> {
+ use self::rayon::prelude::*;
+
+- let mut cfg = rayon::Configuration::new();
+ if let Ok(amt) = env::var("NUM_JOBS") {
+ if let Ok(amt) = amt.parse() {
+- cfg = cfg.num_threads(amt);
++ let _ = rayon::ThreadPoolBuilder::new()
++ .num_threads(amt)
++ .build_global();
+ }
+ }
+- drop(rayon::initialize(cfg));
+-
+- let results: Mutex<Vec<Result<(), Error>>> = Mutex::new(Vec::new());
+-
+- objs.par_iter().with_max_len(1).for_each(
+- |obj| {
+- let res = self.compile_object(obj);
+- results.lock().unwrap().push(res)
+- },
+- );
+
+ // Check for any errors and return the first one found.
+- for result in results.into_inner().unwrap().iter() {
+- if result.is_err() {
+- return result.clone();
+- }
+- }
+-
+- Ok(())
++ objs.par_iter()
++ .with_max_len(1)
++ .map(|obj| self.compile_object(obj))
++ .collect()
+ }
+
+ #[cfg(not(feature = "parallel"))]
+@@ -917,7 +911,8 @@ impl Build {
+
+ fn compile_object(&self, obj: &Object) -> Result<(), Error> {
+ let is_asm = obj.src.extension().and_then(|s| s.to_str()) == Some("asm");
+- let msvc = self.get_target()?.contains("msvc");
++ let target = self.get_target()?;
++ let msvc = target.contains("msvc");
+ let (mut cmd, name) = if msvc && is_asm {
+ self.msvc_macro_assembler()?
+ } else {
+@@ -931,15 +926,17 @@ impl Build {
+ compiler
+ .path
+ .file_name()
+- .ok_or_else(|| {
+- Error::new(ErrorKind::IOError, "Failed to get compiler path.")
+- })?
++ .ok_or_else(|| Error::new(ErrorKind::IOError, "Failed to get compiler path."))?
+ .to_string_lossy()
+ .into_owned(),
+ )
+ };
+- command_add_output_file(&mut cmd, &obj.dst, msvc, is_asm);
+- cmd.arg(if msvc { "/c" } else { "-c" });
++ let is_arm = target.contains("aarch64") || target.contains("arm");
++ command_add_output_file(&mut cmd, &obj.dst, msvc, is_asm, is_arm);
++ // armasm and armasm64 don't requrie -c option
++ if !msvc || !is_asm || !is_arm {
++ cmd.arg(if msvc { "/c" } else { "-c" });
++ }
+ cmd.arg(&obj.src);
+
+ run(&mut cmd, &name)?;
+@@ -967,9 +964,7 @@ impl Build {
+ let name = compiler
+ .path
+ .file_name()
+- .ok_or_else(|| {
+- Error::new(ErrorKind::IOError, "Failed to get compiler path.")
+- })?
++ .ok_or_else(|| Error::new(ErrorKind::IOError, "Failed to get compiler path."))?
+ .to_string_lossy()
+ .into_owned();
+
+@@ -1054,8 +1049,8 @@ impl Build {
+ cmd.args.push(crt_flag.into());
+
+ match &opt_level[..] {
+- "z" | "s" => cmd.args.push("/Os".into()),
+- "1" => cmd.args.push("/O1".into()),
++ // Msvc uses /O1 to enable all optimizations that minimize code size.
++ "z" | "s" | "1" => cmd.args.push("/O1".into()),
+ // -O3 is a valid value for gcc and clang compilers, but not msvc. Cap to /O2.
+ "2" | "3" => cmd.args.push("/O2".into()),
+ _ => {}
+@@ -1070,8 +1065,10 @@ impl Build {
+ cmd.args.push(format!("-O{}", opt_level).into());
+ }
+
+- cmd.push_cc_arg("-ffunction-sections".into());
+- cmd.push_cc_arg("-fdata-sections".into());
++ if !target.contains("-ios") {
++ cmd.push_cc_arg("-ffunction-sections".into());
++ cmd.push_cc_arg("-fdata-sections".into());
++ }
+ if self.pic.unwrap_or(!target.contains("windows-gnu")) {
+ cmd.push_cc_arg("-fPIC".into());
+ }
+@@ -1169,7 +1166,7 @@ impl Build {
+ // linker that we're generating 32-bit executables as well. This'll
+ // typically only be used for build scripts which transitively use
+ // these flags that try to compile executables.
+- if target == "i686-unknown-linux-musl" {
++ if target == "i686-unknown-linux-musl" || target == "i586-unknown-linux-musl" {
+ cmd.args.push("-Wl,-melf_i386".into());
+ }
+
+@@ -1212,14 +1209,13 @@ impl Build {
+ if self.cpp {
+ match (self.cpp_set_stdlib.as_ref(), cmd.family) {
+ (None, _) => {}
+- (Some(stdlib), ToolFamily::Gnu) |
+- (Some(stdlib), ToolFamily::Clang) => {
++ (Some(stdlib), ToolFamily::Gnu) | (Some(stdlib), ToolFamily::Clang) => {
+ cmd.push_cc_arg(format!("-stdlib=lib{}", stdlib).into());
+ }
+ _ => {
+ println!(
+ "cargo:warning=cpp_set_stdlib is specified, but the {:?} compiler \
+- does not support this option, ignored",
++ does not support this option, ignored",
+ cmd.family
+ );
+ }
+@@ -1272,6 +1268,10 @@ impl Build {
+ let target = self.get_target()?;
+ let tool = if target.contains("x86_64") {
+ "ml64.exe"
++ } else if target.contains("arm") {
++ "armasm.exe"
++ } else if target.contains("aarch64") {
++ "armasm64.exe"
+ } else {
+ "ml.exe"
+ };
+@@ -1307,20 +1307,55 @@ impl Build {
+ if target.contains("msvc") {
+ let mut cmd = match self.archiver {
+ Some(ref s) => self.cmd(s),
+- None => {
+- windows_registry::find(&target, "lib.exe").unwrap_or_else(
+- || {
+- self.cmd("lib.exe")
+- },
+- )
+- }
++ None => windows_registry::find(&target, "lib.exe")
++ .unwrap_or_else(|| self.cmd("lib.exe")),
+ };
++
+ let mut out = OsString::from("/OUT:");
+ out.push(dst);
+- run(
+- cmd.arg(out).arg("/nologo").args(&objects).args(&self.objects),
+- "lib.exe",
+- )?;
++ cmd.arg(out).arg("/nologo");
++
++ // Similar to https://github.com/rust-lang/rust/pull/47507
++ // and https://github.com/rust-lang/rust/pull/48548
++ let estimated_command_line_len = objects
++ .iter()
++ .chain(&self.objects)
++ .map(|a| a.as_os_str().len())
++ .sum::<usize>();
++ if estimated_command_line_len > 1024 * 6 {
++ let mut args = String::from("\u{FEFF}"); // BOM
++ for arg in objects.iter().chain(&self.objects) {
++ args.push('"');
++ for c in arg.to_str().unwrap().chars() {
++ if c == '"' {
++ args.push('\\')
++ }
++ args.push(c)
++ }
++ args.push('"');
++ args.push('\n');
++ }
++
++ let mut utf16le = Vec::new();
++ for code_unit in args.encode_utf16() {
++ utf16le.push(code_unit as u8);
++ utf16le.push((code_unit >> 8) as u8);
++ }
++
++ let mut args_file = OsString::from(dst);
++ args_file.push(".args");
++ fs::File::create(&args_file)
++ .unwrap()
++ .write_all(&utf16le)
++ .unwrap();
++
++ let mut args_file_arg = OsString::from("@");
++ args_file_arg.push(args_file);
++ cmd.arg(args_file_arg);
++ } else {
++ cmd.args(&objects).args(&self.objects);
++ }
++ run(&mut cmd, "lib.exe")?;
+
+ // The Rust compiler will look for libfoo.a and foo.lib, but the
+ // MSVC linker will also be passed foo.lib, so be sure that both
+@@ -1412,6 +1447,18 @@ impl Build {
+
+ cmd.args.push("-isysroot".into());
+ cmd.args.push(sdk_path.trim().into());
++ cmd.args.push("-fembed-bitcode".into());
++ /*
++ * TODO we probably ultimatedly 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
++ */
++ /*
++ if self.get_opt_level()? == "0" {
++ cmd.args.push("-fembed-bitcode-marker".into());
++ }
++ */
+
+ Ok(())
+ }
+@@ -1437,37 +1484,44 @@ impl Build {
+ };
+
+ // On Solaris, c++/cc unlikely to exist or be correct.
+- let default = if host.contains("solaris") { gnu } else { traditional };
+-
+- let tool_opt: Option<Tool> =
+- self.env_tool(env)
+- .map(|(tool, cc, args)| {
+- let mut t = Tool::new(PathBuf::from(tool));
+- if let Some(cc) = cc {
+- t.cc_wrapper_path = Some(PathBuf::from(cc));
+- }
+- for arg in args {
+- t.cc_wrapper_args.push(arg.into());
+- }
+- t
+- })
+- .or_else(|| {
+- if target.contains("emscripten") {
+- let tool = if self.cpp { "em++" } else { "emcc" };
+- // Windows uses bat file so we have to be a bit more specific
+- if cfg!(windows) {
+- let mut t = Tool::new(PathBuf::from("cmd"));
+- t.args.push("/c".into());
+- t.args.push(format!("{}.bat", tool).into());
+- Some(t)
+- } else {
+- Some(Tool::new(PathBuf::from(tool)))
+- }
++ let default = if host.contains("solaris") {
++ gnu
++ } else {
++ traditional
++ };
++
++ let tool_opt: Option<Tool> = self.env_tool(env)
++ .map(|(tool, cc, args)| {
++ // 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::new(PathBuf::from(tool.trim()));
++ if let Some(cc) = cc {
++ t.cc_wrapper_path = Some(PathBuf::from(cc));
++ }
++ for arg in args {
++ t.cc_wrapper_args.push(arg.into());
++ }
++ t
++ })
++ .or_else(|| {
++ if target.contains("emscripten") {
++ let tool = if self.cpp { "em++" } else { "emcc" };
++ // Windows uses bat file so we have to be a bit more specific
++ if cfg!(windows) {
++ let mut t = Tool::new(PathBuf::from("cmd"));
++ t.args.push("/c".into());
++ t.args.push(format!("{}.bat", tool).into());
++ Some(t)
+ } else {
+- None
++ Some(Tool::new(PathBuf::from(tool)))
+ }
+- })
+- .or_else(|| windows_registry::find_tool(&target, "cl.exe"));
++ } else {
++ None
++ }
++ })
++ .or_else(|| windows_registry::find_tool(&target, "cl.exe"));
+
+ let tool = match tool_opt {
+ Some(t) => t,
+@@ -1501,6 +1555,7 @@ impl Build {
+ "armv7-unknown-linux-gnueabihf" => Some("arm-linux-gnueabihf"),
+ "armv7-unknown-linux-musleabihf" => Some("arm-linux-musleabihf"),
+ "armv7-unknown-netbsd-eabihf" => Some("armv7--netbsdelf-eabihf"),
++ "i586-unknown-linux-musl" => Some("musl"),
+ "i686-pc-windows-gnu" => Some("i686-w64-mingw32"),
+ "i686-unknown-linux-musl" => Some("musl"),
+ "i686-unknown-netbsd" => Some("i486--netbsdelf"),
+@@ -1509,10 +1564,12 @@ impl Build {
+ "mips64-unknown-linux-gnuabi64" => Some("mips64-linux-gnuabi64"),
+ "mips64el-unknown-linux-gnuabi64" => Some("mips64el-linux-gnuabi64"),
+ "powerpc-unknown-linux-gnu" => Some("powerpc-linux-gnu"),
++ "powerpc-unknown-linux-gnuspe" => Some("powerpc-linux-gnuspe"),
+ "powerpc-unknown-netbsd" => Some("powerpc--netbsd"),
+ "powerpc64-unknown-linux-gnu" => Some("powerpc-linux-gnu"),
+ "powerpc64le-unknown-linux-gnu" => Some("powerpc64le-linux-gnu"),
+ "s390x-unknown-linux-gnu" => Some("s390x-linux-gnu"),
++ "sparc-unknown-linux-gnu" => Some("sparc-linux-gnu"),
+ "sparc64-unknown-linux-gnu" => Some("sparc64-linux-gnu"),
+ "sparc64-unknown-netbsd" => Some("sparc64--netbsd"),
+ "sparcv9-sun-solaris" => Some("sparcv9-sun-solaris"),
+@@ -1538,14 +1595,18 @@ impl Build {
+ };
+
+ let tool = if self.cuda {
+- assert!(tool.args.is_empty(),
+- "CUDA compilation currently assumes empty pre-existing args");
++ assert!(
++ tool.args.is_empty(),
++ "CUDA compilation currently assumes empty pre-existing args"
++ );
+ let nvcc = match self.get_var("NVCC") {
+ Err(_) => "nvcc".into(),
+ Ok(nvcc) => nvcc,
+ };
+ let mut nvcc_tool = Tool::with_features(PathBuf::from(nvcc), self.cuda);
+- nvcc_tool.args.push(format!("-ccbin={}", tool.path.display()).into());
++ nvcc_tool
++ .args
++ .push(format!("-ccbin={}", tool.path.display()).into());
+ nvcc_tool
+ } else {
+ tool
+@@ -1568,10 +1629,7 @@ impl Build {
+ Some(res) => Ok(res),
+ None => Err(Error::new(
+ ErrorKind::EnvVarNotFound,
+- &format!(
+- "Could not find environment variable {}.",
+- var_base
+- ),
++ &format!("Could not find environment variable {}.", var_base),
+ )),
+ }
+ }
+@@ -1585,21 +1643,68 @@ impl Build {
+ .collect()
+ }
+
+-
+ /// Returns compiler path, optional modifier name from whitelist, and arguments vec
+ fn env_tool(&self, name: &str) -> Option<(String, Option<String>, Vec<String>)> {
+- self.get_var(name).ok().map(|tool| {
+- let whitelist = ["ccache", "distcc", "sccache"];
++ let tool = match self.get_var(name) {
++ Ok(tool) => tool,
++ Err(_) => return None,
++ };
+
+- for t in whitelist.iter() {
+- if tool.starts_with(t) && tool[t.len()..].starts_with(' ') {
+- let args = tool.split_whitespace().collect::<Vec<_>>();
++ // If this is an exact path on the filesystem we don't want to do any
++ // interpretation at all, just pass it on through. This'll hopefully get
++ // us to support spaces-in-paths.
++ if Path::new(&tool).exists() {
++ return Some((tool, None, Vec::new()));
++ }
++
++ // Ok now we want to handle a couple of scenarios. We'll assume from
++ // here on out that spaces are splitting separate arguments. Two major
++ // features we want to support are:
++ //
++ // CC='sccache cc'
++ //
++ // aka using `sccache` or any other wrapper/caching-like-thing for
++ // compilations. We want to know what the actual compiler is still,
++ // though, because our `Tool` API support introspection of it to see
++ // what compiler is in use.
++ //
++ // additionally we want to support
++ //
++ // CC='cc -flag'
++ //
++ // where the CC env var is used to also pass default flags to the C
++ // compiler.
++ //
++ // It's true that everything here is a bit of a pain, but apparently if
++ // you're not literally make or bash then you get a lot of bug reports.
++ let known_wrappers = ["ccache", "distcc", "sccache", "icecc"];
++
++ let mut parts = tool.split_whitespace();
++ let maybe_wrapper = match parts.next() {
++ Some(s) => s,
++ None => return None,
++ };
+
+- return (args[1].to_string(), Some(t.to_string()), args[2..].iter().map(|s| s.to_string()).collect());
+- }
++ let file_stem = Path::new(maybe_wrapper)
++ .file_stem()
++ .unwrap()
++ .to_str()
++ .unwrap();
++ if known_wrappers.contains(&file_stem) {
++ if let Some(compiler) = parts.next() {
++ return Some((
++ compiler.to_string(),
++ Some(maybe_wrapper.to_string()),
++ parts.map(|s| s.to_string()).collect(),
++ ));
+ }
+- (tool, None, Vec::new())
+- })
++ }
++
++ Some((
++ maybe_wrapper.to_string(),
++ None,
++ parts.map(|s| s.to_string()).collect(),
++ ))
+ }
+
+ /// Returns the default C++ standard library for the current target: `libc++`
+@@ -1611,7 +1716,7 @@ impl Build {
+ let target = self.get_target()?;
+ if target.contains("msvc") {
+ Ok(None)
+- } else if target.contains("darwin") {
++ } else if target.contains("apple") {
+ Ok(Some("c++".to_string()))
+ } else if target.contains("freebsd") {
+ Ok(Some("c++".to_string()))
+@@ -1700,10 +1805,7 @@ impl Build {
+ Some(s) => Ok(s),
+ None => Err(Error::new(
+ ErrorKind::EnvVarNotFound,
+- &format!(
+- "Environment variable {} not defined.",
+- v.to_string()
+- ),
++ &format!("Environment variable {} not defined.", v.to_string()),
+ )),
+ }
+ }
+@@ -1731,8 +1833,9 @@ impl Tool {
+ let family = if let Some(fname) = path.file_name().and_then(|p| p.to_str()) {
+ if fname.contains("clang") {
+ ToolFamily::Clang
+- } else if fname.contains("cl") && !fname.contains("cloudabi") &&
+- !fname.contains("uclibc") {
++ } else if fname.contains("cl") && !fname.contains("cloudabi")
++ && !fname.contains("uclibc")
++ {
+ ToolFamily::Msvc
+ } else {
+ ToolFamily::Gnu
+@@ -1775,8 +1878,8 @@ impl Tool {
+ cmd.arg(&self.path);
+ cmd.args(&self.cc_wrapper_args);
+ cmd
+- },
+- None => Command::new(&self.path)
++ }
++ None => Command::new(&self.path),
+ };
+ cmd.args(&self.args);
+ for &(ref k, ref v) in self.env.iter() {
+@@ -1822,10 +1925,8 @@ impl Tool {
+ cc_env.push(arg);
+ }
+ cc_env
+- },
+- None => {
+- OsString::from("")
+ }
++ None => OsString::from(""),
+ }
+ }
+
+@@ -1868,8 +1969,7 @@ fn run(cmd: &mut Command, program: &str) -> Result<(), Error> {
+ ErrorKind::ToolExecError,
+ &format!(
+ "Failed to wait on spawned child process, command {:?} with args {:?}.",
+- cmd,
+- program
++ cmd, program
+ ),
+ ))
+ }
+@@ -1884,9 +1984,7 @@ fn run(cmd: &mut Command, program: &str) -> Result<(), Error> {
+ ErrorKind::ToolExecError,
+ &format!(
+ "Command {:?} with args {:?} did not execute successfully (status code {}).",
+- cmd,
+- program,
+- status
++ cmd, program, status
+ ),
+ ))
+ }
+@@ -1909,8 +2007,7 @@ fn run_output(cmd: &mut Command, program: &str) -> Result<Vec<u8>, Error> {
+ ErrorKind::ToolExecError,
+ &format!(
+ "Failed to wait on spawned child process, command {:?} with args {:?}.",
+- cmd,
+- program
++ cmd, program
+ ),
+ ))
+ }
+@@ -1925,9 +2022,7 @@ fn run_output(cmd: &mut Command, program: &str) -> Result<Vec<u8>, Error> {
+ ErrorKind::ToolExecError,
+ &format!(
+ "Command {:?} with args {:?} did not execute successfully (status code {}).",
+- cmd,
+- program,
+- status
++ cmd, program, status
+ ),
+ ))
+ }
+@@ -1943,39 +2038,30 @@ fn spawn(cmd: &mut Command, program: &str) -> Result<(Child, JoinHandle<()>), Er
+ match cmd.stderr(Stdio::piped()).spawn() {
+ Ok(mut child) => {
+ let stderr = BufReader::new(child.stderr.take().unwrap());
+- let print = thread::spawn(move || for line in stderr.split(b'\n').filter_map(
+- |l| l.ok(),
+- )
+- {
+- print!("cargo:warning=");
+- std::io::stdout().write_all(&line).unwrap();
+- println!("");
++ let print = thread::spawn(move || {
++ for line in stderr.split(b'\n').filter_map(|l| l.ok()) {
++ print!("cargo:warning=");
++ std::io::stdout().write_all(&line).unwrap();
++ println!("");
++ }
+ });
+ Ok((child, print))
+ }
+ Err(ref e) if e.kind() == io::ErrorKind::NotFound => {
+ let extra = if cfg!(windows) {
+ " (see https://github.com/alexcrichton/cc-rs#compile-time-requirements \
+- for help)"
++ for help)"
+ } else {
+ ""
+ };
+ Err(Error::new(
+ ErrorKind::ToolNotFound,
+- &format!(
+- "Failed to find tool. Is `{}` installed?{}",
+- program,
+- extra
+- ),
++ &format!("Failed to find tool. Is `{}` installed?{}", program, extra),
+ ))
+ }
+ Err(_) => Err(Error::new(
+ ErrorKind::ToolExecError,
+- &format!(
+- "Command {:?} with args {:?} failed to start.",
+- cmd,
+- program
+- ),
++ &format!("Command {:?} with args {:?} failed to start.", cmd, program),
+ )),
+ }
+ }
+@@ -1984,9 +2070,10 @@ fn fail(s: &str) -> ! {
+ panic!("\n\nInternal error occurred: {}\n\n", s)
+ }
+
+-
+-fn command_add_output_file(cmd: &mut Command, dst: &Path, msvc: bool, is_asm: bool) {
+- if msvc && is_asm {
++fn command_add_output_file(cmd: &mut Command, dst: &Path, msvc: bool, is_asm: bool, is_arm: bool) {
++ if msvc && is_asm && is_arm {
++ cmd.arg("-o").arg(&dst);
++ } else if msvc && is_asm {
+ cmd.arg("/Fo").arg(dst);
+ } else if msvc {
+ let mut s = OsString::from("/Fo");