56
56
#![ allow( deprecated) ]
57
57
#![ deny( missing_docs) ]
58
58
59
+ #[ cfg( feature = "compile_commands" ) ]
60
+ pub use crate :: json_compilation_database:: { store_json_compilation_database, CompileCommand } ;
61
+ #[ cfg( not( feature = "compile_commands" ) ) ]
62
+ use crate :: json_compilation_database:: CompileCommand ;
59
63
use std:: collections:: HashMap ;
60
64
use std:: env;
61
65
use std:: ffi:: { OsStr , OsString } ;
@@ -81,6 +85,7 @@ mod setup_config;
81
85
#[ cfg( windows) ]
82
86
mod vs_instances;
83
87
88
+ mod json_compilation_database;
84
89
pub mod windows_registry;
85
90
86
91
/// A builder for compilation of a native library.
@@ -943,8 +948,17 @@ impl Build {
943
948
944
949
/// Run the compiler, generating the file `output`
945
950
///
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.
947
952
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 > {
948
962
let mut output_components = Path :: new ( output) . components ( ) ;
949
963
match ( output_components. next ( ) , output_components. next ( ) ) {
950
964
( Some ( Component :: Normal ( _) ) , None ) => { }
@@ -990,7 +1004,7 @@ impl Build {
990
1004
991
1005
objects. push ( Object :: new ( file. to_path_buf ( ) , obj) ) ;
992
1006
}
993
- self . compile_objects ( & objects) ?;
1007
+ let entries = self . compile_objects ( & objects) ?;
994
1008
self . assemble ( lib_name, & dst. join ( gnu_lib_name) , & objects) ?;
995
1009
996
1010
if self . get_target ( ) ?. contains ( "msvc" ) {
@@ -1074,7 +1088,7 @@ impl Build {
1074
1088
}
1075
1089
}
1076
1090
1077
- Ok ( ( ) )
1091
+ Ok ( entries )
1078
1092
}
1079
1093
1080
1094
/// Run the compiler, generating the file `output`
@@ -1120,8 +1134,30 @@ impl Build {
1120
1134
}
1121
1135
}
1122
1136
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
+
1123
1159
#[ 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 > {
1125
1161
use std:: sync:: atomic:: { AtomicBool , Ordering :: SeqCst } ;
1126
1162
use std:: sync:: Once ;
1127
1163
@@ -1191,9 +1227,11 @@ impl Build {
1191
1227
threads. push ( JoinOnDrop ( Some ( thread) ) ) ;
1192
1228
}
1193
1229
1230
+ let mut entries = Vec :: new ( ) ;
1231
+
1194
1232
for mut thread in threads {
1195
1233
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" ) ?) ;
1197
1235
}
1198
1236
}
1199
1237
@@ -1203,7 +1241,7 @@ impl Build {
1203
1241
server. acquire_raw ( ) ?;
1204
1242
}
1205
1243
1206
- return Ok ( ( ) ) ;
1244
+ return Ok ( entries ) ;
1207
1245
1208
1246
/// Shared state from the parent thread to the child thread. This
1209
1247
/// package of pointers is temporarily transmuted to a `'static`
@@ -1260,7 +1298,7 @@ impl Build {
1260
1298
return client;
1261
1299
}
1262
1300
1263
- struct JoinOnDrop ( Option < thread:: JoinHandle < Result < ( ) , Error > > > ) ;
1301
+ struct JoinOnDrop ( Option < thread:: JoinHandle < Result < CompileCommand , Error > > > ) ;
1264
1302
1265
1303
impl Drop for JoinOnDrop {
1266
1304
fn drop ( & mut self ) {
@@ -1272,14 +1310,15 @@ impl Build {
1272
1310
}
1273
1311
1274
1312
#[ 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 ( ) ;
1276
1315
for obj in objs {
1277
- self . compile_object ( obj) ?;
1316
+ entries . push ( self . compile_object ( obj) ?) ;
1278
1317
}
1279
- Ok ( ( ) )
1318
+ Ok ( entries )
1280
1319
}
1281
1320
1282
- fn compile_object ( & self , obj : & Object ) -> Result < ( ) , Error > {
1321
+ fn compile_object ( & self , obj : & Object ) -> Result < CompileCommand , Error > {
1283
1322
let is_asm = obj. src . extension ( ) . and_then ( |s| s. to_str ( ) ) == Some ( "asm" ) ;
1284
1323
let target = self . get_target ( ) ?;
1285
1324
let msvc = target. contains ( "msvc" ) ;
@@ -1324,7 +1363,7 @@ impl Build {
1324
1363
}
1325
1364
1326
1365
run ( & mut cmd, & name) ?;
1327
- Ok ( ( ) )
1366
+ Ok ( CompileCommand :: new ( & cmd , obj . src . clone ( ) , obj . dst . clone ( ) ) )
1328
1367
}
1329
1368
1330
1369
/// 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<
3335
3374
}
3336
3375
}
3337
3376
3338
- fn which ( tool : & Path ) -> Option < PathBuf > {
3377
+ pub ( crate ) fn which < P > ( tool : P ) -> Option < PathBuf >
3378
+ where
3379
+ P : AsRef < Path > ,
3380
+ {
3339
3381
fn check_exe ( exe : & mut PathBuf ) -> bool {
3340
3382
let exe_ext = std:: env:: consts:: EXE_EXTENSION ;
3341
3383
exe. exists ( ) || ( !exe_ext. is_empty ( ) && exe. set_extension ( exe_ext) && exe. exists ( ) )
3342
3384
}
3343
3385
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
+ } )
3348
3399
}
3349
3400
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 ( ) )
3356
3402
}
0 commit comments