aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-05-09 11:33:31 +0100
committerGitHub <[email protected]>2021-05-09 11:33:31 +0100
commit6c0cdc5f550c0ccef762fcff7d1fbee9b6245027 (patch)
tree3e56ee06982fddc9e10127999d4ee7a0e6071399
parentcf4d4f646b6227242b2d4e216e8e30b5e111e02e (diff)
parentb7e6537935d421afd7e02585aaa5cec92bee63b0 (diff)
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]>
-rw-r--r--crates/project_model/src/cargo_workspace.rs67
-rw-r--r--crates/project_model/src/rustc_cfg.rs45
-rw-r--r--crates/project_model/src/workspace.rs7
3 files changed, 82 insertions, 37 deletions
diff --git a/crates/project_model/src/cargo_workspace.rs b/crates/project_model/src/cargo_workspace.rs
index bc6e20341..b18699b77 100644
--- a/crates/project_model/src/cargo_workspace.rs
+++ b/crates/project_model/src/cargo_workspace.rs
@@ -201,31 +201,12 @@ impl CargoWorkspace {
201 if let Some(parent) = cargo_toml.parent() { 201 if let Some(parent) = cargo_toml.parent() {
202 meta.current_dir(parent.to_path_buf()); 202 meta.current_dir(parent.to_path_buf());
203 } 203 }
204 let target = if let Some(target) = config.target.as_ref() { 204 let target = if let Some(target) = &config.target {
205 Some(target.clone()) 205 Some(target.clone())
206 } else if let stdout @ Some(_) = cargo_config_build_target(cargo_toml) {
207 stdout
206 } else { 208 } else {
207 // cargo metadata defaults to giving information for _all_ targets. 209 rustc_discover_host_triple(cargo_toml)
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 }
229 }; 210 };
230 if let Some(target) = target { 211 if let Some(target) = target {
231 meta.other_options(vec![String::from("--filter-platform"), target]); 212 meta.other_options(vec![String::from("--filter-platform"), target]);
@@ -368,3 +349,43 @@ impl CargoWorkspace {
368 self.packages.iter().filter(|(_, v)| v.name == name).count() == 1 349 self.packages.iter().filter(|(_, v)| v.name == name).count() == 1
369 } 350 }
370} 351}
352
353fn 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
376fn 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}
diff --git a/crates/project_model/src/rustc_cfg.rs b/crates/project_model/src/rustc_cfg.rs
index 312708575..012eab256 100644
--- a/crates/project_model/src/rustc_cfg.rs
+++ b/crates/project_model/src/rustc_cfg.rs
@@ -2,9 +2,12 @@
2 2
3use std::process::Command; 3use std::process::Command;
4 4
5use anyhow::Result;
6use paths::AbsPath;
7
5use crate::{cfg_flag::CfgFlag, utf8_stdout}; 8use crate::{cfg_flag::CfgFlag, utf8_stdout};
6 9
7pub(crate) fn get(target: Option<&str>) -> Vec<CfgFlag> { 10pub(crate) fn get(cargo_toml: Option<&AbsPath>, target: Option<&str>) -> Vec<CfgFlag> {
8 let _p = profile::span("rustc_cfg::get"); 11 let _p = profile::span("rustc_cfg::get");
9 let mut res = Vec::with_capacity(6 * 2 + 1); 12 let mut res = Vec::with_capacity(6 * 2 + 1);
10 13
@@ -16,19 +19,39 @@ pub(crate) fn get(target: Option<&str>) -> Vec<CfgFlag> {
16 } 19 }
17 } 20 }
18 21
19 let rustc_cfgs = { 22 match get_rust_cfgs(cargo_toml, target) {
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 {
29 Ok(rustc_cfgs) => res.extend(rustc_cfgs.lines().map(|it| it.parse().unwrap())), 23 Ok(rustc_cfgs) => res.extend(rustc_cfgs.lines().map(|it| it.parse().unwrap())),
30 Err(e) => log::error!("failed to get rustc cfgs: {:#}", e), 24 Err(e) => log::error!("failed to get rustc cfgs: {:#}", e),
31 } 25 }
32 26
33 res 27 res
34} 28}
29
30fn 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}
diff --git a/crates/project_model/src/workspace.rs b/crates/project_model/src/workspace.rs
index 2fcd0f8fa..84c702fdf 100644
--- a/crates/project_model/src/workspace.rs
+++ b/crates/project_model/src/workspace.rs
@@ -143,7 +143,8 @@ impl ProjectWorkspace {
143 } else { 143 } else {
144 None 144 None
145 }; 145 };
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());
147 ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg } 148 ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg }
148 } 149 }
149 }; 150 };
@@ -159,7 +160,7 @@ impl ProjectWorkspace {
159 Some(path) => Some(Sysroot::load(path)?), 160 Some(path) => Some(Sysroot::load(path)?),
160 None => None, 161 None => None,
161 }; 162 };
162 let rustc_cfg = rustc_cfg::get(target); 163 let rustc_cfg = rustc_cfg::get(None, target);
163 Ok(ProjectWorkspace::Json { project: project_json, sysroot, rustc_cfg }) 164 Ok(ProjectWorkspace::Json { project: project_json, sysroot, rustc_cfg })
164 } 165 }
165 166
@@ -310,7 +311,7 @@ fn project_json_to_crate_graph(
310 311
311 let target_cfgs = match krate.target.as_deref() { 312 let target_cfgs = match krate.target.as_deref() {
312 Some(target) => { 313 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)))
314 } 315 }
315 None => &rustc_cfg, 316 None => &rustc_cfg,
316 }; 317 };