Skip to content

Commit 42612c9

Browse files
committed
Add support for parsing *FLAGS with shlex
1 parent eb33906 commit 42612c9

File tree

3 files changed

+53
-6
lines changed

3 files changed

+53
-6
lines changed

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ rust-version = "1.63"
2121

2222
[dependencies]
2323
jobserver = { version = "0.1.30", default-features = false, optional = true }
24+
shlex = "1.3.0"
2425

2526
[target.'cfg(unix)'.dependencies]
2627
# Don't turn on the feature "std" for this, see https://github.com/rust-lang/cargo/issues/4866

src/lib.rs

+33-6
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@
8484
//! * `CC_ENABLE_DEBUG_OUTPUT` - if set, compiler command invocations and exit codes will
8585
//! be logged to stdout. This is useful for debugging build script issues, but can be
8686
//! overly verbose for normal use.
87+
//! * `CC_PARSE_FLAGS_WITH_SHLEX` - if set, *FLAGS will be parsed with shlex, similar to
88+
//! `make` and `cmake`. `CFLAGS='-foo "-bar baz"'` will be parsed as `["foo", "-bar baz"]`
89+
//! instead of `["-foo", "\"-bar", "baz\""]`
8790
//! * `CXX...` - see [C++ Support](#c-support).
8891
//!
8992
//! Furthermore, projects using this crate may specify custom environment variables
@@ -227,6 +230,7 @@ use std::sync::{Arc, RwLock};
227230
#[cfg(feature = "parallel")]
228231
mod parallel;
229232
mod windows;
233+
use shlex::Shlex;
230234
// Regardless of whether this should be in this crate's public API,
231235
// it has been since 2015, so don't break it.
232236
pub use windows::find_tools as windows_registry;
@@ -301,6 +305,7 @@ pub struct Build {
301305
apple_versions_cache: Arc<RwLock<HashMap<Box<str>, Arc<str>>>>,
302306
emit_rerun_if_env_changed: bool,
303307
cached_compiler_family: Arc<RwLock<HashMap<Box<Path>, ToolFamily>>>,
308+
parse_flags_with_shlex: Option<bool>,
304309
}
305310

306311
/// Represents the types of errors that may occur while using cc-rs.
@@ -425,6 +430,7 @@ impl Build {
425430
apple_versions_cache: Arc::new(RwLock::new(HashMap::new())),
426431
emit_rerun_if_env_changed: true,
427432
cached_compiler_family: Arc::default(),
433+
parse_flags_with_shlex: None,
428434
}
429435
}
430436

@@ -1277,6 +1283,15 @@ impl Build {
12771283
self
12781284
}
12791285

1286+
/// Configure whether *FLAGS variables are parsed using `shlex`, similarly to `make` and
1287+
/// `cmake`.
1288+
///
1289+
/// This option defaults to `false`.
1290+
pub fn parse_flags_with_shlex(&mut self, parse_flags_with_shlex: bool) -> &mut Build {
1291+
self.parse_flags_with_shlex = Some(parse_flags_with_shlex);
1292+
self
1293+
}
1294+
12801295
#[doc(hidden)]
12811296
pub fn __set_env<A, B>(&mut self, a: A, b: B) -> &mut Build
12821297
where
@@ -3634,6 +3649,10 @@ impl Build {
36343649
})
36353650
}
36363651

3652+
fn get_parse_flags_with_shlex(&self) -> bool {
3653+
self.parse_flags_with_shlex.unwrap_or_else(|| self.getenv("CC_PARSE_FLAGS_WITH_SHLEX").is_some())
3654+
}
3655+
36373656
fn get_dwarf_version(&self) -> Option<u32> {
36383657
// Tentatively matches the DWARF version defaults as of rustc 1.62.
36393658
let target = self.get_target().ok()?;
@@ -3748,12 +3767,20 @@ impl Build {
37483767
}
37493768

37503769
fn envflags(&self, name: &str) -> Result<Vec<String>, Error> {
3751-
Ok(self
3752-
.getenv_with_target_prefixes(name)?
3753-
.to_string_lossy()
3754-
.split_ascii_whitespace()
3755-
.map(ToString::to_string)
3756-
.collect())
3770+
let env_os = self
3771+
.getenv_with_target_prefixes(name)?;
3772+
let env = env_os
3773+
.to_string_lossy();
3774+
3775+
if self.get_parse_flags_with_shlex() {
3776+
Ok(Shlex::new(&env)
3777+
.collect())
3778+
} else {
3779+
Ok(env
3780+
.split_ascii_whitespace()
3781+
.map(ToString::to_string)
3782+
.collect())
3783+
}
37573784
}
37583785

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

tests/cflags.rs

+19
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,22 @@ fn gnu_no_warnings_if_cflags() {
1313

1414
test.cmd(0).must_not_have("-Wall").must_not_have("-Wextra");
1515
}
16+
17+
/// This test is in its own module because it modifies the environment and would affect other tests
18+
/// when run in parallel with them.
19+
#[test]
20+
fn gnu_test_parse_flags_with_shlex() {
21+
env::set_var("CFLAGS", "foo \"bar baz\"");
22+
env::set_var("CC_PARSE_FLAGS_WITH_SHLEX", "1");
23+
let test = Test::gnu();
24+
test.gcc().file("foo.c").compile("foo");
25+
26+
test.cmd(0).must_have("foo").must_have("bar baz");
27+
28+
29+
env::remove_var("CC_PARSE_FLAGS_WITH_SHLEX");
30+
let test = Test::gnu();
31+
test.gcc().file("foo.c").compile("foo");
32+
33+
test.cmd(0).must_have("foo").must_have_in_order("\"bar", "baz\"");
34+
}

0 commit comments

Comments
 (0)