Skip to content

Commit e498713

Browse files
committed
Merge remote-tracking branch 'upstream/master'
2 parents f8fcfe1 + 501a5bf commit e498713

File tree

6 files changed

+113
-15
lines changed

6 files changed

+113
-15
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ rust:
66
matrix:
77
include:
88
# Minimum version supported
9-
- rust: 1.6.0
9+
- rust: 1.9.0
1010
install:
1111
script: cargo build
1212

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ extern crate gcc;
3636
3737
fn main() {
3838
gcc::Config::new()
39-
.files(["foo.c", "bar.c"])
39+
.file("foo.c")
40+
.file("bar.c")
4041
.compile("foo");
4142
}
4243
```

appveyor.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,24 @@
11
environment:
2+
3+
# At the time this was added AppVeyor was having troubles with checking
4+
# revocation of SSL certificates of sites like static.rust-lang.org and what
5+
# we think is crates.io. The libcurl HTTP client by default checks for
6+
# revocation on Windows and according to a mailing list [1] this can be
7+
# disabled.
8+
#
9+
# The `CARGO_HTTP_CHECK_REVOKE` env var here tells cargo to disable SSL
10+
# revocation checking on Windows in libcurl. Note, though, that rustup, which
11+
# we're using to download Rust here, also uses libcurl as the default backend.
12+
# Unlike Cargo, however, rustup doesn't have a mechanism to disable revocation
13+
# checking. To get rustup working we set `RUSTUP_USE_HYPER` which forces it to
14+
# use the Hyper instead of libcurl backend. Both Hyper and libcurl use
15+
# schannel on Windows but it appears that Hyper configures it slightly
16+
# differently such that revocation checking isn't turned on by default.
17+
#
18+
# [1]: https://curl.haxx.se/mail/lib-2016-03/0202.html
19+
RUSTUP_USE_HYPER: 1
20+
CARGO_HTTP_CHECK_REVOKE: false
21+
222
matrix:
323
- TARGET: x86_64-pc-windows-msvc
424
ARCH: amd64

gcc-test/build.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ fn main() {
1111

1212
gcc::Config::new()
1313
.file("src/foo.c")
14+
.flag_if_supported("-Wall")
15+
.flag_if_supported("-Wfoo-bar-this-flag-does-not-exist")
1416
.define("FOO", None)
1517
.define("BAR", Some("1"))
1618
.compile("libfoo.a");

src/lib.rs

Lines changed: 74 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ pub struct Config {
8686
static_crt: Option<bool>,
8787
shared_flag: Option<bool>,
8888
static_flag: Option<bool>,
89+
check_file_created: bool,
8990
}
9091

9192
/// Configuration used to represent an invocation of a C compiler.
@@ -200,6 +201,7 @@ impl Config {
200201
cargo_metadata: true,
201202
pic: None,
202203
static_crt: None,
204+
check_file_created: false,
203205
}
204206
}
205207

@@ -260,6 +262,51 @@ impl Config {
260262
self
261263
}
262264

265+
fn is_flag_supported(&mut self, flag: &str) -> io::Result<bool> {
266+
let out_dir = self.get_out_dir();
267+
let src = out_dir.join("flag_check.c");
268+
if !self.check_file_created {
269+
try!(write!(try!(fs::File::create(&src)), "int main(void) {{ return 0; }}"));
270+
self.check_file_created = true;
271+
}
272+
273+
let obj = out_dir.join("flag_check");
274+
let target = self.get_target();
275+
let mut cfg = Config::new();
276+
cfg.flag(flag)
277+
.target(&target)
278+
.opt_level(0)
279+
.host(&target)
280+
.debug(false)
281+
.cpp(self.cpp);
282+
let compiler = cfg.get_compiler();
283+
let mut cmd = compiler.to_command();
284+
command_add_output_file(&mut cmd, &obj, target.contains("msvc"), false);
285+
cmd.arg(&src);
286+
287+
let output = try!(cmd.output());
288+
Ok(output.stderr.is_empty())
289+
}
290+
291+
/// Add an arbitrary flag to the invocation of the compiler if it supports it
292+
///
293+
/// # Example
294+
///
295+
/// ```no_run
296+
/// gcc::Config::new()
297+
/// .file("src/foo.c")
298+
/// .flag_if_supported("-Wlogical-op") // only supported by GCC
299+
/// .flag_if_supported("-Wunreachable-code") // only supported by clang
300+
/// .compile("foo");
301+
/// ```
302+
pub fn flag_if_supported(&mut self, flag: &str) -> &mut Config {
303+
if self.is_flag_supported(flag).unwrap_or(false) {
304+
self.flag(flag)
305+
} else {
306+
self
307+
}
308+
}
309+
263310
/// Set the `-shared` flag.
264311
///
265312
/// When enabled, the compiler will produce a shared object which can
@@ -499,10 +546,18 @@ impl Config {
499546
/// the `output` may start with `lib` and end with `.a`. The Rust compilier will create
500547
/// the assembly with the lib prefix and .a extension. MSVC will create a file without prefix,
501548
/// ending with `.lib`.
549+
///
550+
/// # Panics
551+
///
552+
/// Panics if `output` is not formatted correctly or if one of the underlying
553+
/// compiler commands fails. It can also panic if it fails reading file names
554+
/// or creating directories.
502555
pub fn compile(&self, output: &str) {
503-
let name_start = if output.starts_with("lib") { 3 } else { 0 };
504-
let name_end = if output.ends_with(".a") { output.len() - 2 } else { output.len() };
505-
let lib_name = &output[name_start..name_end];
556+
let lib_name = if output.starts_with("lib") && output.ends_with(".a") {
557+
&output[3..output.len() - 2]
558+
} else {
559+
&output
560+
};
506561
let dst = self.get_out_dir();
507562

508563
let mut objects = Vec::new();
@@ -591,15 +646,7 @@ impl Config {
591646
.to_string_lossy()
592647
.into_owned())
593648
};
594-
if msvc && is_asm {
595-
cmd.arg("/Fo").arg(dst);
596-
} else if msvc {
597-
let mut s = OsString::from("/Fo");
598-
s.push(&dst);
599-
cmd.arg(s);
600-
} else {
601-
cmd.arg("-o").arg(&dst);
602-
}
649+
command_add_output_file(&mut cmd, dst, msvc, is_asm);
603650
cmd.arg(if msvc { "/c" } else { "-c" });
604651
cmd.arg(file);
605652

@@ -611,7 +658,8 @@ impl Config {
611658
/// This is only relevant for C and C++ files.
612659
///
613660
/// # Panics
614-
/// Panics if more than one file is present in the config.
661+
/// Panics if more than one file is present in the config, or if compiler
662+
/// path has an invalid file name.
615663
///
616664
/// # Example
617665
/// ```no_run
@@ -1346,3 +1394,16 @@ fn fail(s: &str) -> ! {
13461394
println!("\n\n{}\n\n", s);
13471395
panic!()
13481396
}
1397+
1398+
1399+
fn command_add_output_file(cmd: &mut Command, dst: &Path, msvc: bool, is_asm: bool) {
1400+
if msvc && is_asm {
1401+
cmd.arg("/Fo").arg(dst);
1402+
} else if msvc {
1403+
let mut s = OsString::from("/Fo");
1404+
s.push(&dst);
1405+
cmd.arg(s);
1406+
} else {
1407+
cmd.arg("-o").arg(&dst);
1408+
}
1409+
}

tests/test.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,20 @@ fn gnu_shared() {
183183
.must_not_have("-static");
184184
}
185185

186+
#[test]
187+
fn gnu_flag_if_supported() {
188+
let test = Test::gnu();
189+
test.gcc()
190+
.file("foo.c")
191+
.flag_if_supported("-Wall")
192+
.flag_if_supported("-Wflag-does-not-exist")
193+
.compile("libfoo.a");
194+
195+
test.cmd(0)
196+
.must_have("-Wall")
197+
.must_not_have("-Wflag-does-not-exist");
198+
}
199+
186200
#[test]
187201
fn gnu_static() {
188202
let test = Test::gnu();

0 commit comments

Comments
 (0)