aboutsummaryrefslogtreecommitdiff
path: root/crates/project_model
diff options
context:
space:
mode:
Diffstat (limited to 'crates/project_model')
-rw-r--r--crates/project_model/src/cargo_workspace.rs67
-rw-r--r--crates/project_model/src/cfg_flag.rs3
-rw-r--r--crates/project_model/src/rustc_cfg.rs45
-rw-r--r--crates/project_model/src/workspace.rs7
4 files changed, 83 insertions, 39 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/cfg_flag.rs b/crates/project_model/src/cfg_flag.rs
index e92962cf6..bfdfd458f 100644
--- a/crates/project_model/src/cfg_flag.rs
+++ b/crates/project_model/src/cfg_flag.rs
@@ -4,7 +4,6 @@
4use std::str::FromStr; 4use std::str::FromStr;
5 5
6use cfg::CfgOptions; 6use cfg::CfgOptions;
7use stdx::split_once;
8 7
9#[derive(Clone, Eq, PartialEq, Debug)] 8#[derive(Clone, Eq, PartialEq, Debug)]
10pub enum CfgFlag { 9pub enum CfgFlag {
@@ -15,7 +14,7 @@ pub enum CfgFlag {
15impl FromStr for CfgFlag { 14impl FromStr for CfgFlag {
16 type Err = String; 15 type Err = String;
17 fn from_str(s: &str) -> Result<Self, Self::Err> { 16 fn from_str(s: &str) -> Result<Self, Self::Err> {
18 let res = match split_once(s, '=') { 17 let res = match s.split_once('=') {
19 Some((key, value)) => { 18 Some((key, value)) => {
20 if !(value.starts_with('"') && value.ends_with('"')) { 19 if !(value.starts_with('"') && value.ends_with('"')) {
21 return Err(format!("Invalid cfg ({:?}), value should be in quotes", s)); 20 return Err(format!("Invalid cfg ({:?}), value should be in quotes", s));
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 };