project_model/toolchain_info/
rustc_cfg.rs1use anyhow::Context;
4use cfg::CfgAtom;
5use rustc_hash::FxHashMap;
6use toolchain::Tool;
7
8use crate::{toolchain_info::QueryConfig, utf8_stdout};
9
10pub 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 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}