@@ -86,6 +86,7 @@ pub struct Config {
86
86
static_crt : Option < bool > ,
87
87
shared_flag : Option < bool > ,
88
88
static_flag : Option < bool > ,
89
+ check_file_created : bool ,
89
90
}
90
91
91
92
/// Configuration used to represent an invocation of a C compiler.
@@ -200,6 +201,7 @@ impl Config {
200
201
cargo_metadata : true ,
201
202
pic : None ,
202
203
static_crt : None ,
204
+ check_file_created : false ,
203
205
}
204
206
}
205
207
@@ -260,6 +262,51 @@ impl Config {
260
262
self
261
263
}
262
264
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
+
263
310
/// Set the `-shared` flag.
264
311
///
265
312
/// When enabled, the compiler will produce a shared object which can
@@ -499,10 +546,18 @@ impl Config {
499
546
/// the `output` may start with `lib` and end with `.a`. The Rust compilier will create
500
547
/// the assembly with the lib prefix and .a extension. MSVC will create a file without prefix,
501
548
/// 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.
502
555
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
+ } ;
506
561
let dst = self . get_out_dir ( ) ;
507
562
508
563
let mut objects = Vec :: new ( ) ;
@@ -591,15 +646,7 @@ impl Config {
591
646
. to_string_lossy ( )
592
647
. into_owned ( ) )
593
648
} ;
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) ;
603
650
cmd. arg ( if msvc { "/c" } else { "-c" } ) ;
604
651
cmd. arg ( file) ;
605
652
@@ -611,7 +658,8 @@ impl Config {
611
658
/// This is only relevant for C and C++ files.
612
659
///
613
660
/// # 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.
615
663
///
616
664
/// # Example
617
665
/// ```no_run
@@ -1346,3 +1394,16 @@ fn fail(s: &str) -> ! {
1346
1394
println ! ( "\n \n {}\n \n " , s) ;
1347
1395
panic ! ( )
1348
1396
}
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
+ }
0 commit comments