From 8989fb8315538aece975663c3be4aba867e9ee86 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 8 May 2021 18:17:18 +0200 Subject: [PATCH 1/2] 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(-) diff --git a/crates/project_model/src/cargo_workspace.rs b/crates/project_model/src/cargo_workspace.rs index bc6e203414e..f1ad00d36dd 100644 --- a/crates/project_model/src/cargo_workspace.rs +++ b/crates/project_model/src/cargo_workspace.rs @@ -201,31 +201,12 @@ pub fn from_cargo_metadata( 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 @@ fn is_unique(&self, name: &str) -> bool { 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 312708575e0..6de40cfe2ae 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 2fcd0f8face..84c702fdf7e 100644 --- a/crates/project_model/src/workspace.rs +++ b/crates/project_model/src/workspace.rs @@ -143,7 +143,8 @@ pub fn load( } 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 @@ pub fn load_inline( 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, }; From b7e6537935d421afd7e02585aaa5cec92bee63b0 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 9 May 2021 00:07:04 +0200 Subject: [PATCH 2/2] Use RUSTC_BOOTSTRAP=1 instead of +nightly when discovering rust_cfgs throughs cargo --- crates/project_model/src/cargo_workspace.rs | 12 ++-- crates/project_model/src/rustc_cfg.rs | 63 ++++++++++----------- 2 files changed, 35 insertions(+), 40 deletions(-) diff --git a/crates/project_model/src/cargo_workspace.rs b/crates/project_model/src/cargo_workspace.rs index f1ad00d36dd..b18699b7711 100644 --- a/crates/project_model/src/cargo_workspace.rs +++ b/crates/project_model/src/cargo_workspace.rs @@ -375,14 +375,10 @@ fn rustc_discover_host_triple(cargo_toml: &AbsPath) -> Option { 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", - ]); + cargo_config + .current_dir(cargo_toml.parent().unwrap()) + .args(&["-Z", "unstable-options", "config", "get", "build.target"]) + .env("RUSTC_BOOTSTRAP", "1"); // if successful we receive `build.target = "target-triple"` log::debug!("Discovering cargo config target by {:?}", cargo_config); match utf8_stdout(cargo_config) { diff --git a/crates/project_model/src/rustc_cfg.rs b/crates/project_model/src/rustc_cfg.rs index 6de40cfe2ae..012eab256ab 100644 --- a/crates/project_model/src/rustc_cfg.rs +++ b/crates/project_model/src/rustc_cfg.rs @@ -2,6 +2,7 @@ use std::process::Command; +use anyhow::Result; use paths::AbsPath; use crate::{cfg_flag::CfgFlag, utf8_stdout}; @@ -18,41 +19,39 @@ pub(crate) fn get(cargo_toml: Option<&AbsPath>, target: Option<&str>) -> Vec res.extend(rustc_cfgs.lines().map(|it| it.parse().unwrap())), Err(e) => log::error!("failed to get rustc cfgs: {:#}", e), } res } + +fn get_rust_cfgs(cargo_toml: Option<&AbsPath>, target: Option<&str>) -> Result { + let cargo_rust_cfgs = match cargo_toml { + Some(cargo_toml) => { + let mut cargo_config = Command::new(toolchain::cargo()); + cargo_config + .current_dir(cargo_toml.parent().unwrap()) + .args(&["-Z", "unstable-options", "rustc", "--print", "cfg"]) + .env("RUSTC_BOOTSTRAP", "1"); + if let Some(target) = target { + cargo_config.args(&["--target", target]); + } + utf8_stdout(cargo_config).ok() + } + None => None, + }; + match cargo_rust_cfgs { + Some(stdout) => Ok(stdout), + None => { + // 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) + } + } +}