Bug 1414349 - Revendor Rust crates. r=me on a CLOSED TREE
authorMatt Brubeck <mbrubeck@mozilla.com>
Fri, 03 Nov 2017 10:50:38 -0700
changeset 443359 901e1a906ea5a84f85df30c5023fa36244af7af3
parent 443358 1041e4a4b37844729f925a2195af09d652c66871
child 443360 fc37c508c13c982e9d4db7cc85907c3f94474613
push id1618
push userCallek@gmail.com
push dateThu, 11 Jan 2018 17:45:48 +0000
treeherdermozilla-release@882ca853e05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersme
bugs1414349
milestone58.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1414349 - Revendor Rust crates. r=me on a CLOSED TREE MozReview-Commit-ID: 2iVXPRGyZiu
third_party/rust/gcc-0.3.42/.cargo-checksum.json
third_party/rust/gcc-0.3.42/.travis.yml
third_party/rust/gcc-0.3.42/Cargo.toml
third_party/rust/gcc-0.3.42/LICENSE-APACHE
third_party/rust/gcc-0.3.42/LICENSE-MIT
third_party/rust/gcc-0.3.42/README.md
third_party/rust/gcc-0.3.42/appveyor.yml
third_party/rust/gcc-0.3.42/src/bin/gcc-shim.rs
third_party/rust/gcc-0.3.42/src/lib.rs
third_party/rust/gcc-0.3.42/src/registry.rs
third_party/rust/gcc-0.3.42/src/windows_registry.rs
third_party/rust/gcc-0.3.42/tests/cc_env.rs
third_party/rust/gcc-0.3.42/tests/support/mod.rs
third_party/rust/gcc-0.3.42/tests/test.rs
new file mode 100644
--- /dev/null
+++ b/third_party/rust/gcc-0.3.42/.cargo-checksum.json
@@ -0,0 +1,1 @@
+{"files":{".travis.yml":"e68f9d10a8e367890cf734239c39952ee480cf0e8da9520b377df4a2b8ccc9e8","Cargo.toml":"4ae5b4d6f82bd2815ab930eada95a45905e64023d9d5442eebc52e348ae853be","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"ef945d1d641463da2a37f2743dcead1e8e928afbce0496f5d7682ac147327b85","appveyor.yml":"46c77d913eaa45871296942c2cd96ef092c9dcaf19201cb5c500a5107faeb06f","src/bin/gcc-shim.rs":"d6be9137cb48b86891e7b263adbf492e1193ffe682db9ba4a88eb1079b874b58","src/lib.rs":"28451f34b048a99fc17f0ef9a5f541efcf304dd36de589055d0d00f63561fb61","src/registry.rs":"3876ef9573e3bbc050aef41a684b9a510cc1a91b15ae874fe032cf4377b4d116","src/windows_registry.rs":"36c6a7f8322407faff2dcfd4789d0876d034885944bc0340ac7c1f7cbfc307f1","tests/cc_env.rs":"d92c5e3d3d43ac244e63b2cd2c93a521fcf124bf1ccf8d4c6bfa7f8333d88976","tests/support/mod.rs":"56bcfd1e2ff5ae8e581c71229444a3d96094bf689808808dd80e315bd6632083","tests/test.rs":"b63e74d571e7d585edc53693bcf0caae88fc040613ace91e32437d4a62cddb6a"},"package":"291055c78f59ca3d84c99026c9501c469413d386bb46be1e1cf1d285cd1db3b0"}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/third_party/rust/gcc-0.3.42/.travis.yml
@@ -0,0 +1,49 @@
+language: rust
+rust:
+  - stable
+  - beta
+  - nightly
+matrix:
+  include:
+    # Minimum version supported
+    - rust: 1.6.0
+      install:
+      script: cargo build
+
+sudo: false
+install:
+  - if [ "$TRAVIS_OS_NAME" = "linux" ]; then OS=unknown-linux-gnu; else OS=apple-darwin; fi
+  - export TARGET=$ARCH-$OS
+  - curl https://static.rust-lang.org/rustup.sh |
+    sh -s -- --add-target=$TARGET --disable-sudo -y --prefix=`rustc --print sysroot`
+before_script:
+  - pip install 'travis-cargo<0.2' --user && export PATH=$HOME/.local/bin:$PATH
+script:
+  - cargo build --verbose
+  - cargo test --verbose
+  - cargo test --verbose --features parallel
+  - cargo test --manifest-path gcc-test/Cargo.toml --target $TARGET
+  - cargo test --manifest-path gcc-test/Cargo.toml --target $TARGET --features parallel
+  - cargo test --manifest-path gcc-test/Cargo.toml --target $TARGET --release
+  - cargo doc
+  - cargo clean && cargo build
+  - rustdoc --test README.md -L target/debug -L target/debug/deps
+after_success:
+  - travis-cargo --only nightly doc-upload
+env:
+  global:
+    secure: "CBtqrudgE0PS8x3kTr44jKbC2D4nfnmdYVecooNm0qnER4B4TSvZpZSQoCgKK6k4BYQuOSyFTOwYx6M79w39ZMOgyCP9ytB+tyMWL0/+ZuUQL04yVg4M5vd3oJMkOaXbvG56ncgPyFrseY+FPDg+mXAzvJk/nily37YXjkQj2D0="
+
+  matrix:
+    - ARCH=x86_64
+    - ARCH=i686
+notifications:
+  email:
+    on_success: never
+os:
+  - linux
+  - osx
+addons:
+  apt:
+    packages:
+      - g++-multilib
new file mode 100644
--- /dev/null
+++ b/third_party/rust/gcc-0.3.42/Cargo.toml
@@ -0,0 +1,27 @@
+[package]
+
+name = "gcc"
+version = "0.3.42"
+authors = ["Alex Crichton <alex@alexcrichton.com>"]
+license = "MIT/Apache-2.0"
+repository = "https://github.com/alexcrichton/gcc-rs"
+documentation = "https://docs.rs/gcc"
+description = """
+A build-time dependency for Cargo build scripts to assist in invoking the native
+C compiler to compile native C code into a static archive to be linked into Rust
+code.
+"""
+keywords = ["build-dependencies"]
+
+[badges]
+travis-ci = { repository = "alexcrichton/gcc-rs" }
+appveyor = { repository = "alexcrichton/gcc-rs" }
+
+[dependencies]
+rayon = { version = "0.6", optional = true }
+
+[features]
+parallel = ["rayon"]
+
+[dev-dependencies]
+tempdir = "0.3"
new file mode 100644
--- /dev/null
+++ b/third_party/rust/gcc-0.3.42/LICENSE-APACHE
@@ -0,0 +1,201 @@
+                              Apache License
+                        Version 2.0, January 2004
+                     http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+   "License" shall mean the terms and conditions for use, reproduction,
+   and distribution as defined by Sections 1 through 9 of this document.
+
+   "Licensor" shall mean the copyright owner or entity authorized by
+   the copyright owner that is granting the License.
+
+   "Legal Entity" shall mean the union of the acting entity and all
+   other entities that control, are controlled by, or are under common
+   control with that entity. For the purposes of this definition,
+   "control" means (i) the power, direct or indirect, to cause the
+   direction or management of such entity, whether by contract or
+   otherwise, or (ii) ownership of fifty percent (50%) or more of the
+   outstanding shares, or (iii) beneficial ownership of such entity.
+
+   "You" (or "Your") shall mean an individual or Legal Entity
+   exercising permissions granted by this License.
+
+   "Source" form shall mean the preferred form for making modifications,
+   including but not limited to software source code, documentation
+   source, and configuration files.
+
+   "Object" form shall mean any form resulting from mechanical
+   transformation or translation of a Source form, including but
+   not limited to compiled object code, generated documentation,
+   and conversions to other media types.
+
+   "Work" shall mean the work of authorship, whether in Source or
+   Object form, made available under the License, as indicated by a
+   copyright notice that is included in or attached to the work
+   (an example is provided in the Appendix below).
+
+   "Derivative Works" shall mean any work, whether in Source or Object
+   form, that is based on (or derived from) the Work and for which the
+   editorial revisions, annotations, elaborations, or other modifications
+   represent, as a whole, an original work of authorship. For the purposes
+   of this License, Derivative Works shall not include works that remain
+   separable from, or merely link (or bind by name) to the interfaces of,
+   the Work and Derivative Works thereof.
+
+   "Contribution" shall mean any work of authorship, including
+   the original version of the Work and any modifications or additions
+   to that Work or Derivative Works thereof, that is intentionally
+   submitted to Licensor for inclusion in the Work by the copyright owner
+   or by an individual or Legal Entity authorized to submit on behalf of
+   the copyright owner. For the purposes of this definition, "submitted"
+   means any form of electronic, verbal, or written communication sent
+   to the Licensor or its representatives, including but not limited to
+   communication on electronic mailing lists, source code control systems,
+   and issue tracking systems that are managed by, or on behalf of, the
+   Licensor for the purpose of discussing and improving the Work, but
+   excluding communication that is conspicuously marked or otherwise
+   designated in writing by the copyright owner as "Not a Contribution."
+
+   "Contributor" shall mean Licensor and any individual or Legal Entity
+   on behalf of whom a Contribution has been received by Licensor and
+   subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   copyright license to reproduce, prepare Derivative Works of,
+   publicly display, publicly perform, sublicense, and distribute the
+   Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   (except as stated in this section) patent license to make, have made,
+   use, offer to sell, sell, import, and otherwise transfer the Work,
+   where such license applies only to those patent claims licensable
+   by such Contributor that are necessarily infringed by their
+   Contribution(s) alone or by combination of their Contribution(s)
+   with the Work to which such Contribution(s) was submitted. If You
+   institute patent litigation against any entity (including a
+   cross-claim or counterclaim in a lawsuit) alleging that the Work
+   or a Contribution incorporated within the Work constitutes direct
+   or contributory patent infringement, then any patent licenses
+   granted to You under this License for that Work shall terminate
+   as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+   Work or Derivative Works thereof in any medium, with or without
+   modifications, and in Source or Object form, provided that You
+   meet the following conditions:
+
+   (a) You must give any other recipients of the Work or
+       Derivative Works a copy of this License; and
+
+   (b) You must cause any modified files to carry prominent notices
+       stating that You changed the files; and
+
+   (c) You must retain, in the Source form of any Derivative Works
+       that You distribute, all copyright, patent, trademark, and
+       attribution notices from the Source form of the Work,
+       excluding those notices that do not pertain to any part of
+       the Derivative Works; and
+
+   (d) If the Work includes a "NOTICE" text file as part of its
+       distribution, then any Derivative Works that You distribute must
+       include a readable copy of the attribution notices contained
+       within such NOTICE file, excluding those notices that do not
+       pertain to any part of the Derivative Works, in at least one
+       of the following places: within a NOTICE text file distributed
+       as part of the Derivative Works; within the Source form or
+       documentation, if provided along with the Derivative Works; or,
+       within a display generated by the Derivative Works, if and
+       wherever such third-party notices normally appear. The contents
+       of the NOTICE file are for informational purposes only and
+       do not modify the License. You may add Your own attribution
+       notices within Derivative Works that You distribute, alongside
+       or as an addendum to the NOTICE text from the Work, provided
+       that such additional attribution notices cannot be construed
+       as modifying the License.
+
+   You may add Your own copyright statement to Your modifications and
+   may provide additional or different license terms and conditions
+   for use, reproduction, or distribution of Your modifications, or
+   for any such Derivative Works as a whole, provided Your use,
+   reproduction, and distribution of the Work otherwise complies with
+   the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+   any Contribution intentionally submitted for inclusion in the Work
+   by You to the Licensor shall be under the terms and conditions of
+   this License, without any additional terms or conditions.
+   Notwithstanding the above, nothing herein shall supersede or modify
+   the terms of any separate license agreement you may have executed
+   with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+   names, trademarks, service marks, or product names of the Licensor,
+   except as required for reasonable and customary use in describing the
+   origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+   agreed to in writing, Licensor provides the Work (and each
+   Contributor provides its Contributions) on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+   implied, including, without limitation, any warranties or conditions
+   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+   PARTICULAR PURPOSE. You are solely responsible for determining the
+   appropriateness of using or redistributing the Work and assume any
+   risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+   whether in tort (including negligence), contract, or otherwise,
+   unless required by applicable law (such as deliberate and grossly
+   negligent acts) or agreed to in writing, shall any Contributor be
+   liable to You for damages, including any direct, indirect, special,
+   incidental, or consequential damages of any character arising as a
+   result of this License or out of the use or inability to use the
+   Work (including but not limited to damages for loss of goodwill,
+   work stoppage, computer failure or malfunction, or any and all
+   other commercial damages or losses), even if such Contributor
+   has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+   the Work or Derivative Works thereof, You may choose to offer,
+   and charge a fee for, acceptance of support, warranty, indemnity,
+   or other liability obligations and/or rights consistent with this
+   License. However, in accepting such obligations, You may act only
+   on Your own behalf and on Your sole responsibility, not on behalf
+   of any other Contributor, and only if You agree to indemnify,
+   defend, and hold each Contributor harmless for any liability
+   incurred by, or claims asserted against, such Contributor by reason
+   of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+   To apply the Apache License to your work, attach the following
+   boilerplate notice, with the fields enclosed by brackets "[]"
+   replaced with your own identifying information. (Don't include
+   the brackets!)  The text should be enclosed in the appropriate
+   comment syntax for the file format. We also recommend that a
+   file or class name and description of purpose be included on the
+   same "printed page" as the copyright notice for easier
+   identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/gcc-0.3.42/LICENSE-MIT
@@ -0,0 +1,25 @@
+Copyright (c) 2014 Alex Crichton
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/gcc-0.3.42/README.md
@@ -0,0 +1,161 @@
+# gcc-rs
+
+A library to compile C/C++ code into a Rust library/application.
+
+[![Build Status](https://travis-ci.org/alexcrichton/gcc-rs.svg?branch=master)](https://travis-ci.org/alexcrichton/gcc-rs)
+[![Build status](https://ci.appveyor.com/api/projects/status/onu270iw98h81nwv?svg=true)](https://ci.appveyor.com/project/alexcrichton/gcc-rs)
+
+[Documentation](https://docs.rs/gcc)
+
+A simple library meant to be used as a build dependency with Cargo packages in
+order to build a set of C/C++ files into a static archive. Note that while this
+crate is called "gcc", it actually calls out to the most relevant compile for
+a platform, for example using `cl` on MSVC. That is, this crate does indeed work
+on MSVC!
+
+## Using gcc-rs
+
+First, you'll want to both add a build script for your crate (`build.rs`) and
+also add this crate to your `Cargo.toml` via:
+
+```toml
+[package]
+# ...
+build = "build.rs"
+
+[build-dependencies]
+gcc = "0.3"
+```
+
+Next up, you'll want to write a build script like so:
+
+```rust,no_run
+// build.rs
+
+extern crate gcc;
+
+fn main() {
+    gcc::compile_library("libfoo.a", &["foo.c", "bar.c"]);
+}
+```
+
+And that's it! Running `cargo build` should take care of the rest and your Rust
+application will now have the C files `foo.c` and `bar.c` compiled into it. You
+can call the functions in Rust by declaring functions in your Rust code like so:
+
+```
+extern {
+    fn foo_function();
+    fn bar_function();
+}
+
+pub fn call() {
+    unsafe {
+        foo_function();
+        bar_function();
+    }
+}
+
+fn main() {
+    // ...
+}
+```
+
+## External configuration via environment variables
+
+To control the programs and flags used for building, the builder can set a
+number of different environment variables.
+
+* `CFLAGS` - a series of space separated flags passed to "gcc". Note that
+             individual flags cannot currently contain spaces, so doing
+             something like: "-L=foo\ bar" is not possible.
+* `CC` - the actual C compiler used. Note that this is used as an exact
+         executable name, so (for example) no extra flags can be passed inside
+         this variable, and the builder must ensure that there aren't any
+         trailing spaces. This compiler must understand the `-c` flag. For
+         certain `TARGET`s, it also is assumed to know about other flags (most
+         common is `-fPIC`).
+* `AR` - the `ar` (archiver) executable to use to build the static library.
+
+Each of these variables can also be supplied with certain prefixes and suffixes,
+in the following prioritized order:
+
+1. `<var>_<target>` - for example, `CC_x86_64-unknown-linux-gnu`
+2. `<var>_<target_with_underscores>` - for example, `CC_x86_64_unknown_linux_gnu`
+3. `<build-kind>_<var>` - for example, `HOST_CC` or `TARGET_CFLAGS`
+4. `<var>` - a plain `CC`, `AR` as above.
+
+If none of these variables exist, gcc-rs uses built-in defaults
+
+In addition to the the above optional environment variables, `gcc-rs` has some
+functions with hard requirements on some variables supplied by [cargo's
+build-script driver][cargo] that it has the `TARGET`, `OUT_DIR`, `OPT_LEVEL`,
+and `HOST` variables.
+
+[cargo]: http://doc.crates.io/build-script.html#inputs-to-the-build-script
+
+## Optional features
+
+Currently gcc-rs supports parallel compilation (think `make -jN`) but this
+feature is turned off by default. To enable gcc-rs to compile C/C++ in parallel,
+you can change your dependency to:
+
+```toml
+[build-dependencies]
+gcc = { version = "0.3", features = ["parallel"] }
+```
+
+By default gcc-rs will limit parallelism to `$NUM_JOBS`, or if not present it
+will limit it to the number of cpus on the machine.
+
+## Compile-time Requirements
+
+To work properly this crate needs access to a C compiler when the build script
+is being run. This crate does not ship a C compiler with it. The compiler
+required varies per platform, but there are three broad categories:
+
+* Unix platforms require `cc` to be the C compiler. This can be found by
+  installing gcc/clang on Linux distributions and Xcode on OSX, for example.
+* Windows platforms targeting MSVC (e.g. your target triple ends in `-msvc`)
+  require `cl.exe` to be available and in `PATH`. This is typically found in
+  standard Visual Studio installations and the `PATH` can be set up by running
+  the appropriate developer tools shell.
+* Windows platforms targeting MinGW (e.g. your target triple ends in `-gnu`)
+  require `gcc` to be available in `PATH`. We recommend the
+  [MinGW-w64](http://mingw-w64.org) distribution, which is using the
+  [Win-builds](http://win-builds.org) installation system.
+  You may also acquire it via
+  [MSYS2](http://msys2.github.io), as explained [here][msys2-help].  Make sure
+  to install the appropriate architecture corresponding to your installation of
+  rustc. GCC from older [MinGW](http://www.mingw.org) project is compatible
+  only with 32-bit rust compiler.
+
+[msys2-help]: http://github.com/rust-lang/rust#building-on-windows
+
+## C++ support
+
+`gcc-rs` supports C++ libraries compilation by using the `cpp` method on
+`Config`:
+
+```rust,no_run
+extern crate gcc;
+
+fn main() {
+    gcc::Config::new()
+        .cpp(true) // Switch to C++ library compilation.
+        .file("foo.cpp")
+        .compile("libfoo.a");
+}
+```
+
+When using C++ library compilation switch, the `CXX` and `CXXFLAGS` env
+variables are used instead of `CC` and `CFLAGS` and the C++ standard library is
+linked to the crate target.
+
+## License
+
+`gcc-rs` is primarily distributed under the terms of both the MIT license and
+the Apache License (Version 2.0), with portions covered by various BSD-like
+licenses.
+
+See LICENSE-APACHE, and LICENSE-MIT for details.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/gcc-0.3.42/appveyor.yml
@@ -0,0 +1,35 @@
+environment:
+  matrix:
+  - TARGET: x86_64-pc-windows-msvc
+    ARCH: amd64
+    VS: C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat
+  - TARGET: x86_64-pc-windows-msvc
+    ARCH: amd64
+    VS: C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat
+  - TARGET: i686-pc-windows-msvc
+    ARCH: x86
+    VS: C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat
+  - TARGET: i686-pc-windows-msvc
+    ARCH: x86
+    VS: C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat
+  - TARGET: x86_64-pc-windows-gnu
+    MSYS_BITS: 64
+  - TARGET: i686-pc-windows-gnu
+    MSYS_BITS: 32
+install:
+  - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-${env:TARGET}.exe"
+  - rust-nightly-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust"
+  - if defined VS call "%VS%" %ARCH%
+  - set PATH=%PATH%;C:\Program Files (x86)\Rust\bin
+  - if defined MSYS_BITS set PATH=%PATH%;C:\msys64\mingw%MSYS_BITS%\bin
+  - rustc -V
+  - cargo -V
+
+build: false
+
+test_script:
+  - cargo test --target %TARGET%
+  - cargo test --features parallel --target %TARGET%
+  - cargo test --manifest-path gcc-test/Cargo.toml --target %TARGET%
+  - cargo test --manifest-path gcc-test/Cargo.toml --features parallel --target %TARGET%
+  - cargo test --manifest-path gcc-test/Cargo.toml --release --target %TARGET%
new file mode 100644
--- /dev/null
+++ b/third_party/rust/gcc-0.3.42/src/bin/gcc-shim.rs
@@ -0,0 +1,23 @@
+#![cfg_attr(test, allow(dead_code))]
+
+use std::env;
+use std::fs::File;
+use std::io::prelude::*;
+use std::path::PathBuf;
+
+fn main() {
+    let out_dir = PathBuf::from(env::var_os("GCCTEST_OUT_DIR").unwrap());
+    for i in 0.. {
+        let candidate = out_dir.join(format!("out{}", i));
+        if candidate.exists() {
+            continue;
+        }
+        let mut f = File::create(candidate).unwrap();
+        for arg in env::args().skip(1) {
+            writeln!(f, "{}", arg).unwrap();
+        }
+
+        File::create(out_dir.join("libfoo.a")).unwrap();
+        break;
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/gcc-0.3.42/src/lib.rs
@@ -0,0 +1,1128 @@
+//! A library for build scripts to compile custom C code
+//!
+//! This library is intended to be used as a `build-dependencies` entry in
+//! `Cargo.toml`:
+//!
+//! ```toml
+//! [build-dependencies]
+//! gcc = "0.3"
+//! ```
+//!
+//! The purpose of this crate is to provide the utility functions necessary to
+//! compile C code into a static archive which is then linked into a Rust crate.
+//! The top-level `compile_library` function serves as a convenience and more
+//! advanced configuration is available through the `Config` builder.
+//!
+//! This crate will automatically detect situations such as cross compilation or
+//! other environment variables set by Cargo and will build code appropriately.
+//!
+//! # Examples
+//!
+//! Use the default configuration:
+//!
+//! ```no_run
+//! extern crate gcc;
+//!
+//! fn main() {
+//!     gcc::compile_library("libfoo.a", &["src/foo.c"]);
+//! }
+//! ```
+//!
+//! Use more advanced configuration:
+//!
+//! ```no_run
+//! extern crate gcc;
+//!
+//! fn main() {
+//!     gcc::Config::new()
+//!                 .file("src/foo.c")
+//!                 .define("FOO", Some("bar"))
+//!                 .include("src")
+//!                 .compile("libfoo.a");
+//! }
+//! ```
+
+#![doc(html_root_url = "https://docs.rs/gcc/0.3")]
+#![cfg_attr(test, deny(warnings))]
+#![deny(missing_docs)]
+
+#[cfg(feature = "parallel")]
+extern crate rayon;
+
+use std::env;
+use std::ffi::{OsString, OsStr};
+use std::fs;
+use std::path::{PathBuf, Path};
+use std::process::{Command, Stdio};
+use std::io::{self, BufReader, BufRead, Read, Write};
+use std::thread;
+
+#[cfg(windows)]
+mod registry;
+pub mod windows_registry;
+
+/// Extra configuration to pass to gcc.
+pub struct Config {
+    include_directories: Vec<PathBuf>,
+    definitions: Vec<(String, Option<String>)>,
+    objects: Vec<PathBuf>,
+    flags: Vec<String>,
+    files: Vec<PathBuf>,
+    cpp: bool,
+    cpp_link_stdlib: Option<Option<String>>,
+    cpp_set_stdlib: Option<String>,
+    target: Option<String>,
+    host: Option<String>,
+    out_dir: Option<PathBuf>,
+    opt_level: Option<String>,
+    debug: Option<bool>,
+    env: Vec<(OsString, OsString)>,
+    compiler: Option<PathBuf>,
+    archiver: Option<PathBuf>,
+    cargo_metadata: bool,
+    pic: Option<bool>,
+}
+
+/// Configuration used to represent an invocation of a C compiler.
+///
+/// This can be used to figure out what compiler is in use, what the arguments
+/// to it are, and what the environment variables look like for the compiler.
+/// This can be used to further configure other build systems (e.g. forward
+/// along CC and/or CFLAGS) or the `to_command` method can be used to run the
+/// compiler itself.
+pub struct Tool {
+    path: PathBuf,
+    args: Vec<OsString>,
+    env: Vec<(OsString, OsString)>,
+    family: ToolFamily
+}
+
+/// Represents the family of tools this tool belongs to.
+///
+/// Each family of tools differs in how and what arguments they accept.
+///
+/// Detection of a family is done on best-effort basis and may not accurately reflect the tool.
+#[derive(Copy, Clone, Debug)]
+enum ToolFamily {
+    /// Tool is GNU Compiler Collection-like.
+    Gnu,
+    /// Tool is Clang-like. It differs from the GCC in a sense that it accepts superset of flags
+    /// and its cross-compilation approach is different.
+    Clang,
+    /// Tool is the MSVC cl.exe.
+    Msvc,
+}
+
+impl ToolFamily {
+    /// What the flag to request debug info for this family of tools look like
+    fn debug_flag(&self) -> &'static str {
+        match *self {
+            ToolFamily::Msvc => "/Z7",
+            ToolFamily::Gnu |
+            ToolFamily::Clang => "-g",
+        }
+    }
+
+    /// What the flag to include directories into header search path looks like
+    fn include_flag(&self) -> &'static str {
+        match *self {
+            ToolFamily::Msvc => "/I",
+            ToolFamily::Gnu |
+            ToolFamily::Clang => "-I",
+        }
+    }
+
+    /// What the flag to request macro-expanded source output looks like
+    fn expand_flag(&self) -> &'static str {
+        match *self {
+            ToolFamily::Msvc => "/E",
+            ToolFamily::Gnu |
+            ToolFamily::Clang => "-E",
+        }
+    }
+}
+
+/// Compile a library from the given set of input C files.
+///
+/// This will simply compile all files into object files and then assemble them
+/// into the output. This will read the standard environment variables to detect
+/// cross compilations and such.
+///
+/// This function will also print all metadata on standard output for Cargo.
+///
+/// # Example
+///
+/// ```no_run
+/// gcc::compile_library("libfoo.a", &["foo.c", "bar.c"]);
+/// ```
+pub fn compile_library(output: &str, files: &[&str]) {
+    let mut c = Config::new();
+    for f in files.iter() {
+        c.file(*f);
+    }
+    c.compile(output);
+}
+
+impl Config {
+    /// Construct a new instance of a blank set of configuration.
+    ///
+    /// This builder is finished with the `compile` function.
+    pub fn new() -> Config {
+        Config {
+            include_directories: Vec::new(),
+            definitions: Vec::new(),
+            objects: Vec::new(),
+            flags: Vec::new(),
+            files: Vec::new(),
+            cpp: false,
+            cpp_link_stdlib: None,
+            cpp_set_stdlib: None,
+            target: None,
+            host: None,
+            out_dir: None,
+            opt_level: None,
+            debug: None,
+            env: Vec::new(),
+            compiler: None,
+            archiver: None,
+            cargo_metadata: true,
+            pic: None,
+        }
+    }
+
+    /// Add a directory to the `-I` or include path for headers
+    pub fn include<P: AsRef<Path>>(&mut self, dir: P) -> &mut Config {
+        self.include_directories.push(dir.as_ref().to_path_buf());
+        self
+    }
+
+    /// Specify a `-D` variable with an optional value.
+    pub fn define(&mut self, var: &str, val: Option<&str>) -> &mut Config {
+        self.definitions.push((var.to_string(), val.map(|s| s.to_string())));
+        self
+    }
+
+    /// Add an arbitrary object file to link in
+    pub fn object<P: AsRef<Path>>(&mut self, obj: P) -> &mut Config {
+        self.objects.push(obj.as_ref().to_path_buf());
+        self
+    }
+
+    /// Add an arbitrary flag to the invocation of the compiler
+    pub fn flag(&mut self, flag: &str) -> &mut Config {
+        self.flags.push(flag.to_string());
+        self
+    }
+
+    /// Add a file which will be compiled
+    pub fn file<P: AsRef<Path>>(&mut self, p: P) -> &mut Config {
+        self.files.push(p.as_ref().to_path_buf());
+        self
+    }
+
+    /// Set C++ support.
+    ///
+    /// The other `cpp_*` options will only become active if this is set to
+    /// `true`.
+    pub fn cpp(&mut self, cpp: bool) -> &mut Config {
+        self.cpp = cpp;
+        self
+    }
+
+    /// Set the standard library to link against when compiling with C++
+    /// support.
+    ///
+    /// 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.
+    ///
+    /// A value of `None` indicates that no automatic linking should happen,
+    /// otherwise cargo will link against the specified library.
+    ///
+    /// The given library name must not contain the `lib` prefix.
+    pub fn cpp_link_stdlib(&mut self, cpp_link_stdlib: Option<&str>) -> &mut Config {
+        self.cpp_link_stdlib = Some(cpp_link_stdlib.map(|s| s.into()));
+        self
+    }
+
+    /// Force the C++ compiler to use the specified standard library.
+    ///
+    /// Setting this option will automatically set `cpp_link_stdlib` to the same
+    /// value.
+    ///
+    /// The default value of this option is always `None`.
+    ///
+    /// This option has no effect when compiling for a Visual Studio based
+    /// target.
+    ///
+    /// This option sets the `-stdlib` flag, which is only supported by some
+    /// compilers (clang, icc) but not by others (gcc). The library will not
+    /// detect which compiler is used, as such it is the responsibility of the
+    /// caller to ensure that this option is only used in conjuction with a
+    /// compiler which supports the `-stdlib` flag.
+    ///
+    /// A value of `None` indicates that no specific C++ standard library should
+    /// be used, otherwise `-stdlib` is added to the compile invocation.
+    ///
+    /// The given library name must not contain the `lib` prefix.
+    pub fn cpp_set_stdlib(&mut self, cpp_set_stdlib: Option<&str>) -> &mut Config {
+        self.cpp_set_stdlib = cpp_set_stdlib.map(|s| s.into());
+        self.cpp_link_stdlib(cpp_set_stdlib);
+        self
+    }
+
+    /// Configures the target this configuration will be compiling for.
+    ///
+    /// This option is automatically scraped from the `TARGET` environment
+    /// variable by build scripts, so it's not required to call this function.
+    pub fn target(&mut self, target: &str) -> &mut Config {
+        self.target = Some(target.to_string());
+        self
+    }
+
+    /// Configures the host assumed by this configuration.
+    ///
+    /// This option is automatically scraped from the `HOST` environment
+    /// variable by build scripts, so it's not required to call this function.
+    pub fn host(&mut self, host: &str) -> &mut Config {
+        self.host = Some(host.to_string());
+        self
+    }
+
+    /// Configures the optimization level of the generated object files.
+    ///
+    /// This option is automatically scraped from the `OPT_LEVEL` environment
+    /// variable by build scripts, so it's not required to call this function.
+    pub fn opt_level(&mut self, opt_level: u32) -> &mut Config {
+        self.opt_level = Some(opt_level.to_string());
+        self
+    }
+
+    /// Configures the optimization level of the generated object files.
+    ///
+    /// This option is automatically scraped from the `OPT_LEVEL` environment
+    /// variable by build scripts, so it's not required to call this function.
+    pub fn opt_level_str(&mut self, opt_level: &str) -> &mut Config {
+        self.opt_level = Some(opt_level.to_string());
+        self
+    }
+
+    /// Configures whether the compiler will emit debug information when
+    /// generating object files.
+    ///
+    /// This option is automatically scraped from the `PROFILE` environment
+    /// variable by build scripts (only enabled when the profile is "debug"), so
+    /// it's not required to call this function.
+    pub fn debug(&mut self, debug: bool) -> &mut Config {
+        self.debug = Some(debug);
+        self
+    }
+
+    /// Configures the output directory where all object files and static
+    /// libraries will be located.
+    ///
+    /// This option is automatically scraped from the `OUT_DIR` environment
+    /// variable by build scripts, so it's not required to call this function.
+    pub fn out_dir<P: AsRef<Path>>(&mut self, out_dir: P) -> &mut Config {
+        self.out_dir = Some(out_dir.as_ref().to_owned());
+        self
+    }
+
+    /// Configures the compiler to be used to produce output.
+    ///
+    /// This option is automatically determined from the target platform or a
+    /// number of environment variables, so it's not required to call this
+    /// function.
+    pub fn compiler<P: AsRef<Path>>(&mut self, compiler: P) -> &mut Config {
+        self.compiler = Some(compiler.as_ref().to_owned());
+        self
+    }
+
+    /// Configures the tool used to assemble archives.
+    ///
+    /// This option is automatically determined from the target platform or a
+    /// number of environment variables, so it's not required to call this
+    /// function.
+    pub fn archiver<P: AsRef<Path>>(&mut self, archiver: P) -> &mut Config {
+        self.archiver = Some(archiver.as_ref().to_owned());
+        self
+    }
+    /// Define whether metadata should be emitted for cargo allowing it to
+    /// automatically link the binary. Defaults to `true`.
+    pub fn cargo_metadata(&mut self, cargo_metadata: bool) -> &mut Config {
+        self.cargo_metadata = cargo_metadata;
+        self
+    }
+
+    /// Configures whether the compiler will emit position independent code.
+    ///
+    /// This option defaults to `false` for `i686` and `windows-gnu` targets and to `true` for all
+    /// other targets.
+    pub fn pic(&mut self, pic: bool) -> &mut Config {
+        self.pic = Some(pic);
+        self
+    }
+
+
+    #[doc(hidden)]
+    pub fn __set_env<A, B>(&mut self, a: A, b: B) -> &mut Config
+        where A: AsRef<OsStr>,
+              B: AsRef<OsStr>
+    {
+        self.env.push((a.as_ref().to_owned(), b.as_ref().to_owned()));
+        self
+    }
+
+    /// Run the compiler, generating the file `output`
+    ///
+    /// The name `output` must begin with `lib` and end with `.a`
+    pub fn compile(&self, output: &str) {
+        assert!(output.starts_with("lib"));
+        assert!(output.ends_with(".a"));
+        let lib_name = &output[3..output.len() - 2];
+        let dst = self.get_out_dir();
+
+        let mut objects = Vec::new();
+        let mut src_dst = Vec::new();
+        for file in self.files.iter() {
+            let obj = dst.join(file).with_extension("o");
+            let obj = if !obj.starts_with(&dst) {
+                dst.join(obj.file_name().unwrap())
+            } else {
+                obj
+            };
+            fs::create_dir_all(&obj.parent().unwrap()).unwrap();
+            src_dst.push((file.to_path_buf(), obj.clone()));
+            objects.push(obj);
+        }
+        self.compile_objects(&src_dst);
+        self.assemble(lib_name, &dst.join(output), &objects);
+
+        if self.get_target().contains("msvc") {
+            let compiler = self.get_base_compiler();
+            let atlmfc_lib = compiler.env()
+                .iter()
+                .find(|&&(ref var, _)| var.as_os_str() == OsStr::new("LIB"))
+                .and_then(|&(_, ref lib_paths)| {
+                    env::split_paths(lib_paths).find(|path| {
+                        let sub = Path::new("atlmfc/lib");
+                        path.ends_with(sub) || path.parent().map_or(false, |p| p.ends_with(sub))
+                    })
+                });
+
+            if let Some(atlmfc_lib) = atlmfc_lib {
+                self.print(&format!("cargo:rustc-link-search=native={}", atlmfc_lib.display()));
+            }
+        }
+
+        self.print(&format!("cargo:rustc-link-lib=static={}",
+                            &output[3..output.len() - 2]));
+        self.print(&format!("cargo:rustc-link-search=native={}", dst.display()));
+
+        // Add specific C++ libraries, if enabled.
+        if self.cpp {
+            if let Some(stdlib) = self.get_cpp_link_stdlib() {
+                self.print(&format!("cargo:rustc-link-lib={}", stdlib));
+            }
+        }
+    }
+
+    #[cfg(feature = "parallel")]
+    fn compile_objects(&self, objs: &[(PathBuf, PathBuf)]) {
+        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.set_num_threads(amt);
+            }
+        }
+        drop(rayon::initialize(cfg));
+
+        objs.par_iter().weight_max().for_each(|&(ref src, ref dst)| self.compile_object(src, dst));
+    }
+
+    #[cfg(not(feature = "parallel"))]
+    fn compile_objects(&self, objs: &[(PathBuf, PathBuf)]) {
+        for &(ref src, ref dst) in objs {
+            self.compile_object(src, dst);
+        }
+    }
+
+    fn compile_object(&self, file: &Path, dst: &Path) {
+        let is_asm = file.extension().and_then(|s| s.to_str()) == Some("asm");
+        let msvc = self.get_target().contains("msvc");
+        let (mut cmd, name) = if msvc && is_asm {
+            self.msvc_macro_assembler()
+        } else {
+            let compiler = self.get_compiler();
+            let mut cmd = compiler.to_command();
+            for &(ref a, ref b) in self.env.iter() {
+                cmd.env(a, b);
+            }
+            (cmd,
+             compiler.path
+                 .file_name()
+                 .unwrap()
+                 .to_string_lossy()
+                 .into_owned())
+        };
+        if msvc && is_asm {
+            cmd.arg("/Fo").arg(dst);
+        } else if msvc {
+            let mut s = OsString::from("/Fo");
+            s.push(&dst);
+            cmd.arg(s);
+        } else {
+            cmd.arg("-o").arg(&dst);
+        }
+        cmd.arg(if msvc { "/c" } else { "-c" });
+        cmd.arg(file);
+
+        run(&mut cmd, &name);
+    }
+
+    /// Run the compiler, returning the macro-expanded version of the input files.
+    ///
+    /// This is only relevant for C and C++ files.
+    pub fn expand(&self) -> Vec<u8> {
+        let compiler = self.get_compiler();
+        let mut cmd = compiler.to_command();
+        for &(ref a, ref b) in self.env.iter() {
+            cmd.env(a, b);
+        }
+        cmd.arg(compiler.family.expand_flag());
+        for file in self.files.iter() {
+            cmd.arg(file);
+        }
+
+        let name = compiler.path
+            .file_name()
+            .unwrap()
+            .to_string_lossy()
+            .into_owned();
+
+        run(&mut cmd, &name)
+    }
+
+    /// Get the compiler that's in use for this configuration.
+    ///
+    /// This function will return a `Tool` which represents the culmination
+    /// of this configuration at a snapshot in time. The returned compiler can
+    /// be inspected (e.g. the path, arguments, environment) to forward along to
+    /// other tools, or the `to_command` method can be used to invoke the
+    /// compiler itself.
+    ///
+    /// This method will take into account all configuration such as debug
+    /// information, optimization level, include directories, defines, etc.
+    /// Additionally, the compiler binary in use follows the standard
+    /// conventions for this path, e.g. looking at the explicitly set compiler,
+    /// environment variables (a number of which are inspected here), and then
+    /// falling back to the default configuration.
+    pub fn get_compiler(&self) -> Tool {
+        let opt_level = self.get_opt_level();
+        let target = self.get_target();
+
+        let mut cmd = self.get_base_compiler();
+        let nvcc = cmd.path.file_name()
+            .and_then(|p| p.to_str()).map(|p| p.contains("nvcc"))
+            .unwrap_or(false);
+
+        // Non-target flags
+        // If the flag is not conditioned on target variable, it belongs here :)
+        match cmd.family {
+            ToolFamily::Msvc => {
+                cmd.args.push("/nologo".into());
+                let features = env::var("CARGO_CFG_TARGET_FEATURE")
+                                  .unwrap_or(String::new());
+                if features.contains("crt-static") {
+                    cmd.args.push("/MT".into());
+                } else {
+                    cmd.args.push("/MD".into());
+                }
+                match &opt_level[..] {
+                    "z" | "s" => cmd.args.push("/Os".into()),
+                    "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()),
+                    _ => {}
+                }
+            }
+            ToolFamily::Gnu |
+            ToolFamily::Clang => {
+                cmd.args.push(format!("-O{}", opt_level).into());
+                if !nvcc {
+                    cmd.args.push("-ffunction-sections".into());
+                    cmd.args.push("-fdata-sections".into());
+                    if self.pic.unwrap_or(!target.contains("i686") &&
+                                          !target.contains("windows-gnu")) {
+                        cmd.args.push("-fPIC".into());
+                    }
+                } else if self.pic.unwrap_or(false) {
+                    cmd.args.push("-Xcompiler".into());
+                    cmd.args.push("\'-fPIC\'".into());
+                }
+            }
+        }
+        for arg in self.envflags(if self.cpp {"CXXFLAGS"} else {"CFLAGS"}) {
+            cmd.args.push(arg.into());
+        }
+
+        if self.get_debug() {
+            cmd.args.push(cmd.family.debug_flag().into());
+        }
+
+        // Target flags
+        match cmd.family {
+            ToolFamily::Clang => {
+                cmd.args.push(format!("--target={}", target).into());
+            }
+            ToolFamily::Msvc => {
+                if target.contains("i586") {
+                    cmd.args.push("/ARCH:IA32".into());
+                }
+            }
+            ToolFamily::Gnu => {
+                if target.contains("i686") || target.contains("i586") {
+                    cmd.args.push("-m32".into());
+                } else if target.contains("x86_64") || target.contains("powerpc64") {
+                    cmd.args.push("-m64".into());
+                }
+
+                if target.contains("musl") {
+                    cmd.args.push("-static".into());
+                }
+
+                // armv7 targets get to use armv7 instructions
+                if target.starts_with("armv7-unknown-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());
+                    cmd.args.push("-mfpu=vfpv3-d16".into());
+                }
+
+                // For us arm == armv6 by default
+                if target.starts_with("arm-unknown-linux-") {
+                    cmd.args.push("-march=armv6".into());
+                    cmd.args.push("-marm".into());
+                }
+
+                // Turn codegen down on i586 to avoid some instructions.
+                if target.starts_with("i586-unknown-linux-") {
+                    cmd.args.push("-march=pentium".into());
+                }
+
+                // Set codegen level for i686 correctly
+                if target.starts_with("i686-unknown-linux-") {
+                    cmd.args.push("-march=i686".into());
+                }
+
+                // Looks like `musl-gcc` makes is hard for `-m32` to make its way
+                // all the way to the linker, so we need to actually instruct the
+                // 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" {
+                    cmd.args.push("-Wl,-melf_i386".into());
+                }
+
+                if target.starts_with("thumb") {
+                    cmd.args.push("-mthumb".into());
+
+                    if target.ends_with("eabihf") {
+                        cmd.args.push("-mfloat-abi=hard".into())
+                    }
+                }
+                if target.starts_with("thumbv6m") {
+                    cmd.args.push("-march=armv6s-m".into());
+                }
+                if target.starts_with("thumbv7em") {
+                    cmd.args.push("-march=armv7e-m".into());
+
+                    if target.ends_with("eabihf") {
+                        cmd.args.push("-mfpu=fpv4-sp-d16".into())
+                    }
+                }
+                if target.starts_with("thumbv7m") {
+                    cmd.args.push("-march=armv7-m".into());
+                }
+            }
+        }
+
+        if target.contains("-ios") {
+            // FIXME: potential bug. iOS is always compiled with Clang, but Gcc compiler may be
+            // detected instead.
+            self.ios_flags(&mut cmd);
+        }
+
+        if self.cpp {
+            match (self.cpp_set_stdlib.as_ref(), cmd.family) {
+                (Some(stdlib), ToolFamily::Gnu) |
+                (Some(stdlib), ToolFamily::Clang) => {
+                    cmd.args.push(format!("-stdlib=lib{}", stdlib).into());
+                }
+                _ => {
+                    println!("cargo:warning=cpp_set_stdlib is specified, but the {:?} compiler \
+                              does not support this option, ignored", cmd.family);
+                }
+            }
+        }
+
+        for directory in self.include_directories.iter() {
+            cmd.args.push(cmd.family.include_flag().into());
+            cmd.args.push(directory.into());
+        }
+
+        for flag in self.flags.iter() {
+            cmd.args.push(flag.into());
+        }
+
+        for &(ref key, ref value) in self.definitions.iter() {
+            let lead = if let ToolFamily::Msvc = cmd.family {"/"} else {"-"};
+            if let &Some(ref value) = value {
+                cmd.args.push(format!("{}D{}={}", lead, key, value).into());
+            } else {
+                cmd.args.push(format!("{}D{}", lead, key).into());
+            }
+        }
+        cmd
+    }
+
+    fn msvc_macro_assembler(&self) -> (Command, String) {
+        let target = self.get_target();
+        let tool = if target.contains("x86_64") {
+            "ml64.exe"
+        } else {
+            "ml.exe"
+        };
+        let mut cmd = windows_registry::find(&target, tool).unwrap_or_else(|| self.cmd(tool));
+        for directory in self.include_directories.iter() {
+            cmd.arg("/I").arg(directory);
+        }
+        for &(ref key, ref value) in self.definitions.iter() {
+            if let &Some(ref value) = value {
+                cmd.arg(&format!("/D{}={}", key, value));
+            } else {
+                cmd.arg(&format!("/D{}", key));
+            }
+        }
+
+        if target.contains("i686") || target.contains("i586") {
+            cmd.arg("/safeseh");
+        }
+        for flag in self.flags.iter() {
+            cmd.arg(flag);
+        }
+
+        (cmd, tool.to_string())
+    }
+
+    fn assemble(&self, lib_name: &str, dst: &Path, objects: &[PathBuf]) {
+        // Delete the destination if it exists as the `ar` tool at least on Unix
+        // appends to it, which we don't want.
+        let _ = fs::remove_file(&dst);
+
+        let target = self.get_target();
+        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(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");
+
+            // 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
+            // exist for now.
+            let lib_dst = dst.with_file_name(format!("{}.lib", lib_name));
+            let _ = fs::remove_file(&lib_dst);
+            fs::hard_link(&dst, &lib_dst)
+                .or_else(|_| {
+                    // if hard-link fails, just copy (ignoring the number of bytes written)
+                    fs::copy(&dst, &lib_dst).map(|_| ())
+                })
+                .ok()
+                .expect("Copying from {:?} to {:?} failed.");;
+        } else {
+            let ar = self.get_ar();
+            let cmd = ar.file_name().unwrap().to_string_lossy();
+            run(self.cmd(&ar)
+                    .arg("crs")
+                    .arg(dst)
+                    .args(objects)
+                    .args(&self.objects),
+                &cmd);
+        }
+    }
+
+    fn ios_flags(&self, cmd: &mut Tool) {
+        enum ArchSpec {
+            Device(&'static str),
+            Simulator(&'static str),
+        }
+
+        let target = self.get_target();
+        let arch = target.split('-').nth(0).unwrap();
+        let arch = match arch {
+            "arm" | "armv7" | "thumbv7" => ArchSpec::Device("armv7"),
+            "armv7s" | "thumbv7s" => ArchSpec::Device("armv7s"),
+            "arm64" | "aarch64" => ArchSpec::Device("arm64"),
+            "i386" | "i686" => ArchSpec::Simulator("-m32"),
+            "x86_64" => ArchSpec::Simulator("-m64"),
+            _ => fail("Unknown arch for iOS target"),
+        };
+
+        let sdk = match arch {
+            ArchSpec::Device(arch) => {
+                cmd.args.push("-arch".into());
+                cmd.args.push(arch.into());
+                cmd.args.push("-miphoneos-version-min=7.0".into());
+                "iphoneos"
+            }
+            ArchSpec::Simulator(arch) => {
+                cmd.args.push(arch.into());
+                cmd.args.push("-mios-simulator-version-min=7.0".into());
+                "iphonesimulator"
+            }
+        };
+
+        self.print(&format!("Detecting iOS SDK path for {}", sdk));
+        let sdk_path = self.cmd("xcrun")
+            .arg("--show-sdk-path")
+            .arg("--sdk")
+            .arg(sdk)
+            .stderr(Stdio::inherit())
+            .output()
+            .unwrap()
+            .stdout;
+
+        let sdk_path = String::from_utf8(sdk_path).unwrap();
+
+        cmd.args.push("-isysroot".into());
+        cmd.args.push(sdk_path.trim().into());
+    }
+
+    fn cmd<P: AsRef<OsStr>>(&self, prog: P) -> Command {
+        let mut cmd = Command::new(prog);
+        for &(ref a, ref b) in self.env.iter() {
+            cmd.env(a, b);
+        }
+        return cmd;
+    }
+
+    fn get_base_compiler(&self) -> Tool {
+        if let Some(ref c) = self.compiler {
+            return Tool::new(c.clone());
+        }
+        let host = self.get_host();
+        let target = self.get_target();
+        let (env, msvc, gnu, default) = if self.cpp {
+            ("CXX", "cl.exe", "g++", "c++")
+        } else {
+            ("CC", "cl.exe", "gcc", "cc")
+        };
+        self.env_tool(env)
+            .map(|(tool, args)| {
+                let mut t = Tool::new(PathBuf::from(tool));
+                for arg in args {
+                    t.args.push(arg.into());
+                }
+                return t;
+            })
+            .or_else(|| {
+                if target.contains("emscripten") {
+                    if self.cpp {
+                        Some(Tool::new(PathBuf::from("em++")))
+                    } else {
+                        Some(Tool::new(PathBuf::from("emcc")))
+                    }
+                } else {
+                    None
+                }
+            })
+            .or_else(|| windows_registry::find_tool(&target, "cl.exe"))
+            .unwrap_or_else(|| {
+                let compiler = if host.contains("windows") && target.contains("windows") {
+                    if target.contains("msvc") {
+                        msvc.to_string()
+                    } else {
+                        format!("{}.exe", gnu)
+                    }
+                } else if target.contains("android") {
+                    format!("{}-{}", target.replace("armv7", "arm"), gnu)
+                } else if self.get_host() != target {
+                    // CROSS_COMPILE is of the form: "arm-linux-gnueabi-"
+                    let cc_env = self.getenv("CROSS_COMPILE");
+                    let cross_compile = cc_env.as_ref().map(|s| s.trim_right_matches('-'));
+                    let prefix = cross_compile.or(match &target[..] {
+                        "aarch64-unknown-linux-gnu" => Some("aarch64-linux-gnu"),
+                        "arm-unknown-linux-gnueabi" => Some("arm-linux-gnueabi"),
+                        "arm-unknown-linux-gnueabihf" => Some("arm-linux-gnueabihf"),
+                        "arm-unknown-linux-musleabi" => Some("arm-linux-musleabi"),
+                        "arm-unknown-linux-musleabihf" => Some("arm-linux-musleabihf"),
+                        "arm-unknown-netbsdelf-eabi" => Some("arm--netbsdelf-eabi"),
+                        "armv6-unknown-netbsdelf-eabihf" => Some("armv6--netbsdelf-eabihf"),
+                        "armv7-unknown-linux-gnueabihf" => Some("arm-linux-gnueabihf"),
+                        "armv7-unknown-linux-musleabihf" => Some("arm-linux-musleabihf"),
+                        "armv7-unknown-netbsdelf-eabihf" => Some("armv7--netbsdelf-eabihf"),
+                        "i686-pc-windows-gnu" => Some("i686-w64-mingw32"),
+                        "i686-unknown-linux-musl" => Some("musl"),
+                        "i686-unknown-netbsdelf" => Some("i486--netbsdelf"),
+                        "mips-unknown-linux-gnu" => Some("mips-linux-gnu"),
+                        "mipsel-unknown-linux-gnu" => Some("mipsel-linux-gnu"),
+                        "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-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"),
+                        "sparc64-unknown-netbsd" => Some("sparc64--netbsd"),
+                        "thumbv6m-none-eabi" => Some("arm-none-eabi"),
+                        "thumbv7em-none-eabi" => Some("arm-none-eabi"),
+                        "thumbv7em-none-eabihf" => Some("arm-none-eabi"),
+                        "thumbv7m-none-eabi" => Some("arm-none-eabi"),
+                        "x86_64-pc-windows-gnu" => Some("x86_64-w64-mingw32"),
+                        "x86_64-rumprun-netbsd" => Some("x86_64-rumprun-netbsd"),
+                        "x86_64-unknown-linux-musl" => Some("musl"),
+                        "x86_64-unknown-netbsd" => Some("x86_64--netbsd"),
+                        _ => None,
+                    });
+                    match prefix {
+                        Some(prefix) => format!("{}-{}", prefix, gnu),
+                        None => default.to_string(),
+                    }
+                } else {
+                    default.to_string()
+                };
+                Tool::new(PathBuf::from(compiler))
+            })
+    }
+
+    fn get_var(&self, var_base: &str) -> Result<String, String> {
+        let target = self.get_target();
+        let host = self.get_host();
+        let kind = if host == target { "HOST" } else { "TARGET" };
+        let target_u = target.replace("-", "_");
+        let res = self.getenv(&format!("{}_{}", var_base, target))
+            .or_else(|| self.getenv(&format!("{}_{}", var_base, target_u)))
+            .or_else(|| self.getenv(&format!("{}_{}", kind, var_base)))
+            .or_else(|| self.getenv(var_base));
+
+        match res {
+            Some(res) => Ok(res),
+            None => Err("could not get environment variable".to_string()),
+        }
+    }
+
+    fn envflags(&self, name: &str) -> Vec<String> {
+        self.get_var(name)
+            .unwrap_or(String::new())
+            .split(|c: char| c.is_whitespace())
+            .filter(|s| !s.is_empty())
+            .map(|s| s.to_string())
+            .collect()
+    }
+
+    fn env_tool(&self, name: &str) -> Option<(String, Vec<String>)> {
+        self.get_var(name).ok().map(|tool| {
+            let whitelist = ["ccache", "distcc"];
+            for t in whitelist.iter() {
+                if tool.starts_with(t) && tool[t.len()..].starts_with(" ") {
+                    return (t.to_string(), vec![tool[t.len()..].trim_left().to_string()]);
+                }
+            }
+            (tool, Vec::new())
+        })
+    }
+
+    /// Returns the default C++ standard library for the current target: `libc++`
+    /// for OS X and `libstdc++` for anything else.
+    fn get_cpp_link_stdlib(&self) -> Option<String> {
+        self.cpp_link_stdlib.clone().unwrap_or_else(|| {
+            let target = self.get_target();
+            if target.contains("msvc") {
+                None
+            } else if target.contains("darwin") {
+                Some("c++".to_string())
+            } else if target.contains("freebsd") {
+                Some("c++".to_string())
+            } else {
+                Some("stdc++".to_string())
+            }
+        })
+    }
+
+    fn get_ar(&self) -> PathBuf {
+        self.archiver
+            .clone()
+            .or_else(|| self.get_var("AR").map(PathBuf::from).ok())
+            .unwrap_or_else(|| {
+                if self.get_target().contains("android") {
+                    PathBuf::from(format!("{}-ar", self.get_target().replace("armv7", "arm")))
+                } else if self.get_target().contains("emscripten") {
+                    PathBuf::from("emar")
+                } else {
+                    PathBuf::from("ar")
+                }
+            })
+    }
+
+    fn get_target(&self) -> String {
+        self.target.clone().unwrap_or_else(|| self.getenv_unwrap("TARGET"))
+    }
+
+    fn get_host(&self) -> String {
+        self.host.clone().unwrap_or_else(|| self.getenv_unwrap("HOST"))
+    }
+
+    fn get_opt_level(&self) -> String {
+        self.opt_level.as_ref().cloned().unwrap_or_else(|| self.getenv_unwrap("OPT_LEVEL"))
+    }
+
+    fn get_debug(&self) -> bool {
+        self.debug.unwrap_or_else(|| self.getenv_unwrap("PROFILE") == "debug")
+    }
+
+    fn get_out_dir(&self) -> PathBuf {
+        self.out_dir.clone().unwrap_or_else(|| env::var_os("OUT_DIR").map(PathBuf::from).unwrap())
+    }
+
+    fn getenv(&self, v: &str) -> Option<String> {
+        let r = env::var(v).ok();
+        self.print(&format!("{} = {:?}", v, r));
+        r
+    }
+
+    fn getenv_unwrap(&self, v: &str) -> String {
+        match self.getenv(v) {
+            Some(s) => s,
+            None => fail(&format!("environment variable `{}` not defined", v)),
+        }
+    }
+
+    fn print(&self, s: &str) {
+        if self.cargo_metadata {
+            println!("{}", s);
+        }
+    }
+}
+
+impl Tool {
+    fn new(path: PathBuf) -> 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") {
+                ToolFamily::Clang
+            } else if fname.contains("cl") {
+                ToolFamily::Msvc
+            } else {
+                ToolFamily::Gnu
+            }
+        } else {
+            ToolFamily::Gnu
+        };
+        Tool {
+            path: path,
+            args: Vec::new(),
+            env: Vec::new(),
+            family: family
+        }
+    }
+
+    /// Converts this compiler into a `Command` that's ready to be run.
+    ///
+    /// This is useful for when the compiler needs to be executed and the
+    /// command returned will already have the initial arguments and environment
+    /// variables configured.
+    pub fn to_command(&self) -> Command {
+        let mut cmd = Command::new(&self.path);
+        cmd.args(&self.args);
+        for &(ref k, ref v) in self.env.iter() {
+            cmd.env(k, v);
+        }
+        cmd
+    }
+
+    /// Returns the path for this compiler.
+    ///
+    /// Note that this may not be a path to a file on the filesystem, e.g. "cc",
+    /// but rather something which will be resolved when a process is spawned.
+    pub fn path(&self) -> &Path {
+        &self.path
+    }
+
+    /// Returns the default set of arguments to the compiler needed to produce
+    /// executables for the target this compiler generates.
+    pub fn args(&self) -> &[OsString] {
+        &self.args
+    }
+
+    /// Returns the set of environment variables needed for this compiler to
+    /// operate.
+    ///
+    /// This is typically only used for MSVC compilers currently.
+    pub fn env(&self) -> &[(OsString, OsString)] {
+        &self.env
+    }
+}
+
+fn run(cmd: &mut Command, program: &str) -> Vec<u8> {
+    println!("running: {:?}", cmd);
+    // Capture the standard error coming from these programs, and write it out
+    // with cargo:warning= prefixes. Note that this is a bit wonky to avoid
+    // requiring the output to be UTF-8, we instead just ship bytes from one
+    // location to another.
+    let (spawn_result, stdout) = match cmd.stdout(Stdio::piped()).stderr(Stdio::piped()).spawn() {
+        Ok(mut child) => {
+            let stderr = BufReader::new(child.stderr.take().unwrap());
+            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 mut stdout = vec![];
+            child.stdout.take().unwrap().read_to_end(&mut stdout).unwrap();
+            (child.wait(), stdout)
+        }
+        Err(e) => (Err(e), vec![]),
+    };
+    let status = match spawn_result {
+        Ok(status) => status,
+        Err(ref e) if e.kind() == io::ErrorKind::NotFound => {
+            let extra = if cfg!(windows) {
+                " (see https://github.com/alexcrichton/gcc-rs#compile-time-requirements \
+                   for help)"
+            } else {
+                ""
+            };
+            fail(&format!("failed to execute command: {}\nIs `{}` \
+                           not installed?{}",
+                          e,
+                          program,
+                          extra));
+        }
+        Err(e) => fail(&format!("failed to execute command: {}", e)),
+    };
+    println!("{:?}", status);
+    if !status.success() {
+        fail(&format!("command did not execute successfully, got: {}", status));
+    }
+    stdout
+}
+
+fn fail(s: &str) -> ! {
+    println!("\n\n{}\n\n", s);
+    panic!()
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/gcc-0.3.42/src/registry.rs
@@ -0,0 +1,190 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::ffi::{OsString, OsStr};
+use std::io;
+use std::ops::RangeFrom;
+use std::os::raw;
+use std::os::windows::prelude::*;
+
+pub struct RegistryKey(Repr);
+
+type HKEY = *mut u8;
+type DWORD = u32;
+type LPDWORD = *mut DWORD;
+type LPCWSTR = *const u16;
+type LPWSTR = *mut u16;
+type LONG = raw::c_long;
+type PHKEY = *mut HKEY;
+type PFILETIME = *mut u8;
+type LPBYTE = *mut u8;
+type REGSAM = u32;
+
+const ERROR_SUCCESS: DWORD = 0;
+const ERROR_NO_MORE_ITEMS: DWORD = 259;
+const HKEY_LOCAL_MACHINE: HKEY = 0x80000002 as HKEY;
+const REG_SZ: DWORD = 1;
+const KEY_READ: DWORD = 0x20019;
+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 RegCloseKey(hKey: HKEY) -> LONG;
+}
+
+struct OwnedKey(HKEY);
+
+enum Repr {
+    Const(HKEY),
+    Owned(OwnedKey),
+}
+
+pub struct Iter<'a> {
+    idx: RangeFrom<DWORD>,
+    key: &'a RegistryKey,
+}
+
+unsafe impl Sync for Repr {}
+unsafe impl Send for Repr {}
+
+pub static LOCAL_MACHINE: RegistryKey = RegistryKey(Repr::Const(HKEY_LOCAL_MACHINE));
+
+impl RegistryKey {
+    fn raw(&self) -> HKEY {
+        match self.0 {
+            Repr::Const(val) => val,
+            Repr::Owned(ref val) => val.0,
+        }
+    }
+
+    pub fn open(&self, key: &OsStr) -> io::Result<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)
+        };
+        if err == ERROR_SUCCESS as LONG {
+            Ok(RegistryKey(Repr::Owned(OwnedKey(ret))))
+        } else {
+            Err(io::Error::from_raw_os_error(err as i32))
+        }
+    }
+
+    pub fn iter(&self) -> Iter {
+        Iter {
+            idx: 0..,
+            key: self,
+        }
+    }
+
+    pub fn query_str(&self, name: &str) -> io::Result<OsString> {
+        let name: &OsStr = name.as_ref();
+        let name = name.encode_wide().chain(Some(0)).collect::<Vec<_>>();
+        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);
+            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"));
+            }
+
+            // 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);
+            if err != ERROR_SUCCESS as LONG {
+                return Err(io::Error::from_raw_os_error(err as i32));
+            }
+            v.set_len(len as usize / 2);
+
+            // Some registry keys may have a terminating nul character, but
+            // we're not interested in that, so chop it off if it's there.
+            if v[v.len() - 1] == 0 {
+                v.pop();
+            }
+            Ok(OsString::from_wide(&v))
+        }
+    }
+}
+
+impl Drop for OwnedKey {
+    fn drop(&mut self) {
+        unsafe {
+            RegCloseKey(self.0);
+        }
+    }
+}
+
+impl<'a> Iterator for Iter<'a> {
+    type Item = io::Result<OsString>;
+
+    fn next(&mut self) -> Option<io::Result<OsString>> {
+        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 _);
+            if ret == ERROR_NO_MORE_ITEMS as LONG {
+                None
+            } else if ret != ERROR_SUCCESS as LONG {
+                Some(Err(io::Error::from_raw_os_error(ret as i32)))
+            } else {
+                v.set_len(len as usize);
+                Some(Ok(OsString::from_wide(&v)))
+            }
+        })
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/gcc-0.3.42/src/windows_registry.rs
@@ -0,0 +1,424 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! A helper module to probe the Windows Registry when looking for
+//! windows-specific tools.
+
+use std::process::Command;
+
+use Tool;
+
+macro_rules! otry {
+    ($expr:expr) => (match $expr {
+        Some(val) => val,
+        None => return None,
+    })
+}
+
+/// Attempts to find a tool within an MSVC installation using the Windows
+/// registry as a point to search from.
+///
+/// The `target` argument is the target that the tool should work for (e.g.
+/// compile or link for) and the `tool` argument is the tool to find (e.g.
+/// `cl.exe` or `link.exe`).
+///
+/// This function will return `None` if the tool could not be found, or it will
+/// return `Some(cmd)` which represents a command that's ready to execute the
+/// tool with the appropriate environment variables set.
+///
+/// Note that this function always returns `None` for non-MSVC targets.
+pub fn find(target: &str, tool: &str) -> Option<Command> {
+    find_tool(target, tool).map(|c| c.to_command())
+}
+
+/// Similar to the `find` function above, this function will attempt the same
+/// operation (finding a MSVC tool in a local install) but instead returns a
+/// `Tool` which may be introspected.
+#[cfg(not(windows))]
+pub fn find_tool(_target: &str, _tool: &str) -> Option<Tool> {
+    None
+}
+
+/// Documented above.
+#[cfg(windows)]
+pub fn find_tool(target: &str, tool: &str) -> Option<Tool> {
+    use std::env;
+    use std::ffi::OsString;
+    use std::mem;
+    use std::path::{Path, PathBuf};
+    use registry::{RegistryKey, LOCAL_MACHINE};
+
+    struct MsvcTool {
+        tool: PathBuf,
+        libs: Vec<PathBuf>,
+        path: Vec<PathBuf>,
+        include: Vec<PathBuf>,
+    }
+
+    impl MsvcTool {
+        fn new(tool: PathBuf) -> MsvcTool {
+            MsvcTool {
+                tool: tool,
+                libs: Vec::new(),
+                path: Vec::new(),
+                include: Vec::new(),
+            }
+        }
+
+        fn into_tool(self) -> Tool {
+            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);
+            add_env(&mut tool, "INCLUDE", include);
+            tool
+        }
+    }
+
+    // This logic is all tailored for MSVC, if we're not that then bail out
+    // early.
+    if !target.contains("msvc") {
+        return None;
+    }
+
+    // Looks like msbuild isn't located in the same location as other tools like
+    // cl.exe and lib.exe. To handle this we probe for it manually with
+    // dedicated registry keys.
+    if tool.contains("msbuild") {
+        return find_msbuild(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()))
+            .map(|path| Tool::new(path.into()));
+    }
+
+    // Ok, if we're here, now comes the fun part of the probing. Default shells
+    // or shells like MSYS aren't really configured to execute `cl.exe` and the
+    // various compiler tools shipped as part of Visual Studio. Here we try to
+    // first find the relevant tool, then we also have to be sure to fill in
+    // environment variables like `LIB`, `INCLUDE`, and `PATH` to ensure that
+    // the tool is actually usable.
+
+    return find_msvc_latest(tool, target, "15.0")
+        .or_else(|| find_msvc_latest(tool, target, "14.0"))
+        .or_else(|| find_msvc_12(tool, target))
+        .or_else(|| find_msvc_11(tool, target));
+
+    // For MSVC 14 or newer we need to find the Universal CRT as well as either
+    // the Windows 10 SDK or Windows 8.1 SDK.
+    fn find_msvc_latest(tool: &str, target: &str, ver: &str) -> Option<Tool> {
+        let vcdir = otry!(get_vc_dir(ver));
+        let mut tool = otry!(get_tool(tool, &vcdir, target));
+        let sub = otry!(lib_subdir(target));
+        let (ucrt, ucrt_version) = otry!(get_ucrt_dir());
+
+        let ucrt_include = ucrt.join("include").join(&ucrt_version);
+        tool.include.push(ucrt_include.join("ucrt"));
+
+        let ucrt_lib = ucrt.join("lib").join(&ucrt_version);
+        tool.libs.push(ucrt_lib.join("ucrt").join(sub));
+
+        if let Some((sdk, version)) = get_sdk10_dir() {
+            tool.path.push(sdk.join("bin").join(sub));
+            let sdk_lib = sdk.join("lib").join(&version);
+            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("winrt"));
+            tool.include.push(sdk_include.join("shared"));
+        } else if let Some(sdk) = get_sdk81_dir() {
+            tool.path.push(sdk.join("bin").join(sub));
+            let sdk_lib = sdk.join("lib").join("winv6.3");
+            tool.libs.push(sdk_lib.join("um").join(sub));
+            let sdk_include = sdk.join("include");
+            tool.include.push(sdk_include.join("um"));
+            tool.include.push(sdk_include.join("winrt"));
+            tool.include.push(sdk_include.join("shared"));
+        } else {
+            return None;
+        }
+        Some(tool.into_tool())
+    }
+
+    // For MSVC 12 we need to find the Windows 8.1 SDK.
+    fn find_msvc_12(tool: &str, target: &str) -> Option<Tool> {
+        let vcdir = otry!(get_vc_dir("12.0"));
+        let mut tool = otry!(get_tool(tool, &vcdir, target));
+        let sub = otry!(lib_subdir(target));
+        let sdk81 = otry!(get_sdk81_dir());
+        tool.path.push(sdk81.join("bin").join(sub));
+        let sdk_lib = sdk81.join("lib").join("winv6.3");
+        tool.libs.push(sdk_lib.join("um").join(sub));
+        let sdk_include = sdk81.join("include");
+        tool.include.push(sdk_include.join("shared"));
+        tool.include.push(sdk_include.join("um"));
+        tool.include.push(sdk_include.join("winrt"));
+        Some(tool.into_tool())
+    }
+
+    // For MSVC 11 we need to find the Windows 8 SDK.
+    fn find_msvc_11(tool: &str, target: &str) -> Option<Tool> {
+        let vcdir = otry!(get_vc_dir("11.0"));
+        let mut tool = otry!(get_tool(tool, &vcdir, target));
+        let sub = otry!(lib_subdir(target));
+        let sdk8 = otry!(get_sdk8_dir());
+        tool.path.push(sdk8.join("bin").join(sub));
+        let sdk_lib = sdk8.join("lib").join("win8");
+        tool.libs.push(sdk_lib.join("um").join(sub));
+        let sdk_include = sdk8.join("include");
+        tool.include.push(sdk_include.join("shared"));
+        tool.include.push(sdk_include.join("um"));
+        tool.include.push(sdk_include.join("winrt"));
+        Some(tool.into_tool())
+    }
+
+    fn add_env(tool: &mut Tool, env: &str, paths: Vec<PathBuf>) {
+        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()));
+    }
+
+    // Given a possible MSVC installation directory, we look for the linker and
+    // then add the MSVC library path.
+    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)))
+            .filter(|&(ref path, _)| path.is_file())
+            .map(|(path, host)| {
+                let mut tool = MsvcTool::new(path);
+                tool.path.push(host);
+                tool
+            })
+            .filter_map(|mut tool| {
+                let sub = otry!(vc_lib_subdir(target));
+                tool.libs.push(path.join("lib").join(sub));
+                tool.include.push(path.join("include"));
+                let atlmfc_path = path.join("atlmfc");
+                if atlmfc_path.exists() {
+                    tool.libs.push(atlmfc_path.join("lib").join(sub));
+                    tool.include.push(atlmfc_path.join("include"));
+                }
+                Some(tool)
+            })
+            .next()
+    }
+
+    // To find MSVC we look in a specific registry key for the version we are
+    // trying to find.
+    fn get_vc_dir(ver: &str) -> Option<PathBuf> {
+        let key = r"SOFTWARE\Microsoft\VisualStudio\SxS\VC7";
+        let key = otry!(LOCAL_MACHINE.open(key.as_ref()).ok());
+        let path = otry!(key.query_str(ver).ok());
+        Some(path.into())
+    }
+
+    // To find the Universal CRT we look in a specific registry key for where
+    // all the Universal CRTs are located and then sort them asciibetically to
+    // find the newest version. While this sort of sorting isn't ideal,  it is
+    // what vcvars does so that's good enough for us.
+    //
+    // Returns a pair of (root, version) for the ucrt dir if found
+    fn get_ucrt_dir() -> Option<(PathBuf, String)> {
+        let key = r"SOFTWARE\Microsoft\Windows Kits\Installed Roots";
+        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()
+                    .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());
+        let version = max_libdir.components().last().unwrap();
+        let version = version.as_os_str().to_str().unwrap().to_string();
+        Some((root.into(), version))
+    }
+
+    // Vcvars finds the correct version of the Windows 10 SDK by looking
+    // for the include `um\Windows.h` because sometimes a given version will
+    // only have UCRT bits without the rest of the SDK. Since we only care about
+    // libraries and not includes, we instead look for `um\x64\kernel32.lib`.
+    // Since the 32-bit and 64-bit libraries are always installed together we
+    // only need to bother checking x64, making this code a tiny bit simpler.
+    // Like we do for the Universal CRT, we sort the possibilities
+    // asciibetically to find the newest one as that is what vcvars does.
+    fn get_sdk10_dir() -> Option<(PathBuf, String)> {
+        let key = r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0";
+        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())
+            .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 version = dir.components().last().unwrap();
+        let version = version.as_os_str().to_str().unwrap().to_string();
+        Some((root.into(), version))
+    }
+
+    // Interestingly there are several subdirectories, `win7` `win8` and
+    // `winv6.3`. Vcvars seems to only care about `winv6.3` though, so the same
+    // applies to us. Note that if we were targetting kernel mode drivers
+    // instead of user mode applications, we would care.
+    fn get_sdk81_dir() -> Option<PathBuf> {
+        let key = r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v8.1";
+        let key = otry!(LOCAL_MACHINE.open(key.as_ref()).ok());
+        let root = otry!(key.query_str("InstallationFolder").ok());
+        Some(root.into())
+    }
+
+    fn get_sdk8_dir() -> Option<PathBuf> {
+        let key = r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v8.0";
+        let key = otry!(LOCAL_MACHINE.open(key.as_ref()).ok());
+        let root = otry!(key.query_str("InstallationFolder").ok());
+        Some(root.into())
+    }
+
+    const PROCESSOR_ARCHITECTURE_INTEL: u16 = 0;
+    const PROCESSOR_ARCHITECTURE_AMD64: u16 = 9;
+    const X86: u16 = PROCESSOR_ARCHITECTURE_INTEL;
+    const X86_64: u16 = PROCESSOR_ARCHITECTURE_AMD64;
+
+    // When choosing the tool to use, we have to choose the one which matches
+    // the target architecture. Otherwise we end up in situations where someone
+    // on 32-bit Windows is trying to cross compile to 64-bit and it tries to
+    // invoke the native 64-bit compiler which won't work.
+    //
+    // For the return value of this function, the first member of the tuple is
+    // the folder of the tool we will be invoking, while the second member is
+    // the folder of the host toolchain for that tool which is essential when
+    // using a cross linker. We return a Vec since on x64 there are often two
+    // linkers that can target the architecture we desire. The 64-bit host
+    // linker is preferred, and hence first, due to 64-bit allowing it more
+    // address space to work with and potentially being faster.
+    fn bin_subdir(target: &str) -> Vec<(&'static str, &'static str)> {
+        let arch = target.split('-').next().unwrap();
+        match (arch, host_arch()) {
+            ("i586", X86) | ("i686", X86) => vec![("", "")],
+            ("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", "")],
+            _ => vec![],
+        }
+    }
+
+    fn lib_subdir(target: &str) -> Option<&'static str> {
+        let arch = target.split('-').next().unwrap();
+        match arch {
+            "i586" | "i686" => Some("x86"),
+            "x86_64" => Some("x64"),
+            "arm" => Some("arm"),
+            _ => None,
+        }
+    }
+
+    // MSVC's x86 libraries are not in a subfolder
+    fn vc_lib_subdir(target: &str) -> Option<&'static str> {
+        let arch = target.split('-').next().unwrap();
+        match arch {
+            "i586" | "i686" => Some(""),
+            "x86_64" => Some("amd64"),
+            "arm" => Some("arm"),
+            _ => None,
+        }
+    }
+
+    #[allow(bad_style)]
+    fn host_arch() -> u16 {
+        type DWORD = u32;
+        type WORD = u16;
+        type LPVOID = *mut u8;
+        type DWORD_PTR = usize;
+
+        #[repr(C)]
+        struct SYSTEM_INFO {
+            wProcessorArchitecture: WORD,
+            _wReserved: WORD,
+            _dwPageSize: DWORD,
+            _lpMinimumApplicationAddress: LPVOID,
+            _lpMaximumApplicationAddress: LPVOID,
+            _dwActiveProcessorMask: DWORD_PTR,
+            _dwNumberOfProcessors: DWORD,
+            _dwProcessorType: DWORD,
+            _dwAllocationGranularity: DWORD,
+            _wProcessorLevel: WORD,
+            _wProcessorRevision: WORD,
+        }
+
+        extern "system" {
+            fn GetNativeSystemInfo(lpSystemInfo: *mut SYSTEM_INFO);
+        }
+
+        unsafe {
+            let mut info = mem::zeroed();
+            GetNativeSystemInfo(&mut info);
+            info.wProcessorArchitecture
+        }
+    }
+
+    // Given a registry key, look at all the sub keys and find the one which has
+    // the maximal numeric value.
+    //
+    // Returns the name of the maximal key as well as the opened maximal key.
+    fn max_version(key: &RegistryKey) -> Option<(OsString, RegistryKey)> {
+        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()
+                .and_then(|s| s.trim_left_matches("v").replace(".", "").parse().ok());
+            let val = match val {
+                Some(s) => s,
+                None => continue,
+            };
+            if val > max_vers {
+                if let Ok(k) = key.open(&subkey) {
+                    max_vers = val;
+                    max_key = Some((subkey, k));
+                }
+            }
+        }
+        max_key
+    }
+
+    // see http://stackoverflow.com/questions/328017/path-to-msbuild
+    fn find_msbuild(target: &str) -> Option<Tool> {
+        let key = r"SOFTWARE\Microsoft\MSBuild\ToolsVersions";
+        LOCAL_MACHINE.open(key.as_ref())
+            .ok()
+            .and_then(|key| {
+                max_version(&key).and_then(|(_vers, key)| key.query_str("MSBuildToolsPath").ok())
+            })
+            .map(|path| {
+                let mut path = PathBuf::from(path);
+                path.push("MSBuild.exe");
+                let mut tool = Tool::new(path);
+                if target.contains("x86_64") {
+                    tool.env.push(("Platform".into(), "X64".into()));
+                }
+                tool
+            })
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/gcc-0.3.42/tests/cc_env.rs
@@ -0,0 +1,49 @@
+extern crate tempdir;
+extern crate gcc;
+
+use std::env;
+
+mod support;
+use support::Test;
+
+#[test]
+fn main() {
+    ccache();
+    distcc();
+    ccache_spaces();
+}
+
+fn ccache() {
+    let test = Test::gnu();
+    test.shim("ccache");
+
+    env::set_var("CC", "ccache lol-this-is-not-a-compiler foo");
+    test.gcc().file("foo.c").compile("libfoo.a");
+
+    test.cmd(0)
+        .must_have("lol-this-is-not-a-compiler foo")
+        .must_have("foo.c")
+        .must_not_have("ccache");
+}
+
+fn ccache_spaces() {
+    let test = Test::gnu();
+    test.shim("ccache");
+
+    env::set_var("CC", "ccache        lol-this-is-not-a-compiler foo");
+    test.gcc().file("foo.c").compile("libfoo.a");
+    test.cmd(0).must_have("lol-this-is-not-a-compiler foo");
+}
+
+fn distcc() {
+    let test = Test::gnu();
+    test.shim("distcc");
+
+    env::set_var("CC", "distcc lol-this-is-not-a-compiler foo");
+    test.gcc().file("foo.c").compile("libfoo.a");
+
+    test.cmd(0)
+        .must_have("lol-this-is-not-a-compiler foo")
+        .must_have("foo.c")
+        .must_not_have("distcc");
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/gcc-0.3.42/tests/support/mod.rs
@@ -0,0 +1,112 @@
+#![allow(dead_code)]
+
+use std::env;
+use std::ffi::OsStr;
+use std::fs::{self, File};
+use std::io::prelude::*;
+use std::path::PathBuf;
+
+use gcc;
+use tempdir::TempDir;
+
+pub struct Test {
+    pub td: TempDir,
+    pub gcc: PathBuf,
+    pub msvc: bool,
+}
+
+pub struct Execution {
+    args: Vec<String>,
+}
+
+impl Test {
+    pub fn new() -> Test {
+        let mut gcc = PathBuf::from(env::current_exe().unwrap());
+        gcc.pop();
+        if gcc.ends_with("deps") {
+            gcc.pop();
+        }
+        gcc.push(format!("gcc-shim{}", env::consts::EXE_SUFFIX));
+        Test {
+            td: TempDir::new("gcc-test").unwrap(),
+            gcc: gcc,
+            msvc: false,
+        }
+    }
+
+    pub fn gnu() -> Test {
+        let t = Test::new();
+        t.shim("cc").shim("ar");
+        t
+    }
+
+    pub fn msvc() -> Test {
+        let mut t = Test::new();
+        t.shim("cl").shim("lib.exe");
+        t.msvc = true;
+        t
+    }
+
+    pub fn shim(&self, name: &str) -> &Test {
+        let fname = format!("{}{}", name, env::consts::EXE_SUFFIX);
+        fs::hard_link(&self.gcc, self.td.path().join(&fname))
+            .or_else(|_| fs::copy(&self.gcc, self.td.path().join(&fname)).map(|_| ()))
+            .unwrap();
+        self
+    }
+
+    pub fn gcc(&self) -> gcc::Config {
+        let mut cfg = gcc::Config::new();
+        let mut path = env::split_paths(&env::var_os("PATH").unwrap()).collect::<Vec<_>>();
+        path.insert(0, self.td.path().to_owned());
+        let target = if self.msvc {
+            "x86_64-pc-windows-msvc"
+        } else {
+            "x86_64-unknown-linux-gnu"
+        };
+
+        cfg.target(target)
+            .host(target)
+            .opt_level(2)
+            .debug(false)
+            .out_dir(self.td.path())
+            .__set_env("PATH", env::join_paths(path).unwrap())
+            .__set_env("GCCTEST_OUT_DIR", self.td.path());
+        if self.msvc {
+            cfg.compiler(self.td.path().join("cl"));
+            cfg.archiver(self.td.path().join("lib.exe"));
+        }
+        cfg
+    }
+
+    pub fn cmd(&self, i: u32) -> Execution {
+        let mut s = String::new();
+        File::open(self.td.path().join(format!("out{}", i)))
+            .unwrap()
+            .read_to_string(&mut s)
+            .unwrap();
+        Execution { args: s.lines().map(|s| s.to_string()).collect() }
+    }
+}
+
+impl Execution {
+    pub fn must_have<P: AsRef<OsStr>>(&self, p: P) -> &Execution {
+        if !self.has(p.as_ref()) {
+            panic!("didn't find {:?} in {:?}", p.as_ref(), self.args);
+        } else {
+            self
+        }
+    }
+
+    pub fn must_not_have<P: AsRef<OsStr>>(&self, p: P) -> &Execution {
+        if self.has(p.as_ref()) {
+            panic!("found {:?}", p.as_ref());
+        } else {
+            self
+        }
+    }
+
+    pub fn has(&self, p: &OsStr) -> bool {
+        self.args.iter().any(|arg| OsStr::new(arg) == p)
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/gcc-0.3.42/tests/test.rs
@@ -0,0 +1,230 @@
+extern crate gcc;
+extern crate tempdir;
+
+use support::Test;
+
+mod support;
+
+#[test]
+fn gnu_smoke() {
+    let test = Test::gnu();
+    test.gcc()
+        .file("foo.c")
+        .compile("libfoo.a");
+
+    test.cmd(0)
+        .must_have("-O2")
+        .must_have("foo.c")
+        .must_not_have("-g")
+        .must_have("-c")
+        .must_have("-ffunction-sections")
+        .must_have("-fdata-sections");
+    test.cmd(1).must_have(test.td.path().join("foo.o"));
+}
+
+#[test]
+fn gnu_opt_level_1() {
+    let test = Test::gnu();
+    test.gcc()
+        .opt_level(1)
+        .file("foo.c")
+        .compile("libfoo.a");
+
+    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("libfoo.a");
+
+    test.cmd(0)
+        .must_have("-Os")
+        .must_not_have("-O1")
+        .must_not_have("-O2")
+        .must_not_have("-O3")
+        .must_not_have("-Oz");
+}
+
+#[test]
+fn gnu_debug() {
+    let test = Test::gnu();
+    test.gcc()
+        .debug(true)
+        .file("foo.c")
+        .compile("libfoo.a");
+    test.cmd(0).must_have("-g");
+}
+
+#[test]
+fn gnu_x86_64() {
+    for vendor in &["unknown-linux-gnu", "apple-darwin"] {
+        let target = format!("x86_64-{}", vendor);
+        let test = Test::gnu();
+        test.gcc()
+            .target(&target)
+            .host(&target)
+            .file("foo.c")
+            .compile("libfoo.a");
+
+        test.cmd(0)
+            .must_have("-fPIC")
+            .must_have("-m64");
+    }
+}
+
+#[test]
+fn gnu_x86_64_no_pic() {
+    for vendor in &["unknown-linux-gnu", "apple-darwin"] {
+        let target = format!("x86_64-{}", vendor);
+        let test = Test::gnu();
+        test.gcc()
+            .pic(false)
+            .target(&target)
+            .host(&target)
+            .file("foo.c")
+            .compile("libfoo.a");
+
+        test.cmd(0).must_not_have("-fPIC");
+    }
+}
+
+#[test]
+fn gnu_i686() {
+    for vendor in &["unknown-linux-gnu", "apple-darwin"] {
+        let target = format!("i686-{}", vendor);
+        let test = Test::gnu();
+        test.gcc()
+            .target(&target)
+            .host(&target)
+            .file("foo.c")
+            .compile("libfoo.a");
+
+        test.cmd(0)
+            .must_not_have("-fPIC")
+            .must_have("-m32");
+    }
+}
+
+#[test]
+fn gnu_i686_pic() {
+    for vendor in &["unknown-linux-gnu", "apple-darwin"] {
+        let target = format!("i686-{}", vendor);
+        let test = Test::gnu();
+        test.gcc()
+            .pic(true)
+            .target(&target)
+            .host(&target)
+            .file("foo.c")
+            .compile("libfoo.a");
+
+        test.cmd(0).must_have("-fPIC");
+    }
+}
+
+#[test]
+fn gnu_set_stdlib() {
+    let test = Test::gnu();
+    test.gcc()
+        .cpp_set_stdlib(Some("foo"))
+        .file("foo.c")
+        .compile("libfoo.a");
+
+    test.cmd(0).must_not_have("-stdlib=foo");
+}
+
+#[test]
+fn gnu_include() {
+    let test = Test::gnu();
+    test.gcc()
+        .include("foo/bar")
+        .file("foo.c")
+        .compile("libfoo.a");
+
+    test.cmd(0).must_have("-I").must_have("foo/bar");
+}
+
+#[test]
+fn gnu_define() {
+    let test = Test::gnu();
+    test.gcc()
+        .define("FOO", Some("bar"))
+        .define("BAR", None)
+        .file("foo.c")
+        .compile("libfoo.a");
+
+    test.cmd(0).must_have("-DFOO=bar").must_have("-DBAR");
+}
+
+#[test]
+fn gnu_compile_assembly() {
+    let test = Test::gnu();
+    test.gcc()
+        .file("foo.S")
+        .compile("libfoo.a");
+    test.cmd(0).must_have("foo.S");
+}
+
+#[test]
+fn msvc_smoke() {
+    let test = Test::msvc();
+    test.gcc()
+        .file("foo.c")
+        .compile("libfoo.a");
+
+    test.cmd(0)
+        .must_have("/O2")
+        .must_have("foo.c")
+        .must_not_have("/Z7")
+        .must_have("/c");
+    test.cmd(1).must_have(test.td.path().join("foo.o"));
+}
+
+#[test]
+fn msvc_opt_level_0() {
+    let test = Test::msvc();
+    test.gcc()
+        .opt_level(0)
+        .file("foo.c")
+        .compile("libfoo.a");
+
+    test.cmd(0).must_not_have("/O2");
+}
+
+#[test]
+fn msvc_debug() {
+    let test = Test::msvc();
+    test.gcc()
+        .debug(true)
+        .file("foo.c")
+        .compile("libfoo.a");
+    test.cmd(0).must_have("/Z7");
+}
+
+#[test]
+fn msvc_include() {
+    let test = Test::msvc();
+    test.gcc()
+        .include("foo/bar")
+        .file("foo.c")
+        .compile("libfoo.a");
+
+    test.cmd(0).must_have("/I").must_have("foo/bar");
+}
+
+#[test]
+fn msvc_define() {
+    let test = Test::msvc();
+    test.gcc()
+        .define("FOO", Some("bar"))
+        .define("BAR", None)
+        .file("foo.c")
+        .compile("libfoo.a");
+
+    test.cmd(0).must_have("/DFOO=bar").must_have("/DBAR");
+}