5656#![ allow( deprecated) ]
5757#![ deny( missing_docs) ]
5858
59+ #[ cfg( feature = "compile_commands" ) ]
60+ pub use crate :: json_compilation_database:: store_json_compilation_database;
61+ pub use crate :: json_compilation_database:: CompileCommand ;
5962use std:: collections:: HashMap ;
6063use std:: env;
6164use std:: ffi:: { OsStr , OsString } ;
@@ -81,6 +84,7 @@ mod setup_config;
8184#[ cfg( windows) ]
8285mod vs_instances;
8386
87+ mod json_compilation_database;
8488pub mod windows_registry;
8589
8690/// A builder for compilation of a native library.
@@ -943,8 +947,17 @@ impl Build {
943947
944948 /// Run the compiler, generating the file `output`
945949 ///
946- /// This will return a result instead of panicing; see compile() for the complete description.
950+ /// This will return a result instead of panicing; see [ compile()](Build::compile ) for the complete description.
947951 pub fn try_compile ( & self , output : & str ) -> Result < ( ) , Error > {
952+ self . try_recorded_compile ( output) ?;
953+ Ok ( ( ) )
954+ }
955+
956+ /// Run the compiler, generating the file `output` and provides compile commands for creating
957+ /// [JSON Compilation Database](https://clang.llvm.org/docs/JSONCompilationDatabase.html).
958+ ///
959+ /// This will return a result instead of panicing; see [recorded_compile()](Build::recorded_compile) for the complete description.
960+ pub fn try_recorded_compile ( & self , output : & str ) -> Result < Vec < CompileCommand > , Error > {
948961 let mut output_components = Path :: new ( output) . components ( ) ;
949962 match ( output_components. next ( ) , output_components. next ( ) ) {
950963 ( Some ( Component :: Normal ( _) ) , None ) => { }
@@ -990,7 +1003,7 @@ impl Build {
9901003
9911004 objects. push ( Object :: new ( file. to_path_buf ( ) , obj) ) ;
9921005 }
993- self . compile_objects ( & objects) ?;
1006+ let entries = self . compile_objects ( & objects) ?;
9941007 self . assemble ( lib_name, & dst. join ( gnu_lib_name) , & objects) ?;
9951008
9961009 if self . get_target ( ) ?. contains ( "msvc" ) {
@@ -1074,7 +1087,7 @@ impl Build {
10741087 }
10751088 }
10761089
1077- Ok ( ( ) )
1090+ Ok ( entries )
10781091 }
10791092
10801093 /// Run the compiler, generating the file `output`
@@ -1120,8 +1133,29 @@ impl Build {
11201133 }
11211134 }
11221135
1136+ /// Run the compiler, generating the file `output` and provides compile commands for creating
1137+ /// [JSON Compilation Database](https://clang.llvm.org/docs/JSONCompilationDatabase.html),
1138+ ///
1139+ /// ```no_run
1140+ /// let compile_commands = cc::Build::new().file("blobstore.c")
1141+ /// .recorded_compile("blobstore");
1142+ ///
1143+ /// #[cfg(feature = "compile_commands")]
1144+ /// cc::store_json_compilation_database(&compile_commands, "target/compilation_database.json");
1145+ /// ```
1146+ ///
1147+ /// See [compile()](Build::compile) for the further description.
1148+ pub fn recorded_compile ( & self , output : & str ) -> Vec < CompileCommand > {
1149+ match self . try_recorded_compile ( output) {
1150+ Ok ( entries) => entries,
1151+ Err ( e) => {
1152+ fail ( & e. message ) ;
1153+ }
1154+ }
1155+ }
1156+
11231157 #[ cfg( feature = "parallel" ) ]
1124- fn compile_objects < ' me > ( & ' me self , objs : & [ Object ] ) -> Result < ( ) , Error > {
1158+ fn compile_objects < ' me > ( & ' me self , objs : & [ Object ] ) -> Result < Vec < CompileCommand > , Error > {
11251159 use std:: sync:: atomic:: { AtomicBool , Ordering :: SeqCst } ;
11261160 use std:: sync:: Once ;
11271161
@@ -1191,9 +1225,11 @@ impl Build {
11911225 threads. push ( JoinOnDrop ( Some ( thread) ) ) ;
11921226 }
11931227
1228+ let mut entries = Vec :: new ( ) ;
1229+
11941230 for mut thread in threads {
11951231 if let Some ( thread) = thread. 0 . take ( ) {
1196- thread. join ( ) . expect ( "thread should not panic" ) ?;
1232+ entries . push ( thread. join ( ) . expect ( "thread should not panic" ) ?) ;
11971233 }
11981234 }
11991235
@@ -1203,7 +1239,7 @@ impl Build {
12031239 server. acquire_raw ( ) ?;
12041240 }
12051241
1206- return Ok ( ( ) ) ;
1242+ return Ok ( entries ) ;
12071243
12081244 /// Shared state from the parent thread to the child thread. This
12091245 /// package of pointers is temporarily transmuted to a `'static`
@@ -1260,7 +1296,7 @@ impl Build {
12601296 return client;
12611297 }
12621298
1263- struct JoinOnDrop ( Option < thread:: JoinHandle < Result < ( ) , Error > > > ) ;
1299+ struct JoinOnDrop ( Option < thread:: JoinHandle < Result < CompileCommand , Error > > > ) ;
12641300
12651301 impl Drop for JoinOnDrop {
12661302 fn drop ( & mut self ) {
@@ -1272,14 +1308,15 @@ impl Build {
12721308 }
12731309
12741310 #[ cfg( not( feature = "parallel" ) ) ]
1275- fn compile_objects ( & self , objs : & [ Object ] ) -> Result < ( ) , Error > {
1311+ fn compile_objects ( & self , objs : & [ Object ] ) -> Result < Vec < CompileCommand > , Error > {
1312+ let mut entries = Vec :: new ( ) ;
12761313 for obj in objs {
1277- self . compile_object ( obj) ?;
1314+ entries . push ( self . compile_object ( obj) ?) ;
12781315 }
1279- Ok ( ( ) )
1316+ Ok ( entries )
12801317 }
12811318
1282- fn compile_object ( & self , obj : & Object ) -> Result < ( ) , Error > {
1319+ fn compile_object ( & self , obj : & Object ) -> Result < CompileCommand , Error > {
12831320 let is_asm = obj. src . extension ( ) . and_then ( |s| s. to_str ( ) ) == Some ( "asm" ) ;
12841321 let target = self . get_target ( ) ?;
12851322 let msvc = target. contains ( "msvc" ) ;
@@ -1324,7 +1361,7 @@ impl Build {
13241361 }
13251362
13261363 run ( & mut cmd, & name) ?;
1327- Ok ( ( ) )
1364+ Ok ( CompileCommand :: new ( & cmd , obj . src . clone ( ) , obj . dst . clone ( ) ) )
13281365 }
13291366
13301367 /// This will return a result instead of panicing; see expand() for the complete description.
@@ -3287,22 +3324,29 @@ fn map_darwin_target_from_rust_to_compiler_architecture(target: &str) -> Option<
32873324 }
32883325}
32893326
3290- fn which ( tool : & Path ) -> Option < PathBuf > {
3327+ pub ( crate ) fn which < P > ( tool : P ) -> Option < PathBuf >
3328+ where
3329+ P : AsRef < Path > ,
3330+ {
32913331 fn check_exe ( exe : & mut PathBuf ) -> bool {
32923332 let exe_ext = std:: env:: consts:: EXE_EXTENSION ;
32933333 exe. exists ( ) || ( !exe_ext. is_empty ( ) && exe. set_extension ( exe_ext) && exe. exists ( ) )
32943334 }
32953335
3296- // If |tool| is not just one "word," assume it's an actual path...
3297- if tool. components ( ) . count ( ) > 1 {
3298- let mut exe = PathBuf :: from ( tool) ;
3299- return if check_exe ( & mut exe) { Some ( exe) } else { None } ;
3336+ fn non_generic_which ( tool : & Path ) -> Option < PathBuf > {
3337+ // If |tool| is not just one "word," assume it's an actual path...
3338+ if tool. components ( ) . count ( ) > 1 {
3339+ let mut exe = PathBuf :: from ( tool) ;
3340+ return if check_exe ( & mut exe) { Some ( exe) } else { None } ;
3341+ }
3342+
3343+ // Loop through PATH entries searching for the |tool|.
3344+ let path_entries = env:: var_os ( "PATH" ) ?;
3345+ env:: split_paths ( & path_entries) . find_map ( |path_entry| {
3346+ let mut exe = path_entry. join ( tool) ;
3347+ return if check_exe ( & mut exe) { Some ( exe) } else { None } ;
3348+ } )
33003349 }
33013350
3302- // Loop through PATH entries searching for the |tool|.
3303- let path_entries = env:: var_os ( "PATH" ) ?;
3304- env:: split_paths ( & path_entries) . find_map ( |path_entry| {
3305- let mut exe = path_entry. join ( tool) ;
3306- return if check_exe ( & mut exe) { Some ( exe) } else { None } ;
3307- } )
3351+ non_generic_which ( tool. as_ref ( ) )
33083352}
0 commit comments