|
@ -86,6 +86,7 @@ pub struct Config { |
|
|
static_crt: Option<bool>, |
|
|
static_crt: Option<bool>, |
|
|
shared_flag: Option<bool>, |
|
|
shared_flag: Option<bool>, |
|
|
static_flag: Option<bool>, |
|
|
static_flag: Option<bool>, |
|
|
|
|
|
check_file_created: bool, |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/// Configuration used to represent an invocation of a C compiler.
|
|
|
/// Configuration used to represent an invocation of a C compiler.
|
|
@ -200,6 +201,7 @@ impl Config { |
|
|
cargo_metadata: true, |
|
|
cargo_metadata: true, |
|
|
pic: None, |
|
|
pic: None, |
|
|
static_crt: None, |
|
|
static_crt: None, |
|
|
|
|
|
check_file_created: false, |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -260,6 +262,51 @@ impl Config { |
|
|
self |
|
|
self |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fn is_flag_supported(&mut self, flag: &str) -> io::Result<bool> { |
|
|
|
|
|
let out_dir = self.get_out_dir(); |
|
|
|
|
|
let src = out_dir.join("flag_check.c"); |
|
|
|
|
|
if !self.check_file_created { |
|
|
|
|
|
try!(write!(try!(fs::File::create(&src)), "int main(void) {{ return 0; }}")); |
|
|
|
|
|
self.check_file_created = true; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
let obj = out_dir.join("flag_check"); |
|
|
|
|
|
let target = self.get_target(); |
|
|
|
|
|
let mut cfg = Config::new(); |
|
|
|
|
|
cfg.flag(flag) |
|
|
|
|
|
.target(&target) |
|
|
|
|
|
.opt_level(0) |
|
|
|
|
|
.host(&target) |
|
|
|
|
|
.debug(false) |
|
|
|
|
|
.cpp(self.cpp); |
|
|
|
|
|
let compiler = cfg.get_compiler(); |
|
|
|
|
|
let mut cmd = compiler.to_command(); |
|
|
|
|
|
command_add_output_file(&mut cmd, &obj, target.contains("msvc"), false); |
|
|
|
|
|
cmd.arg(&src); |
|
|
|
|
|
|
|
|
|
|
|
let output = try!(cmd.output()); |
|
|
|
|
|
Ok(output.stderr.is_empty()) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Add an arbitrary flag to the invocation of the compiler if it supports it
|
|
|
|
|
|
///
|
|
|
|
|
|
/// # Example
|
|
|
|
|
|
///
|
|
|
|
|
|
/// ```no_run
|
|
|
|
|
|
/// gcc::Config::new()
|
|
|
|
|
|
/// .file("src/foo.c")
|
|
|
|
|
|
/// .flag_if_supported("-Wlogical-op") // only supported by GCC
|
|
|
|
|
|
/// .flag_if_supported("-Wunreachable-code") // only supported by clang
|
|
|
|
|
|
/// .compile("foo");
|
|
|
|
|
|
/// ```
|
|
|
|
|
|
pub fn flag_if_supported(&mut self, flag: &str) -> &mut Config { |
|
|
|
|
|
if self.is_flag_supported(flag).unwrap_or(false) { |
|
|
|
|
|
self.flag(flag) |
|
|
|
|
|
} else { |
|
|
|
|
|
self |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
/// Set the `-shared` flag.
|
|
|
/// Set the `-shared` flag.
|
|
|
///
|
|
|
///
|
|
|
/// When enabled, the compiler will produce a shared object which can
|
|
|
/// When enabled, the compiler will produce a shared object which can
|
|
@ -499,10 +546,18 @@ impl Config { |
|
|
/// the `output` may start with `lib` and end with `.a`. The Rust compilier will create
|
|
|
/// the `output` may start with `lib` and end with `.a`. The Rust compilier will create
|
|
|
/// the assembly with the lib prefix and .a extension. MSVC will create a file without prefix,
|
|
|
/// the assembly with the lib prefix and .a extension. MSVC will create a file without prefix,
|
|
|
/// ending with `.lib`.
|
|
|
/// ending with `.lib`.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// # Panics
|
|
|
|
|
|
///
|
|
|
|
|
|
/// Panics if `output` is not formatted correctly or if one of the underlying
|
|
|
|
|
|
/// compiler commands fails. It can also panic if it fails reading file names
|
|
|
|
|
|
/// or creating directories.
|
|
|
pub fn compile(&self, output: &str) { |
|
|
pub fn compile(&self, output: &str) { |
|
|
let name_start = if output.starts_with("lib") { 3 } else { 0 }; |
|
|
let lib_name = if output.starts_with("lib") && output.ends_with(".a") { |
|
|
let name_end = if output.ends_with(".a") { output.len() - 2 } else { output.len() }; |
|
|
&output[3..output.len() - 2] |
|
|
let lib_name = &output[name_start..name_end]; |
|
|
} else { |
|
|
|
|
|
&output |
|
|
|
|
|
}; |
|
|
let dst = self.get_out_dir(); |
|
|
let dst = self.get_out_dir(); |
|
|
|
|
|
|
|
|
let mut objects = Vec::new(); |
|
|
let mut objects = Vec::new(); |
|
@ -591,15 +646,7 @@ impl Config { |
|
|
.to_string_lossy() |
|
|
.to_string_lossy() |
|
|
.into_owned()) |
|
|
.into_owned()) |
|
|
}; |
|
|
}; |
|
|
if msvc && is_asm { |
|
|
command_add_output_file(&mut cmd, dst, msvc, is_asm); |
|
|
cmd.arg("/Fo").arg(dst); |
|
|
|
|
|
} else if msvc { |
|
|
|
|
|
let mut s = OsString::from("/Fo"); |
|
|
|
|
|
s.push(&dst); |
|
|
|
|
|
cmd.arg(s); |
|
|
|
|
|
} else { |
|
|
|
|
|
cmd.arg("-o").arg(&dst); |
|
|
|
|
|
} |
|
|
|
|
|
cmd.arg(if msvc { "/c" } else { "-c" }); |
|
|
cmd.arg(if msvc { "/c" } else { "-c" }); |
|
|
cmd.arg(file); |
|
|
cmd.arg(file); |
|
|
|
|
|
|
|
@ -611,7 +658,8 @@ impl Config { |
|
|
/// This is only relevant for C and C++ files.
|
|
|
/// This is only relevant for C and C++ files.
|
|
|
///
|
|
|
///
|
|
|
/// # Panics
|
|
|
/// # Panics
|
|
|
/// Panics if more than one file is present in the config.
|
|
|
/// Panics if more than one file is present in the config, or if compiler
|
|
|
|
|
|
/// path has an invalid file name.
|
|
|
///
|
|
|
///
|
|
|
/// # Example
|
|
|
/// # Example
|
|
|
/// ```no_run
|
|
|
/// ```no_run
|
|
@ -1346,3 +1394,16 @@ fn fail(s: &str) -> ! { |
|
|
println!("\n\n{}\n\n", s); |
|
|
println!("\n\n{}\n\n", s); |
|
|
panic!() |
|
|
panic!() |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn command_add_output_file(cmd: &mut Command, dst: &Path, msvc: bool, is_asm: bool) { |
|
|
|
|
|
if msvc && is_asm { |
|
|
|
|
|
cmd.arg("/Fo").arg(dst); |
|
|
|
|
|
} else if msvc { |
|
|
|
|
|
let mut s = OsString::from("/Fo"); |
|
|
|
|
|
s.push(&dst); |
|
|
|
|
|
cmd.arg(s); |
|
|
|
|
|
} else { |
|
|
|
|
|
cmd.arg("-o").arg(&dst); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|