From d76b8b20334d238906daf04e415a922072e51c8a Mon Sep 17 00:00:00 2001
From: Federico Mena Quintero <federico@gnome.org>
Date: Tue, 2 Oct 2018 17:57:39 -0500
Subject: [PATCH] Update cc crate version

---
 Cargo.lock                                  |  12 +-
 third_party/rust/cc/.cargo-checksum.json    |   2 +-
 third_party/rust/cc/.travis.yml             |  23 +-
 third_party/rust/cc/Cargo.toml              |   4 +-
 third_party/rust/cc/README.md               |   2 +-
 third_party/rust/cc/src/com.rs              |  56 +-
 third_party/rust/cc/src/lib.rs              | 709 ++++++++++++++------
 third_party/rust/cc/src/registry.rs         | 112 ++--
 third_party/rust/cc/src/setup_config.rs     |  62 +-
 third_party/rust/cc/src/winapi.rs           |  16 +-
 third_party/rust/cc/src/windows_registry.rs | 186 +++--
 third_party/rust/cc/tests/cc_env.rs         |  46 ++
 third_party/rust/cc/tests/support/mod.rs    |  19 +-
 third_party/rust/cc/tests/test.rs           | 142 ++--
 14 files changed, 940 insertions(+), 451 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index e25b35203..eff696abe 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -194,13 +194,13 @@ name = "bzip2-sys"
 version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "cc"
-version = "1.0.4"
+version = "1.0.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
@@ -255,7 +255,7 @@ name = "cmake"
 version = "0.1.29"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -896,7 +896,7 @@ name = "libloading"
 version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
  "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -1027,7 +1027,7 @@ name = "miniz_oxide_c_api"
 version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
  "crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
  "miniz_oxide 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2241,7 +2241,7 @@ dependencies = [
 "checksum bytes 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d828f97b58cc5de3e40c421d0cf2132d6b2da4ee0e11b8632fa838f0f9333ad6"
 "checksum bzip2 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3eafc42c44e0d827de6b1c131175098fe7fb53b8ce8a47e65cb3ea94688be24"
 "checksum bzip2-sys 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2c5162604199bbb17690ede847eaa6120a3f33d5ab4dcc8e7c25b16d849ae79b"
-"checksum cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "deaf9ec656256bb25b404c51ef50097207b9cbb29c933d31f92cae5a8a0ffee0"
+"checksum cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "f159dfd43363c4d08055a07703eb7a3406b0dac4d0584d96965a3262db3c9d16"
 "checksum cexpr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "393a5f0088efbe41f9d1fcd062f24e83c278608420e62109feb2c8abee07de7d"
 "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de"
 "checksum chrono 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)" = "9213f7cd7c27e95c2b57c49f0e69b1ea65b27138da84a170133fd21b07659c00"
diff --git a/third_party/rust/cc/.cargo-checksum.json b/third_party/rust/cc/.cargo-checksum.json
index ecd0ba869..80e09bfaa 100644
--- 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":"7b18272b20d4b58996deb3e2d5d76f15a27d6a63a061abeefb6553a2b8650736","Cargo.toml":"8b0ccc57b8ea0c2bfc417cc2e5c3a6750eec5c0a82d3de0ce09fe2197d2867af","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"3eeb4b0488908876c439a87cfe2bec6d550b37388993b2d8863fb1c587a84f46","appveyor.yml":"ab45bfdcf2596f357225a54e730c34d518a8f3ad56c2ed33af682cfd45bddc02","src/bin/gcc-shim.rs":"d6be9137cb48b86891e7b263adbf492e1193ffe682db9ba4a88eb1079b874b58","src/com.rs":"8b9a54af5400c259f877126cc68ea63ada4fe66e84c9b840711c95e570b15774","src/lib.rs":"a9c3515602e52501ef43dd4383418baa1e2eb66d250575d16dfcd3e60801bb25","src/registry.rs":"3cc1b5a50879fa751572878ae1d0afbfc960c11665258492754b2c8bccb0ff5d","src/setup_config.rs":"f5c45afc99ad3b7c1311242bc4baf37e861d740ab81bf6ca90e2aa283672e65a","src/winapi.rs":"d7929b36130e33f1caa6bd444b378b83023b2b82d589c6e0ab38c4ff6c950da8","src/windows_registry.rs":"bdf8d441c57e3247a305a593e6280f41021ac81f45c2f3299c406b9a68817b20","tests/cc_env.rs":"bf7b14aa52af04294f648b2934f0f1830c5a0bdac1676310b8aa1f61458e7782","tests/support/mod.rs":"80dc87e54025197104cfb62d1af7a3400a3a0ddf0f2d98ea4ef4111cb1f0c890","tests/test.rs":"653b7d9ad6503aaf2ffc6c9b86014dbad456b53bcd124c9de4714067f49e5095"},"package":"f159dfd43363c4d08055a07703eb7a3406b0dac4d0584d96965a3262db3c9d16"}
\ No newline at end of file
diff --git a/third_party/rust/cc/.travis.yml b/third_party/rust/cc/.travis.yml
index 6f3c53d9a..70349e6b9 100644
--- a/third_party/rust/cc/.travis.yml
+++ b/third_party/rust/cc/.travis.yml
@@ -3,7 +3,7 @@ sudo: false
 
 matrix:
   include:
-    - rust: 1.13.0
+    - rust: 1.16.0
       install:
       script: cargo build
     - rust: stable
@@ -12,6 +12,8 @@ matrix:
       env: TARGET=i686-unknown-linux-gnu
     - os: osx
       env: TARGET=x86_64-apple-darwin NO_ADD=1
+    - os: osx
+      env: TARGET=aarch64-apple-ios NO_RUN=--no-run TARGET_SYSROOT=$(xcrun -sdk iphoneos --show-sdk-path)
     - rust: beta
       env: TARGET=x86_64-unknown-linux-gnu NO_ADD=1
     - rust: nightly
@@ -31,11 +33,20 @@ install:
 
 script:
   - cargo build --verbose
-  - cargo test --verbose
-  - cargo test --verbose --features parallel
-  - cargo test --manifest-path cc-test/Cargo.toml --target $TARGET
-  - cargo test --manifest-path cc-test/Cargo.toml --target $TARGET --features parallel
-  - cargo test --manifest-path cc-test/Cargo.toml --target $TARGET --release
+  # FIXME: no idea why `--test-threads=1` is required on the OSX builder, it
+  # just randomly broke one day when the travis image was upgraded, and
+  # debugging turned up no easily found source of bugs...
+  #
+  # good build - https://travis-ci.org/alexcrichton/cc-rs/builds/409602374
+  #  bad build - https://travis-ci.org/alexcrichton/cc-rs/builds/410489079
+  #
+  # Those are using the same compiler, same commit, same... everything. Except
+  # the OSX image! No idea what changed...
+  - cargo test --verbose $NO_RUN -- --test-threads=1
+  - cargo test --verbose --features parallel $NO_RUN -- --test-threads=1
+  - cargo test --manifest-path cc-test/Cargo.toml --target $TARGET $NO_RUN
+  - cargo test --manifest-path cc-test/Cargo.toml --target $TARGET --features parallel $NO_RUN
+  - cargo test --manifest-path cc-test/Cargo.toml --target $TARGET --release $NO_RUN
   - cargo doc
   - cargo clean && cargo build
   - rustdoc --test README.md -L target/debug -L target/debug/deps
diff --git a/third_party/rust/cc/Cargo.toml b/third_party/rust/cc/Cargo.toml
index 44560a614..f034c7c17 100644
--- a/third_party/rust/cc/Cargo.toml
+++ b/third_party/rust/cc/Cargo.toml
@@ -12,7 +12,7 @@
 
 [package]
 name = "cc"
-version = "1.0.4"
+version = "1.0.25"
 authors = ["Alex Crichton <alex@alexcrichton.com>"]
 description = "A build-time dependency for Cargo build scripts to assist in invoking the native\nC compiler to compile native C code into a static archive to be linked into Rust\ncode.\n"
 homepage = "https://github.com/alexcrichton/cc-rs"
@@ -23,7 +23,7 @@ categories = ["development-tools"]
 license = "MIT/Apache-2.0"
 repository = "https://github.com/alexcrichton/cc-rs"
 [dependencies.rayon]
-version = "0.9"
+version = "1.0"
 optional = true
 [dev-dependencies.tempdir]
 version = "0.3"
diff --git a/third_party/rust/cc/README.md b/third_party/rust/cc/README.md
index 94efa4310..f65d0c058 100644
--- a/third_party/rust/cc/README.md
+++ b/third_party/rust/cc/README.md
@@ -198,5 +198,5 @@ at your option.
 ### Contribution
 
 Unless you explicitly state otherwise, any contribution intentionally submitted
-for inclusion in Serde by you, as defined in the Apache-2.0 license, shall be
+for inclusion in cc-rs by you, as defined in the Apache-2.0 license, shall be
 dual licensed as above, without any additional terms or conditions.
diff --git a/third_party/rust/cc/src/com.rs b/third_party/rust/cc/src/com.rs
index bd8cce714..2b16475a0 100644
--- a/third_party/rust/cc/src/com.rs
+++ b/third_party/rust/cc/src/com.rs
@@ -19,7 +19,7 @@ use winapi::CoInitializeEx;
 use winapi::COINIT_MULTITHREADED;
 use winapi::{SysFreeString, SysStringLen};
 use winapi::IUnknown;
-use winapi::{S_OK, S_FALSE, HRESULT};
+use winapi::{HRESULT, S_FALSE, S_OK};
 
 pub fn initialize() -> Result<(), HRESULT> {
     let err = unsafe { CoInitializeEx(null_mut(), COINIT_MULTITHREADED) };
@@ -30,8 +30,13 @@ pub fn initialize() -> Result<(), HRESULT> {
     Ok(())
 }
 
-pub struct ComPtr<T>(*mut T) where T: Interface;
-impl<T> ComPtr<T> where T: Interface {
+pub struct ComPtr<T>(*mut T)
+where
+    T: Interface;
+impl<T> ComPtr<T>
+where
+    T: Interface,
+{
     /// Creates a `ComPtr` to wrap a raw pointer.
     /// It takes ownership over the pointer which means it does __not__ call `AddRef`.
     /// `T` __must__ be a COM interface that inherits from `IUnknown`.
@@ -40,7 +45,11 @@ impl<T> ComPtr<T> where T: Interface {
         ComPtr(ptr)
     }
     /// Casts up the inheritance chain
-    pub fn up<U>(self) -> ComPtr<U> where T: Deref<Target=U>, U: Interface {
+    pub fn up<U>(self) -> ComPtr<U>
+    where
+        T: Deref<Target = U>,
+        U: Interface,
+    {
         ComPtr(self.into_raw() as *mut U)
     }
     /// Extracts the raw pointer.
@@ -55,20 +64,31 @@ impl<T> ComPtr<T> where T: Interface {
         unsafe { &*(self.0 as *mut IUnknown) }
     }
     /// Performs QueryInterface fun.
-    pub fn cast<U>(&self) -> Result<ComPtr<U>, i32> where U: Interface {
+    pub fn cast<U>(&self) -> Result<ComPtr<U>, i32>
+    where
+        U: Interface,
+    {
         let mut obj = null_mut();
         let err = unsafe { self.as_unknown().QueryInterface(&U::uuidof(), &mut obj) };
-        if err < 0 { return Err(err); }
+        if err < 0 {
+            return Err(err);
+        }
         Ok(unsafe { ComPtr::from_raw(obj as *mut U) })
     }
 }
-impl<T> Deref for ComPtr<T> where T: Interface {
+impl<T> Deref for ComPtr<T>
+where
+    T: Interface,
+{
     type Target = T;
     fn deref(&self) -> &T {
         unsafe { &*self.0 }
     }
 }
-impl<T> Clone for ComPtr<T> where T: Interface {
+impl<T> Clone for ComPtr<T>
+where
+    T: Interface,
+{
     fn clone(&self) -> Self {
         unsafe {
             self.as_unknown().AddRef();
@@ -76,9 +96,14 @@ impl<T> Clone for ComPtr<T> where T: Interface {
         }
     }
 }
-impl<T> Drop for ComPtr<T> where T: Interface {
+impl<T> Drop for ComPtr<T>
+where
+    T: Interface,
+{
     fn drop(&mut self) {
-        unsafe { self.as_unknown().Release(); }
+        unsafe {
+            self.as_unknown().Release();
+        }
     }
 }
 pub struct BStr(BSTR);
@@ -102,7 +127,10 @@ pub trait ToWide {
     fn to_wide(&self) -> Vec<u16>;
     fn to_wide_null(&self) -> Vec<u16>;
 }
-impl<T> ToWide for T where T: AsRef<OsStr> {
+impl<T> ToWide for T
+where
+    T: AsRef<OsStr>,
+{
     fn to_wide(&self) -> Vec<u16> {
         self.as_ref().encode_wide().collect()
     }
@@ -110,7 +138,10 @@ impl<T> ToWide for T where T: AsRef<OsStr> {
         self.as_ref().encode_wide().chain(Some(0)).collect()
     }
 }
-pub trait FromWide where Self: Sized {
+pub trait FromWide
+where
+    Self: Sized,
+{
     fn from_wide(wide: &[u16]) -> Self;
     fn from_wide_null(wide: &[u16]) -> Self {
         let len = wide.iter().take_while(|&&c| c != 0).count();
@@ -122,4 +153,3 @@ impl FromWide for OsString {
         OsStringExt::from_wide(wide)
     }
 }
-
diff --git a/third_party/rust/cc/src/lib.rs b/third_party/rust/cc/src/lib.rs
index 67d8f6fce..7672cf441 100644
--- 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>>,
@@ -116,7 +116,9 @@ pub struct Build {
     shared_flag: Option<bool>,
     static_flag: Option<bool>,
     warnings_into_errors: bool,
-    warnings: bool,
+    warnings: Option<bool>,
+    extra_warnings: Option<bool>,
+    env_cache: Arc<Mutex<HashMap<String, Option<String>>>>,
 }
 
 /// Represents the types of errors that may occur while using cc-rs.
@@ -174,6 +176,7 @@ pub struct Tool {
     env: Vec<(OsString, OsString)>,
     family: ToolFamily,
     cuda: bool,
+    removed_args: Vec<OsString>,
 }
 
 /// Represents the family of tools this tool belongs to.
@@ -189,22 +192,27 @@ enum ToolFamily {
     /// and its cross-compilation approach is different.
     Clang,
     /// Tool is the MSVC cl.exe.
-    Msvc,
+    Msvc { clang_cl: bool },
 }
 
 impl ToolFamily {
     /// What the flag to request debug info for this family of tools look like
-    fn debug_flag(&self) -> &'static str {
+    fn add_debug_flags(&self, cmd: &mut Tool) {
         match *self {
-            ToolFamily::Msvc => "/Z7",
-            ToolFamily::Gnu | ToolFamily::Clang => "-g",
+            ToolFamily::Msvc { .. } => {
+                cmd.push_cc_arg("/Z7".into());
+            }
+            ToolFamily::Gnu | ToolFamily::Clang => {
+                cmd.push_cc_arg("-g".into());
+                cmd.push_cc_arg("-fno-omit-frame-pointer".into());
+            }
         }
     }
 
     /// What the flag to include directories into header search path looks like
     fn include_flag(&self) -> &'static str {
         match *self {
-            ToolFamily::Msvc => "/I",
+            ToolFamily::Msvc { .. } => "/I",
             ToolFamily::Gnu | ToolFamily::Clang => "-I",
         }
     }
@@ -212,26 +220,31 @@ impl ToolFamily {
     /// What the flag to request macro-expanded source output looks like
     fn expand_flag(&self) -> &'static str {
         match *self {
-            ToolFamily::Msvc => "/E",
+            ToolFamily::Msvc { .. } => "/E",
             ToolFamily::Gnu | ToolFamily::Clang => "-E",
         }
     }
 
     /// What the flags to enable all warnings
-    fn warnings_flags(&self) -> &'static [&'static str] {
-        static MSVC_FLAGS: &'static [&'static str] = &["/W4"];
-        static GNU_CLANG_FLAGS: &'static [&'static str] = &["-Wall", "-Wextra"];
+    fn warnings_flags(&self) -> &'static str {
+        match *self {
+            ToolFamily::Msvc { .. } => "/W4",
+            ToolFamily::Gnu | ToolFamily::Clang => "-Wall",
+        }
+    }
 
+    /// What the flags to enable extra warnings
+    fn extra_warnings_flags(&self) -> Option<&'static str> {
         match *self {
-            ToolFamily::Msvc => &MSVC_FLAGS,
-            ToolFamily::Gnu | ToolFamily::Clang => &GNU_CLANG_FLAGS,
+            ToolFamily::Msvc { .. } => None,
+            ToolFamily::Gnu | ToolFamily::Clang => Some("-Wextra"),
         }
     }
 
     /// What the flag to turn warning into errors
     fn warnings_to_errors_flag(&self) -> &'static str {
         match *self {
-            ToolFamily::Msvc => "/WX",
+            ToolFamily::Msvc { .. } => "/WX",
             ToolFamily::Gnu | ToolFamily::Clang => "-Werror",
         }
     }
@@ -240,9 +253,8 @@ impl ToolFamily {
     /// debug info flag passed to the C++ compiler.
     fn nvcc_debug_flag(&self) -> &'static str {
         match *self {
-            ToolFamily::Msvc => unimplemented!(),
-            ToolFamily::Gnu |
-            ToolFamily::Clang => "-G",
+            ToolFamily::Msvc { .. } => unimplemented!(),
+            ToolFamily::Gnu | ToolFamily::Clang => "-G",
         }
     }
 
@@ -250,11 +262,14 @@ impl ToolFamily {
     /// compiler.
     fn nvcc_redirect_flag(&self) -> &'static str {
         match *self {
-            ToolFamily::Msvc => unimplemented!(),
-            ToolFamily::Gnu |
-            ToolFamily::Clang => "-Xcompiler",
+            ToolFamily::Msvc { .. } => unimplemented!(),
+            ToolFamily::Gnu | ToolFamily::Clang => "-Xcompiler",
         }
     }
+
+    fn verbose_stderr(&self) -> bool {
+        *self == ToolFamily::Clang
+    }
 }
 
 /// Represents an object.
@@ -269,10 +284,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 +301,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,
@@ -307,8 +320,10 @@ impl Build {
             cargo_metadata: true,
             pic: None,
             static_crt: None,
-            warnings: true,
+            warnings: None,
+            extra_warnings: None,
             warnings_into_errors: false,
+            env_cache: Arc::new(Mutex::new(HashMap::new())),
         }
     }
 
@@ -344,10 +359,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,22 +411,40 @@ 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");
         let target = self.get_target()?;
+        let host = self.get_host()?;
         let mut cfg = Build::new();
         cfg.flag(flag)
             .target(&target)
             .opt_level(0)
-            .host(&target)
+            .host(&host)
             .debug(false)
             .cpp(self.cpp)
             .cuda(self.cuda);
-        let compiler = cfg.try_get_compiler()?;
+        let mut compiler = cfg.try_get_compiler()?;
+
+        // Clang uses stderr for verbose output, which yields a false positive
+        // result if the CFLAGS/CXXFLAGS include -v to aid in debugging.
+        if compiler.family.verbose_stderr() {
+            compiler.remove_arg("-v".into());
+        }
+
         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 +455,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
@@ -565,7 +599,30 @@ impl Build {
     ///     .compile("libfoo.a");
     /// ```
     pub fn warnings(&mut self, warnings: bool) -> &mut Build {
-        self.warnings = warnings;
+        self.warnings = Some(warnings);
+        self.extra_warnings = Some(warnings);
+        self
+    }
+
+    /// Set extra warnings flags.
+    ///
+    /// Adds some flags:
+    /// - nothing for MSVC.
+    /// - "-Wextra" for GNU and Clang.
+    ///
+    /// Enabled by default.
+    ///
+    /// # Example
+    ///
+    /// ```no_run
+    /// // Disables -Wextra, -Wall remains enabled:
+    /// cc::Build::new()
+    ///     .file("src/foo.c")
+    ///     .extra_warnings(false)
+    ///     .compile("libfoo.a");
+    /// ```
+    pub fn extra_warnings(&mut self, warnings: bool) -> &mut Build {
+        self.extra_warnings = Some(warnings);
         self
     }
 
@@ -575,6 +632,8 @@ impl Build {
     /// The default value of this property depends on the current target: On
     /// OS X `Some("c++")` is used, when compiling for a Visual Studio based
     /// target `None` is used and for other targets `Some("stdc++")` is used.
+    /// If the `CXXSTDLIB` environment variable is set, its value will
+    /// override the default value.
     ///
     /// A value of `None` indicates that no automatic linking should happen,
     /// otherwise cargo will link against the specified library.
@@ -777,9 +836,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 +938,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 +963,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 +978,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 +1016,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();
 
@@ -1032,7 +1079,7 @@ impl Build {
         // Non-target flags
         // If the flag is not conditioned on target variable, it belongs here :)
         match cmd.family {
-            ToolFamily::Msvc => {
+            ToolFamily::Msvc { .. } => {
                 assert!(!self.cuda,
                     "CUDA C++ compilation not supported for MSVC, yet... but you are welcome to implement it :)");
 
@@ -1054,8 +1101,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 +1117,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());
                 }
@@ -1086,8 +1135,8 @@ impl Build {
                 let nvcc_debug_flag = cmd.family.nvcc_debug_flag().into();
                 cmd.args.push(nvcc_debug_flag);
             }
-            let debug_flag = cmd.family.debug_flag().into();
-            cmd.push_cc_arg(debug_flag);
+            let family = cmd.family;
+            family.add_debug_flags(&mut cmd);
         }
 
         // Target flags
@@ -1095,9 +1144,20 @@ impl Build {
             ToolFamily::Clang => {
                 cmd.args.push(format!("--target={}", target).into());
             }
-            ToolFamily::Msvc => {
-                if target.contains("i586") {
-                    cmd.args.push("/ARCH:IA32".into());
+            ToolFamily::Msvc { clang_cl } => {
+                if clang_cl {
+                    if target.contains("x86_64") {
+                        cmd.args.push("-m64".into());
+                    } else if target.contains("i586") {
+                        cmd.args.push("-m32".into());
+                        cmd.args.push("/arch:IA32".into());
+                    } else {
+                        cmd.args.push("-m32".into());
+                    }
+                } else {
+                    if target.contains("i586") {
+                        cmd.args.push("/ARCH:IA32".into());
+                    }
                 }
             }
             ToolFamily::Gnu => {
@@ -1109,24 +1169,35 @@ impl Build {
                     cmd.args.push("-m64".into());
                 }
 
-                if self.static_flag.is_none() && target.contains("musl") {
-                    cmd.args.push("-static".into());
+                if self.static_flag.is_none() {
+                    let features = env::var("CARGO_CFG_TARGET_FEATURE").unwrap_or(String::new());
+                    if features.contains("crt-static") {
+                        cmd.args.push("-static".into());
+                    }
                 }
 
                 // armv7 targets get to use armv7 instructions
-                if target.starts_with("armv7-") && target.contains("-linux-") {
+                if (target.starts_with("armv7") || target.starts_with("thumbv7")) && target.contains("-linux-") {
                     cmd.args.push("-march=armv7-a".into());
                 }
 
-                // On android we can guarantee some extra float instructions
-                // (specified in the android spec online)
-                if target.starts_with("armv7-linux-androideabi") {
-                    cmd.args.push("-march=armv7-a".into());
+                // (x86 Android doesn't say "eabi")
+                if target.contains("-androideabi") && target.contains("v7") {
+                    // -march=armv7-a handled above
                     cmd.args.push("-mthumb".into());
-                    cmd.args.push("-mfpu=vfpv3-d16".into());
+                    if !target.contains("neon") {
+                        // On android we can guarantee some extra float instructions
+                        // (specified in the android spec online)
+                        // NEON guarantees even more; see below.
+                        cmd.args.push("-mfpu=vfpv3-d16".into());
+                    }
                     cmd.args.push("-mfloat-abi=softfp".into());
                 }
 
+                if target.contains("neon") {
+                    cmd.args.push("-mfpu=neon-vfpv4".into());
+                }
+
                 if target.starts_with("armv4t-unknown-linux-") {
                     cmd.args.push("-march=armv4t".into());
                     cmd.args.push("-marm".into());
@@ -1169,7 +1240,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());
                 }
 
@@ -1193,6 +1264,31 @@ impl Build {
                 if target.starts_with("thumbv7m") {
                     cmd.args.push("-march=armv7-m".into());
                 }
+                if target.starts_with("armebv7r") | target.starts_with("armv7r") {
+                    if target.starts_with("armeb") {
+                        cmd.args.push("-mbig-endian".into());
+                    } else {
+                        cmd.args.push("-mlittle-endian".into());
+                    }
+
+                    // ARM mode
+                    cmd.args.push("-marm".into());
+
+                    // R Profile
+                    cmd.args.push("-march=armv7-r".into());
+
+                    if target.ends_with("eabihf") {
+                        // Calling convention
+                        cmd.args.push("-mfloat-abi=hard".into());
+
+                        // lowest common denominator FPU
+                        // (see Cortex-R4 technical reference manual)
+                        cmd.args.push("-mfpu=vfpv3-d16".into())
+                    } else {
+                        // Calling convention
+                        cmd.args.push("-mfloat-abi=soft".into());
+                    }
+                }
             }
         }
 
@@ -1212,14 +1308,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
                     );
                 }
@@ -1231,9 +1326,19 @@ impl Build {
             cmd.args.push(directory.into());
         }
 
-        if self.warnings {
-            for flag in cmd.family.warnings_flags().iter() {
-                cmd.push_cc_arg(flag.into());
+        // If warnings and/or extra_warnings haven't been explicitly set,
+        // then we set them only if the environment doesn't already have
+        // CFLAGS/CXXFLAGS, since those variables presumably already contain
+        // the desired set of warnings flags.
+
+        if self.warnings.unwrap_or(if self.has_flags() { false } else { true }) {
+            let wflags = cmd.family.warnings_flags().into();
+            cmd.push_cc_arg(wflags);
+        }
+
+        if self.extra_warnings.unwrap_or(if self.has_flags() { false } else { true }) {
+            if let Some(wflags) = cmd.family.extra_warnings_flags() {
+                cmd.push_cc_arg(wflags.into());
             }
         }
 
@@ -1248,7 +1353,7 @@ impl Build {
         }
 
         for &(ref key, ref value) in self.definitions.iter() {
-            let lead = if let ToolFamily::Msvc = cmd.family {
+            let lead = if let ToolFamily::Msvc { .. } = cmd.family {
                 "/"
             } else {
                 "-"
@@ -1268,10 +1373,20 @@ impl Build {
         Ok(cmd)
     }
 
+    fn has_flags(&self) -> bool {
+        let flags_env_var_name = if self.cpp { "CXXFLAGS" } else { "CFLAGS" };
+        let flags_env_var_value = self.get_var(flags_env_var_name);
+        if let Ok(_) = flags_env_var_value { true } else { false }
+    }
+
     fn msvc_macro_assembler(&self) -> Result<(Command, String), Error> {
         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 +1422,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 +1562,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(())
     }
@@ -1430,44 +1592,53 @@ impl Build {
         }
         let host = self.get_host()?;
         let target = self.get_target()?;
-        let (env, msvc, gnu, traditional) = if self.cpp {
-            ("CXX", "cl.exe", "g++", "c++")
+        let (env, msvc, gnu, traditional, clang) = if self.cpp {
+            ("CXX", "cl.exe", "g++", "c++", "clang++")
         } else {
-            ("CC", "cl.exe", "gcc", "cc")
+            ("CC", "cl.exe", "gcc", "cc", "clang")
         };
 
         // 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 cl_exe = windows_registry::find_tool(&target, "cl.exe");
+
+        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(|| cl_exe.clone());
 
         let tool = match tool_opt {
             Some(t) => t,
@@ -1479,7 +1650,20 @@ impl Build {
                         format!("{}.exe", gnu)
                     }
                 } else if target.contains("android") {
-                    format!("{}-{}", target.replace("armv7", "arm"), gnu)
+                    let target = target
+                        .replace("armv7neon", "arm")
+                        .replace("armv7", "arm")
+                        .replace("thumbv7neon", "arm")
+                        .replace("thumbv7", "arm");
+                    let gnu_compiler = format!("{}-{}", target, gnu);
+                    let clang_compiler = format!("{}-{}", target, clang);
+                    // Check if gnu compiler is present
+                    // if not, use clang
+                    if Command::new(&gnu_compiler).spawn().is_ok() {
+                        gnu_compiler
+                    } else {
+                        clang_compiler
+                    }
                 } else if target.contains("cloudabi") {
                     format!("{}-{}", target, traditional)
                 } else if self.get_host()? != target {
@@ -1489,6 +1673,7 @@ impl Build {
                     let prefix = cross_compile.or(match &target[..] {
                         "aarch64-unknown-linux-gnu" => Some("aarch64-linux-gnu"),
                         "aarch64-unknown-linux-musl" => Some("aarch64-linux-musl"),
+                        "aarch64-unknown-netbsd" => Some("aarch64--netbsd"),
                         "arm-unknown-linux-gnueabi" => Some("arm-linux-gnueabi"),
                         "armv4t-unknown-linux-gnueabi" => Some("arm-linux-gnueabi"),
                         "armv5te-unknown-linux-gnueabi" => Some("arm-linux-gnueabi"),
@@ -1500,7 +1685,14 @@ impl Build {
                         "armv6-unknown-netbsd-eabihf" => Some("armv6--netbsdelf-eabihf"),
                         "armv7-unknown-linux-gnueabihf" => Some("arm-linux-gnueabihf"),
                         "armv7-unknown-linux-musleabihf" => Some("arm-linux-musleabihf"),
+                        "armv7neon-unknown-linux-gnueabihf" => Some("arm-linux-gnueabihf"),
+                        "armv7neon-unknown-linux-musleabihf" => Some("arm-linux-musleabihf"),
+                        "thumbv7-unknown-linux-gnueabihf" => Some("arm-linux-gnueabihf"),
+                        "thumbv7-unknown-linux-musleabihf" => Some("arm-linux-musleabihf"),
+                        "thumbv7neon-unknown-linux-gnueabihf" => Some("arm-linux-gnueabihf"),
+                        "thumbv7neon-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,13 +1701,19 @@ 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"),
+                        "armebv7r-none-eabi" => Some("arm-none-eabi"),
+                        "armebv7r-none-eabihf" => Some("arm-none-eabi"),
+                        "armv7r-none-eabi" => Some("arm-none-eabi"),
+                        "armv7r-none-eabihf" => Some("arm-none-eabi"),
                         "thumbv6m-none-eabi" => Some("arm-none-eabi"),
                         "thumbv7em-none-eabi" => Some("arm-none-eabi"),
                         "thumbv7em-none-eabihf" => Some("arm-none-eabi"),
@@ -1537,20 +1735,45 @@ impl Build {
             }
         };
 
-        let tool = if self.cuda {
-            assert!(tool.args.is_empty(),
-                "CUDA compilation currently assumes empty pre-existing args");
+        let mut tool = if self.cuda {
+            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
         };
 
+        // If we found `cl.exe` in our environment, the tool we're returning is
+        // an MSVC-like tool, *and* no env vars were set then set env vars for
+        // the tool that we're returning.
+        //
+        // Env vars are needed for things like `link.exe` being put into PATH as
+        // well as header include paths sometimes. These paths are automatically
+        // included by default but if the `CC` or `CXX` env vars are set these
+        // won't be used. This'll ensure that when the env vars are used to
+        // configure for invocations like `clang-cl` we still get a "works out
+        // of the box" experience.
+        if let Some(cl_exe) = cl_exe {
+            if tool.family == (ToolFamily::Msvc { clang_cl: true }) &&
+                tool.env.len() == 0 &&
+                target.contains("msvc")
+            {
+                for &(ref k, ref v) in cl_exe.env.iter() {
+                    tool.env.push((k.to_owned(), v.to_owned()));
+                }
+            }
+        }
+
         Ok(tool)
     }
 
@@ -1568,10 +1791,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 +1805,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++`
@@ -1608,17 +1875,25 @@ impl Build {
         match self.cpp_link_stdlib.clone() {
             Some(s) => Ok(s),
             None => {
-                let target = self.get_target()?;
-                if target.contains("msvc") {
-                    Ok(None)
-                } else if target.contains("darwin") {
-                    Ok(Some("c++".to_string()))
-                } else if target.contains("freebsd") {
-                    Ok(Some("c++".to_string()))
-                } else if target.contains("openbsd") {
-                    Ok(Some("c++".to_string()))
+                if let Ok(stdlib) = self.get_var("CXXSTDLIB") {
+                    if stdlib.is_empty() {
+                        Ok(None)
+                    } else {
+                        Ok(Some(stdlib))
+                    }
                 } else {
-                    Ok(Some("stdc++".to_string()))
+                    let target = self.get_target()?;
+                    if target.contains("msvc") {
+                        Ok(None)
+                    } else if target.contains("apple") {
+                        Ok(Some("c++".to_string()))
+                    } else if target.contains("freebsd") {
+                        Ok(Some("c++".to_string()))
+                    } else if target.contains("openbsd") {
+                        Ok(Some("c++".to_string()))
+                    } else {
+                        Ok(Some("stdc++".to_string()))
+                    }
                 }
             }
         }
@@ -1690,8 +1965,13 @@ impl Build {
     }
 
     fn getenv(&self, v: &str) -> Option<String> {
+        let mut cache = self.env_cache.lock().unwrap();
+        if let Some(val) = cache.get(v) {
+            return val.clone()
+        }
         let r = env::var(v).ok();
         self.print(&format!("{} = {:?}", v, r));
+        cache.insert(v.to_string(), r.clone());
         r
     }
 
@@ -1700,10 +1980,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()),
             )),
         }
     }
@@ -1729,11 +2006,15 @@ impl Tool {
     fn with_features(path: PathBuf, cuda: bool) -> Tool {
         // Try to detect family of the tool from its name, falling back to Gnu.
         let family = if let Some(fname) = path.file_name().and_then(|p| p.to_str()) {
-            if fname.contains("clang") {
+            if fname.contains("clang-cl") {
+                ToolFamily::Msvc { clang_cl: true }
+            } else if fname.contains("cl") &&
+                !fname.contains("cloudabi") &&
+                !fname.contains("uclibc") &&
+                !fname.contains("clang") {
+                ToolFamily::Msvc { clang_cl: false }
+            } else if fname.contains("clang") {
                 ToolFamily::Clang
-            } else if fname.contains("cl") && !fname.contains("cloudabi") &&
-                      !fname.contains("uclibc") {
-                ToolFamily::Msvc
             } else {
                 ToolFamily::Gnu
             }
@@ -1748,9 +2029,15 @@ impl Tool {
             env: Vec::new(),
             family: family,
             cuda: cuda,
+            removed_args: Vec::new(),
         }
     }
 
+    /// Add an argument to be stripped from the final command arguments.
+    fn remove_arg(&mut self, flag: OsString) {
+        self.removed_args.push(flag);
+    }
+
     /// Add a flag, and optionally prepend the NVCC wrapper flag "-Xcompiler".
     ///
     /// Currently this is only used for compiling CUDA sources, since NVCC only
@@ -1773,12 +2060,15 @@ impl Tool {
             Some(ref cc_wrapper_path) => {
                 let mut cmd = Command::new(&cc_wrapper_path);
                 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);
+        cmd.args(&self.cc_wrapper_args);
+
+        let value = self.args.iter().filter(|a| !self.removed_args.contains(a)).collect::<Vec<_>>();
+        cmd.args(&value);
+
         for &(ref k, ref v) in self.env.iter() {
             cmd.env(k, v);
         }
@@ -1822,10 +2112,8 @@ impl Tool {
                     cc_env.push(arg);
                 }
                 cc_env
-            },
-            None => {
-                OsString::from("")
             }
+            None => OsString::from(""),
         }
     }
 
@@ -1855,7 +2143,10 @@ impl Tool {
 
     /// Whether the tool is MSVC-like.
     pub fn is_like_msvc(&self) -> bool {
-        self.family == ToolFamily::Msvc
+        match self.family {
+            ToolFamily::Msvc { .. } => true,
+            _ => false,
+        }
     }
 }
 
@@ -1868,8 +2159,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 +2174,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 +2197,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 +2212,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 +2228,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 +2260,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");
diff --git a/third_party/rust/cc/src/registry.rs b/third_party/rust/cc/src/registry.rs
index a45272344..2ac2fa63b 100644
--- a/third_party/rust/cc/src/registry.rs
+++ b/third_party/rust/cc/src/registry.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use std::ffi::{OsString, OsStr};
+use std::ffi::{OsStr, OsString};
 use std::io;
 use std::ops::RangeFrom;
 use std::os::raw;
@@ -36,28 +36,31 @@ const KEY_WOW64_32KEY: DWORD = 0x200;
 
 #[link(name = "advapi32")]
 extern "system" {
-    fn RegOpenKeyExW(key: HKEY,
-                     lpSubKey: LPCWSTR,
-                     ulOptions: DWORD,
-                     samDesired: REGSAM,
-                     phkResult: PHKEY)
-                     -> LONG;
-    fn RegEnumKeyExW(key: HKEY,
-                     dwIndex: DWORD,
-                     lpName: LPWSTR,
-                     lpcName: LPDWORD,
-                     lpReserved: LPDWORD,
-                     lpClass: LPWSTR,
-                     lpcClass: LPDWORD,
-                     lpftLastWriteTime: PFILETIME)
-                     -> LONG;
-    fn RegQueryValueExW(hKey: HKEY,
-                        lpValueName: LPCWSTR,
-                        lpReserved: LPDWORD,
-                        lpType: LPDWORD,
-                        lpData: LPBYTE,
-                        lpcbData: LPDWORD)
-                        -> LONG;
+    fn RegOpenKeyExW(
+        key: HKEY,
+        lpSubKey: LPCWSTR,
+        ulOptions: DWORD,
+        samDesired: REGSAM,
+        phkResult: PHKEY,
+    ) -> LONG;
+    fn RegEnumKeyExW(
+        key: HKEY,
+        dwIndex: DWORD,
+        lpName: LPWSTR,
+        lpcName: LPDWORD,
+        lpReserved: LPDWORD,
+        lpClass: LPWSTR,
+        lpcClass: LPDWORD,
+        lpftLastWriteTime: PFILETIME,
+    ) -> LONG;
+    fn RegQueryValueExW(
+        hKey: HKEY,
+        lpValueName: LPCWSTR,
+        lpReserved: LPDWORD,
+        lpType: LPDWORD,
+        lpData: LPBYTE,
+        lpcbData: LPDWORD,
+    ) -> LONG;
     fn RegCloseKey(hKey: HKEY) -> LONG;
 }
 
@@ -90,11 +93,13 @@ impl RegistryKey {
         let key = key.encode_wide().chain(Some(0)).collect::<Vec<_>>();
         let mut ret = 0 as *mut _;
         let err = unsafe {
-            RegOpenKeyExW(self.raw(),
-                          key.as_ptr(),
-                          0,
-                          KEY_READ | KEY_WOW64_32KEY,
-                          &mut ret)
+            RegOpenKeyExW(
+                self.raw(),
+                key.as_ptr(),
+                0,
+                KEY_READ | KEY_WOW64_32KEY,
+                &mut ret,
+            )
         };
         if err == ERROR_SUCCESS as LONG {
             Ok(RegistryKey(Repr::Owned(OwnedKey(ret))))
@@ -116,29 +121,36 @@ impl RegistryKey {
         let mut len = 0;
         let mut kind = 0;
         unsafe {
-            let err = RegQueryValueExW(self.raw(),
-                                       name.as_ptr(),
-                                       0 as *mut _,
-                                       &mut kind,
-                                       0 as *mut _,
-                                       &mut len);
+            let err = RegQueryValueExW(
+                self.raw(),
+                name.as_ptr(),
+                0 as *mut _,
+                &mut kind,
+                0 as *mut _,
+                &mut len,
+            );
             if err != ERROR_SUCCESS as LONG {
                 return Err(io::Error::from_raw_os_error(err as i32));
             }
             if kind != REG_SZ {
-                return Err(io::Error::new(io::ErrorKind::Other, "registry key wasn't a string"));
+                return Err(io::Error::new(
+                    io::ErrorKind::Other,
+                    "registry key wasn't a string",
+                ));
             }
 
             // The length here is the length in bytes, but we're using wide
             // characters so we need to be sure to halve it for the capacity
             // passed in.
             let mut v = Vec::with_capacity(len as usize / 2);
-            let err = RegQueryValueExW(self.raw(),
-                                       name.as_ptr(),
-                                       0 as *mut _,
-                                       0 as *mut _,
-                                       v.as_mut_ptr() as *mut _,
-                                       &mut len);
+            let err = RegQueryValueExW(
+                self.raw(),
+                name.as_ptr(),
+                0 as *mut _,
+                0 as *mut _,
+                v.as_mut_ptr() as *mut _,
+                &mut len,
+            );
             if err != ERROR_SUCCESS as LONG {
                 return Err(io::Error::from_raw_os_error(err as i32));
             }
@@ -169,14 +181,16 @@ impl<'a> Iterator for Iter<'a> {
         self.idx.next().and_then(|i| unsafe {
             let mut v = Vec::with_capacity(256);
             let mut len = v.capacity() as DWORD;
-            let ret = RegEnumKeyExW(self.key.raw(),
-                                    i,
-                                    v.as_mut_ptr(),
-                                    &mut len,
-                                    0 as *mut _,
-                                    0 as *mut _,
-                                    0 as *mut _,
-                                    0 as *mut _);
+            let ret = RegEnumKeyExW(
+                self.key.raw(),
+                i,
+                v.as_mut_ptr(),
+                &mut len,
+                0 as *mut _,
+                0 as *mut _,
+                0 as *mut _,
+                0 as *mut _,
+            );
             if ret == ERROR_NO_MORE_ITEMS as LONG {
                 None
             } else if ret != ERROR_SUCCESS as LONG {
diff --git a/third_party/rust/cc/src/setup_config.rs b/third_party/rust/cc/src/setup_config.rs
index 175b7f157..7c03d388f 100644
--- a/third_party/rust/cc/src/setup_config.rs
+++ b/third_party/rust/cc/src/setup_config.rs
@@ -15,7 +15,7 @@ use winapi::{LPFILETIME, ULONG};
 use winapi::S_FALSE;
 use winapi::BSTR;
 use winapi::LPCOLESTR;
-use winapi::{CLSCTX_ALL, CoCreateInstance};
+use winapi::{CoCreateInstance, CLSCTX_ALL};
 use winapi::LPSAFEARRAY;
 use winapi::{IUnknown, IUnknownVtbl};
 use winapi::{HRESULT, LCID, LPCWSTR, PULONGLONG};
@@ -155,7 +155,7 @@ interface ISetupHelper(ISetupHelperVtbl): IUnknown(IUnknownVtbl) {
 }}
 
 DEFINE_GUID!{CLSID_SetupConfiguration,
-    0x177f0c4a, 0x1cd3, 0x4de7, 0xa3, 0x2c, 0x71, 0xdb, 0xbb, 0x9f, 0xa3, 0x6d}
+0x177f0c4a, 0x1cd3, 0x4de7, 0xa3, 0x2c, 0x71, 0xdb, 0xbb, 0x9f, 0xa3, 0x6d}
 
 // Safe wrapper around the COM interfaces
 pub struct SetupConfiguration(ComPtr<ISetupConfiguration>);
@@ -163,31 +163,44 @@ pub struct SetupConfiguration(ComPtr<ISetupConfiguration>);
 impl SetupConfiguration {
     pub fn new() -> Result<SetupConfiguration, i32> {
         let mut obj = null_mut();
-        let err = unsafe { CoCreateInstance(
-            &CLSID_SetupConfiguration, null_mut(), CLSCTX_ALL,
-            &ISetupConfiguration::uuidof(), &mut obj,
-        ) };
-        if err < 0 { return Err(err); }
+        let err = unsafe {
+            CoCreateInstance(
+                &CLSID_SetupConfiguration,
+                null_mut(),
+                CLSCTX_ALL,
+                &ISetupConfiguration::uuidof(),
+                &mut obj,
+            )
+        };
+        if err < 0 {
+            return Err(err);
+        }
         let obj = unsafe { ComPtr::from_raw(obj as *mut ISetupConfiguration) };
         Ok(SetupConfiguration(obj))
     }
     pub fn get_instance_for_current_process(&self) -> Result<SetupInstance, i32> {
         let mut obj = null_mut();
         let err = unsafe { self.0.GetInstanceForCurrentProcess(&mut obj) };
-        if err < 0 { return Err(err); }
+        if err < 0 {
+            return Err(err);
+        }
         Ok(unsafe { SetupInstance::from_raw(obj) })
     }
     pub fn enum_instances(&self) -> Result<EnumSetupInstances, i32> {
         let mut obj = null_mut();
         let err = unsafe { self.0.EnumInstances(&mut obj) };
-        if err < 0 { return Err(err); }
+        if err < 0 {
+            return Err(err);
+        }
         Ok(unsafe { EnumSetupInstances::from_raw(obj) })
     }
     pub fn enum_all_instances(&self) -> Result<EnumSetupInstances, i32> {
         let mut obj = null_mut();
         let this = try!(self.0.cast::<ISetupConfiguration2>());
         let err = unsafe { this.EnumAllInstances(&mut obj) };
-        if err < 0 { return Err(err); }
+        if err < 0 {
+            return Err(err);
+        }
         Ok(unsafe { EnumSetupInstances::from_raw(obj) })
     }
 }
@@ -202,28 +215,36 @@ impl SetupInstance {
         let mut s = null_mut();
         let err = unsafe { self.0.GetInstanceId(&mut s) };
         let bstr = unsafe { BStr::from_raw(s) };
-        if err < 0 { return Err(err); }
+        if err < 0 {
+            return Err(err);
+        }
         Ok(bstr.to_osstring())
     }
     pub fn installation_name(&self) -> Result<OsString, i32> {
         let mut s = null_mut();
         let err = unsafe { self.0.GetInstallationName(&mut s) };
         let bstr = unsafe { BStr::from_raw(s) };
-        if err < 0 { return Err(err); }
+        if err < 0 {
+            return Err(err);
+        }
         Ok(bstr.to_osstring())
     }
     pub fn installation_path(&self) -> Result<OsString, i32> {
         let mut s = null_mut();
         let err = unsafe { self.0.GetInstallationPath(&mut s) };
         let bstr = unsafe { BStr::from_raw(s) };
-        if err < 0 { return Err(err); }
+        if err < 0 {
+            return Err(err);
+        }
         Ok(bstr.to_osstring())
     }
     pub fn installation_version(&self) -> Result<OsString, i32> {
         let mut s = null_mut();
         let err = unsafe { self.0.GetInstallationVersion(&mut s) };
         let bstr = unsafe { BStr::from_raw(s) };
-        if err < 0 { return Err(err); }
+        if err < 0 {
+            return Err(err);
+        }
         Ok(bstr.to_osstring())
     }
     pub fn product_path(&self) -> Result<OsString, i32> {
@@ -231,7 +252,9 @@ impl SetupInstance {
         let this = try!(self.0.cast::<ISetupInstance2>());
         let err = unsafe { this.GetProductPath(&mut s) };
         let bstr = unsafe { BStr::from_raw(s) };
-        if err < 0 { return Err(err); }
+        if err < 0 {
+            return Err(err);
+        }
         Ok(bstr.to_osstring())
     }
 }
@@ -249,9 +272,12 @@ impl Iterator for EnumSetupInstances {
     fn next(&mut self) -> Option<Result<SetupInstance, i32>> {
         let mut obj = null_mut();
         let err = unsafe { self.0.Next(1, &mut obj, null_mut()) };
-        if err < 0 { return Some(Err(err)); }
-        if err == S_FALSE { return None; }
+        if err < 0 {
+            return Some(Err(err));
+        }
+        if err == S_FALSE {
+            return None;
+        }
         Some(Ok(unsafe { SetupInstance::from_raw(obj) }))
     }
 }
-
diff --git a/third_party/rust/cc/src/winapi.rs b/third_party/rust/cc/src/winapi.rs
index 3fb04087f..cc83963b6 100644
--- a/third_party/rust/cc/src/winapi.rs
+++ b/third_party/rust/cc/src/winapi.rs
@@ -44,8 +44,8 @@ pub const CLSCTX_INPROC_HANDLER: CLSCTX = 0x2;
 pub const CLSCTX_LOCAL_SERVER: CLSCTX = 0x4;
 pub const CLSCTX_REMOTE_SERVER: CLSCTX = 0x10;
 
-pub const CLSCTX_ALL: CLSCTX = CLSCTX_INPROC_SERVER |
-    CLSCTX_INPROC_HANDLER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER;
+pub const CLSCTX_ALL: CLSCTX =
+    CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER;
 
 #[repr(C)]
 #[derive(Copy, Clone)]
@@ -69,13 +69,17 @@ pub trait Interface {
 
 #[link(name = "ole32")]
 #[link(name = "oleaut32")]
-extern { }
+extern "C" {}
 
 extern "system" {
     pub fn CoInitializeEx(pvReserved: LPVOID, dwCoInit: DWORD) -> HRESULT;
-    pub fn CoCreateInstance(rclsid: REFCLSID, pUnkOuter: LPUNKNOWN,
-                            dwClsContext: DWORD, riid: REFIID,
-                            ppv: *mut LPVOID) -> HRESULT;
+    pub fn CoCreateInstance(
+        rclsid: REFCLSID,
+        pUnkOuter: LPUNKNOWN,
+        dwClsContext: DWORD,
+        riid: REFIID,
+        ppv: *mut LPVOID,
+    ) -> HRESULT;
     pub fn SysFreeString(bstrString: BSTR);
     pub fn SysStringLen(pbstr: BSTR) -> UINT;
 }
diff --git a/third_party/rust/cc/src/windows_registry.rs b/third_party/rust/cc/src/windows_registry.rs
index 9099e0f8d..bbcbb09aa 100644
--- a/third_party/rust/cc/src/windows_registry.rs
+++ b/third_party/rust/cc/src/windows_registry.rs
@@ -65,11 +65,19 @@ pub fn find_tool(target: &str, tool: &str) -> Option<Tool> {
         return impl_::find_msbuild(target);
     }
 
+    if tool.contains("devenv") {
+        return impl_::find_devenv(target);
+    }
+
     // If VCINSTALLDIR is set, then someone's probably already run vcvars and we
     // should just find whatever that indicates.
     if env::var_os("VCINSTALLDIR").is_some() {
         return env::var_os("PATH")
-            .and_then(|path| env::split_paths(&path).map(|p| p.join(tool)).find(|p| p.exists()))
+            .and_then(|path| {
+                env::split_paths(&path)
+                    .map(|p| p.join(tool))
+                    .find(|p| p.exists())
+            })
             .map(|path| Tool::new(path.into()));
     }
 
@@ -119,19 +127,20 @@ pub fn find_vs_version() -> Result<VsVers, String> {
     use std::env;
 
     match env::var("VisualStudioVersion") {
-        Ok(version) => {
-            match &version[..] {
-                "15.0" => Ok(VsVers::Vs15),
-                "14.0" => Ok(VsVers::Vs14),
-                "12.0" => Ok(VsVers::Vs12),
-                vers => Err(format!("\n\n\
-                                     unsupported or unknown VisualStudio version: {}\n\
-                                     if another version is installed consider running \
-                                     the appropriate vcvars script before building this \
-                                     crate\n\
-                                     ", vers)),
-            }
-        }
+        Ok(version) => match &version[..] {
+            "15.0" => Ok(VsVers::Vs15),
+            "14.0" => Ok(VsVers::Vs14),
+            "12.0" => Ok(VsVers::Vs12),
+            vers => Err(format!(
+                "\n\n\
+                 unsupported or unknown VisualStudio version: {}\n\
+                 if another version is installed consider running \
+                 the appropriate vcvars script before building this \
+                 crate\n\
+                 ",
+                vers
+            )),
+        },
         _ => {
             // Check for the presense of a specific registry key
             // that indicates visual studio is installed.
@@ -142,12 +151,14 @@ pub fn find_vs_version() -> Result<VsVers, String> {
             } else if impl_::has_msbuild_version("12.0") {
                 Ok(VsVers::Vs12)
             } else {
-                Err(format!("\n\n\
-                             couldn't determine visual studio generator\n\
-                             if VisualStudio is installed, however, consider \
-                             running the appropriate vcvars script before building \
-                             this crate\n\
-                             "))
+                Err(format!(
+                    "\n\n\
+                     couldn't determine visual studio generator\n\
+                     if VisualStudio is installed, however, consider \
+                     running the appropriate vcvars script before building \
+                     this crate\n\
+                     "
+                ))
             }
         }
     }
@@ -185,7 +196,12 @@ mod impl_ {
         }
 
         fn into_tool(self) -> Tool {
-            let MsvcTool { tool, libs, path, include } = self;
+            let MsvcTool {
+                tool,
+                libs,
+                path,
+                include,
+            } = self;
             let mut tool = Tool::new(tool.into());
             add_env(&mut tool, "LIB", libs);
             add_env(&mut tool, "PATH", path);
@@ -217,11 +233,13 @@ mod impl_ {
         None
     }
 
-    fn tool_from_vs15_instance(tool: &str, target: &str,
-                               instance: &SetupInstance) -> Option<Tool> {
-        let (bin_path, host_dylib_path, lib_path, include_path) = otry!(vs15_vc_paths(target, instance));
+    fn tool_from_vs15_instance(tool: &str, target: &str, instance: &SetupInstance) -> Option<Tool> {
+        let (bin_path, host_dylib_path, lib_path, include_path) =
+            otry!(vs15_vc_paths(target, instance));
         let tool_path = bin_path.join(tool);
-        if !tool_path.exists() { return None };
+        if !tool_path.exists() {
+            return None;
+        };
 
         let mut tool = MsvcTool::new(tool_path);
         tool.path.push(host_dylib_path);
@@ -238,9 +256,13 @@ mod impl_ {
         Some(tool.into_tool())
     }
 
-    fn vs15_vc_paths(target: &str, instance: &SetupInstance) -> Option<(PathBuf, PathBuf, PathBuf, PathBuf)> {
+    fn vs15_vc_paths(
+        target: &str,
+        instance: &SetupInstance,
+    ) -> Option<(PathBuf, PathBuf, PathBuf, PathBuf)> {
         let instance_path: PathBuf = otry!(instance.installation_path().ok()).into();
-        let version_path = instance_path.join(r"VC\Auxiliary\Build\Microsoft.VCToolsVersion.default.txt");
+        let version_path =
+            instance_path.join(r"VC\Auxiliary\Build\Microsoft.VCToolsVersion.default.txt");
         let mut version_file = otry!(File::open(version_path).ok());
         let mut version = String::new();
         otry!(version_file.read_to_string(&mut version).ok());
@@ -255,11 +277,15 @@ mod impl_ {
         let path = instance_path.join(r"VC\Tools\MSVC").join(version);
         // This is the path to the toolchain for a particular target, running
         // on a given host
-        let bin_path = path.join("bin").join(&format!("Host{}", host)).join(&target);
+        let bin_path = path.join("bin")
+            .join(&format!("Host{}", host))
+            .join(&target);
         // But! we also need PATH to contain the target directory for the host
         // architecture, because it contains dlls like mspdb140.dll compiled for
         // the host architecture.
-        let host_dylib_path = path.join("bin").join(&format!("Host{}", host)).join(&host.to_lowercase());
+        let host_dylib_path = path.join("bin")
+            .join(&format!("Host{}", host))
+            .join(&host.to_lowercase());
         let lib_path = path.join("lib").join(&target);
         let include_path = path.join("include");
         Some((bin_path, host_dylib_path, lib_path, include_path))
@@ -288,7 +314,8 @@ mod impl_ {
         let sub = otry!(lib_subdir(target));
         let (ucrt, ucrt_version) = otry!(get_ucrt_dir());
 
-        tool.path.push(ucrt.join("bin").join(&ucrt_version).join(sub));
+        tool.path
+            .push(ucrt.join("bin").join(&ucrt_version).join(sub));
 
         let ucrt_include = ucrt.join("include").join(&ucrt_version);
         tool.include.push(ucrt_include.join("ucrt"));
@@ -302,6 +329,7 @@ mod impl_ {
             tool.libs.push(sdk_lib.join("um").join(sub));
             let sdk_include = sdk.join("include").join(&version);
             tool.include.push(sdk_include.join("um"));
+            tool.include.push(sdk_include.join("cppwinrt"));
             tool.include.push(sdk_include.join("winrt"));
             tool.include.push(sdk_include.join("shared"));
         } else if let Some(sdk) = get_sdk81_dir() {
@@ -353,7 +381,8 @@ mod impl_ {
         let prev = env::var_os(env).unwrap_or(OsString::new());
         let prev = env::split_paths(&prev);
         let new = paths.into_iter().chain(prev);
-        tool.env.push((env.to_string().into(), env::join_paths(new).unwrap()));
+        tool.env
+            .push((env.to_string().into(), env::join_paths(new).unwrap()));
     }
 
     // Given a possible MSVC installation directory, we look for the linker and
@@ -361,7 +390,12 @@ mod impl_ {
     fn get_tool(tool: &str, path: &Path, target: &str) -> Option<MsvcTool> {
         bin_subdir(target)
             .into_iter()
-            .map(|(sub, host)| (path.join("bin").join(sub).join(tool), path.join("bin").join(host)))
+            .map(|(sub, host)| {
+                (
+                    path.join("bin").join(sub).join(tool),
+                    path.join("bin").join(host),
+                )
+            })
             .filter(|&(ref path, _)| path.is_file())
             .map(|(path, host)| {
                 let mut tool = MsvcTool::new(path);
@@ -402,16 +436,17 @@ mod impl_ {
         let key = otry!(LOCAL_MACHINE.open(key.as_ref()).ok());
         let root = otry!(key.query_str("KitsRoot10").ok());
         let readdir = otry!(Path::new(&root).join("lib").read_dir().ok());
-        let max_libdir = otry!(readdir.filter_map(|dir| dir.ok())
-            .map(|dir| dir.path())
-            .filter(|dir| {
-                dir.components()
+        let max_libdir = otry!(
+            readdir
+                .filter_map(|dir| dir.ok())
+                .map(|dir| dir.path())
+                .filter(|dir| dir.components()
                     .last()
                     .and_then(|c| c.as_os_str().to_str())
                     .map(|c| c.starts_with("10.") && dir.join("ucrt").is_dir())
-                    .unwrap_or(false)
-            })
-            .max());
+                    .unwrap_or(false))
+                .max()
+        );
         let version = max_libdir.components().last().unwrap();
         let version = version.as_os_str().to_str().unwrap().to_string();
         Some((root.into(), version))
@@ -430,14 +465,17 @@ mod impl_ {
         let key = otry!(LOCAL_MACHINE.open(key.as_ref()).ok());
         let root = otry!(key.query_str("InstallationFolder").ok());
         let readdir = otry!(Path::new(&root).join("lib").read_dir().ok());
-        let mut dirs = readdir.filter_map(|dir| dir.ok())
+        let mut dirs = readdir
+            .filter_map(|dir| dir.ok())
             .map(|dir| dir.path())
             .collect::<Vec<_>>();
         dirs.sort();
-        let dir = otry!(dirs.into_iter()
-            .rev()
-            .filter(|dir| dir.join("um").join("x64").join("kernel32.lib").is_file())
-            .next());
+        let dir = otry!(
+            dirs.into_iter()
+                .rev()
+                .filter(|dir| dir.join("um").join("x64").join("kernel32.lib").is_file())
+                .next()
+        );
         let version = dir.components().last().unwrap();
         let version = version.as_os_str().to_str().unwrap().to_string();
         Some((root.into(), version))
@@ -485,8 +523,8 @@ mod impl_ {
             ("i586", X86_64) | ("i686", X86_64) => vec![("amd64_x86", "amd64"), ("", "")],
             ("x86_64", X86) => vec![("x86_amd64", "")],
             ("x86_64", X86_64) => vec![("amd64", "amd64"), ("x86_amd64", "")],
-            ("arm", X86) => vec![("x86_arm", "")],
-            ("arm", X86_64) => vec![("amd64_arm", "amd64"), ("x86_arm", "")],
+            ("arm", X86) | ("thumbv7a", X86) => vec![("x86_arm", "")],
+            ("arm", X86_64) | ("thumbv7a", X86_64) => vec![("amd64_arm", "amd64"), ("x86_arm", "")],
             _ => vec![],
         }
     }
@@ -496,7 +534,8 @@ mod impl_ {
         match arch {
             "i586" | "i686" => Some("x86"),
             "x86_64" => Some("x64"),
-            "arm" => Some("arm"),
+            "arm" | "thumbv7a" => Some("arm"),
+            "aarch64" => Some("arm64"),
             _ => None,
         }
     }
@@ -507,7 +546,8 @@ mod impl_ {
         match arch {
             "i586" | "i686" => Some(""),
             "x86_64" => Some("amd64"),
-            "arm" => Some("arm"),
+            "arm" | "thumbv7a" => Some("arm"),
+            "aarch64" => Some("arm64"),
             _ => None,
         }
     }
@@ -553,7 +593,8 @@ mod impl_ {
         let mut max_vers = 0;
         let mut max_key = None;
         for subkey in key.iter().filter_map(|k| k.ok()) {
-            let val = subkey.to_str()
+            let val = subkey
+                .to_str()
                 .and_then(|s| s.trim_left_matches("v").replace(".", "").parse().ok());
             let val = match val {
                 Some(s) => s,
@@ -572,18 +613,39 @@ mod impl_ {
     pub fn has_msbuild_version(version: &str) -> bool {
         match version {
             "15.0" => {
-                find_msbuild_vs15("x86_64-pc-windows-msvc").is_some() ||
-                    find_msbuild_vs15("i686-pc-windows-msvc").is_some()
-            }
-            "12.0" | "14.0" => {
-                LOCAL_MACHINE.open(
-                    &OsString::from(format!("SOFTWARE\\Microsoft\\MSBuild\\ToolsVersions\\{}",
-                                            version))).is_ok()
+                find_msbuild_vs15("x86_64-pc-windows-msvc").is_some()
+                    || find_msbuild_vs15("i686-pc-windows-msvc").is_some()
             }
-            _ => false
+            "12.0" | "14.0" => LOCAL_MACHINE
+                .open(&OsString::from(format!(
+                    "SOFTWARE\\Microsoft\\MSBuild\\ToolsVersions\\{}",
+                    version
+                )))
+                .is_ok(),
+            _ => false,
         }
     }
 
+    pub fn find_devenv(target: &str) -> Option<Tool> {
+        find_devenv_vs15(&target)
+    }
+
+    fn find_devenv_vs15(target: &str) -> Option<Tool> {
+        let key = r"SOFTWARE\WOW6432Node\Microsoft\VisualStudio\SxS\VS7";
+        LOCAL_MACHINE
+            .open(key.as_ref())
+            .ok()
+            .and_then(|key| key.query_str("15.0").ok())
+            .map(|path| {
+                let path = PathBuf::from(path).join(r"Common7\IDE\devenv.exe");
+                let mut tool = Tool::new(path);
+                if target.contains("x86_64") {
+                    tool.env.push(("Platform".into(), "X64".into()));
+                }
+                tool
+            })
+    }
+
     // see http://stackoverflow.com/questions/328017/path-to-msbuild
     pub fn find_msbuild(target: &str) -> Option<Tool> {
         // VS 15 (2017) changed how to locate msbuild
@@ -599,11 +661,10 @@ mod impl_ {
         // or that find_msvc_15 could just use this registry key
         // instead of the COM interface.
         let key = r"SOFTWARE\WOW6432Node\Microsoft\VisualStudio\SxS\VS7";
-        LOCAL_MACHINE.open(key.as_ref())
+        LOCAL_MACHINE
+            .open(key.as_ref())
             .ok()
-            .and_then(|key| {
-                key.query_str("15.0").ok()
-            })
+            .and_then(|key| key.query_str("15.0").ok())
             .map(|path| {
                 let path = PathBuf::from(path).join(r"MSBuild\15.0\Bin\MSBuild.exe");
                 let mut tool = Tool::new(path);
@@ -616,7 +677,8 @@ mod impl_ {
 
     fn find_old_msbuild(target: &str) -> Option<Tool> {
         let key = r"SOFTWARE\Microsoft\MSBuild\ToolsVersions";
-        LOCAL_MACHINE.open(key.as_ref())
+        LOCAL_MACHINE
+            .open(key.as_ref())
             .ok()
             .and_then(|key| {
                 max_version(&key).and_then(|(_vers, key)| key.query_str("MSBuildToolsPath").ok())
diff --git a/third_party/rust/cc/tests/cc_env.rs b/third_party/rust/cc/tests/cc_env.rs
index 8ffe651a6..f9386d7f5 100644
--- a/third_party/rust/cc/tests/cc_env.rs
+++ b/third_party/rust/cc/tests/cc_env.rs
@@ -14,6 +14,10 @@ fn main() {
     distcc();
     ccache_spaces();
     ccache_env_flags();
+    leading_spaces();
+    extra_flags();
+    path_to_ccache();
+    more_spaces();
 }
 
 fn ccache() {
@@ -71,3 +75,45 @@ fn ccache_env_flags() {
 
     env::set_var("CC", "");
 }
+
+fn leading_spaces() {
+    let test = Test::gnu();
+    test.shim("ccache");
+
+    env::set_var("CC", " test ");
+    let compiler = test.gcc().file("foo.c").get_compiler();
+    assert_eq!(compiler.path(), Path::new("test"));
+
+    env::set_var("CC", "");
+}
+
+fn extra_flags() {
+    let test = Test::gnu();
+    test.shim("ccache");
+
+    env::set_var("CC", "ccache cc -m32");
+    let compiler = test.gcc().file("foo.c").get_compiler();
+    assert_eq!(compiler.path(), Path::new("cc"));
+}
+
+fn path_to_ccache() {
+    let test = Test::gnu();
+    test.shim("ccache");
+
+    env::set_var("CC", "/path/to/ccache.exe cc -m32");
+    let compiler = test.gcc().file("foo.c").get_compiler();
+    assert_eq!(compiler.path(), Path::new("cc"));
+    assert_eq!(
+        compiler.cc_env(),
+        OsString::from("/path/to/ccache.exe cc -m32"),
+    );
+}
+
+fn more_spaces() {
+    let test = Test::gnu();
+    test.shim("ccache");
+
+    env::set_var("CC", "cc -m32");
+    let compiler = test.gcc().file("foo.c").get_compiler();
+    assert_eq!(compiler.path(), Path::new("cc"));
+}
diff --git a/third_party/rust/cc/tests/support/mod.rs b/third_party/rust/cc/tests/support/mod.rs
index bb56bf305..cae81513b 100644
--- a/third_party/rust/cc/tests/support/mod.rs
+++ b/third_party/rust/cc/tests/support/mod.rs
@@ -85,7 +85,9 @@ impl Test {
             .unwrap()
             .read_to_string(&mut s)
             .unwrap();
-        Execution { args: s.lines().map(|s| s.to_string()).collect() }
+        Execution {
+            args: s.lines().map(|s| s.to_string()).collect(),
+        }
     }
 }
 
@@ -111,11 +113,18 @@ impl Execution {
     }
 
     pub fn must_have_in_order(&self, before: &str, after: &str) -> &Execution {
-        let before_position = self.args.iter().rposition(|x| OsStr::new(x) == OsStr::new(before));
-        let after_position = self.args.iter().rposition(|x| OsStr::new(x) == OsStr::new(after));
+        let before_position = self.args
+            .iter()
+            .rposition(|x| OsStr::new(x) == OsStr::new(before));
+        let after_position = self.args
+            .iter()
+            .rposition(|x| OsStr::new(x) == OsStr::new(after));
         match (before_position, after_position) {
-            (Some(b), Some(a)) if b < a => {},
-            (b, a) => { panic!("{:?} (last position: {:?}) did not appear before {:?} (last position: {:?})", before, b, after, a) },
+            (Some(b), Some(a)) if b < a => {}
+            (b, a) => panic!(
+                "{:?} (last position: {:?}) did not appear before {:?} (last position: {:?})",
+                before, b, after, a
+            ),
         };
         self
     }
diff --git a/third_party/rust/cc/tests/test.rs b/third_party/rust/cc/tests/test.rs
index 7e5a28d86..820072f68 100644
--- a/third_party/rust/cc/tests/test.rs
+++ b/third_party/rust/cc/tests/test.rs
@@ -1,6 +1,7 @@
 extern crate cc;
 extern crate tempdir;
 
+use std::env;
 use support::Test;
 
 mod support;
@@ -8,9 +9,7 @@ mod support;
 #[test]
 fn gnu_smoke() {
     let test = Test::gnu();
-    test.gcc()
-        .file("foo.c")
-        .compile("foo");
+    test.gcc().file("foo.c").compile("foo");
 
     test.cmd(0)
         .must_have("-O2")
@@ -25,23 +24,15 @@ fn gnu_smoke() {
 #[test]
 fn gnu_opt_level_1() {
     let test = Test::gnu();
-    test.gcc()
-        .opt_level(1)
-        .file("foo.c")
-        .compile("foo");
+    test.gcc().opt_level(1).file("foo.c").compile("foo");
 
-    test.cmd(0)
-        .must_have("-O1")
-        .must_not_have("-O2");
+    test.cmd(0).must_have("-O1").must_not_have("-O2");
 }
 
 #[test]
 fn gnu_opt_level_s() {
     let test = Test::gnu();
-    test.gcc()
-        .opt_level_str("s")
-        .file("foo.c")
-        .compile("foo");
+    test.gcc().opt_level_str("s").file("foo.c").compile("foo");
 
     test.cmd(0)
         .must_have("-Os")
@@ -54,10 +45,7 @@ fn gnu_opt_level_s() {
 #[test]
 fn gnu_debug() {
     let test = Test::gnu();
-    test.gcc()
-        .debug(true)
-        .file("foo.c")
-        .compile("foo");
+    test.gcc().debug(true).file("foo.c").compile("foo");
     test.cmd(0).must_have("-g");
 }
 
@@ -81,8 +69,33 @@ fn gnu_warnings() {
         .file("foo.c")
         .compile("foo");
 
-    test.cmd(0).must_have("-Wall")
-               .must_have("-Wextra");
+    test.cmd(0).must_have("-Wall").must_have("-Wextra");
+}
+
+#[test]
+fn gnu_extra_warnings0() {
+    let test = Test::gnu();
+    test.gcc()
+        .warnings(true)
+        .extra_warnings(false)
+        .flag("-Wno-missing-field-initializers")
+        .file("foo.c")
+        .compile("foo");
+
+    test.cmd(0).must_have("-Wall").must_not_have("-Wextra");
+}
+
+#[test]
+fn gnu_extra_warnings1() {
+    let test = Test::gnu();
+    test.gcc()
+        .warnings(false)
+        .extra_warnings(true)
+        .flag("-Wno-missing-field-initializers")
+        .file("foo.c")
+        .compile("foo");
+
+    test.cmd(0).must_not_have("-Wall").must_have("-Wextra");
 }
 
 #[test]
@@ -94,7 +107,32 @@ fn gnu_warnings_overridable() {
         .file("foo.c")
         .compile("foo");
 
-    test.cmd(0).must_have_in_order("-Wall", "-Wno-missing-field-initializers");
+    test.cmd(0)
+        .must_have_in_order("-Wall", "-Wno-missing-field-initializers");
+}
+
+#[test]
+fn gnu_no_warnings_if_cflags() {
+    env::set_var("CFLAGS", "-Wflag-does-not-exist");
+    let test = Test::gnu();
+    test.gcc()
+        .file("foo.c")
+        .compile("foo");
+
+    test.cmd(0).must_not_have("-Wall").must_not_have("-Wextra");
+    env::set_var("CFLAGS", "");
+}
+
+#[test]
+fn gnu_no_warnings_if_cxxflags() {
+    env::set_var("CXXFLAGS", "-Wflag-does-not-exist");
+    let test = Test::gnu();
+    test.gcc()
+        .file("foo.c")
+        .compile("foo");
+
+    test.cmd(0).must_not_have("-Wall").must_not_have("-Wextra");
+    env::set_var("CXXFLAGS", "");
 }
 
 #[test]
@@ -108,9 +146,7 @@ fn gnu_x86_64() {
             .file("foo.c")
             .compile("foo");
 
-        test.cmd(0)
-            .must_have("-fPIC")
-            .must_have("-m64");
+        test.cmd(0).must_have("-fPIC").must_have("-m64");
     }
 }
 
@@ -141,8 +177,7 @@ fn gnu_i686() {
             .file("foo.c")
             .compile("foo");
 
-        test.cmd(0)
-            .must_have("-m32");
+        test.cmd(0).must_have("-m32");
     }
 }
 
@@ -176,10 +211,7 @@ fn gnu_set_stdlib() {
 #[test]
 fn gnu_include() {
     let test = Test::gnu();
-    test.gcc()
-        .include("foo/bar")
-        .file("foo.c")
-        .compile("foo");
+    test.gcc().include("foo/bar").file("foo.c").compile("foo");
 
     test.cmd(0).must_have("-I").must_have("foo/bar");
 }
@@ -199,9 +231,7 @@ fn gnu_define() {
 #[test]
 fn gnu_compile_assembly() {
     let test = Test::gnu();
-    test.gcc()
-        .file("foo.S")
-        .compile("foo");
+    test.gcc().file("foo.S").compile("foo");
     test.cmd(0).must_have("foo.S");
 }
 
@@ -214,25 +244,25 @@ fn gnu_shared() {
         .static_flag(false)
         .compile("foo");
 
-    test.cmd(0)
-        .must_have("-shared")
-        .must_not_have("-static");
+    test.cmd(0).must_have("-shared").must_not_have("-static");
 }
 
 #[test]
 fn gnu_flag_if_supported() {
     if cfg!(windows) {
-        return
+        return;
     }
     let test = Test::gnu();
     test.gcc()
         .file("foo.c")
+        .flag("-v")
         .flag_if_supported("-Wall")
         .flag_if_supported("-Wflag-does-not-exist")
         .flag_if_supported("-std=c++11")
         .compile("foo");
 
     test.cmd(0)
+        .must_have("-v")
         .must_have("-Wall")
         .must_not_have("-Wflag-does-not-exist")
         .must_not_have("-std=c++11");
@@ -241,7 +271,7 @@ fn gnu_flag_if_supported() {
 #[test]
 fn gnu_flag_if_supported_cpp() {
     if cfg!(windows) {
-        return
+        return;
     }
     let test = Test::gnu();
     test.gcc()
@@ -250,8 +280,7 @@ fn gnu_flag_if_supported_cpp() {
         .flag_if_supported("-std=c++11")
         .compile("foo");
 
-    test.cmd(0)
-        .must_have("-std=c++11");
+    test.cmd(0).must_have("-std=c++11");
 }
 
 #[test]
@@ -263,17 +292,13 @@ fn gnu_static() {
         .static_flag(true)
         .compile("foo");
 
-    test.cmd(0)
-        .must_have("-static")
-        .must_not_have("-shared");
+    test.cmd(0).must_have("-static").must_not_have("-shared");
 }
 
 #[test]
 fn msvc_smoke() {
     let test = Test::msvc();
-    test.gcc()
-        .file("foo.c")
-        .compile("foo");
+    test.gcc().file("foo.c").compile("foo");
 
     test.cmd(0)
         .must_have("/O2")
@@ -287,10 +312,7 @@ fn msvc_smoke() {
 #[test]
 fn msvc_opt_level_0() {
     let test = Test::msvc();
-    test.gcc()
-        .opt_level(0)
-        .file("foo.c")
-        .compile("foo");
+    test.gcc().opt_level(0).file("foo.c").compile("foo");
 
     test.cmd(0).must_not_have("/O2");
 }
@@ -298,20 +320,14 @@ fn msvc_opt_level_0() {
 #[test]
 fn msvc_debug() {
     let test = Test::msvc();
-    test.gcc()
-        .debug(true)
-        .file("foo.c")
-        .compile("foo");
+    test.gcc().debug(true).file("foo.c").compile("foo");
     test.cmd(0).must_have("/Z7");
 }
 
 #[test]
 fn msvc_include() {
     let test = Test::msvc();
-    test.gcc()
-        .include("foo/bar")
-        .file("foo.c")
-        .compile("foo");
+    test.gcc().include("foo/bar").file("foo.c").compile("foo");
 
     test.cmd(0).must_have("/I").must_have("foo/bar");
 }
@@ -331,10 +347,7 @@ fn msvc_define() {
 #[test]
 fn msvc_static_crt() {
     let test = Test::msvc();
-    test.gcc()
-        .static_crt(true)
-        .file("foo.c")
-        .compile("foo");
+    test.gcc().static_crt(true).file("foo.c").compile("foo");
 
     test.cmd(0).must_have("/MT");
 }
@@ -342,10 +355,7 @@ fn msvc_static_crt() {
 #[test]
 fn msvc_no_static_crt() {
     let test = Test::msvc();
-    test.gcc()
-        .static_crt(false)
-        .file("foo.c")
-        .compile("foo");
+    test.gcc().static_crt(false).file("foo.c").compile("foo");
 
     test.cmd(0).must_have("/MD");
 }
-- 
2.19.0

