project_model/toolchain_info/
rustc_cfg.rs

1//! Get the built-in cfg flags for the to be compile platform.
2
3use anyhow::Context;
4use cfg::CfgAtom;
5use rustc_hash::FxHashMap;
6use toolchain::Tool;
7
8use crate::{toolchain_info::QueryConfig, utf8_stdout};
9
10/// Uses `rustc --print cfg` to fetch the builtin cfgs.
11pub fn get(
12    config: QueryConfig<'_>,
13    target: Option<&str>,
14    extra_env: &FxHashMap<String, Option<String>>,
15) -> Vec<CfgAtom> {
16    let _p = tracing::info_span!("rustc_cfg::get").entered();
17
18    let rustc_cfgs = rustc_print_cfg(target, extra_env, config);
19    let rustc_cfgs = match rustc_cfgs {
20        Ok(cfgs) => cfgs,
21        Err(e) => {
22            tracing::warn!(?e, "failed to get rustc cfgs");
23            return vec![];
24        }
25    };
26
27    // These are unstable but the standard libraries gate on them.
28    let unstable = vec![
29        r#"target_has_atomic_equal_alignment="8""#,
30        r#"target_has_atomic_equal_alignment="16""#,
31        r#"target_has_atomic_equal_alignment="32""#,
32        r#"target_has_atomic_equal_alignment="64""#,
33        r#"target_has_atomic_equal_alignment="128""#,
34        r#"target_has_atomic_equal_alignment="ptr""#,
35        r#"target_has_atomic_load_store"#,
36        r#"target_has_atomic_load_store="8""#,
37        r#"target_has_atomic_load_store="16""#,
38        r#"target_has_atomic_load_store="32""#,
39        r#"target_has_atomic_load_store="64""#,
40        r#"target_has_atomic_load_store="128""#,
41        r#"target_has_atomic_load_store="ptr""#,
42        r#"target_thread_local"#,
43        r#"target_has_atomic"#,
44    ];
45    let rustc_cfgs =
46        rustc_cfgs.lines().chain(unstable).map(crate::parse_cfg).collect::<Result<Vec<_>, _>>();
47    match rustc_cfgs {
48        Ok(rustc_cfgs) => {
49            tracing::debug!(?rustc_cfgs, "rustc cfgs found");
50            rustc_cfgs
51        }
52        Err(e) => {
53            tracing::error!(?e, "failed to parse rustc cfgs");
54            vec![]
55        }
56    }
57}
58
59fn rustc_print_cfg(
60    target: Option<&str>,
61    extra_env: &FxHashMap<String, Option<String>>,
62    config: QueryConfig<'_>,
63) -> anyhow::Result<String> {
64    const RUSTC_ARGS: [&str; 2] = ["--print", "cfg"];
65    let (sysroot, current_dir) = match config {
66        QueryConfig::Cargo(sysroot, cargo_toml, _) => {
67            let mut cmd = sysroot.tool(Tool::Cargo, cargo_toml.parent(), extra_env);
68            cmd.env("__CARGO_TEST_CHANNEL_OVERRIDE_DO_NOT_USE_THIS", "nightly");
69            cmd.args(["rustc", "-Z", "unstable-options"]).args(RUSTC_ARGS);
70            if let Some(target) = target {
71                cmd.args(["--target", target]);
72            }
73            cmd.args(["--", "-O"]);
74
75            match utf8_stdout(&mut cmd) {
76                Ok(it) => return Ok(it),
77                Err(e) => {
78                    tracing::warn!(
79                        %e,
80                        "failed to run `{cmd:?}`, falling back to invoking rustc directly"
81                    );
82                    (sysroot, cargo_toml.parent().as_ref())
83                }
84            }
85        }
86        QueryConfig::Rustc(sysroot, current_dir) => (sysroot, current_dir),
87    };
88
89    let mut cmd = sysroot.tool(Tool::Rustc, current_dir, extra_env);
90    cmd.args(RUSTC_ARGS);
91    cmd.arg("-O");
92    if let Some(target) = target {
93        cmd.args(["--target", target]);
94    }
95
96    utf8_stdout(&mut cmd).with_context(|| format!("unable to fetch cfgs via `{cmd:?}`"))
97}
98
99#[cfg(test)]
100mod tests {
101    use paths::{AbsPathBuf, Utf8PathBuf};
102
103    use crate::{ManifestPath, Sysroot};
104
105    use super::*;
106
107    #[test]
108    fn cargo() {
109        let manifest_path = concat!(env!("CARGO_MANIFEST_DIR"), "/Cargo.toml");
110        let sysroot = Sysroot::empty();
111        let manifest_path =
112            ManifestPath::try_from(AbsPathBuf::assert(Utf8PathBuf::from(manifest_path))).unwrap();
113        let cfg = QueryConfig::Cargo(&sysroot, &manifest_path, &None);
114        assert_ne!(get(cfg, None, &FxHashMap::default()), vec![]);
115    }
116
117    #[test]
118    fn rustc() {
119        let sysroot = Sysroot::empty();
120        let cfg = QueryConfig::Rustc(&sysroot, env!("CARGO_MANIFEST_DIR").as_ref());
121        assert_ne!(get(cfg, None, &FxHashMap::default()), vec![]);
122    }
123}