@@ -90,6 +90,10 @@ pub mod windows_registry;
90
90
mod command_helpers;
91
91
use command_helpers:: * ;
92
92
93
+ mod tool;
94
+ pub use tool:: Tool ;
95
+ use tool:: ToolFamily ;
96
+
93
97
/// A builder for compilation of a native library.
94
98
///
95
99
/// A `Build` is the main type of the `cc` crate and is used to control all the
@@ -187,98 +191,6 @@ impl Display for Error {
187
191
188
192
impl std:: error:: Error for Error { }
189
193
190
- /// Configuration used to represent an invocation of a C compiler.
191
- ///
192
- /// This can be used to figure out what compiler is in use, what the arguments
193
- /// to it are, and what the environment variables look like for the compiler.
194
- /// This can be used to further configure other build systems (e.g. forward
195
- /// along CC and/or CFLAGS) or the `to_command` method can be used to run the
196
- /// compiler itself.
197
- #[ derive( Clone , Debug ) ]
198
- pub struct Tool {
199
- path : PathBuf ,
200
- cc_wrapper_path : Option < PathBuf > ,
201
- cc_wrapper_args : Vec < OsString > ,
202
- args : Vec < OsString > ,
203
- env : Vec < ( OsString , OsString ) > ,
204
- family : ToolFamily ,
205
- cuda : bool ,
206
- removed_args : Vec < OsString > ,
207
- has_internal_target_arg : bool ,
208
- }
209
-
210
- /// Represents the family of tools this tool belongs to.
211
- ///
212
- /// Each family of tools differs in how and what arguments they accept.
213
- ///
214
- /// Detection of a family is done on best-effort basis and may not accurately reflect the tool.
215
- #[ derive( Copy , Clone , Debug , PartialEq ) ]
216
- enum ToolFamily {
217
- /// Tool is GNU Compiler Collection-like.
218
- Gnu ,
219
- /// Tool is Clang-like. It differs from the GCC in a sense that it accepts superset of flags
220
- /// and its cross-compilation approach is different.
221
- Clang ,
222
- /// Tool is the MSVC cl.exe.
223
- Msvc { clang_cl : bool } ,
224
- }
225
-
226
- impl ToolFamily {
227
- /// What the flag to request debug info for this family of tools look like
228
- fn add_debug_flags ( & self , cmd : & mut Tool , dwarf_version : Option < u32 > ) {
229
- match * self {
230
- ToolFamily :: Msvc { .. } => {
231
- cmd. push_cc_arg ( "-Z7" . into ( ) ) ;
232
- }
233
- ToolFamily :: Gnu | ToolFamily :: Clang => {
234
- cmd. push_cc_arg (
235
- dwarf_version
236
- . map_or_else ( || "-g" . into ( ) , |v| format ! ( "-gdwarf-{}" , v) )
237
- . into ( ) ,
238
- ) ;
239
- }
240
- }
241
- }
242
-
243
- /// What the flag to force frame pointers.
244
- fn add_force_frame_pointer ( & self , cmd : & mut Tool ) {
245
- match * self {
246
- ToolFamily :: Gnu | ToolFamily :: Clang => {
247
- cmd. push_cc_arg ( "-fno-omit-frame-pointer" . into ( ) ) ;
248
- }
249
- _ => ( ) ,
250
- }
251
- }
252
-
253
- /// What the flags to enable all warnings
254
- fn warnings_flags ( & self ) -> & ' static str {
255
- match * self {
256
- ToolFamily :: Msvc { .. } => "-W4" ,
257
- ToolFamily :: Gnu | ToolFamily :: Clang => "-Wall" ,
258
- }
259
- }
260
-
261
- /// What the flags to enable extra warnings
262
- fn extra_warnings_flags ( & self ) -> Option < & ' static str > {
263
- match * self {
264
- ToolFamily :: Msvc { .. } => None ,
265
- ToolFamily :: Gnu | ToolFamily :: Clang => Some ( "-Wextra" ) ,
266
- }
267
- }
268
-
269
- /// What the flag to turn warning into errors
270
- fn warnings_to_errors_flag ( & self ) -> & ' static str {
271
- match * self {
272
- ToolFamily :: Msvc { .. } => "-WX" ,
273
- ToolFamily :: Gnu | ToolFamily :: Clang => "-Werror" ,
274
- }
275
- }
276
-
277
- fn verbose_stderr ( & self ) -> bool {
278
- * self == ToolFamily :: Clang
279
- }
280
- }
281
-
282
194
/// Represents an object.
283
195
///
284
196
/// This is a source file -> object file pair.
@@ -3555,280 +3467,6 @@ impl Default for Build {
3555
3467
}
3556
3468
}
3557
3469
3558
- impl Tool {
3559
- fn new ( path : PathBuf , cargo_output : & CargoOutput ) -> Self {
3560
- Tool :: with_features ( path, None , false , cargo_output)
3561
- }
3562
-
3563
- fn with_clang_driver (
3564
- path : PathBuf ,
3565
- clang_driver : Option < & str > ,
3566
- cargo_output : & CargoOutput ,
3567
- ) -> Self {
3568
- Self :: with_features ( path, clang_driver, false , cargo_output)
3569
- }
3570
-
3571
- #[ cfg( windows) ]
3572
- /// Explicitly set the `ToolFamily`, skipping name-based detection.
3573
- fn with_family ( path : PathBuf , family : ToolFamily ) -> Self {
3574
- Self {
3575
- path,
3576
- cc_wrapper_path : None ,
3577
- cc_wrapper_args : Vec :: new ( ) ,
3578
- args : Vec :: new ( ) ,
3579
- env : Vec :: new ( ) ,
3580
- family,
3581
- cuda : false ,
3582
- removed_args : Vec :: new ( ) ,
3583
- has_internal_target_arg : false ,
3584
- }
3585
- }
3586
-
3587
- fn with_features (
3588
- path : PathBuf ,
3589
- clang_driver : Option < & str > ,
3590
- cuda : bool ,
3591
- cargo_output : & CargoOutput ,
3592
- ) -> Self {
3593
- fn detect_family ( path : & Path , cargo_output : & CargoOutput ) -> ToolFamily {
3594
- let mut cmd = Command :: new ( path) ;
3595
- cmd. arg ( "--version" ) ;
3596
-
3597
- let stdout = match run_output (
3598
- & mut cmd,
3599
- & path. to_string_lossy ( ) ,
3600
- // tool detection issues should always be shown as warnings
3601
- cargo_output,
3602
- )
3603
- . ok ( )
3604
- . and_then ( |o| String :: from_utf8 ( o) . ok ( ) )
3605
- {
3606
- Some ( s) => s,
3607
- None => {
3608
- // --version failed. fallback to gnu
3609
- cargo_output. print_warning ( & format_args ! ( "Failed to run: {:?}" , cmd) ) ;
3610
- return ToolFamily :: Gnu ;
3611
- }
3612
- } ;
3613
- if stdout. contains ( "clang" ) {
3614
- ToolFamily :: Clang
3615
- } else if stdout. contains ( "GCC" ) {
3616
- ToolFamily :: Gnu
3617
- } else {
3618
- // --version doesn't include clang for GCC
3619
- cargo_output. print_warning ( & format_args ! (
3620
- "Compiler version doesn't include clang or GCC: {:?}" ,
3621
- cmd
3622
- ) ) ;
3623
- ToolFamily :: Gnu
3624
- }
3625
- }
3626
-
3627
- // Try to detect family of the tool from its name, falling back to Gnu.
3628
- let family = if let Some ( fname) = path. file_name ( ) . and_then ( |p| p. to_str ( ) ) {
3629
- if fname. contains ( "clang-cl" ) {
3630
- ToolFamily :: Msvc { clang_cl : true }
3631
- } else if fname. ends_with ( "cl" ) || fname == "cl.exe" {
3632
- ToolFamily :: Msvc { clang_cl : false }
3633
- } else if fname. contains ( "clang" ) {
3634
- match clang_driver {
3635
- Some ( "cl" ) => ToolFamily :: Msvc { clang_cl : true } ,
3636
- _ => ToolFamily :: Clang ,
3637
- }
3638
- } else {
3639
- detect_family ( & path, cargo_output)
3640
- }
3641
- } else {
3642
- detect_family ( & path, cargo_output)
3643
- } ;
3644
-
3645
- Tool {
3646
- path,
3647
- cc_wrapper_path : None ,
3648
- cc_wrapper_args : Vec :: new ( ) ,
3649
- args : Vec :: new ( ) ,
3650
- env : Vec :: new ( ) ,
3651
- family,
3652
- cuda,
3653
- removed_args : Vec :: new ( ) ,
3654
- has_internal_target_arg : false ,
3655
- }
3656
- }
3657
-
3658
- /// Add an argument to be stripped from the final command arguments.
3659
- fn remove_arg ( & mut self , flag : OsString ) {
3660
- self . removed_args . push ( flag) ;
3661
- }
3662
-
3663
- /// Push an "exotic" flag to the end of the compiler's arguments list.
3664
- ///
3665
- /// Nvidia compiler accepts only the most common compiler flags like `-D`,
3666
- /// `-I`, `-c`, etc. Options meant specifically for the underlying
3667
- /// host C++ compiler have to be prefixed with `-Xcompiler`.
3668
- /// [Another possible future application for this function is passing
3669
- /// clang-specific flags to clang-cl, which otherwise accepts only
3670
- /// MSVC-specific options.]
3671
- fn push_cc_arg ( & mut self , flag : OsString ) {
3672
- if self . cuda {
3673
- self . args . push ( "-Xcompiler" . into ( ) ) ;
3674
- }
3675
- self . args . push ( flag) ;
3676
- }
3677
-
3678
- /// Checks if an argument or flag has already been specified or conflicts.
3679
- ///
3680
- /// Currently only checks optimization flags.
3681
- fn is_duplicate_opt_arg ( & self , flag : & OsString ) -> bool {
3682
- let flag = flag. to_str ( ) . unwrap ( ) ;
3683
- let mut chars = flag. chars ( ) ;
3684
-
3685
- // Only duplicate check compiler flags
3686
- if self . is_like_msvc ( ) {
3687
- if chars. next ( ) != Some ( '/' ) {
3688
- return false ;
3689
- }
3690
- } else if self . is_like_gnu ( ) || self . is_like_clang ( ) {
3691
- if chars. next ( ) != Some ( '-' ) {
3692
- return false ;
3693
- }
3694
- }
3695
-
3696
- // Check for existing optimization flags (-O, /O)
3697
- if chars. next ( ) == Some ( 'O' ) {
3698
- return self
3699
- . args ( )
3700
- . iter ( )
3701
- . any ( |a| a. to_str ( ) . unwrap_or ( "" ) . chars ( ) . nth ( 1 ) == Some ( 'O' ) ) ;
3702
- }
3703
-
3704
- // TODO Check for existing -m..., -m...=..., /arch:... flags
3705
- false
3706
- }
3707
-
3708
- /// Don't push optimization arg if it conflicts with existing args.
3709
- fn push_opt_unless_duplicate ( & mut self , flag : OsString ) {
3710
- if self . is_duplicate_opt_arg ( & flag) {
3711
- println ! ( "Info: Ignoring duplicate arg {:?}" , & flag) ;
3712
- } else {
3713
- self . push_cc_arg ( flag) ;
3714
- }
3715
- }
3716
-
3717
- /// Converts this compiler into a `Command` that's ready to be run.
3718
- ///
3719
- /// This is useful for when the compiler needs to be executed and the
3720
- /// command returned will already have the initial arguments and environment
3721
- /// variables configured.
3722
- pub fn to_command ( & self ) -> Command {
3723
- let mut cmd = match self . cc_wrapper_path {
3724
- Some ( ref cc_wrapper_path) => {
3725
- let mut cmd = Command :: new ( cc_wrapper_path) ;
3726
- cmd. arg ( & self . path ) ;
3727
- cmd
3728
- }
3729
- None => Command :: new ( & self . path ) ,
3730
- } ;
3731
- cmd. args ( & self . cc_wrapper_args ) ;
3732
-
3733
- let value = self
3734
- . args
3735
- . iter ( )
3736
- . filter ( |a| !self . removed_args . contains ( a) )
3737
- . collect :: < Vec < _ > > ( ) ;
3738
- cmd. args ( & value) ;
3739
-
3740
- for ( k, v) in self . env . iter ( ) {
3741
- cmd. env ( k, v) ;
3742
- }
3743
- cmd
3744
- }
3745
-
3746
- /// Returns the path for this compiler.
3747
- ///
3748
- /// Note that this may not be a path to a file on the filesystem, e.g. "cc",
3749
- /// but rather something which will be resolved when a process is spawned.
3750
- pub fn path ( & self ) -> & Path {
3751
- & self . path
3752
- }
3753
-
3754
- /// Returns the default set of arguments to the compiler needed to produce
3755
- /// executables for the target this compiler generates.
3756
- pub fn args ( & self ) -> & [ OsString ] {
3757
- & self . args
3758
- }
3759
-
3760
- /// Returns the set of environment variables needed for this compiler to
3761
- /// operate.
3762
- ///
3763
- /// This is typically only used for MSVC compilers currently.
3764
- pub fn env ( & self ) -> & [ ( OsString , OsString ) ] {
3765
- & self . env
3766
- }
3767
-
3768
- /// Returns the compiler command in format of CC environment variable.
3769
- /// Or empty string if CC env was not present
3770
- ///
3771
- /// This is typically used by configure script
3772
- pub fn cc_env ( & self ) -> OsString {
3773
- match self . cc_wrapper_path {
3774
- Some ( ref cc_wrapper_path) => {
3775
- let mut cc_env = cc_wrapper_path. as_os_str ( ) . to_owned ( ) ;
3776
- cc_env. push ( " " ) ;
3777
- cc_env. push ( self . path . to_path_buf ( ) . into_os_string ( ) ) ;
3778
- for arg in self . cc_wrapper_args . iter ( ) {
3779
- cc_env. push ( " " ) ;
3780
- cc_env. push ( arg) ;
3781
- }
3782
- cc_env
3783
- }
3784
- None => OsString :: from ( "" ) ,
3785
- }
3786
- }
3787
-
3788
- /// Returns the compiler flags in format of CFLAGS environment variable.
3789
- /// Important here - this will not be CFLAGS from env, its internal gcc's flags to use as CFLAGS
3790
- /// This is typically used by configure script
3791
- pub fn cflags_env ( & self ) -> OsString {
3792
- let mut flags = OsString :: new ( ) ;
3793
- for ( i, arg) in self . args . iter ( ) . enumerate ( ) {
3794
- if i > 0 {
3795
- flags. push ( " " ) ;
3796
- }
3797
- flags. push ( arg) ;
3798
- }
3799
- flags
3800
- }
3801
-
3802
- /// Whether the tool is GNU Compiler Collection-like.
3803
- pub fn is_like_gnu ( & self ) -> bool {
3804
- self . family == ToolFamily :: Gnu
3805
- }
3806
-
3807
- /// Whether the tool is Clang-like.
3808
- pub fn is_like_clang ( & self ) -> bool {
3809
- self . family == ToolFamily :: Clang
3810
- }
3811
-
3812
- /// Whether the tool is AppleClang under .xctoolchain
3813
- #[ cfg( target_vendor = "apple" ) ]
3814
- fn is_xctoolchain_clang ( & self ) -> bool {
3815
- let path = self . path . to_string_lossy ( ) ;
3816
- path. contains ( ".xctoolchain/" )
3817
- }
3818
- #[ cfg( not( target_vendor = "apple" ) ) ]
3819
- fn is_xctoolchain_clang ( & self ) -> bool {
3820
- false
3821
- }
3822
-
3823
- /// Whether the tool is MSVC-like.
3824
- pub fn is_like_msvc ( & self ) -> bool {
3825
- match self . family {
3826
- ToolFamily :: Msvc { .. } => true ,
3827
- _ => false ,
3828
- }
3829
- }
3830
- }
3831
-
3832
3470
fn fail ( s : & str ) -> ! {
3833
3471
eprintln ! ( "\n \n error occurred: {}\n \n " , s) ;
3834
3472
std:: process:: exit ( 1 ) ;
0 commit comments