@@ -90,6 +90,10 @@ pub mod windows_registry;
9090mod command_helpers;
9191use command_helpers:: * ;
9292
93+ mod tool;
94+ pub use tool:: Tool ;
95+ use tool:: ToolFamily ;
96+
9397/// A builder for compilation of a native library.
9498///
9599/// 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 {
187191
188192impl std:: error:: Error for Error { }
189193
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-
282194/// Represents an object.
283195///
284196/// This is a source file -> object file pair.
@@ -3555,280 +3467,6 @@ impl Default for Build {
35553467 }
35563468}
35573469
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-
38323470fn fail ( s : & str ) -> ! {
38333471 eprintln ! ( "\n \n error occurred: {}\n \n " , s) ;
38343472 std:: process:: exit ( 1 ) ;
0 commit comments