Skip to content

Commit 306b961

Browse files
committed
build: Inherit flags from rustc
Where applicable, detect which RUSTFLAGS were set for rustc and convert them into their corresponding cc flags in order to ensure consistent codegen across Rust and non-Rust modules.
1 parent 290a629 commit 306b961

File tree

1 file changed

+197
-0
lines changed

1 file changed

+197
-0
lines changed

src/lib.rs

+197
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,7 @@ pub struct Build {
312312
emit_rerun_if_env_changed: bool,
313313
cached_compiler_family: Arc<RwLock<HashMap<Box<Path>, ToolFamily>>>,
314314
shell_escaped_flags: Option<bool>,
315+
inherit_rustflags: bool,
315316
}
316317

317318
/// Represents the types of errors that may occur while using cc-rs.
@@ -437,6 +438,7 @@ impl Build {
437438
emit_rerun_if_env_changed: true,
438439
cached_compiler_family: Arc::default(),
439440
shell_escaped_flags: None,
441+
inherit_rustflags: true,
440442
}
441443
}
442444

@@ -1313,6 +1315,15 @@ impl Build {
13131315
self
13141316
}
13151317

1318+
/// Configure whether cc should automatically inherit compatible flags passed to rustc
1319+
/// from `CARGO_ENCODED_RUSTFLAGS`.
1320+
///
1321+
/// This option defaults to `true`.
1322+
pub fn inherit_rustflags(&mut self, inherit_rustflags: bool) -> &mut Build {
1323+
self.inherit_rustflags = inherit_rustflags;
1324+
self
1325+
}
1326+
13161327
#[doc(hidden)]
13171328
pub fn __set_env<A, B>(&mut self, a: A, b: B) -> &mut Build
13181329
where
@@ -1904,6 +1915,11 @@ impl Build {
19041915
cmd.args.push((**flag).into());
19051916
}
19061917

1918+
// Add cc flags inherited from matching rustc flags
1919+
if self.inherit_rustflags {
1920+
self.add_inherited_rustflags(&mut cmd)?;
1921+
}
1922+
19071923
for flag in self.flags_supported.iter() {
19081924
if self
19091925
.is_flag_supported_inner(flag, &cmd.path, &target)
@@ -2439,6 +2455,32 @@ impl Build {
24392455
Ok(())
24402456
}
24412457

2458+
fn add_inherited_rustflags(&self, cmd: &mut Tool) -> Result<(), Error> {
2459+
let env_os = match self.getenv("CARGO_ENCODED_RUSTFLAGS") {
2460+
Some(env) => env,
2461+
// No encoded RUSTFLAGS -> nothing to do
2462+
None => return Ok(()),
2463+
};
2464+
let mut cc_flags: Vec<OsString> = env_os
2465+
.to_string_lossy()
2466+
.split("\u{1f}")
2467+
// Strip prefixes from rustc flags
2468+
.flat_map(|flag| {
2469+
if flag == "-Z" || flag == "-C" {
2470+
None
2471+
} else if flag.starts_with("-Z") || flag.starts_with("-C") {
2472+
Some(&flag[2..])
2473+
} else {
2474+
Some(flag)
2475+
}
2476+
})
2477+
.flat_map(|flag| rustc_to_cc_flag(flag, cmd.family))
2478+
.collect();
2479+
2480+
cmd.args.append(&mut cc_flags);
2481+
Ok(())
2482+
}
2483+
24422484
fn has_flags(&self) -> bool {
24432485
let flags_env_var_name = if self.cpp { "CXXFLAGS" } else { "CFLAGS" };
24442486
let flags_env_var_value = self.getenv_with_target_prefixes(flags_env_var_name);
@@ -4221,6 +4263,161 @@ fn map_darwin_target_from_rust_to_compiler_architecture(target: &Target) -> &str
42214263
}
42224264
}
42234265

4266+
// Rust and clang/cc don't agree on what equivalent flags should look like either.
4267+
fn rustc_to_cc_flag(flag: &str, family: ToolFamily) -> Option<OsString> {
4268+
match family {
4269+
ToolFamily::Clang { .. } | ToolFamily::Gnu => match flag {
4270+
_ if flag.starts_with("branch-protection=") => {
4271+
Some(format!("-m{}", flag.replace(",", "+")).into())
4272+
}
4273+
_ if flag.starts_with("code-model=") => {
4274+
Some(flag.replace("code-model", "-mcmodel").into())
4275+
}
4276+
_ if flag.starts_with("no-vectorize-loops") => Some("-fno-vectorize".into()),
4277+
_ if flag.starts_with("no-vectorize-slp") => Some("-fno-slp-vectorize".into()),
4278+
_ if flag.starts_with("profile-generate") => Some(format!("-f{}", flag).into()),
4279+
_ if flag.starts_with("profile-use") => Some(format!("-f{}", flag).into()),
4280+
_ if flag.starts_with("control-flow-guard=") => {
4281+
let (_, rustc_val) = flag.split_once("=").unwrap();
4282+
let cc_val = match rustc_val {
4283+
"y" | "yes" | "on" | "true" | "checks" => "cf",
4284+
"nochecks" => "cf-nochecks",
4285+
"n" | "no" | "off" | "false" => "none",
4286+
_ => return None,
4287+
};
4288+
Some(format!("-mguard={cc_val}").into())
4289+
}
4290+
_ if flag.starts_with("embed-bitcode=") => {
4291+
let (_, rustc_val) = flag.split_once("=").unwrap();
4292+
let cc_val = match rustc_val {
4293+
"y" | "yes" | "on" | "true" => "all",
4294+
"n" | "no" | "off" | "false" => "off",
4295+
_ => return None,
4296+
};
4297+
Some(format!("-fembed-bitcode={cc_val}").into())
4298+
}
4299+
_ if flag.starts_with("force-frame-pointers") => {
4300+
let force_frame_pointers = if flag.contains("=") {
4301+
let (_, rustc_val) = flag.split_once("=").unwrap();
4302+
match rustc_val {
4303+
"y" | "yes" | "on" | "true" => true,
4304+
"n" | "no" | "off" | "false" => false,
4305+
_ => return None,
4306+
}
4307+
} else {
4308+
true
4309+
};
4310+
let cc_flag = if force_frame_pointers {
4311+
"-fno-omit-frame-pointer"
4312+
} else {
4313+
"-fomit-frame-pointer"
4314+
};
4315+
Some(cc_flag.into())
4316+
}
4317+
_ if flag.starts_with("link-dead-code") => {
4318+
if flag.contains("=") {
4319+
let (_, rustc_val) = flag.split_once("=").unwrap();
4320+
match rustc_val {
4321+
"n" | "no" | "off" | "false" => Some("-dead_strip".into()),
4322+
_ => None,
4323+
}
4324+
} else {
4325+
None
4326+
}
4327+
}
4328+
_ if flag.starts_with("lto") => {
4329+
let lto_mode = if flag.contains("=") {
4330+
let (_, rustc_val) = flag.split_once("=").unwrap();
4331+
match rustc_val {
4332+
"y" | "yes" | "on" | "true" | "fat" => "full",
4333+
"thin" => "thin",
4334+
_ => return None,
4335+
}
4336+
} else {
4337+
"full"
4338+
};
4339+
4340+
Some(format!("-flto={}", lto_mode).into())
4341+
}
4342+
_ if flag.starts_with("no-redzone") => {
4343+
let no_redzone = if flag.contains("=") {
4344+
let (_, rustc_val) = flag.split_once("=").unwrap();
4345+
match rustc_val {
4346+
"y" | "yes" | "on" | "true" => true,
4347+
"n" | "no" | "off" | "false" => false,
4348+
_ => return None,
4349+
}
4350+
} else {
4351+
true
4352+
};
4353+
4354+
let cc_flag = if no_redzone {
4355+
"-mno-red-zone"
4356+
} else {
4357+
"-mred-zone"
4358+
};
4359+
Some(cc_flag.into())
4360+
}
4361+
_ if flag.starts_with("relocation-model=") => {
4362+
let (_, rustc_val) = flag.split_once("=").unwrap();
4363+
let cc_flag = match rustc_val {
4364+
"pic" => "-fPIC",
4365+
"pie" => "-fPIE",
4366+
"dynamic-no-pic" => "-mdynamic-no-pic",
4367+
_ => return None,
4368+
};
4369+
Some(cc_flag.into())
4370+
}
4371+
_ if flag.starts_with("soft-float") => {
4372+
let soft_float = if flag.contains("=") {
4373+
let (_, rustc_val) = flag.split_once("=").unwrap();
4374+
match rustc_val {
4375+
"y" | "yes" | "on" | "true" => true,
4376+
"n" | "no" | "off" | "false" => false,
4377+
_ => return None,
4378+
}
4379+
} else {
4380+
true
4381+
};
4382+
4383+
let cc_flag = if soft_float {
4384+
"-msoft-float"
4385+
} else {
4386+
"-mno-soft-float"
4387+
};
4388+
Some(cc_flag.into())
4389+
}
4390+
_ => None,
4391+
},
4392+
ToolFamily::Msvc { .. } => match flag {
4393+
_ if flag.starts_with("control-flow-guard=") => {
4394+
let (_, rustc_val) = flag.split_once("=").unwrap();
4395+
let cc_val = match rustc_val {
4396+
"y" | "yes" | "on" | "true" | "checks" => "cf",
4397+
"n" | "no" | "off" | "false" => "cf-",
4398+
_ => return None,
4399+
};
4400+
Some(format!("/guard:{cc_val}").into())
4401+
}
4402+
_ if flag.starts_with("force-frame-pointers") => {
4403+
let force_frame_pointers = if flag.contains("=") {
4404+
let (_, rustc_val) = flag.split_once("=").unwrap();
4405+
match rustc_val {
4406+
"y" | "yes" | "on" | "true" => true,
4407+
"n" | "no" | "off" | "false" => false,
4408+
_ => return None,
4409+
}
4410+
} else {
4411+
true
4412+
};
4413+
let cc_flag = if force_frame_pointers { "/Oy-" } else { "/Oy" };
4414+
Some(cc_flag.into())
4415+
}
4416+
_ => None,
4417+
},
4418+
}
4419+
}
4420+
42244421
#[derive(Clone, Copy, PartialEq)]
42254422
enum AsmFileExt {
42264423
/// `.asm` files. On MSVC targets, we assume these should be passed to MASM

0 commit comments

Comments
 (0)