@@ -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,23 @@ 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
+ args. extend ( codegen_flags. cc_flags ( & self , path, family, target) ) ;
2473
+ Ok ( ( ) )
2474
+ }
2475
+
2442
2476
fn has_flags ( & self ) -> bool {
2443
2477
let flags_env_var_name = if self . cpp { "CXXFLAGS" } else { "CFLAGS" } ;
2444
2478
let flags_env_var_value = self . getenv_with_target_prefixes ( flags_env_var_name) ;
@@ -4221,6 +4255,291 @@ fn map_darwin_target_from_rust_to_compiler_architecture(target: &Target) -> &str
4221
4255
}
4222
4256
}
4223
4257
4258
+ #[ derive( Debug ) ]
4259
+ struct RustcCodegenFlags {
4260
+ branch_protection : Option < String > ,
4261
+ code_model : Option < String > ,
4262
+ no_vectorize_loops : bool ,
4263
+ no_vectorize_slp : bool ,
4264
+ profile_generate : Option < String > ,
4265
+ profile_use : Option < String > ,
4266
+ control_flow_guard : Option < String > ,
4267
+ lto : Option < String > ,
4268
+ relocation_model : Option < String > ,
4269
+ embed_bitcode : Option < bool > ,
4270
+ force_frame_pointers : Option < bool > ,
4271
+ link_dead_code : Option < bool > ,
4272
+ no_redzone : Option < bool > ,
4273
+ soft_float : Option < bool > ,
4274
+ }
4275
+
4276
+ impl RustcCodegenFlags {
4277
+ // Parse flags obtained from CARGO_ENCODED_RUSTFLAGS
4278
+ fn parse ( rustflags_env : & str ) -> RustcCodegenFlags {
4279
+ fn is_flag_prefix ( flag : & str ) -> bool {
4280
+ match flag {
4281
+ "-Z" | "-C" | "--codegen" => true ,
4282
+ _ => false ,
4283
+ }
4284
+ }
4285
+
4286
+ fn join_flag_prefix < ' a > ( prev : & ' a str , curr : & ' a str ) -> Cow < ' a , str > {
4287
+ match prev {
4288
+ "--codegen" | "-C" => Cow :: from ( format ! ( "-C{}" , curr) ) ,
4289
+ "-Z" => Cow :: from ( format ! ( "-Z{}" , curr) ) ,
4290
+ _ => Cow :: from ( curr) ,
4291
+ }
4292
+ }
4293
+
4294
+ let mut codegen_flags = RustcCodegenFlags {
4295
+ branch_protection : None ,
4296
+ code_model : None ,
4297
+ no_vectorize_loops : false ,
4298
+ no_vectorize_slp : false ,
4299
+ profile_generate : None ,
4300
+ profile_use : None ,
4301
+ control_flow_guard : None ,
4302
+ lto : None ,
4303
+ relocation_model : None ,
4304
+ embed_bitcode : None ,
4305
+ force_frame_pointers : None ,
4306
+ link_dead_code : None ,
4307
+ no_redzone : None ,
4308
+ soft_float : None ,
4309
+ } ;
4310
+
4311
+ let env_flags: Vec < & str > = rustflags_env. split ( "\u{1f} " ) . collect ( ) ;
4312
+
4313
+ if !is_flag_prefix ( env_flags[ 0 ] ) {
4314
+ codegen_flags. set_rustc_flag ( env_flags[ 0 ] ) ;
4315
+ }
4316
+
4317
+ for i in 1 ..env_flags. len ( ) {
4318
+ let curr = env_flags[ i] ;
4319
+ let prev = env_flags[ i - 1 ] ;
4320
+
4321
+ // Do not process prefixes on their own
4322
+ if !is_flag_prefix ( curr) {
4323
+ // Concat flags preceded by a prefix
4324
+ let rustc_flag = join_flag_prefix ( prev, curr) ;
4325
+ codegen_flags. set_rustc_flag ( & rustc_flag) ;
4326
+ }
4327
+ }
4328
+
4329
+ codegen_flags
4330
+ }
4331
+
4332
+ fn set_rustc_flag ( & mut self , flag : & str ) {
4333
+ if flag. starts_with ( "-Z" ) {
4334
+ self . set_unstable_rustc_flag ( flag) ;
4335
+ } else {
4336
+ self . set_stable_rustc_flag ( flag) ;
4337
+ }
4338
+ }
4339
+
4340
+ fn set_stable_rustc_flag ( & mut self , flag : & str ) {
4341
+ let ( flag, value) = if let Some ( ( flag, value) ) = flag. split_once ( '=' ) {
4342
+ ( flag, Some ( value. to_owned ( ) ) )
4343
+ } else {
4344
+ ( flag, None )
4345
+ } ;
4346
+
4347
+ match flag {
4348
+ "-Ccode-model" => self . code_model = value,
4349
+ "-Cno-vectorize-loops" => self . no_vectorize_loops = true ,
4350
+ "-Cno-vectorize-slp" => self . no_vectorize_slp = true ,
4351
+ "-Cprofile-generate" => self . profile_generate = value,
4352
+ "-Cprofile-use" => self . profile_use = value,
4353
+ "-Ccontrol-flow-guard" => self . control_flow_guard = value. or ( Some ( "true" . into ( ) ) ) ,
4354
+ "-Clto" => self . lto = value. or ( Some ( "true" . into ( ) ) ) ,
4355
+ "-Crelocation-model" => self . relocation_model = value,
4356
+ "-Cembed-bitcode" => {
4357
+ self . embed_bitcode = value. map_or ( Some ( true ) , |val| match val. as_str ( ) {
4358
+ "y" | "yes" | "on" | "true" => Some ( true ) ,
4359
+ "n" | "no" | "off" | "false" => Some ( false ) ,
4360
+ _ => None ,
4361
+ } ) ;
4362
+ }
4363
+ "-Cforce-frame-pointers" => {
4364
+ self . force_frame_pointers = value. map_or ( Some ( true ) , |val| match val. as_str ( ) {
4365
+ "y" | "yes" | "on" | "true" => Some ( true ) ,
4366
+ "n" | "no" | "off" | "false" => Some ( false ) ,
4367
+ _ => None ,
4368
+ } ) ;
4369
+ }
4370
+ "-Clink-dead-code" => {
4371
+ self . link_dead_code = value. map_or ( Some ( true ) , |val| match val. as_str ( ) {
4372
+ "y" | "yes" | "on" | "true" => Some ( true ) ,
4373
+ "n" | "no" | "off" | "false" => Some ( false ) ,
4374
+ _ => None ,
4375
+ } )
4376
+ }
4377
+ "-Cno-redzone" => {
4378
+ self . no_redzone = value. map_or ( Some ( true ) , |val| match val. as_str ( ) {
4379
+ "y" | "yes" | "on" | "true" => Some ( true ) ,
4380
+ "n" | "no" | "off" | "false" => Some ( false ) ,
4381
+ _ => None ,
4382
+ } ) ;
4383
+ }
4384
+ "-Csoft-float" => {
4385
+ self . soft_float = value. map_or ( Some ( true ) , |val| match val. as_str ( ) {
4386
+ "y" | "yes" | "on" | "true" => Some ( true ) ,
4387
+ "n" | "no" | "off" | "false" => Some ( false ) ,
4388
+ _ => None ,
4389
+ } ) ;
4390
+ }
4391
+ _ => { }
4392
+ }
4393
+ }
4394
+
4395
+ fn set_unstable_rustc_flag ( & mut self , flag : & str ) {
4396
+ let ( flag, value) = if let Some ( ( flag, value) ) = flag. split_once ( '=' ) {
4397
+ ( flag, Some ( value. to_owned ( ) ) )
4398
+ } else {
4399
+ ( flag, None )
4400
+ } ;
4401
+
4402
+ match flag {
4403
+ "-Zbranch-protection" => self . branch_protection = value,
4404
+ _ => { }
4405
+ }
4406
+ }
4407
+
4408
+ // Rust and clang/cc don't agree on what equivalent flags should look like either.
4409
+ fn cc_flags (
4410
+ & self ,
4411
+ build : & Build ,
4412
+ path : & PathBuf ,
4413
+ family : & ToolFamily ,
4414
+ target : & Target ,
4415
+ ) -> Vec < OsString > {
4416
+ let push_if_supported = |flags : & mut Vec < OsString > , flag : OsString | {
4417
+ if build
4418
+ . is_flag_supported_inner ( & flag, path, target)
4419
+ . unwrap_or ( false )
4420
+ {
4421
+ flags. push ( flag) ;
4422
+ } else {
4423
+ build. cargo_output . print_warning ( & format ! (
4424
+ "Inherited flag {:?} is not supported by the currently used CC" ,
4425
+ flag
4426
+ ) ) ;
4427
+ }
4428
+ } ;
4429
+
4430
+ let mut flags: Vec < OsString > = vec ! [ ] ;
4431
+
4432
+ match family {
4433
+ ToolFamily :: Clang { .. } | ToolFamily :: Gnu => {
4434
+ if let Some ( value) = & self . branch_protection {
4435
+ push_if_supported (
4436
+ & mut flags,
4437
+ format ! ( "-mbranch-protection={}" , value. replace( "," , "+" ) ) . into ( ) ,
4438
+ ) ;
4439
+ }
4440
+ if let Some ( value) = & self . code_model {
4441
+ push_if_supported ( & mut flags, format ! ( "-mcmodel={value}" ) . into ( ) ) ;
4442
+ }
4443
+ if self . no_vectorize_loops {
4444
+ push_if_supported ( & mut flags, "-fno-vectorize" . into ( ) ) ;
4445
+ }
4446
+ if self . no_vectorize_slp {
4447
+ push_if_supported ( & mut flags, "-fno-slp-vectorize" . into ( ) ) ;
4448
+ }
4449
+ if let Some ( value) = & self . profile_generate {
4450
+ push_if_supported ( & mut flags, format ! ( "-fprofile-generate={value}" ) . into ( ) ) ;
4451
+ }
4452
+ if let Some ( value) = & self . profile_use {
4453
+ push_if_supported ( & mut flags, format ! ( "-fprofile-use={value}" ) . into ( ) ) ;
4454
+ }
4455
+ if let Some ( value) = & self . control_flow_guard {
4456
+ let cc_val = match value. as_str ( ) {
4457
+ "y" | "yes" | "on" | "true" | "checks" => Some ( "cf" ) ,
4458
+ "nochecks" => Some ( "cf-nochecks" ) ,
4459
+ "n" | "no" | "off" | "false" => Some ( "none" ) ,
4460
+ _ => None ,
4461
+ } ;
4462
+ if let Some ( cc_val) = cc_val {
4463
+ push_if_supported ( & mut flags, format ! ( "-mguard={cc_val}" ) . into ( ) ) ;
4464
+ }
4465
+ }
4466
+ if let Some ( value) = & self . lto {
4467
+ let cc_val = match value. as_str ( ) {
4468
+ "y" | "yes" | "on" | "true" | "fat" => Some ( "full" ) ,
4469
+ "thin" => Some ( "thin" ) ,
4470
+ _ => None ,
4471
+ } ;
4472
+ if let Some ( cc_val) = cc_val {
4473
+ push_if_supported ( & mut flags, format ! ( "-flto={cc_val}" ) . into ( ) ) ;
4474
+ }
4475
+ }
4476
+ if let Some ( value) = & self . relocation_model {
4477
+ let cc_flag = match value. as_str ( ) {
4478
+ "pic" => Some ( "-fPIC" ) ,
4479
+ "pie" => Some ( "-fPIE" ) ,
4480
+ "dynamic-no-pic" => Some ( "-mdynamic-no-pic" ) ,
4481
+ _ => None ,
4482
+ } ;
4483
+ if let Some ( cc_flag) = cc_flag {
4484
+ push_if_supported ( & mut flags, cc_flag. into ( ) ) ;
4485
+ }
4486
+ }
4487
+ if let Some ( value) = & self . embed_bitcode {
4488
+ let cc_val = if * value { "all" } else { "off" } ;
4489
+ push_if_supported ( & mut flags, format ! ( "-fembed-bitcode={cc_val}" ) . into ( ) ) ;
4490
+ }
4491
+ if let Some ( value) = & self . force_frame_pointers {
4492
+ let cc_flag = if * value {
4493
+ "-fno-omit-frame-pointer"
4494
+ } else {
4495
+ "-fomit-frame-pointer"
4496
+ } ;
4497
+ push_if_supported ( & mut flags, cc_flag. into ( ) ) ;
4498
+ }
4499
+ if let Some ( value) = & self . link_dead_code {
4500
+ if !value {
4501
+ push_if_supported ( & mut flags, "-dead_strip" . into ( ) ) ;
4502
+ }
4503
+ }
4504
+ if let Some ( value) = & self . no_redzone {
4505
+ let cc_flag = if * value {
4506
+ "-mno-red-zone"
4507
+ } else {
4508
+ "-mred-zone"
4509
+ } ;
4510
+ push_if_supported ( & mut flags, cc_flag. into ( ) ) ;
4511
+ }
4512
+ if let Some ( value) = & self . soft_float {
4513
+ let cc_flag = if * value {
4514
+ "-msoft-float"
4515
+ } else {
4516
+ "-mno-soft-float"
4517
+ } ;
4518
+ push_if_supported ( & mut flags, cc_flag. into ( ) ) ;
4519
+ }
4520
+ }
4521
+ ToolFamily :: Msvc { .. } => {
4522
+ if let Some ( value) = & self . control_flow_guard {
4523
+ let cc_val = match value. as_str ( ) {
4524
+ "y" | "yes" | "on" | "true" | "checks" => Some ( "cf" ) ,
4525
+ "n" | "no" | "off" | "false" => Some ( "cf-" ) ,
4526
+ _ => None ,
4527
+ } ;
4528
+ if let Some ( cc_val) = cc_val {
4529
+ push_if_supported ( & mut flags, format ! ( "/guard:{cc_val}" ) . into ( ) ) ;
4530
+ }
4531
+ }
4532
+ if let Some ( value) = & self . force_frame_pointers {
4533
+ let cc_flag = if * value { "/Oy-" } else { "/Oy" } ;
4534
+ push_if_supported ( & mut flags, cc_flag. into ( ) ) ;
4535
+ }
4536
+ }
4537
+ }
4538
+
4539
+ flags
4540
+ }
4541
+ }
4542
+
4224
4543
#[ derive( Clone , Copy , PartialEq ) ]
4225
4544
enum AsmFileExt {
4226
4545
/// `.asm` files. On MSVC targets, we assume these should be passed to MASM
0 commit comments