From ccd991547bacfe92251ddb812fb42e1a18c162fe Mon Sep 17 00:00:00 2001 From: Michal Rostecki Date: Thu, 2 Mar 2023 16:54:05 +0100 Subject: [PATCH] Fix `CARGO_CFG_` vars for configs defined both with and without value When a rustc cfg is defined both with and without value, the environment variable should provide all the values. Before this change, it ended up being empty. Fixes: #11789 --- src/cargo/core/compiler/custom_build.rs | 18 ++----- tests/testsuite/build_script_env.rs | 62 +++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 14 deletions(-) diff --git a/src/cargo/core/compiler/custom_build.rs b/src/cargo/core/compiler/custom_build.rs index 40df22bb7ae..40df2261abb 100644 --- a/src/cargo/core/compiler/custom_build.rs +++ b/src/cargo/core/compiler/custom_build.rs @@ -231,14 +231,11 @@ fn build_work(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult { for cfg in bcx.target_data.cfg(unit.kind) { match *cfg { Cfg::Name(ref n) => { - cfg_map.insert(n.clone(), None); + cfg_map.insert(n.clone(), Vec::new()); } Cfg::KeyPair(ref k, ref v) => { - if let Some(ref mut values) = - *cfg_map.entry(k.clone()).or_insert_with(|| Some(Vec::new())) - { - values.push(v.clone()) - } + let values = cfg_map.entry(k.clone()).or_default(); + values.push(v.clone()); } } } @@ -249,14 +246,7 @@ fn build_work(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult { continue; } let k = format!("CARGO_CFG_{}", super::envify(&k)); - match v { - Some(list) => { - cmd.env(&k, list.join(",")); - } - None => { - cmd.env(&k, ""); - } - } + cmd.env(&k, v.join(",")); } // Also inform the build script of the rustc compiler context. diff --git a/tests/testsuite/build_script_env.rs b/tests/testsuite/build_script_env.rs index 6ad4ab97b19..bc87b7120a5 100644 --- a/tests/testsuite/build_script_env.rs +++ b/tests/testsuite/build_script_env.rs @@ -239,3 +239,65 @@ fn cfg_paradox() { .with_stderr_contains("[..]--cfg=bertrand[..]") .run(); } + +/// This test checks how Cargo handles rustc cfgs which are defined both with +/// and without a value. The expected behavior is that the environment variable +/// is going to contain all the values. +/// +/// For example, this configuration: +/// ``` +/// target_has_atomic +/// target_has_atomic="16" +/// target_has_atomic="32" +/// target_has_atomic="64" +/// target_has_atomic="8" +/// target_has_atomic="ptr" +/// ``` +/// +/// Should result in the following environment variable: +/// +/// ``` +/// CARGO_CFG_TARGET_HAS_ATOMIC=16,32,64,8,ptr +/// ``` +/// +/// On the other hand, configuration symbols without any value should result in +/// an empty string. +/// +/// For example, this configuration: +/// +/// ``` +/// target_thread_local +/// ``` +/// +/// Should result in the following environment variable: +/// +/// ``` +/// CARGO_CFG_TARGET_THREAD_LOCAL= +/// ``` +#[cargo_test(nightly, reason = "affected rustc cfg is unstable")] +#[cfg(target_arch = "x86_64")] +fn rustc_cfg_with_and_without_value() { + let build_rs = r#" + fn main() { + let cfg = std::env::var("CARGO_CFG_TARGET_HAS_ATOMIC"); + eprintln!("CARGO_CFG_TARGET_HAS_ATOMIC={cfg:?}"); + let cfg = std::env::var("CARGO_CFG_WINDOWS"); + eprintln!("CARGO_CFG_WINDOWS={cfg:?}"); + let cfg = std::env::var("CARGO_CFG_UNIX"); + eprintln!("CARGO_CFG_UNIX={cfg:?}"); + } + "#; + let p = project() + .file("src/lib.rs", r#""#) + .file("build.rs", build_rs) + .build(); + + let mut check = p.cargo("check -vv"); + #[cfg(target_has_atomic = "64")] + check.with_stderr_contains("[foo 0.0.1] CARGO_CFG_TARGET_HAS_ATOMIC=Ok(\"[..]64[..]\")"); + #[cfg(windows)] + check.with_stderr_contains("[foo 0.0.1] CARGO_CFG_WINDOWS=Ok(\"\")"); + #[cfg(unix)] + check.with_stderr_contains("[foo 0.0.1] CARGO_CFG_UNIX=Ok(\"\")"); + check.run(); +}