Auto merge of #39523 - alexcrichton:fpic, r=aturon

Pass -fPIC to native compiles on 32-bit

This is apparently a regression from 1.14.0 to 1.15.0. Previously we
passed `-fPIC` to C compilers on i686 targets, but the `gcc` crate
apparently [explicitly] didn't do this. I don't recall why that was
avoided but it was [previously passed by the makefiles][mk] and this
seems to have [caused a regression][regression] in Firefox, so this
commit reverts back to passing `-fPIC`.

[explicitly]: https://github.com/alexcrichton/gcc-rs/commit/362bdf20
[mk]: https://github.com/rust-lang/rust/blob/c781fc4a/mk/cfg/i686-unknown-linux-gnu.mk#L11
[regression]: https://bugzilla.mozilla.org/show_bug.cgi?id=1336155
This commit is contained in:
bors 2017-02-08 20:49:24 +00:00
commit 29dece1c8b
12 changed files with 601 additions and 429 deletions

20
src/Cargo.lock generated
View File

@ -19,7 +19,7 @@ version = "0.0.0"
dependencies = [ dependencies = [
"build_helper 0.1.0", "build_helper 0.1.0",
"core 0.0.0", "core 0.0.0",
"gcc 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.0.0", "libc 0.0.0",
] ]
@ -42,7 +42,7 @@ dependencies = [
"build_helper 0.1.0", "build_helper 0.1.0",
"cmake 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", "cmake 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
"filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)",
"getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)",
@ -74,7 +74,7 @@ name = "cmake"
version = "0.1.18" version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"gcc 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -91,7 +91,7 @@ name = "compiler_builtins"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"core 0.0.0", "core 0.0.0",
"gcc 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -133,7 +133,7 @@ name = "flate"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"build_helper 0.1.0", "build_helper 0.1.0",
"gcc 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -142,7 +142,7 @@ version = "0.0.0"
[[package]] [[package]]
name = "gcc" name = "gcc"
version = "0.3.40" version = "0.3.43"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
@ -406,7 +406,7 @@ name = "rustc_llvm"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"build_helper 0.1.0", "build_helper 0.1.0",
"gcc 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_bitflags 0.0.0", "rustc_bitflags 0.0.0",
] ]
@ -549,7 +549,7 @@ version = "0.0.0"
dependencies = [ dependencies = [
"arena 0.0.0", "arena 0.0.0",
"build_helper 0.1.0", "build_helper 0.1.0",
"gcc 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.0.0", "log 0.0.0",
"rustc 0.0.0", "rustc 0.0.0",
"rustc_back 0.0.0", "rustc_back 0.0.0",
@ -581,7 +581,7 @@ dependencies = [
"collections 0.0.0", "collections 0.0.0",
"compiler_builtins 0.0.0", "compiler_builtins 0.0.0",
"core 0.0.0", "core 0.0.0",
"gcc 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.0.0", "libc 0.0.0",
"panic_abort 0.0.0", "panic_abort 0.0.0",
"panic_unwind 0.0.0", "panic_unwind 0.0.0",
@ -671,7 +671,7 @@ dependencies = [
"checksum cmake 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0e5bcf27e097a184c1df4437654ed98df3d7a516e8508a6ba45d8b092bbdf283" "checksum cmake 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0e5bcf27e097a184c1df4437654ed98df3d7a516e8508a6ba45d8b092bbdf283"
"checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f" "checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f"
"checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922" "checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922"
"checksum gcc 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)" = "872db9e59486ef2b14f8e8c10e9ef02de2bccef6363d7f34835dedb386b3d950" "checksum gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)" = "c07c758b972368e703a562686adb39125707cc1ef3399da8c019fc6c2498a75d"
"checksum getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9047cfbd08a437050b363d35ef160452c5fe8ea5187ae0a624708c91581d685" "checksum getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9047cfbd08a437050b363d35ef160452c5fe8ea5187ae0a624708c91581d685"
"checksum libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "044d1360593a78f5c8e5e710beccdc24ab71d1f01bc19a29bcacdba22e8475d8" "checksum libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "044d1360593a78f5c8e5e710beccdc24ab71d1f01bc19a29bcacdba22e8475d8"
"checksum log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ab83497bf8bf4ed2a74259c1c802351fcd67a65baa86394b6ba73c36f4838054" "checksum log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ab83497bf8bf4ed2a74259c1c802351fcd67a65baa86394b6ba73c36f4838054"

View File

@ -1 +1 @@
{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".gitignore":"f9b1ca6ae27d1c18215265024629a8960c31379f206d9ed20f64e0b2dcf79805",".travis.yml":"675ffe583db77282d010306f29e6d81e5070ab081deddd0300137dfbd2cb83de","Cargo.toml":"19bb617b74de761515ef5d087fd0e30912fda1d7c22fd04fa211236dab99a509","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"ecb2d93f4c81edbd48d8742ff7887dc0a4530a5890967839090bbc972d49bebe","appveyor.yml":"46c77d913eaa45871296942c2cd96ef092c9dcaf19201cb5c500a5107faeb06f","src/bin/gcc-shim.rs":"11edfe1fc6f932bd42ffffda5145833302bc163e0b87dc0d54f4bd0997ad4708","src/lib.rs":"7e7c60beccfdd145e876da81bb07dd09c5248dab0b26d93190bab4242799d51a","src/registry.rs":"3e2a42581ebb82e325dd5600c6571cef937b35003b2927dc618967f5238a2058","src/windows_registry.rs":"1f4211caec5a192b5f05c8a47efb27aa6a0ab976c659b9318a0cf603a28d6746","tests/cc_env.rs":"d92c5e3d3d43ac244e63b2cd2c93a521fcf124bf1ccf8d4c6bfa7f8333d88976","tests/support/mod.rs":"f4dad5a8133c3dd6678d9a3de057b82e624ef547b9b3e4ac9508a48962fc387b","tests/test.rs":"164220f11be2eebc20315826513999970660a82feff8cc4b15b4e9d73d98324e"},"package":"872db9e59486ef2b14f8e8c10e9ef02de2bccef6363d7f34835dedb386b3d950"} {"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".gitignore":"4cc6445feac7e9a1f8f1e1c51cc3afd0cf7bb931e3c5a6f18c41258401652702",".travis.yml":"e68f9d10a8e367890cf734239c39952ee480cf0e8da9520b377df4a2b8ccc9e8","Cargo.toml":"4c5eb683d4c57fff819ebf564a8db93b5c87284993def6bc066ba1e311d5b090","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"b1a639560fd536f2c3ab708a8e1066b675edd4d018dfa4e5e18d0d7327d81c15","appveyor.yml":"46c77d913eaa45871296942c2cd96ef092c9dcaf19201cb5c500a5107faeb06f","src/bin/gcc-shim.rs":"d6be9137cb48b86891e7b263adbf492e1193ffe682db9ba4a88eb1079b874b58","src/lib.rs":"eb4ca086dd2ffa5e30f022f556d0def6d1142160da392afb328393b3f435e8f7","src/registry.rs":"3876ef9573e3bbc050aef41a684b9a510cc1a91b15ae874fe032cf4377b4d116","src/windows_registry.rs":"36c6a7f8322407faff2dcfd4789d0876d034885944bc0340ac7c1f7cbfc307f1","tests/cc_env.rs":"d92c5e3d3d43ac244e63b2cd2c93a521fcf124bf1ccf8d4c6bfa7f8333d88976","tests/support/mod.rs":"56bcfd1e2ff5ae8e581c71229444a3d96094bf689808808dd80e315bd6632083","tests/test.rs":"b63e74d571e7d585edc53693bcf0caae88fc040613ace91e32437d4a62cddb6a"},"package":"c07c758b972368e703a562686adb39125707cc1ef3399da8c019fc6c2498a75d"}

View File

@ -1,2 +1,4 @@
target target
Cargo.lock Cargo.lock
.idea
*.iml

View File

@ -3,6 +3,13 @@ rust:
- stable - stable
- beta - beta
- nightly - nightly
matrix:
include:
# Minimum version supported
- rust: 1.6.0
install:
script: cargo build
sudo: false sudo: false
install: install:
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then OS=unknown-linux-gnu; else OS=apple-darwin; fi - if [ "$TRAVIS_OS_NAME" = "linux" ]; then OS=unknown-linux-gnu; else OS=apple-darwin; fi

View File

@ -1,11 +1,11 @@
[package] [package]
name = "gcc" name = "gcc"
version = "0.3.40" version = "0.3.43"
authors = ["Alex Crichton <alex@alexcrichton.com>"] authors = ["Alex Crichton <alex@alexcrichton.com>"]
license = "MIT/Apache-2.0" license = "MIT/Apache-2.0"
repository = "https://github.com/alexcrichton/gcc-rs" repository = "https://github.com/alexcrichton/gcc-rs"
documentation = "http://alexcrichton.com/gcc-rs" documentation = "https://docs.rs/gcc"
description = """ description = """
A build-time dependency for Cargo build scripts to assist in invoking the native 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 C compiler to compile native C code into a static archive to be linked into Rust
@ -13,8 +13,12 @@ code.
""" """
keywords = ["build-dependencies"] keywords = ["build-dependencies"]
[badges]
travis-ci = { repository = "alexcrichton/gcc-rs" }
appveyor = { repository = "alexcrichton/gcc-rs" }
[dependencies] [dependencies]
rayon = { version = "0.4", optional = true } rayon = { version = "0.6", optional = true }
[features] [features]
parallel = ["rayon"] parallel = ["rayon"]

View File

@ -5,7 +5,7 @@ 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://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) [![Build status](https://ci.appveyor.com/api/projects/status/onu270iw98h81nwv?svg=true)](https://ci.appveyor.com/project/alexcrichton/gcc-rs)
[Documentation](http://alexcrichton.com/gcc-rs) [Documentation](https://docs.rs/gcc)
A simple library meant to be used as a build dependency with Cargo packages in 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 order to build a set of C/C++ files into a static archive. Note that while this
@ -106,7 +106,9 @@ gcc = { version = "0.3", features = ["parallel"] }
``` ```
By default gcc-rs will limit parallelism to `$NUM_JOBS`, or if not present it 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. will limit it to the number of cpus on the machine. If you are using cargo,
use `-jN` option of `build`, `test` and `run` commands as `$NUM_JOBS`
is supplied by cargo.
## Compile-time Requirements ## Compile-time Requirements

View File

@ -10,7 +10,7 @@ fn main() {
for i in 0.. { for i in 0.. {
let candidate = out_dir.join(format!("out{}", i)); let candidate = out_dir.join(format!("out{}", i));
if candidate.exists() { if candidate.exists() {
continue continue;
} }
let mut f = File::create(candidate).unwrap(); let mut f = File::create(candidate).unwrap();
for arg in env::args().skip(1) { for arg in env::args().skip(1) {
@ -18,6 +18,6 @@ fn main() {
} }
File::create(out_dir.join("libfoo.a")).unwrap(); File::create(out_dir.join("libfoo.a")).unwrap();
break break;
} }
} }

View File

@ -42,7 +42,7 @@
//! } //! }
//! ``` //! ```
#![doc(html_root_url = "http://alexcrichton.com/gcc-rs")] #![doc(html_root_url = "https://docs.rs/gcc/0.3")]
#![cfg_attr(test, deny(warnings))] #![cfg_attr(test, deny(warnings))]
#![deny(missing_docs)] #![deny(missing_docs)]
@ -52,10 +52,10 @@ extern crate rayon;
use std::env; use std::env;
use std::ffi::{OsString, OsStr}; use std::ffi::{OsString, OsStr};
use std::fs; use std::fs;
use std::io;
use std::path::{PathBuf, Path}; use std::path::{PathBuf, Path};
use std::process::{Command, Stdio}; use std::process::{Command, Stdio};
use std::io::{BufReader, BufRead, Write}; use std::io::{self, BufReader, BufRead, Read, Write};
use std::thread;
#[cfg(windows)] #[cfg(windows)]
mod registry; mod registry;
@ -94,6 +94,52 @@ pub struct Tool {
path: PathBuf, path: PathBuf,
args: Vec<OsString>, args: Vec<OsString>,
env: Vec<(OsString, 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. /// Compile a library from the given set of input C files.
@ -114,7 +160,7 @@ pub fn compile_library(output: &str, files: &[&str]) {
for f in files.iter() { for f in files.iter() {
c.file(*f); c.file(*f);
} }
c.compile(output) c.compile(output);
} }
impl Config { impl Config {
@ -194,8 +240,7 @@ impl Config {
/// otherwise cargo will link against the specified library. /// otherwise cargo will link against the specified library.
/// ///
/// The given library name must not contain the `lib` prefix. /// The given library name must not contain the `lib` prefix.
pub fn cpp_link_stdlib(&mut self, cpp_link_stdlib: Option<&str>) pub fn cpp_link_stdlib(&mut self, cpp_link_stdlib: Option<&str>) -> &mut Config {
-> &mut Config {
self.cpp_link_stdlib = Some(cpp_link_stdlib.map(|s| s.into())); self.cpp_link_stdlib = Some(cpp_link_stdlib.map(|s| s.into()));
self self
} }
@ -220,8 +265,7 @@ impl Config {
/// be used, otherwise `-stdlib` is added to the compile invocation. /// be used, otherwise `-stdlib` is added to the compile invocation.
/// ///
/// The given library name must not contain the `lib` prefix. /// The given library name must not contain the `lib` prefix.
pub fn cpp_set_stdlib(&mut self, cpp_set_stdlib: Option<&str>) pub fn cpp_set_stdlib(&mut self, cpp_set_stdlib: Option<&str>) -> &mut Config {
-> &mut Config {
self.cpp_set_stdlib = cpp_set_stdlib.map(|s| s.into()); self.cpp_set_stdlib = cpp_set_stdlib.map(|s| s.into());
self.cpp_link_stdlib(cpp_set_stdlib); self.cpp_link_stdlib(cpp_set_stdlib);
self self
@ -322,7 +366,8 @@ impl Config {
#[doc(hidden)] #[doc(hidden)]
pub fn __set_env<A, B>(&mut self, a: A, b: B) -> &mut Config pub fn __set_env<A, B>(&mut self, a: A, b: B) -> &mut Config
where A: AsRef<OsStr>, B: AsRef<OsStr> where A: AsRef<OsStr>,
B: AsRef<OsStr>
{ {
self.env.push((a.as_ref().to_owned(), b.as_ref().to_owned())); self.env.push((a.as_ref().to_owned(), b.as_ref().to_owned()));
self self
@ -355,18 +400,18 @@ impl Config {
if self.get_target().contains("msvc") { if self.get_target().contains("msvc") {
let compiler = self.get_base_compiler(); let compiler = self.get_base_compiler();
let atlmfc_lib = compiler.env().iter().find(|&&(ref var, _)| { let atlmfc_lib = compiler.env()
var == OsStr::new("LIB") .iter()
}).and_then(|&(_, ref lib_paths)| { .find(|&&(ref var, _)| var.as_os_str() == OsStr::new("LIB"))
env::split_paths(lib_paths).find(|path| { .and_then(|&(_, ref lib_paths)| {
let sub = Path::new("atlmfc/lib"); env::split_paths(lib_paths).find(|path| {
path.ends_with(sub) || path.parent().map_or(false, |p| p.ends_with(sub)) 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 { if let Some(atlmfc_lib) = atlmfc_lib {
self.print(&format!("cargo:rustc-link-search=native={}", self.print(&format!("cargo:rustc-link-search=native={}", atlmfc_lib.display()));
atlmfc_lib.display()));
} }
} }
@ -394,9 +439,7 @@ impl Config {
} }
drop(rayon::initialize(cfg)); drop(rayon::initialize(cfg));
objs.par_iter().weight_max().for_each(|&(ref src, ref dst)| { objs.par_iter().weight_max().for_each(|&(ref src, ref dst)| self.compile_object(src, dst));
self.compile_object(src, dst)
})
} }
#[cfg(not(feature = "parallel"))] #[cfg(not(feature = "parallel"))]
@ -417,8 +460,12 @@ impl Config {
for &(ref a, ref b) in self.env.iter() { for &(ref a, ref b) in self.env.iter() {
cmd.env(a, b); cmd.env(a, b);
} }
(cmd, compiler.path.file_name().unwrap() (cmd,
.to_string_lossy().into_owned()) compiler.path
.file_name()
.unwrap()
.to_string_lossy()
.into_owned())
}; };
if msvc && is_asm { if msvc && is_asm {
cmd.arg("/Fo").arg(dst); cmd.arg("/Fo").arg(dst);
@ -429,12 +476,35 @@ impl Config {
} else { } else {
cmd.arg("-o").arg(&dst); cmd.arg("-o").arg(&dst);
} }
cmd.arg(if msvc {"/c"} else {"-c"}); cmd.arg(if msvc { "/c" } else { "-c" });
cmd.arg(file); cmd.arg(file);
run(&mut cmd, &name); 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. /// Get the compiler that's in use for this configuration.
/// ///
/// This function will return a `Tool` which represents the culmination /// This function will return a `Tool` which represents the culmination
@ -451,136 +521,159 @@ impl Config {
/// falling back to the default configuration. /// falling back to the default configuration.
pub fn get_compiler(&self) -> Tool { pub fn get_compiler(&self) -> Tool {
let opt_level = self.get_opt_level(); let opt_level = self.get_opt_level();
let debug = self.get_debug();
let target = self.get_target(); let target = self.get_target();
let msvc = target.contains("msvc");
self.print(&format!("debug={} opt-level={}", debug, opt_level));
let mut cmd = self.get_base_compiler(); let mut cmd = self.get_base_compiler();
let nvcc = cmd.path.to_str() let nvcc = cmd.path.file_name()
.map(|path| path.contains("nvcc")) .and_then(|p| p.to_str()).map(|p| p.contains("nvcc"))
.unwrap_or(false); .unwrap_or(false);
if msvc { // Non-target flags
cmd.args.push("/nologo".into()); // If the flag is not conditioned on target variable, it belongs here :)
let features = env::var("CARGO_CFG_TARGET_FEATURE") match cmd.family {
.unwrap_or(String::new()); ToolFamily::Msvc => {
if features.contains("crt-static") { cmd.args.push("/nologo".into());
cmd.args.push("/MT".into()); let features = env::var("CARGO_CFG_TARGET_FEATURE")
} else { .unwrap_or(String::new());
cmd.args.push("/MD".into()); 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()),
_ => {}
}
} }
match &opt_level[..] { ToolFamily::Gnu |
"z" | "s" => cmd.args.push("/Os".into()), ToolFamily::Clang => {
"2" => cmd.args.push("/O2".into()), cmd.args.push(format!("-O{}", opt_level).into());
"1" => cmd.args.push("/O1".into()), if !nvcc {
_ => {} cmd.args.push("-ffunction-sections".into());
cmd.args.push("-fdata-sections".into());
if self.pic.unwrap_or(!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());
}
} }
if target.contains("i586") {
cmd.args.push("/ARCH:IA32".into());
}
} else if nvcc {
cmd.args.push(format!("-O{}", opt_level).into());
} else {
cmd.args.push(format!("-O{}", opt_level).into());
cmd.args.push("-ffunction-sections".into());
cmd.args.push("-fdata-sections".into());
} }
for arg in self.envflags(if self.cpp {"CXXFLAGS"} else {"CFLAGS"}) { for arg in self.envflags(if self.cpp {"CXXFLAGS"} else {"CFLAGS"}) {
cmd.args.push(arg.into()); cmd.args.push(arg.into());
} }
if debug { if self.get_debug() {
cmd.args.push(if msvc {"/Z7"} else {"-g"}.into()); 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") { 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); self.ios_flags(&mut cmd);
} else if !msvc {
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 !nvcc && self.pic.unwrap_or(!target.contains("i686") && !target.contains("windows-gnu")) {
cmd.args.push("-fPIC".into());
} else if nvcc && self.pic.unwrap_or(false) {
cmd.args.push("-Xcompiler".into());
cmd.args.push("\'-fPIC\'".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 self.cpp && !msvc { if self.cpp {
if let Some(ref stdlib) = self.cpp_set_stdlib { match (self.cpp_set_stdlib.as_ref(), cmd.family) {
cmd.args.push(format!("-stdlib=lib{}", stdlib).into()); (None, _) => { }
(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() { for directory in self.include_directories.iter() {
cmd.args.push(if msvc {"/I"} else {"-I"}.into()); cmd.args.push(cmd.family.include_flag().into());
cmd.args.push(directory.into()); cmd.args.push(directory.into());
} }
@ -589,7 +682,7 @@ impl Config {
} }
for &(ref key, ref value) in self.definitions.iter() { for &(ref key, ref value) in self.definitions.iter() {
let lead = if msvc {"/"} else {"-"}; let lead = if let ToolFamily::Msvc = cmd.family {"/"} else {"-"};
if let &Some(ref value) = value { if let &Some(ref value) = value {
cmd.args.push(format!("{}D{}={}", lead, key, value).into()); cmd.args.push(format!("{}D{}={}", lead, key, value).into());
} else { } else {
@ -601,10 +694,12 @@ impl Config {
fn msvc_macro_assembler(&self) -> (Command, String) { fn msvc_macro_assembler(&self) -> (Command, String) {
let target = self.get_target(); let target = self.get_target();
let tool = if target.contains("x86_64") {"ml64.exe"} else {"ml.exe"}; let tool = if target.contains("x86_64") {
let mut cmd = windows_registry::find(&target, tool).unwrap_or_else(|| { "ml64.exe"
self.cmd(tool) } else {
}); "ml.exe"
};
let mut cmd = windows_registry::find(&target, tool).unwrap_or_else(|| self.cmd(tool));
for directory in self.include_directories.iter() { for directory in self.include_directories.iter() {
cmd.arg("/I").arg(directory); cmd.arg("/I").arg(directory);
} }
@ -635,31 +730,37 @@ impl Config {
if target.contains("msvc") { if target.contains("msvc") {
let mut cmd = match self.archiver { let mut cmd = match self.archiver {
Some(ref s) => self.cmd(s), Some(ref s) => self.cmd(s),
None => windows_registry::find(&target, "lib.exe") None => windows_registry::find(&target, "lib.exe").unwrap_or(self.cmd("lib.exe")),
.unwrap_or(self.cmd("lib.exe")),
}; };
let mut out = OsString::from("/OUT:"); let mut out = OsString::from("/OUT:");
out.push(dst); out.push(dst);
run(cmd.arg(out).arg("/nologo") run(cmd.arg(out)
.args(objects) .arg("/nologo")
.args(&self.objects), "lib.exe"); .args(objects)
.args(&self.objects),
"lib.exe");
// The Rust compiler will look for libfoo.a and foo.lib, but the // 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 // MSVC linker will also be passed foo.lib, so be sure that both
// exist for now. // exist for now.
let lib_dst = dst.with_file_name(format!("{}.lib", lib_name)); let lib_dst = dst.with_file_name(format!("{}.lib", lib_name));
let _ = fs::remove_file(&lib_dst); let _ = fs::remove_file(&lib_dst);
fs::hard_link(&dst, &lib_dst).or_else(|_| { fs::hard_link(&dst, &lib_dst)
//if hard-link fails, just copy (ignoring the number of bytes written) .or_else(|_| {
fs::copy(&dst, &lib_dst).map(|_| ()) // if hard-link fails, just copy (ignoring the number of bytes written)
}).ok().expect("Copying from {:?} to {:?} failed.");; fs::copy(&dst, &lib_dst).map(|_| ())
})
.ok()
.expect("Copying from {:?} to {:?} failed.");;
} else { } else {
let ar = self.get_ar(); let ar = self.get_ar();
let cmd = ar.file_name().unwrap().to_string_lossy(); let cmd = ar.file_name().unwrap().to_string_lossy();
run(self.cmd(&ar).arg("crs") run(self.cmd(&ar)
.arg(dst) .arg("crs")
.args(objects) .arg(dst)
.args(&self.objects), &cmd); .args(objects)
.args(&self.objects),
&cmd);
} }
} }
@ -677,7 +778,7 @@ impl Config {
"arm64" | "aarch64" => ArchSpec::Device("arm64"), "arm64" | "aarch64" => ArchSpec::Device("arm64"),
"i386" | "i686" => ArchSpec::Simulator("-m32"), "i386" | "i686" => ArchSpec::Simulator("-m32"),
"x86_64" => ArchSpec::Simulator("-m64"), "x86_64" => ArchSpec::Simulator("-m64"),
_ => fail("Unknown arch for iOS target") _ => fail("Unknown arch for iOS target"),
}; };
let sdk = match arch { let sdk = match arch {
@ -686,7 +787,7 @@ impl Config {
cmd.args.push(arch.into()); cmd.args.push(arch.into());
cmd.args.push("-miphoneos-version-min=7.0".into()); cmd.args.push("-miphoneos-version-min=7.0".into());
"iphoneos" "iphoneos"
}, }
ArchSpec::Simulator(arch) => { ArchSpec::Simulator(arch) => {
cmd.args.push(arch.into()); cmd.args.push(arch.into());
cmd.args.push("-mios-simulator-version-min=7.0".into()); cmd.args.push("-mios-simulator-version-min=7.0".into());
@ -715,12 +816,12 @@ impl Config {
for &(ref a, ref b) in self.env.iter() { for &(ref a, ref b) in self.env.iter() {
cmd.env(a, b); cmd.env(a, b);
} }
return cmd return cmd;
} }
fn get_base_compiler(&self) -> Tool { fn get_base_compiler(&self) -> Tool {
if let Some(ref c) = self.compiler { if let Some(ref c) = self.compiler {
return Tool::new(c.clone()) return Tool::new(c.clone());
} }
let host = self.get_host(); let host = self.get_host();
let target = self.get_target(); let target = self.get_target();
@ -729,87 +830,88 @@ impl Config {
} else { } else {
("CC", "cl.exe", "gcc", "cc") ("CC", "cl.exe", "gcc", "cc")
}; };
self.env_tool(env).map(|(tool, args)| { self.env_tool(env)
let mut t = Tool::new(PathBuf::from(tool)); .map(|(tool, args)| {
for arg in args { let mut t = Tool::new(PathBuf::from(tool));
t.args.push(arg.into()); for arg in args {
} t.args.push(arg.into());
return t }
}).or_else(|| { return t;
if target.contains("emscripten") { })
if self.cpp { .or_else(|| {
Some(Tool::new(PathBuf::from("em++"))) if target.contains("emscripten") {
if self.cpp {
Some(Tool::new(PathBuf::from("em++")))
} else {
Some(Tool::new(PathBuf::from("emcc")))
}
} else { } else {
Some(Tool::new(PathBuf::from("emcc"))) None
} }
} else { })
None .or_else(|| windows_registry::find_tool(&target, "cl.exe"))
} .unwrap_or_else(|| {
}).or_else(|| { let compiler = if host.contains("windows") && target.contains("windows") {
windows_registry::find_tool(&target, "cl.exe") if target.contains("msvc") {
}).unwrap_or_else(|| { msvc.to_string()
let compiler = if host.contains("windows") && } else {
target.contains("windows") { format!("{}.exe", gnu)
if target.contains("msvc") { }
msvc.to_string() } 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 { } else {
format!("{}.exe", gnu) default.to_string()
} };
} else if target.contains("android") { Tool::new(PathBuf::from(compiler))
format!("{}-{}", target, 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> { fn get_var(&self, var_base: &str) -> Result<String, String> {
let target = self.get_target(); let target = self.get_target();
let host = self.get_host(); let host = self.get_host();
let kind = if host == target {"HOST"} else {"TARGET"}; let kind = if host == target { "HOST" } else { "TARGET" };
let target_u = target.replace("-", "_"); let target_u = target.replace("-", "_");
let res = self.getenv(&format!("{}_{}", var_base, target)) let res = self.getenv(&format!("{}_{}", var_base, target))
.or_else(|| self.getenv(&format!("{}_{}", var_base, target_u))) .or_else(|| self.getenv(&format!("{}_{}", var_base, target_u)))
@ -823,8 +925,10 @@ impl Config {
} }
fn envflags(&self, name: &str) -> Vec<String> { fn envflags(&self, name: &str) -> Vec<String> {
self.get_var(name).unwrap_or(String::new()) self.get_var(name)
.split(|c: char| c.is_whitespace()).filter(|s| !s.is_empty()) .unwrap_or(String::new())
.split(|c: char| c.is_whitespace())
.filter(|s| !s.is_empty())
.map(|s| s.to_string()) .map(|s| s.to_string())
.collect() .collect()
} }
@ -834,8 +938,7 @@ impl Config {
let whitelist = ["ccache", "distcc"]; let whitelist = ["ccache", "distcc"];
for t in whitelist.iter() { for t in whitelist.iter() {
if tool.starts_with(t) && tool[t.len()..].starts_with(" ") { if tool.starts_with(t) && tool[t.len()..].starts_with(" ") {
return (t.to_string(), return (t.to_string(), vec![tool[t.len()..].trim_left().to_string()]);
vec![tool[t.len()..].trim_left().to_string()])
} }
} }
(tool, Vec::new()) (tool, Vec::new())
@ -860,17 +963,18 @@ impl Config {
} }
fn get_ar(&self) -> PathBuf { fn get_ar(&self) -> PathBuf {
self.archiver.clone().or_else(|| { self.archiver
self.get_var("AR").map(PathBuf::from).ok() .clone()
}).unwrap_or_else(|| { .or_else(|| self.get_var("AR").map(PathBuf::from).ok())
if self.get_target().contains("android") { .unwrap_or_else(|| {
PathBuf::from(format!("{}-ar", self.get_target())) if self.get_target().contains("android") {
} else if self.get_target().contains("emscripten") { PathBuf::from(format!("{}-ar", self.get_target().replace("armv7", "arm")))
PathBuf::from("emar") } else if self.get_target().contains("emscripten") {
} else { PathBuf::from("emar")
PathBuf::from("ar") } else {
} PathBuf::from("ar")
}) }
})
} }
fn get_target(&self) -> String { fn get_target(&self) -> String {
@ -882,9 +986,7 @@ impl Config {
} }
fn get_opt_level(&self) -> String { fn get_opt_level(&self) -> String {
self.opt_level.as_ref().cloned().unwrap_or_else(|| { self.opt_level.as_ref().cloned().unwrap_or_else(|| self.getenv_unwrap("OPT_LEVEL"))
self.getenv_unwrap("OPT_LEVEL")
})
} }
fn get_debug(&self) -> bool { fn get_debug(&self) -> bool {
@ -892,9 +994,7 @@ impl Config {
} }
fn get_out_dir(&self) -> PathBuf { fn get_out_dir(&self) -> PathBuf {
self.out_dir.clone().unwrap_or_else(|| { self.out_dir.clone().unwrap_or_else(|| env::var_os("OUT_DIR").map(PathBuf::from).unwrap())
env::var_os("OUT_DIR").map(PathBuf::from).unwrap()
})
} }
fn getenv(&self, v: &str) -> Option<String> { fn getenv(&self, v: &str) -> Option<String> {
@ -919,10 +1019,23 @@ impl Config {
impl Tool { impl Tool {
fn new(path: PathBuf) -> 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 { Tool {
path: path, path: path,
args: Vec::new(), args: Vec::new(),
env: Vec::new(), env: Vec::new(),
family: family
} }
} }
@ -937,7 +1050,7 @@ impl Tool {
for &(ref k, ref v) in self.env.iter() { for &(ref k, ref v) in self.env.iter() {
cmd.env(k, v); cmd.env(k, v);
} }
return cmd cmd
} }
/// Returns the path for this compiler. /// Returns the path for this compiler.
@ -963,23 +1076,27 @@ impl Tool {
} }
} }
fn run(cmd: &mut Command, program: &str) { fn run(cmd: &mut Command, program: &str) -> Vec<u8> {
println!("running: {:?}", cmd); println!("running: {:?}", cmd);
// Capture the standard error coming from these programs, and write it out // 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 // 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 // requiring the output to be UTF-8, we instead just ship bytes from one
// location to another. // location to another.
let spawn_result = match cmd.stderr(Stdio::piped()).spawn() { let (spawn_result, stdout) = match cmd.stdout(Stdio::piped()).stderr(Stdio::piped()).spawn() {
Ok(mut child) => { Ok(mut child) => {
let stderr = BufReader::new(child.stderr.take().unwrap()); let stderr = BufReader::new(child.stderr.take().unwrap());
for line in stderr.split(b'\n').filter_map(|l| l.ok()) { thread::spawn(move || {
print!("cargo:warning="); for line in stderr.split(b'\n').filter_map(|l| l.ok()) {
std::io::stdout().write_all(&line).unwrap(); print!("cargo:warning=");
println!(""); std::io::stdout().write_all(&line).unwrap();
} println!("");
child.wait() }
});
let mut stdout = vec![];
child.stdout.take().unwrap().read_to_end(&mut stdout).unwrap();
(child.wait(), stdout)
} }
Err(e) => Err(e), Err(e) => (Err(e), vec![]),
}; };
let status = match spawn_result { let status = match spawn_result {
Ok(status) => status, Ok(status) => status,
@ -991,7 +1108,10 @@ fn run(cmd: &mut Command, program: &str) {
"" ""
}; };
fail(&format!("failed to execute command: {}\nIs `{}` \ fail(&format!("failed to execute command: {}\nIs `{}` \
not installed?{}", e, program, extra)); not installed?{}",
e,
program,
extra));
} }
Err(e) => fail(&format!("failed to execute command: {}", e)), Err(e) => fail(&format!("failed to execute command: {}", e)),
}; };
@ -999,6 +1119,7 @@ fn run(cmd: &mut Command, program: &str) {
if !status.success() { if !status.success() {
fail(&format!("command did not execute successfully, got: {}", status)); fail(&format!("command did not execute successfully, got: {}", status));
} }
stdout
} }
fn fail(s: &str) -> ! { fn fail(s: &str) -> ! {

View File

@ -40,7 +40,8 @@ extern "system" {
lpSubKey: LPCWSTR, lpSubKey: LPCWSTR,
ulOptions: DWORD, ulOptions: DWORD,
samDesired: REGSAM, samDesired: REGSAM,
phkResult: PHKEY) -> LONG; phkResult: PHKEY)
-> LONG;
fn RegEnumKeyExW(key: HKEY, fn RegEnumKeyExW(key: HKEY,
dwIndex: DWORD, dwIndex: DWORD,
lpName: LPWSTR, lpName: LPWSTR,
@ -48,13 +49,15 @@ extern "system" {
lpReserved: LPDWORD, lpReserved: LPDWORD,
lpClass: LPWSTR, lpClass: LPWSTR,
lpcClass: LPDWORD, lpcClass: LPDWORD,
lpftLastWriteTime: PFILETIME) -> LONG; lpftLastWriteTime: PFILETIME)
-> LONG;
fn RegQueryValueExW(hKey: HKEY, fn RegQueryValueExW(hKey: HKEY,
lpValueName: LPCWSTR, lpValueName: LPCWSTR,
lpReserved: LPDWORD, lpReserved: LPDWORD,
lpType: LPDWORD, lpType: LPDWORD,
lpData: LPBYTE, lpData: LPBYTE,
lpcbData: LPDWORD) -> LONG; lpcbData: LPDWORD)
-> LONG;
fn RegCloseKey(hKey: HKEY) -> LONG; fn RegCloseKey(hKey: HKEY) -> LONG;
} }
@ -73,8 +76,7 @@ pub struct Iter<'a> {
unsafe impl Sync for Repr {} unsafe impl Sync for Repr {}
unsafe impl Send for Repr {} unsafe impl Send for Repr {}
pub static LOCAL_MACHINE: RegistryKey = pub static LOCAL_MACHINE: RegistryKey = RegistryKey(Repr::Const(HKEY_LOCAL_MACHINE));
RegistryKey(Repr::Const(HKEY_LOCAL_MACHINE));
impl RegistryKey { impl RegistryKey {
fn raw(&self) -> HKEY { fn raw(&self) -> HKEY {
@ -88,8 +90,11 @@ impl RegistryKey {
let key = key.encode_wide().chain(Some(0)).collect::<Vec<_>>(); let key = key.encode_wide().chain(Some(0)).collect::<Vec<_>>();
let mut ret = 0 as *mut _; let mut ret = 0 as *mut _;
let err = unsafe { let err = unsafe {
RegOpenKeyExW(self.raw(), key.as_ptr(), 0, RegOpenKeyExW(self.raw(),
KEY_READ | KEY_WOW64_32KEY, &mut ret) key.as_ptr(),
0,
KEY_READ | KEY_WOW64_32KEY,
&mut ret)
}; };
if err == ERROR_SUCCESS as LONG { if err == ERROR_SUCCESS as LONG {
Ok(RegistryKey(Repr::Owned(OwnedKey(ret)))) Ok(RegistryKey(Repr::Owned(OwnedKey(ret))))
@ -99,7 +104,10 @@ impl RegistryKey {
} }
pub fn iter(&self) -> Iter { pub fn iter(&self) -> Iter {
Iter { idx: 0.., key: self } Iter {
idx: 0..,
key: self,
}
} }
pub fn query_str(&self, name: &str) -> io::Result<OsString> { pub fn query_str(&self, name: &str) -> io::Result<OsString> {
@ -108,25 +116,31 @@ impl RegistryKey {
let mut len = 0; let mut len = 0;
let mut kind = 0; let mut kind = 0;
unsafe { unsafe {
let err = RegQueryValueExW(self.raw(), name.as_ptr(), 0 as *mut _, let err = RegQueryValueExW(self.raw(),
&mut kind, 0 as *mut _, &mut len); name.as_ptr(),
0 as *mut _,
&mut kind,
0 as *mut _,
&mut len);
if err != ERROR_SUCCESS as LONG { if err != ERROR_SUCCESS as LONG {
return Err(io::Error::from_raw_os_error(err as i32)) return Err(io::Error::from_raw_os_error(err as i32));
} }
if kind != REG_SZ { if kind != REG_SZ {
return Err(io::Error::new(io::ErrorKind::Other, return Err(io::Error::new(io::ErrorKind::Other, "registry key wasn't a string"));
"registry key wasn't a string"))
} }
// The length here is the length in bytes, but we're using wide // 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 // characters so we need to be sure to halve it for the capacity
// passed in. // passed in.
let mut v = Vec::with_capacity(len as usize / 2); let mut v = Vec::with_capacity(len as usize / 2);
let err = RegQueryValueExW(self.raw(), name.as_ptr(), 0 as *mut _, let err = RegQueryValueExW(self.raw(),
0 as *mut _, v.as_mut_ptr() as *mut _, name.as_ptr(),
0 as *mut _,
0 as *mut _,
v.as_mut_ptr() as *mut _,
&mut len); &mut len);
if err != ERROR_SUCCESS as LONG { if err != ERROR_SUCCESS as LONG {
return Err(io::Error::from_raw_os_error(err as i32)) return Err(io::Error::from_raw_os_error(err as i32));
} }
v.set_len(len as usize / 2); v.set_len(len as usize / 2);
@ -142,7 +156,9 @@ impl RegistryKey {
impl Drop for OwnedKey { impl Drop for OwnedKey {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { RegCloseKey(self.0); } unsafe {
RegCloseKey(self.0);
}
} }
} }
@ -153,8 +169,13 @@ impl<'a> Iterator for Iter<'a> {
self.idx.next().and_then(|i| unsafe { self.idx.next().and_then(|i| unsafe {
let mut v = Vec::with_capacity(256); let mut v = Vec::with_capacity(256);
let mut len = v.capacity() as DWORD; let mut len = v.capacity() as DWORD;
let ret = RegEnumKeyExW(self.key.raw(), i, v.as_mut_ptr(), &mut len, let ret = RegEnumKeyExW(self.key.raw(),
0 as *mut _, 0 as *mut _, 0 as *mut _, i,
v.as_mut_ptr(),
&mut len,
0 as *mut _,
0 as *mut _,
0 as *mut _,
0 as *mut _); 0 as *mut _);
if ret == ERROR_NO_MORE_ITEMS as LONG { if ret == ERROR_NO_MORE_ITEMS as LONG {
None None

View File

@ -78,31 +78,29 @@ pub fn find_tool(target: &str, tool: &str) -> Option<Tool> {
add_env(&mut tool, "LIB", libs); add_env(&mut tool, "LIB", libs);
add_env(&mut tool, "PATH", path); add_env(&mut tool, "PATH", path);
add_env(&mut tool, "INCLUDE", include); add_env(&mut tool, "INCLUDE", include);
return tool tool
} }
} }
// This logic is all tailored for MSVC, if we're not that then bail out // This logic is all tailored for MSVC, if we're not that then bail out
// early. // early.
if !target.contains("msvc") { if !target.contains("msvc") {
return None return None;
} }
// Looks like msbuild isn't located in the same location as other tools like // 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 // cl.exe and lib.exe. To handle this we probe for it manually with
// dedicated registry keys. // dedicated registry keys.
if tool.contains("msbuild") { if tool.contains("msbuild") {
return find_msbuild(target) return find_msbuild(target);
} }
// If VCINSTALLDIR is set, then someone's probably already run vcvars and we // If VCINSTALLDIR is set, then someone's probably already run vcvars and we
// should just find whatever that indicates. // should just find whatever that indicates.
if env::var_os("VCINSTALLDIR").is_some() { if env::var_os("VCINSTALLDIR").is_some() {
return env::var_os("PATH").and_then(|path| { return env::var_os("PATH")
env::split_paths(&path).map(|p| p.join(tool)).find(|p| p.exists()) .and_then(|path| env::split_paths(&path).map(|p| p.join(tool)).find(|p| p.exists()))
}).map(|path| { .map(|path| Tool::new(path.into()));
Tool::new(path.into())
})
} }
// Ok, if we're here, now comes the fun part of the probing. Default shells // Ok, if we're here, now comes the fun part of the probing. Default shells
@ -112,13 +110,10 @@ pub fn find_tool(target: &str, tool: &str) -> Option<Tool> {
// environment variables like `LIB`, `INCLUDE`, and `PATH` to ensure that // environment variables like `LIB`, `INCLUDE`, and `PATH` to ensure that
// the tool is actually usable. // the tool is actually usable.
return find_msvc_latest(tool, target, "15.0").or_else(|| { return find_msvc_latest(tool, target, "15.0")
find_msvc_latest(tool, target, "14.0") .or_else(|| find_msvc_latest(tool, target, "14.0"))
}).or_else(|| { .or_else(|| find_msvc_12(tool, target))
find_msvc_12(tool, target) .or_else(|| find_msvc_11(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 // 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. // the Windows 10 SDK or Windows 8.1 SDK.
@ -151,7 +146,7 @@ pub fn find_tool(target: &str, tool: &str) -> Option<Tool> {
tool.include.push(sdk_include.join("winrt")); tool.include.push(sdk_include.join("winrt"));
tool.include.push(sdk_include.join("shared")); tool.include.push(sdk_include.join("shared"));
} else { } else {
return None return None;
} }
Some(tool.into_tool()) Some(tool.into_tool())
} }
@ -198,26 +193,27 @@ pub fn find_tool(target: &str, tool: &str) -> Option<Tool> {
// Given a possible MSVC installation directory, we look for the linker and // Given a possible MSVC installation directory, we look for the linker and
// then add the MSVC library path. // then add the MSVC library path.
fn get_tool(tool: &str, path: &Path, target: &str) -> Option<MsvcTool> { fn get_tool(tool: &str, path: &Path, target: &str) -> Option<MsvcTool> {
bin_subdir(target).into_iter().map(|(sub, host)| { bin_subdir(target)
(path.join("bin").join(sub).join(tool), .into_iter()
path.join("bin").join(host)) .map(|(sub, host)| (path.join("bin").join(sub).join(tool), path.join("bin").join(host)))
}).filter(|&(ref path, _)| { .filter(|&(ref path, _)| path.is_file())
path.is_file() .map(|(path, host)| {
}).map(|(path, host)| { let mut tool = MsvcTool::new(path);
let mut tool = MsvcTool::new(path); tool.path.push(host);
tool.path.push(host); tool
tool })
}).filter_map(|mut tool| { .filter_map(|mut tool| {
let sub = otry!(vc_lib_subdir(target)); let sub = otry!(vc_lib_subdir(target));
tool.libs.push(path.join("lib").join(sub)); tool.libs.push(path.join("lib").join(sub));
tool.include.push(path.join("include")); tool.include.push(path.join("include"));
let atlmfc_path = path.join("atlmfc"); let atlmfc_path = path.join("atlmfc");
if atlmfc_path.exists() { if atlmfc_path.exists() {
tool.libs.push(atlmfc_path.join("lib").join(sub)); tool.libs.push(atlmfc_path.join("lib").join(sub));
tool.include.push(atlmfc_path.join("include")); tool.include.push(atlmfc_path.join("include"));
} }
Some(tool) Some(tool)
}).next() })
.next()
} }
// To find MSVC we look in a specific registry key for the version we are // To find MSVC we look in a specific registry key for the version we are
@ -240,17 +236,16 @@ pub fn find_tool(target: &str, tool: &str) -> Option<Tool> {
let key = otry!(LOCAL_MACHINE.open(key.as_ref()).ok()); let key = otry!(LOCAL_MACHINE.open(key.as_ref()).ok());
let root = otry!(key.query_str("KitsRoot10").ok()); let root = otry!(key.query_str("KitsRoot10").ok());
let readdir = otry!(Path::new(&root).join("lib").read_dir().ok()); let readdir = otry!(Path::new(&root).join("lib").read_dir().ok());
let max_libdir = otry!(readdir.filter_map(|dir| { let max_libdir = otry!(readdir.filter_map(|dir| dir.ok())
dir.ok() .map(|dir| dir.path())
}).map(|dir| { .filter(|dir| {
dir.path() dir.components()
}).filter(|dir| { .last()
dir.components().last().and_then(|c| { .and_then(|c| c.as_os_str().to_str())
c.as_os_str().to_str() .map(|c| c.starts_with("10.") && dir.join("ucrt").is_dir())
}).map(|c| { .unwrap_or(false)
c.starts_with("10.") && dir.join("ucrt").is_dir() })
}).unwrap_or(false) .max());
}).max());
let version = max_libdir.components().last().unwrap(); let version = max_libdir.components().last().unwrap();
let version = version.as_os_str().to_str().unwrap().to_string(); let version = version.as_os_str().to_str().unwrap().to_string();
Some((root.into(), version)) Some((root.into(), version))
@ -270,12 +265,13 @@ pub fn find_tool(target: &str, tool: &str) -> Option<Tool> {
let root = otry!(key.query_str("InstallationFolder").ok()); let root = otry!(key.query_str("InstallationFolder").ok());
let readdir = otry!(Path::new(&root).join("lib").read_dir().ok()); let readdir = otry!(Path::new(&root).join("lib").read_dir().ok());
let mut dirs = readdir.filter_map(|dir| dir.ok()) let mut dirs = readdir.filter_map(|dir| dir.ok())
.map(|dir| dir.path()) .map(|dir| dir.path())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
dirs.sort(); dirs.sort();
let dir = otry!(dirs.into_iter().rev().filter(|dir| { let dir = otry!(dirs.into_iter()
dir.join("um").join("x64").join("kernel32.lib").is_file() .rev()
}).next()); .filter(|dir| dir.join("um").join("x64").join("kernel32.lib").is_file())
.next());
let version = dir.components().last().unwrap(); let version = dir.components().last().unwrap();
let version = version.as_os_str().to_str().unwrap().to_string(); let version = version.as_os_str().to_str().unwrap().to_string();
Some((root.into(), version)) Some((root.into(), version))
@ -319,10 +315,8 @@ pub fn find_tool(target: &str, tool: &str) -> Option<Tool> {
fn bin_subdir(target: &str) -> Vec<(&'static str, &'static str)> { fn bin_subdir(target: &str) -> Vec<(&'static str, &'static str)> {
let arch = target.split('-').next().unwrap(); let arch = target.split('-').next().unwrap();
match (arch, host_arch()) { match (arch, host_arch()) {
("i586", X86) | ("i586", X86) | ("i686", X86) => vec![("", "")],
("i686", X86) => vec![("", "")], ("i586", X86_64) | ("i686", X86_64) => vec![("amd64_x86", "amd64"), ("", "")],
("i586", X86_64) |
("i686", X86_64) => vec![("amd64_x86", "amd64"), ("", "")],
("x86_64", X86) => vec![("x86_amd64", "")], ("x86_64", X86) => vec![("x86_amd64", "")],
("x86_64", X86_64) => vec![("amd64", "amd64"), ("x86_amd64", "")], ("x86_64", X86_64) => vec![("amd64", "amd64"), ("x86_amd64", "")],
("arm", X86) => vec![("x86_arm", "")], ("arm", X86) => vec![("x86_arm", "")],
@ -393,9 +387,8 @@ pub fn find_tool(target: &str, tool: &str) -> Option<Tool> {
let mut max_vers = 0; let mut max_vers = 0;
let mut max_key = None; let mut max_key = None;
for subkey in key.iter().filter_map(|k| k.ok()) { for subkey in key.iter().filter_map(|k| k.ok()) {
let val = subkey.to_str().and_then(|s| { let val = subkey.to_str()
s.trim_left_matches("v").replace(".", "").parse().ok() .and_then(|s| s.trim_left_matches("v").replace(".", "").parse().ok());
});
let val = match val { let val = match val {
Some(s) => s, Some(s) => s,
None => continue, None => continue,
@ -407,24 +400,25 @@ pub fn find_tool(target: &str, tool: &str) -> Option<Tool> {
} }
} }
} }
return max_key max_key
} }
// see http://stackoverflow.com/questions/328017/path-to-msbuild // see http://stackoverflow.com/questions/328017/path-to-msbuild
fn find_msbuild(target: &str) -> Option<Tool> { fn find_msbuild(target: &str) -> Option<Tool> {
let key = r"SOFTWARE\Microsoft\MSBuild\ToolsVersions"; let key = r"SOFTWARE\Microsoft\MSBuild\ToolsVersions";
LOCAL_MACHINE.open(key.as_ref()).ok().and_then(|key| { LOCAL_MACHINE.open(key.as_ref())
max_version(&key).and_then(|(_vers, key)| { .ok()
key.query_str("MSBuildToolsPath").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
}) })
}).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
})
} }
} }

View File

@ -37,28 +37,27 @@ impl Test {
pub fn gnu() -> Test { pub fn gnu() -> Test {
let t = Test::new(); let t = Test::new();
t.shim("cc").shim("ar"); t.shim("cc").shim("ar");
return t t
} }
pub fn msvc() -> Test { pub fn msvc() -> Test {
let mut t = Test::new(); let mut t = Test::new();
t.shim("cl").shim("lib.exe"); t.shim("cl").shim("lib.exe");
t.msvc = true; t.msvc = true;
return t t
} }
pub fn shim(&self, name: &str) -> &Test { pub fn shim(&self, name: &str) -> &Test {
let fname = format!("{}{}", name, env::consts::EXE_SUFFIX); let fname = format!("{}{}", name, env::consts::EXE_SUFFIX);
fs::hard_link(&self.gcc, self.td.path().join(&fname)).or_else(|_| { fs::hard_link(&self.gcc, self.td.path().join(&fname))
fs::copy(&self.gcc, self.td.path().join(&fname)).map(|_| ()) .or_else(|_| fs::copy(&self.gcc, self.td.path().join(&fname)).map(|_| ()))
}).unwrap(); .unwrap();
self self
} }
pub fn gcc(&self) -> gcc::Config { pub fn gcc(&self) -> gcc::Config {
let mut cfg = gcc::Config::new(); let mut cfg = gcc::Config::new();
let mut path = env::split_paths(&env::var_os("PATH").unwrap()) let mut path = env::split_paths(&env::var_os("PATH").unwrap()).collect::<Vec<_>>();
.collect::<Vec<_>>();
path.insert(0, self.td.path().to_owned()); path.insert(0, self.td.path().to_owned());
let target = if self.msvc { let target = if self.msvc {
"x86_64-pc-windows-msvc" "x86_64-pc-windows-msvc"
@ -66,26 +65,27 @@ impl Test {
"x86_64-unknown-linux-gnu" "x86_64-unknown-linux-gnu"
}; };
cfg.target(target).host(target) cfg.target(target)
.opt_level(2) .host(target)
.debug(false) .opt_level(2)
.out_dir(self.td.path()) .debug(false)
.__set_env("PATH", env::join_paths(path).unwrap()) .out_dir(self.td.path())
.__set_env("GCCTEST_OUT_DIR", self.td.path()); .__set_env("PATH", env::join_paths(path).unwrap())
.__set_env("GCCTEST_OUT_DIR", self.td.path());
if self.msvc { if self.msvc {
cfg.compiler(self.td.path().join("cl")); cfg.compiler(self.td.path().join("cl"));
cfg.archiver(self.td.path().join("lib.exe")); cfg.archiver(self.td.path().join("lib.exe"));
} }
return cfg cfg
} }
pub fn cmd(&self, i: u32) -> Execution { pub fn cmd(&self, i: u32) -> Execution {
let mut s = String::new(); let mut s = String::new();
File::open(self.td.path().join(format!("out{}", i))).unwrap() File::open(self.td.path().join(format!("out{}", i)))
.read_to_string(&mut s).unwrap(); .unwrap()
Execution { .read_to_string(&mut s)
args: s.lines().map(|s| s.to_string()).collect(), .unwrap();
} Execution { args: s.lines().map(|s| s.to_string()).collect() }
} }
} }
@ -107,8 +107,6 @@ impl Execution {
} }
pub fn has(&self, p: &OsStr) -> bool { pub fn has(&self, p: &OsStr) -> bool {
self.args.iter().any(|arg| { self.args.iter().any(|arg| OsStr::new(arg) == p)
OsStr::new(arg) == p
})
} }
} }

View File

@ -9,14 +9,16 @@ mod support;
fn gnu_smoke() { fn gnu_smoke() {
let test = Test::gnu(); let test = Test::gnu();
test.gcc() test.gcc()
.file("foo.c").compile("libfoo.a"); .file("foo.c")
.compile("libfoo.a");
test.cmd(0).must_have("-O2") test.cmd(0)
.must_have("foo.c") .must_have("-O2")
.must_not_have("-g") .must_have("foo.c")
.must_have("-c") .must_not_have("-g")
.must_have("-ffunction-sections") .must_have("-c")
.must_have("-fdata-sections"); .must_have("-ffunction-sections")
.must_have("-fdata-sections");
test.cmd(1).must_have(test.td.path().join("foo.o")); test.cmd(1).must_have(test.td.path().join("foo.o"));
} }
@ -25,10 +27,12 @@ fn gnu_opt_level_1() {
let test = Test::gnu(); let test = Test::gnu();
test.gcc() test.gcc()
.opt_level(1) .opt_level(1)
.file("foo.c").compile("libfoo.a"); .file("foo.c")
.compile("libfoo.a");
test.cmd(0).must_have("-O1") test.cmd(0)
.must_not_have("-O2"); .must_have("-O1")
.must_not_have("-O2");
} }
#[test] #[test]
@ -36,13 +40,15 @@ fn gnu_opt_level_s() {
let test = Test::gnu(); let test = Test::gnu();
test.gcc() test.gcc()
.opt_level_str("s") .opt_level_str("s")
.file("foo.c").compile("libfoo.a"); .file("foo.c")
.compile("libfoo.a");
test.cmd(0).must_have("-Os") test.cmd(0)
.must_not_have("-O1") .must_have("-Os")
.must_not_have("-O2") .must_not_have("-O1")
.must_not_have("-O3") .must_not_have("-O2")
.must_not_have("-Oz"); .must_not_have("-O3")
.must_not_have("-Oz");
} }
#[test] #[test]
@ -50,7 +56,8 @@ fn gnu_debug() {
let test = Test::gnu(); let test = Test::gnu();
test.gcc() test.gcc()
.debug(true) .debug(true)
.file("foo.c").compile("libfoo.a"); .file("foo.c")
.compile("libfoo.a");
test.cmd(0).must_have("-g"); test.cmd(0).must_have("-g");
} }
@ -62,10 +69,12 @@ fn gnu_x86_64() {
test.gcc() test.gcc()
.target(&target) .target(&target)
.host(&target) .host(&target)
.file("foo.c").compile("libfoo.a"); .file("foo.c")
.compile("libfoo.a");
test.cmd(0).must_have("-fPIC") test.cmd(0)
.must_have("-m64"); .must_have("-fPIC")
.must_have("-m64");
} }
} }
@ -78,7 +87,8 @@ fn gnu_x86_64_no_pic() {
.pic(false) .pic(false)
.target(&target) .target(&target)
.host(&target) .host(&target)
.file("foo.c").compile("libfoo.a"); .file("foo.c")
.compile("libfoo.a");
test.cmd(0).must_not_have("-fPIC"); test.cmd(0).must_not_have("-fPIC");
} }
@ -92,10 +102,12 @@ fn gnu_i686() {
test.gcc() test.gcc()
.target(&target) .target(&target)
.host(&target) .host(&target)
.file("foo.c").compile("libfoo.a"); .file("foo.c")
.compile("libfoo.a");
test.cmd(0).must_not_have("-fPIC") test.cmd(0)
.must_have("-m32"); .must_not_have("-fPIC")
.must_have("-m32");
} }
} }
@ -108,7 +120,8 @@ fn gnu_i686_pic() {
.pic(true) .pic(true)
.target(&target) .target(&target)
.host(&target) .host(&target)
.file("foo.c").compile("libfoo.a"); .file("foo.c")
.compile("libfoo.a");
test.cmd(0).must_have("-fPIC"); test.cmd(0).must_have("-fPIC");
} }
@ -119,7 +132,8 @@ fn gnu_set_stdlib() {
let test = Test::gnu(); let test = Test::gnu();
test.gcc() test.gcc()
.cpp_set_stdlib(Some("foo")) .cpp_set_stdlib(Some("foo"))
.file("foo.c").compile("libfoo.a"); .file("foo.c")
.compile("libfoo.a");
test.cmd(0).must_not_have("-stdlib=foo"); test.cmd(0).must_not_have("-stdlib=foo");
} }
@ -129,7 +143,8 @@ fn gnu_include() {
let test = Test::gnu(); let test = Test::gnu();
test.gcc() test.gcc()
.include("foo/bar") .include("foo/bar")
.file("foo.c").compile("libfoo.a"); .file("foo.c")
.compile("libfoo.a");
test.cmd(0).must_have("-I").must_have("foo/bar"); test.cmd(0).must_have("-I").must_have("foo/bar");
} }
@ -140,7 +155,8 @@ fn gnu_define() {
test.gcc() test.gcc()
.define("FOO", Some("bar")) .define("FOO", Some("bar"))
.define("BAR", None) .define("BAR", None)
.file("foo.c").compile("libfoo.a"); .file("foo.c")
.compile("libfoo.a");
test.cmd(0).must_have("-DFOO=bar").must_have("-DBAR"); test.cmd(0).must_have("-DFOO=bar").must_have("-DBAR");
} }
@ -149,7 +165,8 @@ fn gnu_define() {
fn gnu_compile_assembly() { fn gnu_compile_assembly() {
let test = Test::gnu(); let test = Test::gnu();
test.gcc() test.gcc()
.file("foo.S").compile("libfoo.a"); .file("foo.S")
.compile("libfoo.a");
test.cmd(0).must_have("foo.S"); test.cmd(0).must_have("foo.S");
} }
@ -157,12 +174,14 @@ fn gnu_compile_assembly() {
fn msvc_smoke() { fn msvc_smoke() {
let test = Test::msvc(); let test = Test::msvc();
test.gcc() test.gcc()
.file("foo.c").compile("libfoo.a"); .file("foo.c")
.compile("libfoo.a");
test.cmd(0).must_have("/O2") test.cmd(0)
.must_have("foo.c") .must_have("/O2")
.must_not_have("/Z7") .must_have("foo.c")
.must_have("/c"); .must_not_have("/Z7")
.must_have("/c");
test.cmd(1).must_have(test.td.path().join("foo.o")); test.cmd(1).must_have(test.td.path().join("foo.o"));
} }
@ -171,7 +190,8 @@ fn msvc_opt_level_0() {
let test = Test::msvc(); let test = Test::msvc();
test.gcc() test.gcc()
.opt_level(0) .opt_level(0)
.file("foo.c").compile("libfoo.a"); .file("foo.c")
.compile("libfoo.a");
test.cmd(0).must_not_have("/O2"); test.cmd(0).must_not_have("/O2");
} }
@ -181,7 +201,8 @@ fn msvc_debug() {
let test = Test::msvc(); let test = Test::msvc();
test.gcc() test.gcc()
.debug(true) .debug(true)
.file("foo.c").compile("libfoo.a"); .file("foo.c")
.compile("libfoo.a");
test.cmd(0).must_have("/Z7"); test.cmd(0).must_have("/Z7");
} }
@ -190,7 +211,8 @@ fn msvc_include() {
let test = Test::msvc(); let test = Test::msvc();
test.gcc() test.gcc()
.include("foo/bar") .include("foo/bar")
.file("foo.c").compile("libfoo.a"); .file("foo.c")
.compile("libfoo.a");
test.cmd(0).must_have("/I").must_have("foo/bar"); test.cmd(0).must_have("/I").must_have("foo/bar");
} }
@ -201,7 +223,8 @@ fn msvc_define() {
test.gcc() test.gcc()
.define("FOO", Some("bar")) .define("FOO", Some("bar"))
.define("BAR", None) .define("BAR", None)
.file("foo.c").compile("libfoo.a"); .file("foo.c")
.compile("libfoo.a");
test.cmd(0).must_have("/DFOO=bar").must_have("/DBAR"); test.cmd(0).must_have("/DFOO=bar").must_have("/DBAR");
} }