Browse Source

Merge remote-tracking branch 'upstream/master'

cmd
James Higgs 8 years ago
parent
commit
e4987130c2
  1. 2
      .travis.yml
  2. 3
      README.md
  3. 20
      appveyor.yml
  4. 2
      gcc-test/build.rs
  5. 87
      src/lib.rs
  6. 14
      tests/test.rs

2
.travis.yml

@ -6,7 +6,7 @@ rust:
matrix:
include:
# Minimum version supported
- rust: 1.6.0
- rust: 1.9.0
install:
script: cargo build

3
README.md

@ -36,7 +36,8 @@ extern crate gcc;
fn main() {
gcc::Config::new()
.files(["foo.c", "bar.c"])
.file("foo.c")
.file("bar.c")
.compile("foo");
}
```

20
appveyor.yml

@ -1,4 +1,24 @@
environment:
# At the time this was added AppVeyor was having troubles with checking
# revocation of SSL certificates of sites like static.rust-lang.org and what
# we think is crates.io. The libcurl HTTP client by default checks for
# revocation on Windows and according to a mailing list [1] this can be
# disabled.
#
# The `CARGO_HTTP_CHECK_REVOKE` env var here tells cargo to disable SSL
# revocation checking on Windows in libcurl. Note, though, that rustup, which
# we're using to download Rust here, also uses libcurl as the default backend.
# Unlike Cargo, however, rustup doesn't have a mechanism to disable revocation
# checking. To get rustup working we set `RUSTUP_USE_HYPER` which forces it to
# use the Hyper instead of libcurl backend. Both Hyper and libcurl use
# schannel on Windows but it appears that Hyper configures it slightly
# differently such that revocation checking isn't turned on by default.
#
# [1]: https://curl.haxx.se/mail/lib-2016-03/0202.html
RUSTUP_USE_HYPER: 1
CARGO_HTTP_CHECK_REVOKE: false
matrix:
- TARGET: x86_64-pc-windows-msvc
ARCH: amd64

2
gcc-test/build.rs

@ -11,6 +11,8 @@ fn main() {
gcc::Config::new()
.file("src/foo.c")
.flag_if_supported("-Wall")
.flag_if_supported("-Wfoo-bar-this-flag-does-not-exist")
.define("FOO", None)
.define("BAR", Some("1"))
.compile("libfoo.a");

87
src/lib.rs

@ -86,6 +86,7 @@ pub struct Config {
static_crt: Option<bool>,
shared_flag: Option<bool>,
static_flag: Option<bool>,
check_file_created: bool,
}
/// Configuration used to represent an invocation of a C compiler.
@ -200,6 +201,7 @@ impl Config {
cargo_metadata: true,
pic: None,
static_crt: None,
check_file_created: false,
}
}
@ -260,6 +262,51 @@ impl Config {
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.
///
/// 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 assembly with the lib prefix and .a extension. MSVC will create a file without prefix,
/// 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) {
let name_start = if output.starts_with("lib") { 3 } else { 0 };
let name_end = if output.ends_with(".a") { output.len() - 2 } else { output.len() };
let lib_name = &output[name_start..name_end];
let lib_name = if output.starts_with("lib") && output.ends_with(".a") {
&output[3..output.len() - 2]
} else {
&output
};
let dst = self.get_out_dir();
let mut objects = Vec::new();
@ -591,15 +646,7 @@ impl Config {
.to_string_lossy()
.into_owned())
};
if msvc && is_asm {
cmd.arg("/Fo").arg(dst);
} else if msvc {
let mut s = OsString::from("/Fo");
s.push(&dst);
cmd.arg(s);
} else {
cmd.arg("-o").arg(&dst);
}
command_add_output_file(&mut cmd, dst, msvc, is_asm);
cmd.arg(if msvc { "/c" } else { "-c" });
cmd.arg(file);
@ -611,7 +658,8 @@ impl Config {
/// This is only relevant for C and C++ files.
///
/// # 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
/// ```no_run
@ -1346,3 +1394,16 @@ fn fail(s: &str) -> ! {
println!("\n\n{}\n\n", s);
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);
}
}

14
tests/test.rs

@ -183,6 +183,20 @@ fn gnu_shared() {
.must_not_have("-static");
}
#[test]
fn gnu_flag_if_supported() {
let test = Test::gnu();
test.gcc()
.file("foo.c")
.flag_if_supported("-Wall")
.flag_if_supported("-Wflag-does-not-exist")
.compile("libfoo.a");
test.cmd(0)
.must_have("-Wall")
.must_not_have("-Wflag-does-not-exist");
}
#[test]
fn gnu_static() {
let test = Test::gnu();

Loading…
Cancel
Save