Browse Source

merged

cl-test
fedor 7 years ago
parent
commit
a96717d334
  1. 2
      Cargo.toml
  2. 2
      README.md
  3. 445
      src/lib.rs

2
Cargo.toml

@ -1,7 +1,7 @@
[package] [package]
name = "cc" name = "cc"
version = "1.0.1" version = "1.0.2"
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/cc-rs" repository = "https://github.com/alexcrichton/cc-rs"

2
README.md

@ -97,6 +97,8 @@ and `HOST` variables.
## Optional features ## Optional features
### Parallel
Currently cc-rs supports parallel compilation (think `make -jN`) but this Currently cc-rs supports parallel compilation (think `make -jN`) but this
feature is turned off by default. To enable cc-rs to compile C/C++ in parallel, feature is turned off by default. To enable cc-rs to compile C/C++ in parallel,
you can change your dependency to: you can change your dependency to:

445
src/lib.rs

@ -21,6 +21,22 @@
//! //!
//! [`Build`]: struct.Build.html //! [`Build`]: struct.Build.html
//! //!
//! # Parallelism
//!
//! To parallelize computation, enable the `parallel` feature for the crate.
//!
//! ```toml
//! [build-dependencies]
//! cc = { version = "1.0", features = ["parallel"] }
//! ```
//! To specify the max number of concurrent compilation jobs, set the `NUM_JOBS`
//! environment variable to the desired amount.
//!
//! Cargo will also set this environment variable when executed with the `-jN` flag.
//!
//! If `NUM_JOBS` is not set, the `RAYON_NUM_THREADS` environment variable can
//! also specify the build paralellism.
//!
//! # Examples //! # Examples
//! //!
//! Use the `Build` struct to compile `src/foo.c`: //! Use the `Build` struct to compile `src/foo.c`:
@ -128,7 +144,10 @@ pub struct Error {
impl Error { impl Error {
fn new(kind: ErrorKind, message: &str) -> Error { fn new(kind: ErrorKind, message: &str) -> Error {
Error { kind: kind, message: message.to_owned() } Error {
kind: kind,
message: message.to_owned(),
}
} }
} }
@ -152,7 +171,7 @@ pub struct Tool {
cc_args: Vec<OsString>, cc_args: Vec<OsString>,
args: Vec<OsString>, args: Vec<OsString>,
env: Vec<(OsString, OsString)>, env: Vec<(OsString, OsString)>,
family: ToolFamily family: ToolFamily,
} }
/// Represents the family of tools this tool belongs to. /// Represents the family of tools this tool belongs to.
@ -176,8 +195,7 @@ impl ToolFamily {
fn debug_flag(&self) -> &'static str { fn debug_flag(&self) -> &'static str {
match *self { match *self {
ToolFamily::Msvc => "/Z7", ToolFamily::Msvc => "/Z7",
ToolFamily::Gnu | ToolFamily::Gnu | ToolFamily::Clang => "-g",
ToolFamily::Clang => "-g",
} }
} }
@ -185,8 +203,7 @@ impl ToolFamily {
fn include_flag(&self) -> &'static str { fn include_flag(&self) -> &'static str {
match *self { match *self {
ToolFamily::Msvc => "/I", ToolFamily::Msvc => "/I",
ToolFamily::Gnu | ToolFamily::Gnu | ToolFamily::Clang => "-I",
ToolFamily::Clang => "-I",
} }
} }
@ -194,8 +211,7 @@ impl ToolFamily {
fn expand_flag(&self) -> &'static str { fn expand_flag(&self) -> &'static str {
match *self { match *self {
ToolFamily::Msvc => "/E", ToolFamily::Msvc => "/E",
ToolFamily::Gnu | ToolFamily::Gnu | ToolFamily::Clang => "-E",
ToolFamily::Clang => "-E",
} }
} }
@ -206,8 +222,7 @@ impl ToolFamily {
match *self { match *self {
ToolFamily::Msvc => &MSVC_FLAGS, ToolFamily::Msvc => &MSVC_FLAGS,
ToolFamily::Gnu | ToolFamily::Gnu | ToolFamily::Clang => &GNU_CLANG_FLAGS,
ToolFamily::Clang => &GNU_CLANG_FLAGS,
} }
} }
@ -215,8 +230,7 @@ impl ToolFamily {
fn warnings_to_errors_flag(&self) -> &'static str { fn warnings_to_errors_flag(&self) -> &'static str {
match *self { match *self {
ToolFamily::Msvc => "/WX", ToolFamily::Msvc => "/WX",
ToolFamily::Gnu | ToolFamily::Gnu | ToolFamily::Clang => "-Werror",
ToolFamily::Clang => "-Werror"
} }
} }
} }
@ -288,7 +302,10 @@ impl Build {
/// .compile("foo"); /// .compile("foo");
/// ``` /// ```
pub fn define<'a, V: Into<Option<&'a str>>>(&mut self, var: &str, val: V) -> &mut Build { pub fn define<'a, V: Into<Option<&'a str>>>(&mut self, var: &str, val: V) -> &mut Build {
self.definitions.push((var.to_string(), val.into().map(|s| s.to_string()))); self.definitions.push((
var.to_string(),
val.into().map(|s| s.to_string()),
));
self self
} }
@ -336,11 +353,11 @@ impl Build {
let target = self.get_target()?; let target = self.get_target()?;
let mut cfg = Build::new(); let mut cfg = Build::new();
cfg.flag(flag) cfg.flag(flag)
.target(&target) .target(&target)
.opt_level(0) .opt_level(0)
.host(&target) .host(&target)
.debug(false) .debug(false)
.cpp(self.cpp); .cpp(self.cpp);
let compiler = cfg.try_get_compiler()?; let compiler = cfg.try_get_compiler()?;
let mut cmd = compiler.to_command(); let mut cmd = compiler.to_command();
command_add_output_file(&mut cmd, &obj, target.contains("msvc"), false); command_add_output_file(&mut cmd, &obj, target.contains("msvc"), false);
@ -419,8 +436,10 @@ impl Build {
/// Add files which will be compiled /// Add files which will be compiled
pub fn files<P>(&mut self, p: P) -> &mut Build pub fn files<P>(&mut self, p: P) -> &mut Build
where P: IntoIterator, where
P::Item: AsRef<Path> { P: IntoIterator,
P::Item: AsRef<Path>,
{
for file in p.into_iter() { for file in p.into_iter() {
self.file(file); self.file(file);
} }
@ -506,7 +525,10 @@ impl Build {
/// .cpp_link_stdlib("stdc++") /// .cpp_link_stdlib("stdc++")
/// .compile("libfoo.so"); /// .compile("libfoo.so");
/// ``` /// ```
pub fn cpp_link_stdlib<'a, V: Into<Option<&'a str>>>(&mut self, cpp_link_stdlib: V) -> &mut Build { pub fn cpp_link_stdlib<'a, V: Into<Option<&'a str>>>(
&mut self,
cpp_link_stdlib: V,
) -> &mut Build {
self.cpp_link_stdlib = Some(cpp_link_stdlib.into().map(|s| s.into())); self.cpp_link_stdlib = Some(cpp_link_stdlib.into().map(|s| s.into()));
self self
} }
@ -544,7 +566,10 @@ impl Build {
/// .cpp_set_stdlib("c++") /// .cpp_set_stdlib("c++")
/// .compile("libfoo.a"); /// .compile("libfoo.a");
/// ``` /// ```
pub fn cpp_set_stdlib<'a, V: Into<Option<&'a str>>>(&mut self, cpp_set_stdlib: V) -> &mut Build { pub fn cpp_set_stdlib<'a, V: Into<Option<&'a str>>>(
&mut self,
cpp_set_stdlib: V,
) -> &mut Build {
let cpp_set_stdlib = cpp_set_stdlib.into(); let cpp_set_stdlib = cpp_set_stdlib.into();
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);
@ -679,10 +704,13 @@ impl Build {
#[doc(hidden)] #[doc(hidden)]
pub fn __set_env<A, B>(&mut self, a: A, b: B) -> &mut Build pub fn __set_env<A, B>(&mut self, a: A, b: B) -> &mut Build
where A: AsRef<OsStr>, where
B: AsRef<OsStr> 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
} }
@ -691,14 +719,14 @@ impl Build {
/// This will return a result instead of panicing; see compile() for the complete description. /// This will return a result instead of panicing; see compile() for the complete description.
pub fn try_compile(&self, output: &str) -> Result<(), Error> { pub fn try_compile(&self, output: &str) -> Result<(), Error> {
let (lib_name, gnu_lib_name) = if output.starts_with("lib") && output.ends_with(".a") { let (lib_name, gnu_lib_name) = if output.starts_with("lib") && output.ends_with(".a") {
(&output[3..output.len() - 2], output.to_owned()) (&output[3..output.len() - 2], output.to_owned())
} else { } else {
let mut gnu = String::with_capacity(5 + output.len()); let mut gnu = String::with_capacity(5 + output.len());
gnu.push_str("lib"); gnu.push_str("lib");
gnu.push_str(&output); gnu.push_str(&output);
gnu.push_str(".a"); gnu.push_str(".a");
(output, gnu) (output, gnu)
}; };
let dst = self.get_out_dir()?; let dst = self.get_out_dir()?;
let mut objects = Vec::new(); let mut objects = Vec::new();
@ -706,14 +734,21 @@ impl Build {
for file in self.files.iter() { for file in self.files.iter() {
let obj = dst.join(file).with_extension("o"); let obj = dst.join(file).with_extension("o");
let obj = if !obj.starts_with(&dst) { let obj = if !obj.starts_with(&dst) {
dst.join(obj.file_name().ok_or_else(|| Error::new(ErrorKind::IOError, "Getting object file details failed."))?) dst.join(obj.file_name().ok_or_else(|| {
Error::new(ErrorKind::IOError, "Getting object file details failed.")
})?)
} else { } else {
obj obj
}; };
match obj.parent() { match obj.parent() {
Some(s) => fs::create_dir_all(s)?, Some(s) => fs::create_dir_all(s)?,
None => return Err(Error::new(ErrorKind::IOError, "Getting object file details failed.")), None => {
return Err(Error::new(
ErrorKind::IOError,
"Getting object file details failed.",
))
}
}; };
src_dst.push((file.to_path_buf(), obj.clone())); src_dst.push((file.to_path_buf(), obj.clone()));
@ -724,7 +759,8 @@ impl Build {
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() let atlmfc_lib = compiler
.env()
.iter() .iter()
.find(|&&(ref var, _)| var.as_os_str() == OsStr::new("LIB")) .find(|&&(ref var, _)| var.as_os_str() == OsStr::new("LIB"))
.and_then(|&(_, ref lib_paths)| { .and_then(|&(_, ref lib_paths)| {
@ -735,7 +771,10 @@ impl Build {
}); });
if let Some(atlmfc_lib) = atlmfc_lib { if let Some(atlmfc_lib) = atlmfc_lib {
self.print(&format!("cargo:rustc-link-search=native={}", atlmfc_lib.display())); self.print(&format!(
"cargo:rustc-link-search=native={}",
atlmfc_lib.display()
));
} }
} }
@ -784,8 +823,12 @@ impl Build {
let results: Mutex<Vec<Result<(), Error>>> = Mutex::new(Vec::new()); let results: Mutex<Vec<Result<(), Error>>> = Mutex::new(Vec::new());
objs.par_iter().with_max_len(1) objs.par_iter().with_max_len(1).for_each(
.for_each(|&(ref src, ref dst)| results.lock().unwrap().push(self.compile_object(src, dst))); |&(ref src, ref dst)| {
let res = self.compile_object(src, dst);
results.lock().unwrap().push(res)
},
);
// Check for any errors and return the first one found. // Check for any errors and return the first one found.
for result in results.into_inner().unwrap().iter() { for result in results.into_inner().unwrap().iter() {
@ -816,12 +859,17 @@ impl Build {
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 cmd,
.file_name() compiler
.ok_or_else(|| Error::new(ErrorKind::IOError, "Failed to get compiler path."))? .path
.to_string_lossy() .file_name()
.into_owned()) .ok_or_else(|| {
Error::new(ErrorKind::IOError, "Failed to get compiler path.")
})?
.to_string_lossy()
.into_owned(),
)
}; };
command_add_output_file(&mut cmd, dst, msvc, is_asm); command_add_output_file(&mut cmd, dst, msvc, is_asm);
cmd.arg(if msvc { "/c" } else { "-c" }); cmd.arg(if msvc { "/c" } else { "-c" });
@ -840,16 +888,21 @@ impl Build {
} }
cmd.arg(compiler.family.expand_flag()); cmd.arg(compiler.family.expand_flag());
assert!(self.files.len() <= 1, assert!(
"Expand may only be called for a single file"); self.files.len() <= 1,
"Expand may only be called for a single file"
);
for file in self.files.iter() { for file in self.files.iter() {
cmd.arg(file); cmd.arg(file);
} }
let name = compiler.path let name = compiler
.path
.file_name() .file_name()
.ok_or_else(|| Error::new(ErrorKind::IOError, "Failed to get compiler path."))? .ok_or_else(|| {
Error::new(ErrorKind::IOError, "Failed to get compiler path.")
})?
.to_string_lossy() .to_string_lossy()
.into_owned(); .into_owned();
@ -908,8 +961,10 @@ impl Build {
let target = self.get_target()?; let target = self.get_target()?;
let mut cmd = self.get_base_compiler()?; let mut cmd = self.get_base_compiler()?;
let nvcc = cmd.path.file_name() let nvcc = cmd.path
.and_then(|p| p.to_str()).map(|p| p.contains("nvcc")) .file_name()
.and_then(|p| p.to_str())
.map(|p| p.contains("nvcc"))
.unwrap_or(false); .unwrap_or(false);
// Non-target flags // Non-target flags
@ -922,14 +977,14 @@ impl Build {
Some(true) => "/MT", Some(true) => "/MT",
Some(false) => "/MD", Some(false) => "/MD",
None => { None => {
let features = env::var("CARGO_CFG_TARGET_FEATURE") let features =
.unwrap_or(String::new()); env::var("CARGO_CFG_TARGET_FEATURE").unwrap_or(String::new());
if features.contains("crt-static") { if features.contains("crt-static") {
"/MT" "/MT"
} else { } else {
"/MD" "/MD"
} }
}, }
}; };
cmd.args.push(crt_flag.into()); cmd.args.push(crt_flag.into());
@ -941,8 +996,7 @@ impl Build {
_ => {} _ => {}
} }
} }
ToolFamily::Gnu | ToolFamily::Gnu | ToolFamily::Clang => {
ToolFamily::Clang => {
// arm-linux-androideabi-gcc 4.8 shipped with Android NDK does // arm-linux-androideabi-gcc 4.8 shipped with Android NDK does
// not support '-Oz' // not support '-Oz'
if opt_level == "z" && cmd.family != ToolFamily::Clang { if opt_level == "z" && cmd.family != ToolFamily::Clang {
@ -963,7 +1017,7 @@ impl Build {
} }
} }
} }
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());
} }
@ -1080,14 +1134,17 @@ impl Build {
if self.cpp { if self.cpp {
match (self.cpp_set_stdlib.as_ref(), cmd.family) { match (self.cpp_set_stdlib.as_ref(), cmd.family) {
(None, _) => { } (None, _) => {}
(Some(stdlib), ToolFamily::Gnu) | (Some(stdlib), ToolFamily::Gnu) |
(Some(stdlib), ToolFamily::Clang) => { (Some(stdlib), ToolFamily::Clang) => {
cmd.args.push(format!("-stdlib=lib{}", stdlib).into()); cmd.args.push(format!("-stdlib=lib{}", stdlib).into());
} }
_ => { _ => {
println!("cargo:warning=cpp_set_stdlib is specified, but the {:?} compiler \ println!(
does not support this option, ignored", cmd.family); "cargo:warning=cpp_set_stdlib is specified, but the {:?} compiler \
does not support this option, ignored",
cmd.family
);
} }
} }
} }
@ -1114,7 +1171,11 @@ impl Build {
} }
for &(ref key, ref value) in self.definitions.iter() { for &(ref key, ref value) in self.definitions.iter() {
let lead = if let ToolFamily::Msvc = cmd.family {"/"} 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 {
@ -1167,37 +1228,46 @@ impl Build {
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").unwrap_or_else(|| self.cmd("lib.exe")), None => {
windows_registry::find(&target, "lib.exe").unwrap_or_else(
|| {
self.cmd("lib.exe")
},
)
}
}; };
let mut out = OsString::from("/OUT:"); let mut out = OsString::from("/OUT:");
out.push(dst); out.push(dst);
run(cmd.arg(out) run(
.arg("/nologo") cmd.arg(out).arg("/nologo").args(objects).args(
.args(objects) &self.objects,
.args(&self.objects), ),
"lib.exe")?; "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);
match fs::hard_link(&dst, &lib_dst) match fs::hard_link(&dst, &lib_dst).or_else(|_| {
.or_else(|_| { // if hard-link fails, just copy (ignoring the number of bytes written)
// if hard-link fails, just copy (ignoring the number of bytes written) fs::copy(&dst, &lib_dst).map(|_| ())
fs::copy(&dst, &lib_dst).map(|_| ()) }) {
}) {
Ok(_) => (), Ok(_) => (),
Err(_) => return Err(Error::new(ErrorKind::IOError, "Could not copy or create a hard-link to the generated lib file.")), Err(_) => {
return Err(Error::new(
ErrorKind::IOError,
"Could not copy or create a hard-link to the generated lib file.",
))
}
}; };
} else { } else {
let (mut ar, cmd) = self.get_ar()?; let (mut ar, cmd) = self.get_ar()?;
run(ar run(
.arg("crs") ar.arg("crs").arg(dst).args(objects).args(&self.objects),
.arg(dst) &cmd,
.args(objects) )?;
.args(&self.objects),
&cmd)?;
} }
Ok(()) Ok(())
@ -1210,14 +1280,24 @@ impl Build {
} }
let target = self.get_target()?; let target = self.get_target()?;
let arch = target.split('-').nth(0).ok_or_else(|| Error::new(ErrorKind::ArchitectureInvalid, "Unknown architecture for iOS target."))?; let arch = target.split('-').nth(0).ok_or_else(|| {
Error::new(
ErrorKind::ArchitectureInvalid,
"Unknown architecture for iOS target.",
)
})?;
let arch = match arch { let arch = match arch {
"arm" | "armv7" | "thumbv7" => ArchSpec::Device("armv7"), "arm" | "armv7" | "thumbv7" => ArchSpec::Device("armv7"),
"armv7s" | "thumbv7s" => ArchSpec::Device("armv7s"), "armv7s" | "thumbv7s" => ArchSpec::Device("armv7s"),
"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"),
_ => return Err(Error::new(ErrorKind::ArchitectureInvalid, "Unknown architecture for iOS target.")), _ => {
return Err(Error::new(
ErrorKind::ArchitectureInvalid,
"Unknown architecture for iOS target.",
))
}
}; };
let sdk = match arch { let sdk = match arch {
@ -1245,7 +1325,12 @@ impl Build {
let sdk_path = match String::from_utf8(sdk_path) { let sdk_path = match String::from_utf8(sdk_path) {
Ok(p) => p, Ok(p) => p,
Err(_) => return Err(Error::new(ErrorKind::IOError, "Unable to determine iOS SDK path.")), Err(_) => {
return Err(Error::new(
ErrorKind::IOError,
"Unable to determine iOS SDK path.",
))
}
}; };
cmd.args.push("-isysroot".into()); cmd.args.push("-isysroot".into());
@ -1283,38 +1368,35 @@ impl Build {
"cc" "cc"
}; };
let tool_opt: Option<Tool> = self.env_tool(env) let tool_opt: Option<Tool> =
.map(|(tool, cc, args)| { self.env_tool(env)
let mut t = Tool::new(PathBuf::from(tool)); .map(|(tool, cc, args)| {
if let Some(cc) = cc { let mut t = Tool::new(PathBuf::from(tool));
t.cc_path = Some(PathBuf::from(cc)); if let Some(cc) = cc {
} t.cc_path = Some(PathBuf::from(cc));
for arg in args { }
t.cc_args.push(arg.into()); for arg in args {
} t.cc_args.push(arg.into());
t }
}) t
.or_else(|| { })
if target.contains("emscripten") { .or_else(|| {
let tool = if self.cpp { if target.contains("emscripten") {
"em++" let tool = if self.cpp { "em++" } else { "emcc" };
} else { // Windows uses bat file so we have to be a bit more specific
"emcc" if cfg!(windows) {
}; let mut t = Tool::new(PathBuf::from("cmd"));
// Windows uses bat file so we have to be a bit more specific t.args.push("/c".into());
if cfg!(windows) { t.args.push(format!("{}.bat", tool).into());
let mut t = Tool::new(PathBuf::from("cmd")); Some(t)
t.args.push("/c".into()); } else {
t.args.push(format!("{}.bat", tool).into()); Some(Tool::new(PathBuf::from(tool)))
Some(t) }
} else { } else {
Some(Tool::new(PathBuf::from(tool))) None
} }
} else { })
None .or_else(|| windows_registry::find_tool(&target, "cl.exe"));
}
})
.or_else(|| windows_registry::find_tool(&target, "cl.exe"));
let tool = match tool_opt { let tool = match tool_opt {
Some(t) => t, Some(t) => t,
@ -1355,6 +1437,7 @@ impl Build {
"powerpc64-unknown-linux-gnu" => Some("powerpc-linux-gnu"), "powerpc64-unknown-linux-gnu" => Some("powerpc-linux-gnu"),
"powerpc64le-unknown-linux-gnu" => Some("powerpc64le-linux-gnu"), "powerpc64le-unknown-linux-gnu" => Some("powerpc64le-linux-gnu"),
"s390x-unknown-linux-gnu" => Some("s390x-linux-gnu"), "s390x-unknown-linux-gnu" => Some("s390x-linux-gnu"),
"sparc64-unknown-linux-gnu" => Some("sparc64-linux-gnu"),
"sparc64-unknown-netbsd" => Some("sparc64--netbsd"), "sparc64-unknown-netbsd" => Some("sparc64--netbsd"),
"sparcv9-sun-solaris" => Some("sparcv9-sun-solaris"), "sparcv9-sun-solaris" => Some("sparcv9-sun-solaris"),
"thumbv6m-none-eabi" => Some("arm-none-eabi"), "thumbv6m-none-eabi" => Some("arm-none-eabi"),
@ -1393,7 +1476,13 @@ impl Build {
match res { match res {
Some(res) => Ok(res), Some(res) => Ok(res),
None => Err(Error::new(ErrorKind::EnvVarNotFound, &format!("Could not find environment variable {}.", var_base))), None => Err(Error::new(
ErrorKind::EnvVarNotFound,
&format!(
"Could not find environment variable {}.",
var_base
),
)),
} }
} }
@ -1439,17 +1528,17 @@ impl Build {
} else { } else {
Ok(Some("stdc++".to_string())) Ok(Some("stdc++".to_string()))
} }
}, }
} }
} }
fn get_ar(&self) -> Result<(Command, String), Error> { fn get_ar(&self) -> Result<(Command, String), Error> {
if let Some(ref p) = self.archiver { if let Some(ref p) = self.archiver {
let name = p.file_name().and_then(|s| s.to_str()).unwrap_or("ar"); let name = p.file_name().and_then(|s| s.to_str()).unwrap_or("ar");
return Ok((self.cmd(p), name.to_string())) return Ok((self.cmd(p), name.to_string()));
} }
if let Ok(p) = self.get_var("AR") { if let Ok(p) = self.get_var("AR") {
return Ok((self.cmd(&p), p)) return Ok((self.cmd(&p), p));
} }
let program = if self.get_target()?.contains("android") { let program = if self.get_target()?.contains("android") {
format!("{}-ar", self.get_target()?.replace("armv7", "arm")) format!("{}-ar", self.get_target()?.replace("armv7", "arm"))
@ -1458,7 +1547,7 @@ impl Build {
if cfg!(windows) { if cfg!(windows) {
let mut cmd = self.cmd("cmd"); let mut cmd = self.cmd("cmd");
cmd.arg("/c").arg("emar.bat"); cmd.arg("/c").arg("emar.bat");
return Ok((cmd, "emar.bat".to_string())) return Ok((cmd, "emar.bat".to_string()));
} }
"emar".to_string() "emar".to_string()
@ -1490,20 +1579,21 @@ impl Build {
} }
fn get_debug(&self) -> bool { fn get_debug(&self) -> bool {
self.debug.unwrap_or_else(|| { self.debug.unwrap_or_else(|| match self.getenv("DEBUG") {
match self.getenv("DEBUG") { Some(s) => s != "false",
Some(s) => s != "false", None => false,
None => false,
}
}) })
} }
fn get_out_dir(&self) -> Result<PathBuf, Error> { fn get_out_dir(&self) -> Result<PathBuf, Error> {
match self.out_dir.clone() { match self.out_dir.clone() {
Some(p) => Ok(p), Some(p) => Ok(p),
None => Ok(env::var_os("OUT_DIR") None => Ok(env::var_os("OUT_DIR").map(PathBuf::from).ok_or_else(|| {
.map(PathBuf::from) Error::new(
.ok_or_else(|| Error::new(ErrorKind::EnvVarNotFound, "Environment variable OUT_DIR not defined."))?), ErrorKind::EnvVarNotFound,
"Environment variable OUT_DIR not defined.",
)
})?),
} }
} }
@ -1516,7 +1606,13 @@ impl Build {
fn getenv_unwrap(&self, v: &str) -> Result<String, Error> { fn getenv_unwrap(&self, v: &str) -> Result<String, Error> {
match self.getenv(v) { match self.getenv(v) {
Some(s) => Ok(s), Some(s) => Ok(s),
None => Err(Error::new(ErrorKind::EnvVarNotFound, &format!("Environment variable {} not defined.", v.to_string()))), None => Err(Error::new(
ErrorKind::EnvVarNotFound,
&format!(
"Environment variable {} not defined.",
v.to_string()
),
)),
} }
} }
@ -1553,7 +1649,7 @@ impl Tool {
cc_args: Vec::new(), cc_args: Vec::new(),
args: Vec::new(), args: Vec::new(),
env: Vec::new(), env: Vec::new(),
family: family family: family,
} }
} }
@ -1629,13 +1725,37 @@ impl Tool {
} }
flags flags
} }
/// Whether the tool is GNU Compiler Collection-like.
pub fn is_like_gnu(&self) -> bool {
self.family == ToolFamily::Gnu
}
/// Whether the tool is Clang-like.
pub fn is_like_clang(&self) -> bool {
self.family == ToolFamily::Clang
}
/// Whether the tool is MSVC-like.
pub fn is_like_msvc(&self) -> bool {
self.family == ToolFamily::Msvc
}
} }
fn run(cmd: &mut Command, program: &str) -> Result<(), Error> { fn run(cmd: &mut Command, program: &str) -> Result<(), Error> {
let (mut child, print) = spawn(cmd, program)?; let (mut child, print) = spawn(cmd, program)?;
let status = match child.wait() { let status = match child.wait() {
Ok(s) => s, Ok(s) => s,
Err(_) => return Err(Error::new(ErrorKind::ToolExecError, &format!("Failed to wait on spawned child process, command {:?} with args {:?}.", cmd, program))), Err(_) => {
return Err(Error::new(
ErrorKind::ToolExecError,
&format!(
"Failed to wait on spawned child process, command {:?} with args {:?}.",
cmd,
program
),
))
}
}; };
print.join().unwrap(); print.join().unwrap();
println!("{}", status); println!("{}", status);
@ -1643,7 +1763,15 @@ fn run(cmd: &mut Command, program: &str) -> Result<(), Error> {
if status.success() { if status.success() {
Ok(()) Ok(())
} else { } else {
Err(Error::new(ErrorKind::ToolExecError, &format!("Command {:?} with args {:?} did not execute successfully (status code {}).", cmd, program, status))) Err(Error::new(
ErrorKind::ToolExecError,
&format!(
"Command {:?} with args {:?} did not execute successfully (status code {}).",
cmd,
program,
status
),
))
} }
} }
@ -1651,10 +1779,24 @@ fn run_output(cmd: &mut Command, program: &str) -> Result<Vec<u8>, Error> {
cmd.stdout(Stdio::piped()); cmd.stdout(Stdio::piped());
let (mut child, print) = spawn(cmd, program)?; let (mut child, print) = spawn(cmd, program)?;
let mut stdout = vec![]; let mut stdout = vec![];
child.stdout.take().unwrap().read_to_end(&mut stdout).unwrap(); child
.stdout
.take()
.unwrap()
.read_to_end(&mut stdout)
.unwrap();
let status = match child.wait() { let status = match child.wait() {
Ok(s) => s, Ok(s) => s,
Err(_) => return Err(Error::new(ErrorKind::ToolExecError, &format!("Failed to wait on spawned child process, command {:?} with args {:?}.", cmd, program))), Err(_) => {
return Err(Error::new(
ErrorKind::ToolExecError,
&format!(
"Failed to wait on spawned child process, command {:?} with args {:?}.",
cmd,
program
),
))
}
}; };
print.join().unwrap(); print.join().unwrap();
println!("{}", status); println!("{}", status);
@ -1662,7 +1804,15 @@ fn run_output(cmd: &mut Command, program: &str) -> Result<Vec<u8>, Error> {
if status.success() { if status.success() {
Ok(stdout) Ok(stdout)
} else { } else {
Err(Error::new(ErrorKind::ToolExecError, &format!("Command {:?} with args {:?} did not execute successfully (status code {}).", cmd, program, status))) Err(Error::new(
ErrorKind::ToolExecError,
&format!(
"Command {:?} with args {:?} did not execute successfully (status code {}).",
cmd,
program,
status
),
))
} }
} }
@ -1676,12 +1826,13 @@ fn spawn(cmd: &mut Command, program: &str) -> Result<(Child, JoinHandle<()>), Er
match cmd.stderr(Stdio::piped()).spawn() { match cmd.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());
let print = thread::spawn(move || { let print = thread::spawn(move || for line in stderr.split(b'\n').filter_map(
for line in stderr.split(b'\n').filter_map(|l| l.ok()) { |l| l.ok(),
print!("cargo:warning="); )
std::io::stdout().write_all(&line).unwrap(); {
println!(""); print!("cargo:warning=");
} std::io::stdout().write_all(&line).unwrap();
println!("");
}); });
Ok((child, print)) Ok((child, print))
} }
@ -1692,9 +1843,23 @@ fn spawn(cmd: &mut Command, program: &str) -> Result<(Child, JoinHandle<()>), Er
} else { } else {
"" ""
}; };
Err(Error::new(ErrorKind::ToolNotFound, &format!("Failed to find tool. Is `{}` installed?{}", program, extra))) Err(Error::new(
ErrorKind::ToolNotFound,
&format!(
"Failed to find tool. Is `{}` installed?{}",
program,
extra
),
))
} }
Err(_) => Err(Error::new(ErrorKind::ToolExecError, &format!("Command {:?} with args {:?} failed to start.", cmd, program))), Err(_) => Err(Error::new(
ErrorKind::ToolExecError,
&format!(
"Command {:?} with args {:?} failed to start.",
cmd,
program
),
)),
} }
} }

Loading…
Cancel
Save