Browse Source

Merge pull request #123 from FaultyRAM/rustfmt

Ran rustfmt
vs2017
Alex Crichton 8 years ago
committed by GitHub
parent
commit
a6287bf501
  1. 64
      gcc-test/build.rs
  2. 2
      gcc-test/src/lib.rs
  3. 8
      gcc-test/tests/all.rs
  4. 4
      src/bin/gcc-shim.rs
  5. 306
      src/lib.rs
  6. 59
      src/registry.rs
  7. 138
      src/windows_registry.rs
  8. 42
      tests/support/mod.rs
  9. 103
      tests/test.rs

64
gcc-test/build.rs

@ -10,34 +10,35 @@ fn main() {
fs::create_dir(&out).unwrap(); fs::create_dir(&out).unwrap();
gcc::Config::new() gcc::Config::new()
.file("src/foo.c") .file("src/foo.c")
.define("FOO", None) .define("FOO", None)
.define("BAR", Some("1")) .define("BAR", Some("1"))
.compile("libfoo.a"); .compile("libfoo.a");
gcc::Config::new() gcc::Config::new()
.file("src/bar1.c") .file("src/bar1.c")
.file("src/bar2.c") .file("src/bar2.c")
.include("src/include") .include("src/include")
.compile("libbar.a"); .compile("libbar.a");
let target = std::env::var("TARGET").unwrap(); let target = std::env::var("TARGET").unwrap();
let file = target.split("-").next().unwrap(); let file = target.split("-").next().unwrap();
let file = format!("src/{}.{}", file, let file = format!("src/{}.{}",
if target.contains("msvc") {"asm"} else {"S"}); file,
if target.contains("msvc") { "asm" } else { "S" });
gcc::Config::new() gcc::Config::new()
.file(file) .file(file)
.compile("libasm.a"); .compile("libasm.a");
gcc::Config::new() gcc::Config::new()
.file("src/baz.cpp") .file("src/baz.cpp")
.cpp(true) .cpp(true)
.compile("libbaz.a"); .compile("libbaz.a");
if target.contains("windows") { if target.contains("windows") {
gcc::Config::new() gcc::Config::new()
.file("src/windows.c") .file("src/windows.c")
.compile("libwindows.a"); .compile("libwindows.a");
} }
// Test that the `windows_registry` module will set PATH by looking for // Test that the `windows_registry` module will set PATH by looking for
@ -47,11 +48,12 @@ fn main() {
let out = out.join("tmp"); let out = out.join("tmp");
fs::create_dir(&out).unwrap(); fs::create_dir(&out).unwrap();
println!("nmake 1"); println!("nmake 1");
let status = gcc::windows_registry::find(&target, "nmake.exe").unwrap() let status = gcc::windows_registry::find(&target, "nmake.exe")
.arg("/fsrc/NMakefile") .unwrap()
.env("OUT_DIR", &out) .arg("/fsrc/NMakefile")
.status() .env("OUT_DIR", &out)
.unwrap(); .status()
.unwrap();
assert!(status.success()); assert!(status.success());
fs::remove_dir_all(&out).unwrap(); fs::remove_dir_all(&out).unwrap();
@ -62,11 +64,12 @@ fn main() {
env::remove_var("INCLUDE"); env::remove_var("INCLUDE");
env::remove_var("LIB"); env::remove_var("LIB");
println!("nmake 2"); println!("nmake 2");
let status = gcc::windows_registry::find(&target, "nmake.exe").unwrap() let status = gcc::windows_registry::find(&target, "nmake.exe")
.arg("/fsrc/NMakefile") .unwrap()
.env("OUT_DIR", &out) .arg("/fsrc/NMakefile")
.status() .env("OUT_DIR", &out)
.unwrap(); .status()
.unwrap();
assert!(status.success()); assert!(status.success());
println!("cargo:rustc-link-lib=msvc"); println!("cargo:rustc-link-lib=msvc");
println!("cargo:rustc-link-search={}", out.display()); println!("cargo:rustc-link-search={}", out.display());
@ -74,7 +77,8 @@ fn main() {
// This tests whether we can build a library but not link it to the main // This tests whether we can build a library but not link it to the main
// crate. The test module will do its own linking. // crate. The test module will do its own linking.
gcc::Config::new().cargo_metadata(false) gcc::Config::new()
.file("src/opt_linkage.c") .cargo_metadata(false)
.compile("libOptLinkage.a"); .file("src/opt_linkage.c")
.compile("libOptLinkage.a");
} }

2
gcc-test/src/lib.rs

@ -1,4 +1,4 @@
extern { extern "C" {
pub fn foo() -> i32; pub fn foo() -> i32;
pub fn bar1() -> i32; pub fn bar1() -> i32;

8
gcc-test/tests/all.rs

@ -3,7 +3,7 @@ extern crate gcc_test;
use gcc_test::*; use gcc_test::*;
#[link(name = "OptLinkage", kind = "static")] #[link(name = "OptLinkage", kind = "static")]
extern { extern "C" {
fn answer() -> i32; fn answer() -> i32;
} }
@ -54,7 +54,7 @@ fn msvc_here() {
#[test] #[test]
fn opt_linkage() { fn opt_linkage() {
unsafe { unsafe {
assert_eq!(answer(), 42); assert_eq!(answer(), 42);
} }
} }

4
src/bin/gcc-shim.rs

@ -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;
} }
} }

306
src/lib.rs

@ -114,7 +114,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 +194,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 +219,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 +320,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 +354,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.as_os_str() == 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 +393,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 +414,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,7 +430,7 @@ 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);
@ -457,14 +458,14 @@ impl Config {
self.print(&format!("debug={} opt-level={}", debug, opt_level)); 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
.to_str()
.map(|path| path.contains("nvcc")) .map(|path| path.contains("nvcc"))
.unwrap_or(false); .unwrap_or(false);
if msvc { if msvc {
cmd.args.push("/nologo".into()); cmd.args.push("/nologo".into());
let features = env::var("CARGO_CFG_TARGET_FEATURE") let features = env::var("CARGO_CFG_TARGET_FEATURE").unwrap_or(String::new());
.unwrap_or(String::new());
if features.contains("crt-static") { if features.contains("crt-static") {
cmd.args.push("/MT".into()); cmd.args.push("/MT".into());
} else { } else {
@ -486,12 +487,12 @@ impl Config {
cmd.args.push("-ffunction-sections".into()); cmd.args.push("-ffunction-sections".into());
cmd.args.push("-fdata-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 debug {
cmd.args.push(if msvc {"/Z7"} else {"-g"}.into()); cmd.args.push(if msvc { "/Z7" } else { "-g" }.into());
} }
if target.contains("-ios") { if target.contains("-ios") {
@ -503,7 +504,8 @@ impl Config {
cmd.args.push("-m64".into()); cmd.args.push("-m64".into());
} }
if !nvcc && self.pic.unwrap_or(!target.contains("i686") && !target.contains("windows-gnu")) { if !nvcc &&
self.pic.unwrap_or(!target.contains("i686") && !target.contains("windows-gnu")) {
cmd.args.push("-fPIC".into()); cmd.args.push("-fPIC".into());
} else if nvcc && self.pic.unwrap_or(false) { } else if nvcc && self.pic.unwrap_or(false) {
cmd.args.push("-Xcompiler".into()); cmd.args.push("-Xcompiler".into());
@ -580,7 +582,7 @@ impl Config {
} }
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(if msvc { "/I" } else { "-I" }.into());
cmd.args.push(directory.into()); cmd.args.push(directory.into());
} }
@ -589,7 +591,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 msvc { "/" } 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 +603,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 +639,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 +687,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 +696,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 +725,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 +739,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(|| {
if target.contains("emscripten") {
if self.cpp {
Some(Tool::new(PathBuf::from("em++")))
} else {
Some(Tool::new(PathBuf::from("emcc")))
} }
} else { return t;
None })
} .or_else(|| {
}).or_else(|| { if target.contains("emscripten") {
windows_registry::find_tool(&target, "cl.exe") if self.cpp {
}).unwrap_or_else(|| { Some(Tool::new(PathBuf::from("em++")))
let compiler = if host.contains("windows") && } else {
target.contains("windows") { Some(Tool::new(PathBuf::from("emcc")))
if target.contains("msvc") { }
msvc.to_string()
} else { } else {
format!("{}.exe", gnu) None
}
} else if target.contains("android") {
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() .or_else(|| windows_registry::find_tool(&target, "cl.exe"))
}; .unwrap_or_else(|| {
Tool::new(PathBuf::from(compiler)) 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, 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 +834,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 +847,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 +872,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()))
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 +895,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 +903,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> {
@ -937,7 +946,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.
@ -991,7 +1000,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)),
}; };

59
src/registry.rs

@ -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

138
src/windows_registry.rs

@ -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
})
} }
} }

42
tests/support/mod.rs

@ -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
})
} }
} }

103
tests/test.rs

@ -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")
.must_have("foo.c") test.cmd(0)
.must_not_have("-g") .must_have("-O2")
.must_have("-c") .must_have("foo.c")
.must_have("-ffunction-sections") .must_not_have("-g")
.must_have("-fdata-sections"); .must_have("-c")
.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")
.must_have("foo.c") test.cmd(0)
.must_not_have("/Z7") .must_have("/O2")
.must_have("/c"); .must_have("foo.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");
} }

Loading…
Cancel
Save