Skip to content

Commit 8989fb8

Browse files
committed
Discover rustc_cfg through unstable cargo options
1 parent 526040e commit 8989fb8

File tree

3 files changed

+83
-33
lines changed

3 files changed

+83
-33
lines changed

crates/project_model/src/cargo_workspace.rs

Lines changed: 48 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -201,31 +201,12 @@ impl CargoWorkspace {
201201
if let Some(parent) = cargo_toml.parent() {
202202
meta.current_dir(parent.to_path_buf());
203203
}
204-
let target = if let Some(target) = config.target.as_ref() {
204+
let target = if let Some(target) = &config.target {
205205
Some(target.clone())
206+
} else if let stdout @ Some(_) = cargo_config_build_target(cargo_toml) {
207+
stdout
206208
} else {
207-
// cargo metadata defaults to giving information for _all_ targets.
208-
// In the absence of a preference from the user, we use the host platform.
209-
let mut rustc = Command::new(toolchain::rustc());
210-
rustc.current_dir(cargo_toml.parent().unwrap()).arg("-vV");
211-
log::debug!("Discovering host platform by {:?}", rustc);
212-
match utf8_stdout(rustc) {
213-
Ok(stdout) => {
214-
let field = "host: ";
215-
let target = stdout.lines().find_map(|l| l.strip_prefix(field));
216-
if let Some(target) = target {
217-
Some(target.to_string())
218-
} else {
219-
// If we fail to resolve the host platform, it's not the end of the world.
220-
log::info!("rustc -vV did not report host platform, got:\n{}", stdout);
221-
None
222-
}
223-
}
224-
Err(e) => {
225-
log::warn!("Failed to discover host platform: {}", e);
226-
None
227-
}
228-
}
209+
rustc_discover_host_triple(cargo_toml)
229210
};
230211
if let Some(target) = target {
231212
meta.other_options(vec![String::from("--filter-platform"), target]);
@@ -368,3 +349,47 @@ impl CargoWorkspace {
368349
self.packages.iter().filter(|(_, v)| v.name == name).count() == 1
369350
}
370351
}
352+
353+
fn rustc_discover_host_triple(cargo_toml: &AbsPath) -> Option<String> {
354+
let mut rustc = Command::new(toolchain::rustc());
355+
rustc.current_dir(cargo_toml.parent().unwrap()).arg("-vV");
356+
log::debug!("Discovering host platform by {:?}", rustc);
357+
match utf8_stdout(rustc) {
358+
Ok(stdout) => {
359+
let field = "host: ";
360+
let target = stdout.lines().find_map(|l| l.strip_prefix(field));
361+
if let Some(target) = target {
362+
Some(target.to_string())
363+
} else {
364+
// If we fail to resolve the host platform, it's not the end of the world.
365+
log::info!("rustc -vV did not report host platform, got:\n{}", stdout);
366+
None
367+
}
368+
}
369+
Err(e) => {
370+
log::warn!("Failed to discover host platform: {}", e);
371+
None
372+
}
373+
}
374+
}
375+
376+
fn cargo_config_build_target(cargo_toml: &AbsPath) -> Option<String> {
377+
let mut cargo_config = Command::new(toolchain::cargo());
378+
cargo_config.current_dir(cargo_toml.parent().unwrap()).args(&[
379+
"+nightly",
380+
"-Z",
381+
"unstable-options",
382+
"config",
383+
"get",
384+
"build.target",
385+
]);
386+
// if successful we receive `build.target = "target-triple"`
387+
log::debug!("Discovering cargo config target by {:?}", cargo_config);
388+
match utf8_stdout(cargo_config) {
389+
Ok(stdout) => stdout
390+
.strip_prefix("build.target = \"")
391+
.and_then(|stdout| stdout.strip_suffix('"'))
392+
.map(ToOwned::to_owned),
393+
Err(_) => None,
394+
}
395+
}

crates/project_model/src/rustc_cfg.rs

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22
33
use std::process::Command;
44

5+
use paths::AbsPath;
6+
57
use crate::{cfg_flag::CfgFlag, utf8_stdout};
68

7-
pub(crate) fn get(target: Option<&str>) -> Vec<CfgFlag> {
9+
pub(crate) fn get(cargo_toml: Option<&AbsPath>, target: Option<&str>) -> Vec<CfgFlag> {
810
let _p = profile::span("rustc_cfg::get");
911
let mut res = Vec::with_capacity(6 * 2 + 1);
1012

@@ -17,12 +19,34 @@ pub(crate) fn get(target: Option<&str>) -> Vec<CfgFlag> {
1719
}
1820

1921
let rustc_cfgs = {
20-
let mut cmd = Command::new(toolchain::rustc());
21-
cmd.args(&["--print", "cfg", "-O"]);
22-
if let Some(target) = target {
23-
cmd.args(&["--target", target]);
24-
}
25-
utf8_stdout(cmd)
22+
cargo_toml
23+
.and_then(|cargo_toml| {
24+
let mut cargo_config = Command::new(toolchain::cargo());
25+
cargo_config.current_dir(cargo_toml.parent().unwrap()).args(&[
26+
"+nightly",
27+
"-Z",
28+
"unstable-options",
29+
"rustc",
30+
"--print",
31+
"cfg",
32+
]);
33+
if let Some(target) = target {
34+
cargo_config.args(&["--target", target]);
35+
}
36+
utf8_stdout(cargo_config).ok()
37+
})
38+
.map_or_else(
39+
|| {
40+
// using unstable cargo features failed, fall back to using plain rustc
41+
let mut cmd = Command::new(toolchain::rustc());
42+
cmd.args(&["--print", "cfg", "-O"]);
43+
if let Some(target) = target {
44+
cmd.args(&["--target", target]);
45+
}
46+
utf8_stdout(cmd)
47+
},
48+
Ok,
49+
)
2650
};
2751

2852
match rustc_cfgs {

crates/project_model/src/workspace.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,8 @@ impl ProjectWorkspace {
143143
} else {
144144
None
145145
};
146-
let rustc_cfg = rustc_cfg::get(config.target.as_deref());
146+
147+
let rustc_cfg = rustc_cfg::get(Some(&cargo_toml), config.target.as_deref());
147148
ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg }
148149
}
149150
};
@@ -159,7 +160,7 @@ impl ProjectWorkspace {
159160
Some(path) => Some(Sysroot::load(path)?),
160161
None => None,
161162
};
162-
let rustc_cfg = rustc_cfg::get(target);
163+
let rustc_cfg = rustc_cfg::get(None, target);
163164
Ok(ProjectWorkspace::Json { project: project_json, sysroot, rustc_cfg })
164165
}
165166

@@ -310,7 +311,7 @@ fn project_json_to_crate_graph(
310311

311312
let target_cfgs = match krate.target.as_deref() {
312313
Some(target) => {
313-
cfg_cache.entry(target).or_insert_with(|| rustc_cfg::get(Some(target)))
314+
cfg_cache.entry(target).or_insert_with(|| rustc_cfg::get(None, Some(target)))
314315
}
315316
None => &rustc_cfg,
316317
};

0 commit comments

Comments
 (0)