From 8989fb8315538aece975663c3be4aba867e9ee86 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 8 May 2021 18:17:18 +0200 Subject: Discover rustc_cfg through unstable cargo options --- crates/project_model/src/cargo_workspace.rs | 71 +++++++++++++++++++---------- crates/project_model/src/rustc_cfg.rs | 38 ++++++++++++--- crates/project_model/src/workspace.rs | 7 +-- 3 files changed, 83 insertions(+), 33 deletions(-) (limited to 'crates/project_model') diff --git a/crates/project_model/src/cargo_workspace.rs b/crates/project_model/src/cargo_workspace.rs index bc6e20341..f1ad00d36 100644 --- a/crates/project_model/src/cargo_workspace.rs +++ b/crates/project_model/src/cargo_workspace.rs @@ -201,31 +201,12 @@ impl CargoWorkspace { if let Some(parent) = cargo_toml.parent() { meta.current_dir(parent.to_path_buf()); } - let target = if let Some(target) = config.target.as_ref() { + let target = if let Some(target) = &config.target { Some(target.clone()) + } else if let stdout @ Some(_) = cargo_config_build_target(cargo_toml) { + stdout } else { - // cargo metadata defaults to giving information for _all_ targets. - // In the absence of a preference from the user, we use the host platform. - let mut rustc = Command::new(toolchain::rustc()); - rustc.current_dir(cargo_toml.parent().unwrap()).arg("-vV"); - log::debug!("Discovering host platform by {:?}", rustc); - match utf8_stdout(rustc) { - Ok(stdout) => { - let field = "host: "; - let target = stdout.lines().find_map(|l| l.strip_prefix(field)); - if let Some(target) = target { - Some(target.to_string()) - } else { - // If we fail to resolve the host platform, it's not the end of the world. - log::info!("rustc -vV did not report host platform, got:\n{}", stdout); - None - } - } - Err(e) => { - log::warn!("Failed to discover host platform: {}", e); - None - } - } + rustc_discover_host_triple(cargo_toml) }; if let Some(target) = target { meta.other_options(vec![String::from("--filter-platform"), target]); @@ -368,3 +349,47 @@ impl CargoWorkspace { self.packages.iter().filter(|(_, v)| v.name == name).count() == 1 } } + +fn rustc_discover_host_triple(cargo_toml: &AbsPath) -> Option { + let mut rustc = Command::new(toolchain::rustc()); + rustc.current_dir(cargo_toml.parent().unwrap()).arg("-vV"); + log::debug!("Discovering host platform by {:?}", rustc); + match utf8_stdout(rustc) { + Ok(stdout) => { + let field = "host: "; + let target = stdout.lines().find_map(|l| l.strip_prefix(field)); + if let Some(target) = target { + Some(target.to_string()) + } else { + // If we fail to resolve the host platform, it's not the end of the world. + log::info!("rustc -vV did not report host platform, got:\n{}", stdout); + None + } + } + Err(e) => { + log::warn!("Failed to discover host platform: {}", e); + None + } + } +} + +fn cargo_config_build_target(cargo_toml: &AbsPath) -> Option { + let mut cargo_config = Command::new(toolchain::cargo()); + cargo_config.current_dir(cargo_toml.parent().unwrap()).args(&[ + "+nightly", + "-Z", + "unstable-options", + "config", + "get", + "build.target", + ]); + // if successful we receive `build.target = "target-triple"` + log::debug!("Discovering cargo config target by {:?}", cargo_config); + match utf8_stdout(cargo_config) { + Ok(stdout) => stdout + .strip_prefix("build.target = \"") + .and_then(|stdout| stdout.strip_suffix('"')) + .map(ToOwned::to_owned), + Err(_) => None, + } +} diff --git a/crates/project_model/src/rustc_cfg.rs b/crates/project_model/src/rustc_cfg.rs index 312708575..6de40cfe2 100644 --- a/crates/project_model/src/rustc_cfg.rs +++ b/crates/project_model/src/rustc_cfg.rs @@ -2,9 +2,11 @@ use std::process::Command; +use paths::AbsPath; + use crate::{cfg_flag::CfgFlag, utf8_stdout}; -pub(crate) fn get(target: Option<&str>) -> Vec { +pub(crate) fn get(cargo_toml: Option<&AbsPath>, target: Option<&str>) -> Vec { let _p = profile::span("rustc_cfg::get"); let mut res = Vec::with_capacity(6 * 2 + 1); @@ -17,12 +19,34 @@ pub(crate) fn get(target: Option<&str>) -> Vec { } let rustc_cfgs = { - let mut cmd = Command::new(toolchain::rustc()); - cmd.args(&["--print", "cfg", "-O"]); - if let Some(target) = target { - cmd.args(&["--target", target]); - } - utf8_stdout(cmd) + cargo_toml + .and_then(|cargo_toml| { + let mut cargo_config = Command::new(toolchain::cargo()); + cargo_config.current_dir(cargo_toml.parent().unwrap()).args(&[ + "+nightly", + "-Z", + "unstable-options", + "rustc", + "--print", + "cfg", + ]); + if let Some(target) = target { + cargo_config.args(&["--target", target]); + } + utf8_stdout(cargo_config).ok() + }) + .map_or_else( + || { + // using unstable cargo features failed, fall back to using plain rustc + let mut cmd = Command::new(toolchain::rustc()); + cmd.args(&["--print", "cfg", "-O"]); + if let Some(target) = target { + cmd.args(&["--target", target]); + } + utf8_stdout(cmd) + }, + Ok, + ) }; match rustc_cfgs { 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 { } else { None }; - let rustc_cfg = rustc_cfg::get(config.target.as_deref()); + + let rustc_cfg = rustc_cfg::get(Some(&cargo_toml), config.target.as_deref()); ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg } } }; @@ -159,7 +160,7 @@ impl ProjectWorkspace { Some(path) => Some(Sysroot::load(path)?), None => None, }; - let rustc_cfg = rustc_cfg::get(target); + let rustc_cfg = rustc_cfg::get(None, target); Ok(ProjectWorkspace::Json { project: project_json, sysroot, rustc_cfg }) } @@ -310,7 +311,7 @@ fn project_json_to_crate_graph( let target_cfgs = match krate.target.as_deref() { Some(target) => { - cfg_cache.entry(target).or_insert_with(|| rustc_cfg::get(Some(target))) + cfg_cache.entry(target).or_insert_with(|| rustc_cfg::get(None, Some(target))) } None => &rustc_cfg, }; -- cgit v1.2.3