5656#![ allow( deprecated) ]
5757#![ deny( missing_docs) ]
5858
59+ #[ cfg( not( feature = "compile_commands" ) ) ]
60+ use crate :: json_compilation_database:: CompileCommand ;
61+ #[ cfg( feature = "compile_commands" ) ]
62+ pub use crate :: json_compilation_database:: { store_json_compilation_database, CompileCommand } ;
5963use std:: collections:: HashMap ;
6064use std:: env;
6165use std:: ffi:: { OsStr , OsString } ;
@@ -81,6 +85,7 @@ mod setup_config;
8185#[ cfg( windows) ]
8286mod vs_instances;
8387
88+ mod json_compilation_database;
8489pub mod windows_registry;
8590
8691/// A builder for compilation of a native library.
@@ -943,8 +948,17 @@ impl Build {
943948
944949 /// Run the compiler, generating the file `output`
945950 ///
946- /// This will return a result instead of panicing; see compile() for the complete description.
951+ /// This will return a result instead of panicing; see [ compile()](Build::compile ) for the complete description.
947952 pub fn try_compile ( & self , output : & str ) -> Result < ( ) , Error > {
953+ self . try_recorded_compile ( output) ?;
954+ Ok ( ( ) )
955+ }
956+
957+ /// Run the compiler, generating the file `output` and provides compile commands for creating
958+ /// [JSON Compilation Database](https://clang.llvm.org/docs/JSONCompilationDatabase.html).
959+ ///
960+ /// This will return a result instead of panicing; see [recorded_compile()](Build::recorded_compile) for the complete description.
961+ pub fn try_recorded_compile ( & self , output : & str ) -> Result < Vec < CompileCommand > , Error > {
948962 let mut output_components = Path :: new ( output) . components ( ) ;
949963 match ( output_components. next ( ) , output_components. next ( ) ) {
950964 ( Some ( Component :: Normal ( _) ) , None ) => { }
@@ -990,7 +1004,7 @@ impl Build {
9901004
9911005 objects. push ( Object :: new ( file. to_path_buf ( ) , obj) ) ;
9921006 }
993- self . compile_objects ( & objects) ?;
1007+ let entries = self . compile_objects ( & objects) ?;
9941008 self . assemble ( lib_name, & dst. join ( gnu_lib_name) , & objects) ?;
9951009
9961010 if self . get_target ( ) ?. contains ( "msvc" ) {
@@ -1074,7 +1088,7 @@ impl Build {
10741088 }
10751089 }
10761090
1077- Ok ( ( ) )
1091+ Ok ( entries )
10781092 }
10791093
10801094 /// Run the compiler, generating the file `output`
@@ -1120,8 +1134,30 @@ impl Build {
11201134 }
11211135 }
11221136
1137+ /// Run the compiler, generating the file `output` and provides compile commands for creating
1138+ /// [JSON Compilation Database](https://clang.llvm.org/docs/JSONCompilationDatabase.html),
1139+ ///
1140+ /// ```no_run
1141+ /// let compile_commands = cc::Build::new().file("blobstore.c")
1142+ /// .recorded_compile("blobstore");
1143+ ///
1144+ /// #[cfg(feature = "compile_commands")]
1145+ /// cc::store_json_compilation_database(&compile_commands, "target/compilation_database.json");
1146+ /// ```
1147+ ///
1148+ /// See [compile()](Build::compile) for the further description.
1149+ #[ cfg( feature = "compile_commands" ) ]
1150+ pub fn recorded_compile ( & self , output : & str ) -> Vec < CompileCommand > {
1151+ match self . try_recorded_compile ( output) {
1152+ Ok ( entries) => entries,
1153+ Err ( e) => {
1154+ fail ( & e. message ) ;
1155+ }
1156+ }
1157+ }
1158+
11231159 #[ cfg( feature = "parallel" ) ]
1124- fn compile_objects < ' me > ( & ' me self , objs : & [ Object ] ) -> Result < ( ) , Error > {
1160+ fn compile_objects < ' me > ( & ' me self , objs : & [ Object ] ) -> Result < Vec < CompileCommand > , Error > {
11251161 use std:: sync:: atomic:: { AtomicBool , Ordering :: SeqCst } ;
11261162 use std:: sync:: Once ;
11271163
@@ -1191,9 +1227,11 @@ impl Build {
11911227 threads. push ( JoinOnDrop ( Some ( thread) ) ) ;
11921228 }
11931229
1230+ let mut entries = Vec :: new ( ) ;
1231+
11941232 for mut thread in threads {
11951233 if let Some ( thread) = thread. 0 . take ( ) {
1196- thread. join ( ) . expect ( "thread should not panic" ) ?;
1234+ entries . push ( thread. join ( ) . expect ( "thread should not panic" ) ?) ;
11971235 }
11981236 }
11991237
@@ -1203,7 +1241,7 @@ impl Build {
12031241 server. acquire_raw ( ) ?;
12041242 }
12051243
1206- return Ok ( ( ) ) ;
1244+ return Ok ( entries ) ;
12071245
12081246 /// Shared state from the parent thread to the child thread. This
12091247 /// package of pointers is temporarily transmuted to a `'static`
@@ -1260,7 +1298,7 @@ impl Build {
12601298 return client;
12611299 }
12621300
1263- struct JoinOnDrop ( Option < thread:: JoinHandle < Result < ( ) , Error > > > ) ;
1301+ struct JoinOnDrop ( Option < thread:: JoinHandle < Result < CompileCommand , Error > > > ) ;
12641302
12651303 impl Drop for JoinOnDrop {
12661304 fn drop ( & mut self ) {
@@ -1272,14 +1310,15 @@ impl Build {
12721310 }
12731311
12741312 #[ cfg( not( feature = "parallel" ) ) ]
1275- fn compile_objects ( & self , objs : & [ Object ] ) -> Result < ( ) , Error > {
1313+ fn compile_objects ( & self , objs : & [ Object ] ) -> Result < Vec < CompileCommand > , Error > {
1314+ let mut entries = Vec :: new ( ) ;
12761315 for obj in objs {
1277- self . compile_object ( obj) ?;
1316+ entries . push ( self . compile_object ( obj) ?) ;
12781317 }
1279- Ok ( ( ) )
1318+ Ok ( entries )
12801319 }
12811320
1282- fn compile_object ( & self , obj : & Object ) -> Result < ( ) , Error > {
1321+ fn compile_object ( & self , obj : & Object ) -> Result < CompileCommand , Error > {
12831322 let is_asm = obj. src . extension ( ) . and_then ( |s| s. to_str ( ) ) == Some ( "asm" ) ;
12841323 let target = self . get_target ( ) ?;
12851324 let msvc = target. contains ( "msvc" ) ;
@@ -1324,7 +1363,7 @@ impl Build {
13241363 }
13251364
13261365 run ( & mut cmd, & name) ?;
1327- Ok ( ( ) )
1366+ Ok ( CompileCommand :: new ( & cmd , obj . src . clone ( ) , obj . dst . clone ( ) ) )
13281367 }
13291368
13301369 /// This will return a result instead of panicing; see expand() for the complete description.
@@ -3335,22 +3374,29 @@ fn map_darwin_target_from_rust_to_compiler_architecture(target: &str) -> Option<
33353374 }
33363375}
33373376
3338- fn which ( tool : & Path ) -> Option < PathBuf > {
3377+ pub ( crate ) fn which < P > ( tool : P ) -> Option < PathBuf >
3378+ where
3379+ P : AsRef < Path > ,
3380+ {
33393381 fn check_exe ( exe : & mut PathBuf ) -> bool {
33403382 let exe_ext = std:: env:: consts:: EXE_EXTENSION ;
33413383 exe. exists ( ) || ( !exe_ext. is_empty ( ) && exe. set_extension ( exe_ext) && exe. exists ( ) )
33423384 }
33433385
3344- // If |tool| is not just one "word," assume it's an actual path...
3345- if tool. components ( ) . count ( ) > 1 {
3346- let mut exe = PathBuf :: from ( tool) ;
3347- return if check_exe ( & mut exe) { Some ( exe) } else { None } ;
3386+ fn non_generic_which ( tool : & Path ) -> Option < PathBuf > {
3387+ // If |tool| is not just one "word," assume it's an actual path...
3388+ if tool. components ( ) . count ( ) > 1 {
3389+ let mut exe = PathBuf :: from ( tool) ;
3390+ return if check_exe ( & mut exe) { Some ( exe) } else { None } ;
3391+ }
3392+
3393+ // Loop through PATH entries searching for the |tool|.
3394+ let path_entries = env:: var_os ( "PATH" ) ?;
3395+ env:: split_paths ( & path_entries) . find_map ( |path_entry| {
3396+ let mut exe = path_entry. join ( tool) ;
3397+ return if check_exe ( & mut exe) { Some ( exe) } else { None } ;
3398+ } )
33483399 }
33493400
3350- // Loop through PATH entries searching for the |tool|.
3351- let path_entries = env:: var_os ( "PATH" ) ?;
3352- env:: split_paths ( & path_entries) . find_map ( |path_entry| {
3353- let mut exe = path_entry. join ( tool) ;
3354- return if check_exe ( & mut exe) { Some ( exe) } else { None } ;
3355- } )
3401+ non_generic_which ( tool. as_ref ( ) )
33563402}
0 commit comments