project_model/toolchain_info/
target_data_layout.rs1use anyhow::Context;
4use rustc_hash::FxHashMap;
5use toolchain::Tool;
6
7use crate::{Sysroot, toolchain_info::QueryConfig, utf8_stdout};
8
9pub fn get(
11 config: QueryConfig<'_>,
12 target: Option<&str>,
13 extra_env: &FxHashMap<String, Option<String>>,
14) -> anyhow::Result<String> {
15 const RUSTC_ARGS: [&str; 2] = ["--print", "target-spec-json"];
16 let process = |output: String| {
17 (|| Some(output.split_once(r#""data-layout": ""#)?.1.split_once('"')?.0.to_owned()))()
18 .ok_or_else(|| {
19 anyhow::format_err!("could not parse target-spec-json from command output")
20 })
21 };
22 let (sysroot, current_dir) = match config {
23 QueryConfig::Cargo(sysroot, cargo_toml, _) => {
24 let mut cmd = sysroot.tool(Tool::Cargo, cargo_toml.parent(), extra_env);
25 cmd.env("RUSTC_BOOTSTRAP", "1");
26 cmd.args(["rustc", "-Z", "unstable-options"]).args(RUSTC_ARGS);
27 if let Some(target) = target {
28 cmd.args(["--target", target]);
29 }
30 cmd.args(["--", "-Z", "unstable-options"]);
31 match utf8_stdout(&mut cmd) {
32 Ok(output) => return process(output),
33 Err(e) => {
34 tracing::warn!(%e, "failed to run `{cmd:?}`, falling back to invoking rustc directly");
35 (sysroot, cargo_toml.parent().as_ref())
36 }
37 }
38 }
39 QueryConfig::Rustc(sysroot, current_dir) => (sysroot, current_dir),
40 };
41
42 let mut cmd = Sysroot::tool(sysroot, Tool::Rustc, current_dir, extra_env);
43 cmd.env("RUSTC_BOOTSTRAP", "1").args(["-Z", "unstable-options"]).args(RUSTC_ARGS);
44 if let Some(target) = target {
45 cmd.args(["--target", target]);
46 }
47 utf8_stdout(&mut cmd)
48 .with_context(|| format!("unable to fetch target-data-layout via `{cmd:?}`"))
49 .and_then(process)
50}
51
52#[cfg(test)]
53mod tests {
54 use paths::{AbsPathBuf, Utf8PathBuf};
55
56 use crate::{ManifestPath, Sysroot};
57
58 use super::*;
59
60 #[test]
61 fn cargo() {
62 let manifest_path = concat!(env!("CARGO_MANIFEST_DIR"), "/Cargo.toml");
63 let sysroot = Sysroot::empty();
64 let manifest_path =
65 ManifestPath::try_from(AbsPathBuf::assert(Utf8PathBuf::from(manifest_path))).unwrap();
66 let cfg = QueryConfig::Cargo(&sysroot, &manifest_path, &None);
67 assert!(get(cfg, None, &FxHashMap::default()).is_ok());
68 }
69
70 #[test]
71 fn rustc() {
72 let sysroot = Sysroot::empty();
73 let cfg = QueryConfig::Rustc(&sysroot, env!("CARGO_MANIFEST_DIR").as_ref());
74 assert!(get(cfg, None, &FxHashMap::default()).is_ok());
75 }
76}