Skip to content

Commit 6c0cdc5

Browse files
bors[bot]Veykril
andauthored
Merge #8774
8774: feat: Honor `.cargo/config.toml` r=matklad a=Veykril ![f1Gup1aiAn](https://user-images.githubusercontent.com/3757771/117545448-1dcaae00-b026-11eb-977a-0f35a5e3f2e0.gif) Implements `cargo/.config` build target and cfg access by using unstable cargo options: - `cargo config get` to read the target triple out of the config to pass to `cargo metadata` --filter-platform - `cargo rustc --print` to read out the `rustc_cfgs`, this causes us to honor `rustflags` and the like. If those commands fail, due to not having a nightly toolchain present for example, they will fall back to invoking rustc directly as we currently do. I personally think it should be fine to use these unstable options as they are unlikely to change(even if they did it shouldn't be a problem due to the fallback) and don't burden the user if they do not have a nightly toolchain at hand since we fall back to the previous behaviour. cc #8741 Closes #6604, Closes #5904, Closes #8430, Closes #8480 Co-authored-by: Lukas Wirth <[email protected]>
2 parents cf4d4f6 + b7e6537 commit 6c0cdc5

File tree

3 files changed

+82
-37
lines changed

3 files changed

+82
-37
lines changed

crates/project_model/src/cargo_workspace.rs

Lines changed: 44 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,43 @@ 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
379+
.current_dir(cargo_toml.parent().unwrap())
380+
.args(&["-Z", "unstable-options", "config", "get", "build.target"])
381+
.env("RUSTC_BOOTSTRAP", "1");
382+
// if successful we receive `build.target = "target-triple"`
383+
log::debug!("Discovering cargo config target by {:?}", cargo_config);
384+
match utf8_stdout(cargo_config) {
385+
Ok(stdout) => stdout
386+
.strip_prefix("build.target = \"")
387+
.and_then(|stdout| stdout.strip_suffix('"'))
388+
.map(ToOwned::to_owned),
389+
Err(_) => None,
390+
}
391+
}

crates/project_model/src/rustc_cfg.rs

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

5+
use anyhow::Result;
6+
use paths::AbsPath;
7+
58
use crate::{cfg_flag::CfgFlag, utf8_stdout};
69

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

@@ -16,19 +19,39 @@ pub(crate) fn get(target: Option<&str>) -> Vec<CfgFlag> {
1619
}
1720
}
1821

19-
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)
26-
};
27-
28-
match rustc_cfgs {
22+
match get_rust_cfgs(cargo_toml, target) {
2923
Ok(rustc_cfgs) => res.extend(rustc_cfgs.lines().map(|it| it.parse().unwrap())),
3024
Err(e) => log::error!("failed to get rustc cfgs: {:#}", e),
3125
}
3226

3327
res
3428
}
29+
30+
fn get_rust_cfgs(cargo_toml: Option<&AbsPath>, target: Option<&str>) -> Result<String> {
31+
let cargo_rust_cfgs = match cargo_toml {
32+
Some(cargo_toml) => {
33+
let mut cargo_config = Command::new(toolchain::cargo());
34+
cargo_config
35+
.current_dir(cargo_toml.parent().unwrap())
36+
.args(&["-Z", "unstable-options", "rustc", "--print", "cfg"])
37+
.env("RUSTC_BOOTSTRAP", "1");
38+
if let Some(target) = target {
39+
cargo_config.args(&["--target", target]);
40+
}
41+
utf8_stdout(cargo_config).ok()
42+
}
43+
None => None,
44+
};
45+
match cargo_rust_cfgs {
46+
Some(stdout) => Ok(stdout),
47+
None => {
48+
// using unstable cargo features failed, fall back to using plain rustc
49+
let mut cmd = Command::new(toolchain::rustc());
50+
cmd.args(&["--print", "cfg", "-O"]);
51+
if let Some(target) = target {
52+
cmd.args(&["--target", target]);
53+
}
54+
utf8_stdout(cmd)
55+
}
56+
}
57+
}

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)