@@ -312,6 +312,7 @@ pub struct Build {
312
312
emit_rerun_if_env_changed : bool ,
313
313
cached_compiler_family : Arc < RwLock < HashMap < Box < Path > , ToolFamily > > > ,
314
314
shell_escaped_flags : Option < bool > ,
315
+ inherit_rustflags : bool ,
315
316
}
316
317
317
318
/// Represents the types of errors that may occur while using cc-rs.
@@ -437,6 +438,7 @@ impl Build {
437
438
emit_rerun_if_env_changed : true ,
438
439
cached_compiler_family : Arc :: default ( ) ,
439
440
shell_escaped_flags : None ,
441
+ inherit_rustflags : true ,
440
442
}
441
443
}
442
444
@@ -664,6 +666,7 @@ impl Build {
664
666
. debug ( false )
665
667
. cpp ( self . cpp )
666
668
. cuda ( self . cuda )
669
+ . inherit_rustflags ( false )
667
670
. emit_rerun_if_env_changed ( self . emit_rerun_if_env_changed ) ;
668
671
if let Some ( target) = & self . target {
669
672
cfg. target ( target) ;
@@ -1313,6 +1316,15 @@ impl Build {
1313
1316
self
1314
1317
}
1315
1318
1319
+ /// Configure whether cc should automatically inherit compatible flags passed to rustc
1320
+ /// from `CARGO_ENCODED_RUSTFLAGS`.
1321
+ ///
1322
+ /// This option defaults to `true`.
1323
+ pub fn inherit_rustflags ( & mut self , inherit_rustflags : bool ) -> & mut Build {
1324
+ self . inherit_rustflags = inherit_rustflags;
1325
+ self
1326
+ }
1327
+
1316
1328
#[ doc( hidden) ]
1317
1329
pub fn __set_env < A , B > ( & mut self , a : A , b : B ) -> & mut Build
1318
1330
where
@@ -1904,6 +1916,11 @@ impl Build {
1904
1916
cmd. args . push ( ( * * flag) . into ( ) ) ;
1905
1917
}
1906
1918
1919
+ // Add cc flags inherited from matching rustc flags
1920
+ if self . inherit_rustflags {
1921
+ self . add_inherited_rustflags ( & mut cmd, & target) ?;
1922
+ }
1923
+
1907
1924
for flag in self . flags_supported . iter ( ) {
1908
1925
if self
1909
1926
. is_flag_supported_inner ( flag, & cmd. path , & target)
@@ -2439,6 +2456,25 @@ impl Build {
2439
2456
Ok ( ( ) )
2440
2457
}
2441
2458
2459
+ fn add_inherited_rustflags ( & self , cmd : & mut Tool , target : & Target ) -> Result < ( ) , Error > {
2460
+ let env_os = match self . getenv ( "CARGO_ENCODED_RUSTFLAGS" ) {
2461
+ Some ( env) => env,
2462
+ // No encoded RUSTFLAGS -> nothing to do
2463
+ None => return Ok ( ( ) ) ,
2464
+ } ;
2465
+
2466
+ let Tool {
2467
+ family, path, args, ..
2468
+ } = cmd;
2469
+
2470
+ let env = env_os. to_string_lossy ( ) ;
2471
+ let codegen_flags = RustcCodegenFlags :: parse ( & env) ;
2472
+ println ! ( "flags: {:?}" , codegen_flags) ;
2473
+ args. extend ( codegen_flags. cc_flags ( & self , path, family, target) ) ;
2474
+ println ! ( "ccflags: {:?}" , args) ;
2475
+ Ok ( ( ) )
2476
+ }
2477
+
2442
2478
fn has_flags ( & self ) -> bool {
2443
2479
let flags_env_var_name = if self . cpp { "CXXFLAGS" } else { "CFLAGS" } ;
2444
2480
let flags_env_var_value = self . getenv_with_target_prefixes ( flags_env_var_name) ;
@@ -4221,6 +4257,291 @@ fn map_darwin_target_from_rust_to_compiler_architecture(target: &Target) -> &str
4221
4257
}
4222
4258
}
4223
4259
4260
+ #[ derive( Debug ) ]
4261
+ struct RustcCodegenFlags {
4262
+ branch_protection : Option < String > ,
4263
+ code_model : Option < String > ,
4264
+ no_vectorize_loops : bool ,
4265
+ no_vectorize_slp : bool ,
4266
+ profile_generate : Option < String > ,
4267
+ profile_use : Option < String > ,
4268
+ control_flow_guard : Option < String > ,
4269
+ lto : Option < String > ,
4270
+ relocation_model : Option < String > ,
4271
+ embed_bitcode : Option < bool > ,
4272
+ force_frame_pointers : Option < bool > ,
4273
+ link_dead_code : Option < bool > ,
4274
+ no_redzone : Option < bool > ,
4275
+ soft_float : Option < bool > ,
4276
+ }
4277
+
4278
+ impl RustcCodegenFlags {
4279
+ // Parse flags obtained from CARGO_ENCODED_RUSTFLAGS
4280
+ fn parse ( rustflags_env : & str ) -> RustcCodegenFlags {
4281
+ fn is_flag_prefix ( flag : & str ) -> bool {
4282
+ match flag {
4283
+ "-Z" | "-C" | "--codegen" => true ,
4284
+ _ => false ,
4285
+ }
4286
+ }
4287
+
4288
+ fn join_flag_prefix < ' a > ( prev : & ' a str , curr : & ' a str ) -> Cow < ' a , str > {
4289
+ match prev {
4290
+ "--codegen" | "-C" => Cow :: from ( format ! ( "-C{}" , curr) ) ,
4291
+ "-Z" => Cow :: from ( format ! ( "-Z{}" , curr) ) ,
4292
+ _ => Cow :: from ( curr) ,
4293
+ }
4294
+ }
4295
+
4296
+ let mut codegen_flags = RustcCodegenFlags {
4297
+ branch_protection : None ,
4298
+ code_model : None ,
4299
+ no_vectorize_loops : false ,
4300
+ no_vectorize_slp : false ,
4301
+ profile_generate : None ,
4302
+ profile_use : None ,
4303
+ control_flow_guard : None ,
4304
+ lto : None ,
4305
+ relocation_model : None ,
4306
+ embed_bitcode : None ,
4307
+ force_frame_pointers : None ,
4308
+ link_dead_code : None ,
4309
+ no_redzone : None ,
4310
+ soft_float : None ,
4311
+ } ;
4312
+
4313
+ let env_flags: Vec < & str > = rustflags_env. split ( "\u{1f} " ) . collect ( ) ;
4314
+
4315
+ if !is_flag_prefix ( env_flags[ 0 ] ) {
4316
+ codegen_flags. set_rustc_flag ( env_flags[ 0 ] ) ;
4317
+ }
4318
+
4319
+ for i in 1 ..env_flags. len ( ) {
4320
+ let curr = env_flags[ i] ;
4321
+ let prev = env_flags[ i - 1 ] ;
4322
+
4323
+ // Do not process prefixes on their own
4324
+ if !is_flag_prefix ( curr) {
4325
+ // Concat flags preceded by a prefix
4326
+ let rustc_flag = join_flag_prefix ( prev, curr) ;
4327
+ codegen_flags. set_rustc_flag ( & rustc_flag) ;
4328
+ }
4329
+ }
4330
+
4331
+ codegen_flags
4332
+ }
4333
+
4334
+ fn set_rustc_flag ( & mut self , flag : & str ) {
4335
+ if flag. starts_with ( "-Z" ) {
4336
+ self . set_unstable_rustc_flag ( flag) ;
4337
+ } else {
4338
+ self . set_stable_rustc_flag ( flag) ;
4339
+ }
4340
+ }
4341
+
4342
+ fn set_stable_rustc_flag ( & mut self , flag : & str ) {
4343
+ let ( flag, value) = if let Some ( ( flag, value) ) = flag. split_once ( '=' ) {
4344
+ ( flag, Some ( value. to_owned ( ) ) )
4345
+ } else {
4346
+ ( flag, None )
4347
+ } ;
4348
+
4349
+ match flag {
4350
+ "-Ccode-model" => self . code_model = value,
4351
+ "-Cno-vectorize-loops" => self . no_vectorize_loops = true ,
4352
+ "-Cno-vectorize-slp" => self . no_vectorize_slp = true ,
4353
+ "-Cprofile-generate" => self . profile_generate = value,
4354
+ "-Cprofile-use" => self . profile_use = value,
4355
+ "-Ccontrol-flow-guard" => self . control_flow_guard = value. or ( Some ( "true" . into ( ) ) ) ,
4356
+ "-Clto" => self . lto = value. or ( Some ( "true" . into ( ) ) ) ,
4357
+ "-Crelocation-model" => self . relocation_model = value,
4358
+ "-Cembed-bitcode" => {
4359
+ self . embed_bitcode = value. map_or ( Some ( true ) , |val| match val. as_str ( ) {
4360
+ "y" | "yes" | "on" | "true" => Some ( true ) ,
4361
+ "n" | "no" | "off" | "false" => Some ( false ) ,
4362
+ _ => None ,
4363
+ } ) ;
4364
+ }
4365
+ "-Cforce-frame-pointers" => {
4366
+ self . force_frame_pointers = value. map_or ( Some ( true ) , |val| match val. as_str ( ) {
4367
+ "y" | "yes" | "on" | "true" => Some ( true ) ,
4368
+ "n" | "no" | "off" | "false" => Some ( false ) ,
4369
+ _ => None ,
4370
+ } ) ;
4371
+ }
4372
+ "-Clink-dead-code" => {
4373
+ self . link_dead_code = value. map_or ( Some ( true ) , |val| match val. as_str ( ) {
4374
+ "y" | "yes" | "on" | "true" => Some ( true ) ,
4375
+ "n" | "no" | "off" | "false" => Some ( false ) ,
4376
+ _ => None ,
4377
+ } )
4378
+ }
4379
+ "-Cno-redzone" => {
4380
+ self . no_redzone = value. map_or ( Some ( true ) , |val| match val. as_str ( ) {
4381
+ "y" | "yes" | "on" | "true" => Some ( true ) ,
4382
+ "n" | "no" | "off" | "false" => Some ( false ) ,
4383
+ _ => None ,
4384
+ } ) ;
4385
+ }
4386
+ "-Csoft-float" => {
4387
+ self . soft_float = value. map_or ( Some ( true ) , |val| match val. as_str ( ) {
4388
+ "y" | "yes" | "on" | "true" => Some ( true ) ,
4389
+ "n" | "no" | "off" | "false" => Some ( false ) ,
4390
+ _ => None ,
4391
+ } ) ;
4392
+ }
4393
+ _ => { }
4394
+ }
4395
+ }
4396
+
4397
+ fn set_unstable_rustc_flag ( & mut self , flag : & str ) {
4398
+ let ( flag, value) = if let Some ( ( flag, value) ) = flag. split_once ( '=' ) {
4399
+ ( flag, Some ( value. to_owned ( ) ) )
4400
+ } else {
4401
+ ( flag, None )
4402
+ } ;
4403
+
4404
+ match flag {
4405
+ "-Zbranch-protection" => self . branch_protection = value,
4406
+ _ => { }
4407
+ }
4408
+ }
4409
+
4410
+ // Rust and clang/cc don't agree on what equivalent flags should look like either.
4411
+ fn cc_flags (
4412
+ & self ,
4413
+ build : & Build ,
4414
+ path : & PathBuf ,
4415
+ family : & ToolFamily ,
4416
+ target : & Target ,
4417
+ ) -> Vec < OsString > {
4418
+ let push_if_supported = |flags : & mut Vec < OsString > , flag : OsString | {
4419
+ if build
4420
+ . is_flag_supported_inner ( & flag, path, target)
4421
+ . unwrap_or ( false )
4422
+ {
4423
+ flags. push ( flag) ;
4424
+ } else {
4425
+ build. cargo_output . print_warning ( & format ! (
4426
+ "Inherited flag {:?} is not supported by the currently used CC" ,
4427
+ flag
4428
+ ) ) ;
4429
+ }
4430
+ } ;
4431
+
4432
+ let mut flags: Vec < OsString > = vec ! [ ] ;
4433
+
4434
+ match family {
4435
+ ToolFamily :: Clang { .. } | ToolFamily :: Gnu => {
4436
+ if let Some ( value) = & self . branch_protection {
4437
+ push_if_supported (
4438
+ & mut flags,
4439
+ format ! ( "-mbranch-protection={}" , value. replace( "," , "+" ) ) . into ( ) ,
4440
+ ) ;
4441
+ }
4442
+ if let Some ( value) = & self . code_model {
4443
+ push_if_supported ( & mut flags, format ! ( "-mcmodel={value}" ) . into ( ) ) ;
4444
+ }
4445
+ if self . no_vectorize_loops {
4446
+ push_if_supported ( & mut flags, "-fno-vectorize" . into ( ) ) ;
4447
+ }
4448
+ if self . no_vectorize_slp {
4449
+ push_if_supported ( & mut flags, "-fno-slp-vectorize" . into ( ) ) ;
4450
+ }
4451
+ if let Some ( value) = & self . profile_generate {
4452
+ push_if_supported ( & mut flags, format ! ( "-fprofile-generate={value}" ) . into ( ) ) ;
4453
+ }
4454
+ if let Some ( value) = & self . profile_use {
4455
+ push_if_supported ( & mut flags, format ! ( "-fprofile-use={value}" ) . into ( ) ) ;
4456
+ }
4457
+ if let Some ( value) = & self . control_flow_guard {
4458
+ let cc_val = match value. as_str ( ) {
4459
+ "y" | "yes" | "on" | "true" | "checks" => Some ( "cf" ) ,
4460
+ "nochecks" => Some ( "cf-nochecks" ) ,
4461
+ "n" | "no" | "off" | "false" => Some ( "none" ) ,
4462
+ _ => None ,
4463
+ } ;
4464
+ if let Some ( cc_val) = cc_val {
4465
+ push_if_supported ( & mut flags, format ! ( "-mguard={cc_val}" ) . into ( ) ) ;
4466
+ }
4467
+ }
4468
+ if let Some ( value) = & self . lto {
4469
+ let cc_val = match value. as_str ( ) {
4470
+ "y" | "yes" | "on" | "true" | "fat" => Some ( "full" ) ,
4471
+ "thin" => Some ( "thin" ) ,
4472
+ _ => None ,
4473
+ } ;
4474
+ if let Some ( cc_val) = cc_val {
4475
+ push_if_supported ( & mut flags, format ! ( "-flto={cc_val}" ) . into ( ) ) ;
4476
+ }
4477
+ }
4478
+ if let Some ( value) = & self . relocation_model {
4479
+ let cc_flag = match value. as_str ( ) {
4480
+ "pic" => Some ( "-fPIC" ) ,
4481
+ "pie" => Some ( "-fPIE" ) ,
4482
+ "dynamic-no-pic" => Some ( "-mdynamic-no-pic" ) ,
4483
+ _ => None ,
4484
+ } ;
4485
+ if let Some ( cc_flag) = cc_flag {
4486
+ push_if_supported ( & mut flags, cc_flag. into ( ) ) ;
4487
+ }
4488
+ }
4489
+ if let Some ( value) = & self . embed_bitcode {
4490
+ let cc_val = if * value { "all" } else { "off" } ;
4491
+ push_if_supported ( & mut flags, format ! ( "-fembed-bitcode={cc_val}" ) . into ( ) ) ;
4492
+ }
4493
+ if let Some ( value) = & self . force_frame_pointers {
4494
+ let cc_flag = if * value {
4495
+ "-fno-omit-frame-pointer"
4496
+ } else {
4497
+ "-fomit-frame-pointer"
4498
+ } ;
4499
+ push_if_supported ( & mut flags, cc_flag. into ( ) ) ;
4500
+ }
4501
+ if let Some ( value) = & self . link_dead_code {
4502
+ if !value {
4503
+ push_if_supported ( & mut flags, "-dead_strip" . into ( ) ) ;
4504
+ }
4505
+ }
4506
+ if let Some ( value) = & self . no_redzone {
4507
+ let cc_flag = if * value {
4508
+ "-mno-red-zone"
4509
+ } else {
4510
+ "-mred-zone"
4511
+ } ;
4512
+ push_if_supported ( & mut flags, cc_flag. into ( ) ) ;
4513
+ }
4514
+ if let Some ( value) = & self . soft_float {
4515
+ let cc_flag = if * value {
4516
+ "-msoft-float"
4517
+ } else {
4518
+ "-mno-soft-float"
4519
+ } ;
4520
+ push_if_supported ( & mut flags, cc_flag. into ( ) ) ;
4521
+ }
4522
+ }
4523
+ ToolFamily :: Msvc { .. } => {
4524
+ if let Some ( value) = & self . control_flow_guard {
4525
+ let cc_val = match value. as_str ( ) {
4526
+ "y" | "yes" | "on" | "true" | "checks" => Some ( "cf" ) ,
4527
+ "n" | "no" | "off" | "false" => Some ( "cf-" ) ,
4528
+ _ => None ,
4529
+ } ;
4530
+ if let Some ( cc_val) = cc_val {
4531
+ push_if_supported ( & mut flags, format ! ( "/guard:{cc_val}" ) . into ( ) ) ;
4532
+ }
4533
+ }
4534
+ if let Some ( value) = & self . force_frame_pointers {
4535
+ let cc_flag = if * value { "/Oy-" } else { "/Oy" } ;
4536
+ push_if_supported ( & mut flags, cc_flag. into ( ) ) ;
4537
+ }
4538
+ }
4539
+ }
4540
+
4541
+ flags
4542
+ }
4543
+ }
4544
+
4224
4545
#[ derive( Clone , Copy , PartialEq ) ]
4225
4546
enum AsmFileExt {
4226
4547
/// `.asm` files. On MSVC targets, we assume these should be passed to MASM
0 commit comments