Skip to content

Commit 0dd683c

Browse files
authored
Always read from all CFLAGS-style flags (#1401)
1 parent fcf940e commit 0dd683c

File tree

3 files changed

+110
-32
lines changed

3 files changed

+110
-32
lines changed

src/lib.rs

+53-30
Original file line numberDiff line numberDiff line change
@@ -653,7 +653,12 @@ impl Build {
653653
/// ```
654654
///
655655
pub fn try_flags_from_environment(&mut self, environ_key: &str) -> Result<&mut Build, Error> {
656-
let flags = self.envflags(environ_key)?;
656+
let flags = self.envflags(environ_key)?.ok_or_else(|| {
657+
Error::new(
658+
ErrorKind::EnvVarNotFound,
659+
format!("could not find environment variable {environ_key}"),
660+
)
661+
})?;
657662
self.flags.extend(
658663
flags
659664
.into_iter()
@@ -1907,7 +1912,8 @@ impl Build {
19071912
cmd.args.push(directory.as_os_str().into());
19081913
}
19091914

1910-
if let Ok(flags) = self.envflags(if self.cpp { "CXXFLAGS" } else { "CFLAGS" }) {
1915+
let flags = self.envflags(if self.cpp { "CXXFLAGS" } else { "CFLAGS" })?;
1916+
if let Some(flags) = &flags {
19111917
for arg in flags {
19121918
cmd.push_cc_arg(arg.into());
19131919
}
@@ -1918,12 +1924,12 @@ impl Build {
19181924
// CFLAGS/CXXFLAGS, since those variables presumably already contain
19191925
// the desired set of warnings flags.
19201926

1921-
if self.warnings.unwrap_or(!self.has_flags()) {
1927+
if self.warnings.unwrap_or(flags.is_none()) {
19221928
let wflags = cmd.family.warnings_flags().into();
19231929
cmd.push_cc_arg(wflags);
19241930
}
19251931

1926-
if self.extra_warnings.unwrap_or(!self.has_flags()) {
1932+
if self.extra_warnings.unwrap_or(flags.is_none()) {
19271933
if let Some(wflags) = cmd.family.extra_warnings_flags() {
19281934
cmd.push_cc_arg(wflags.into());
19291935
}
@@ -2443,12 +2449,6 @@ impl Build {
24432449
Ok(())
24442450
}
24452451

2446-
fn has_flags(&self) -> bool {
2447-
let flags_env_var_name = if self.cpp { "CXXFLAGS" } else { "CFLAGS" };
2448-
let flags_env_var_value = self.getenv_with_target_prefixes(flags_env_var_name);
2449-
flags_env_var_value.is_ok()
2450-
}
2451-
24522452
fn msvc_macro_assembler(&self) -> Result<Command, Error> {
24532453
let target = self.get_target()?;
24542454
let tool = if target.arch == "x86_64" {
@@ -3115,8 +3115,8 @@ impl Build {
31153115
fn try_get_archiver_and_flags(&self) -> Result<(Command, PathBuf, bool), Error> {
31163116
let (mut cmd, name) = self.get_base_archiver()?;
31173117
let mut any_flags = false;
3118-
if let Ok(flags) = self.envflags("ARFLAGS") {
3119-
any_flags |= !flags.is_empty();
3118+
if let Some(flags) = self.envflags("ARFLAGS")? {
3119+
any_flags = true;
31203120
cmd.args(flags);
31213121
}
31223122
for flag in &self.ar_flags {
@@ -3162,7 +3162,7 @@ impl Build {
31623162
/// see [`Self::get_ranlib`] for the complete description.
31633163
pub fn try_get_ranlib(&self) -> Result<Command, Error> {
31643164
let mut cmd = self.get_base_ranlib()?;
3165-
if let Ok(flags) = self.envflags("RANLIBFLAGS") {
3165+
if let Some(flags) = self.envflags("RANLIBFLAGS")? {
31663166
cmd.args(flags);
31673167
}
31683168
Ok(cmd)
@@ -3643,41 +3643,64 @@ impl Build {
36433643
})
36443644
}
36453645

3646-
fn getenv_with_target_prefixes(&self, var_base: &str) -> Result<Arc<OsStr>, Error> {
3646+
/// The list of environment variables to check for a given env, in order of priority.
3647+
fn target_envs(&self, env: &str) -> Result<[String; 4], Error> {
36473648
let target = self.get_raw_target()?;
36483649
let kind = if self.get_is_cross_compile()? {
36493650
"TARGET"
36503651
} else {
36513652
"HOST"
36523653
};
36533654
let target_u = target.replace('-', "_");
3655+
3656+
Ok([
3657+
format!("{env}_{target}"),
3658+
format!("{env}_{target_u}"),
3659+
format!("{kind}_{env}"),
3660+
env.to_string(),
3661+
])
3662+
}
3663+
3664+
/// Get a single-valued environment variable with target variants.
3665+
fn getenv_with_target_prefixes(&self, env: &str) -> Result<Arc<OsStr>, Error> {
3666+
// Take from first environment variable in the environment.
36543667
let res = self
3655-
.getenv(&format!("{}_{}", var_base, target))
3656-
.or_else(|| self.getenv(&format!("{}_{}", var_base, target_u)))
3657-
.or_else(|| self.getenv(&format!("{}_{}", kind, var_base)))
3658-
.or_else(|| self.getenv(var_base));
3668+
.target_envs(env)?
3669+
.iter()
3670+
.filter_map(|env| self.getenv(env))
3671+
.next();
36593672

36603673
match res {
36613674
Some(res) => Ok(res),
36623675
None => Err(Error::new(
36633676
ErrorKind::EnvVarNotFound,
3664-
format!("Could not find environment variable {}.", var_base),
3677+
format!("could not find environment variable {env}"),
36653678
)),
36663679
}
36673680
}
36683681

3669-
fn envflags(&self, name: &str) -> Result<Vec<String>, Error> {
3670-
let env_os = self.getenv_with_target_prefixes(name)?;
3671-
let env = env_os.to_string_lossy();
3672-
3673-
if self.get_shell_escaped_flags() {
3674-
Ok(Shlex::new(&env).collect())
3675-
} else {
3676-
Ok(env
3677-
.split_ascii_whitespace()
3678-
.map(ToString::to_string)
3679-
.collect())
3682+
/// Get values from CFLAGS-style environment variable.
3683+
fn envflags(&self, env: &str) -> Result<Option<Vec<String>>, Error> {
3684+
// Collect from all environment variables, in reverse order as in
3685+
// `getenv_with_target_prefixes` precedence (so that `CFLAGS_$TARGET`
3686+
// can override flags in `TARGET_CFLAGS`, which overrides those in
3687+
// `CFLAGS`).
3688+
let mut any_set = false;
3689+
let mut res = vec![];
3690+
for env in self.target_envs(env)?.iter().rev() {
3691+
if let Some(var) = self.getenv(env) {
3692+
any_set = true;
3693+
3694+
let var = var.to_string_lossy();
3695+
if self.get_shell_escaped_flags() {
3696+
res.extend(Shlex::new(&var));
3697+
} else {
3698+
res.extend(var.split_ascii_whitespace().map(ToString::to_string));
3699+
}
3700+
}
36803701
}
3702+
3703+
Ok(if any_set { Some(res) } else { None })
36813704
}
36823705

36833706
fn fix_env_for_apple_os(&self, cmd: &mut Command) -> Result<(), Error> {

tests/cc_env.rs

+31
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ fn main() {
1616
path_to_ccache();
1717
more_spaces();
1818
clang_cl();
19+
env_var_alternatives_override();
1920
}
2021

2122
fn ccache() {
@@ -126,3 +127,33 @@ fn clang_cl() {
126127
test_compiler(test.gcc());
127128
}
128129
}
130+
131+
fn env_var_alternatives_override() {
132+
let compiler1 = format!("clang1{}", env::consts::EXE_SUFFIX);
133+
let compiler2 = format!("clang2{}", env::consts::EXE_SUFFIX);
134+
let compiler3 = format!("clang3{}", env::consts::EXE_SUFFIX);
135+
let compiler4 = format!("clang4{}", env::consts::EXE_SUFFIX);
136+
137+
let test = Test::new();
138+
test.shim(&compiler1);
139+
test.shim(&compiler2);
140+
test.shim(&compiler3);
141+
test.shim(&compiler4);
142+
143+
env::set_var("CC", &compiler1);
144+
let compiler = test.gcc().target("x86_64-unknown-none").get_compiler();
145+
assert_eq!(compiler.path(), Path::new(&compiler1));
146+
147+
env::set_var("HOST_CC", &compiler2);
148+
env::set_var("TARGET_CC", &compiler2);
149+
let compiler = test.gcc().target("x86_64-unknown-none").get_compiler();
150+
assert_eq!(compiler.path(), Path::new(&compiler2));
151+
152+
env::set_var("CC_x86_64_unknown_none", &compiler3);
153+
let compiler = test.gcc().target("x86_64-unknown-none").get_compiler();
154+
assert_eq!(compiler.path(), Path::new(&compiler3));
155+
156+
env::set_var("CC_x86_64-unknown-none", &compiler4);
157+
let compiler = test.gcc().target("x86_64-unknown-none").get_compiler();
158+
assert_eq!(compiler.path(), Path::new(&compiler4));
159+
}

tests/cflags.rs

+26-2
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,39 @@
1+
//! This test is in its own module because it modifies the environment and would affect other tests
2+
//! when run in parallel with them.
13
mod support;
24

35
use crate::support::Test;
46
use std::env;
57

6-
/// This test is in its own module because it modifies the environment and would affect other tests
7-
/// when run in parallel with them.
88
#[test]
9+
fn cflags() {
10+
gnu_no_warnings_if_cflags();
11+
cflags_order();
12+
}
13+
914
fn gnu_no_warnings_if_cflags() {
1015
env::set_var("CFLAGS", "-arbitrary");
1116
let test = Test::gnu();
1217
test.gcc().file("foo.c").compile("foo");
1318

1419
test.cmd(0).must_not_have("-Wall").must_not_have("-Wextra");
1520
}
21+
22+
/// Test the ordering of `CFLAGS*` variables.
23+
fn cflags_order() {
24+
unsafe { env::set_var("CFLAGS", "-arbitrary1") };
25+
unsafe { env::set_var("HOST_CFLAGS", "-arbitrary2") };
26+
unsafe { env::set_var("TARGET_CFLAGS", "-arbitrary2") };
27+
unsafe { env::set_var("CFLAGS_x86_64_unknown_none", "-arbitrary3") };
28+
unsafe { env::set_var("CFLAGS_x86_64-unknown-none", "-arbitrary4") };
29+
let test = Test::gnu();
30+
test.gcc()
31+
.target("x86_64-unknown-none")
32+
.file("foo.c")
33+
.compile("foo");
34+
35+
test.cmd(0)
36+
.must_have_in_order("-arbitrary1", "-arbitrary2")
37+
.must_have_in_order("-arbitrary2", "-arbitrary3")
38+
.must_have_in_order("-arbitrary3", "-arbitrary4");
39+
}

0 commit comments

Comments
 (0)