mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 04:53:34 +00:00
Cleanup target fetching for cargo metadata
This commit is contained in:
parent
633a10cb58
commit
029261f9cc
10 changed files with 209 additions and 140 deletions
|
@ -13,8 +13,8 @@ use serde_json::from_value;
|
||||||
use span::Edition;
|
use span::Edition;
|
||||||
use toolchain::Tool;
|
use toolchain::Tool;
|
||||||
|
|
||||||
use crate::{utf8_stdout, ManifestPath, Sysroot, SysrootQueryMetadata};
|
|
||||||
use crate::{CfgOverrides, InvocationStrategy};
|
use crate::{CfgOverrides, InvocationStrategy};
|
||||||
|
use crate::{ManifestPath, Sysroot, SysrootQueryMetadata};
|
||||||
|
|
||||||
/// [`CargoWorkspace`] represents the logical structure of, well, a Cargo
|
/// [`CargoWorkspace`] represents the logical structure of, well, a Cargo
|
||||||
/// workspace. It pretty closely mirrors `cargo metadata` output.
|
/// workspace. It pretty closely mirrors `cargo metadata` output.
|
||||||
|
@ -251,6 +251,18 @@ impl TargetKind {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub struct CargoMetadataConfig {
|
||||||
|
/// List of features to activate.
|
||||||
|
pub features: CargoFeatures,
|
||||||
|
/// rustc targets
|
||||||
|
pub targets: Vec<String>,
|
||||||
|
/// Extra args to pass to the cargo command.
|
||||||
|
pub extra_args: Vec<String>,
|
||||||
|
/// Extra env vars to set when invoking the cargo command
|
||||||
|
pub extra_env: FxHashMap<String, String>,
|
||||||
|
}
|
||||||
|
|
||||||
// Deserialize helper for the cargo metadata
|
// Deserialize helper for the cargo metadata
|
||||||
#[derive(Deserialize, Default)]
|
#[derive(Deserialize, Default)]
|
||||||
struct PackageMetadata {
|
struct PackageMetadata {
|
||||||
|
@ -265,7 +277,7 @@ impl CargoWorkspace {
|
||||||
pub fn fetch_metadata(
|
pub fn fetch_metadata(
|
||||||
cargo_toml: &ManifestPath,
|
cargo_toml: &ManifestPath,
|
||||||
current_dir: &AbsPath,
|
current_dir: &AbsPath,
|
||||||
config: &CargoConfig,
|
config: &CargoMetadataConfig,
|
||||||
sysroot: &Sysroot,
|
sysroot: &Sysroot,
|
||||||
locked: bool,
|
locked: bool,
|
||||||
progress: &dyn Fn(String),
|
progress: &dyn Fn(String),
|
||||||
|
@ -276,14 +288,12 @@ impl CargoWorkspace {
|
||||||
fn fetch_metadata_(
|
fn fetch_metadata_(
|
||||||
cargo_toml: &ManifestPath,
|
cargo_toml: &ManifestPath,
|
||||||
current_dir: &AbsPath,
|
current_dir: &AbsPath,
|
||||||
config: &CargoConfig,
|
config: &CargoMetadataConfig,
|
||||||
sysroot: &Sysroot,
|
sysroot: &Sysroot,
|
||||||
locked: bool,
|
locked: bool,
|
||||||
no_deps: bool,
|
no_deps: bool,
|
||||||
progress: &dyn Fn(String),
|
progress: &dyn Fn(String),
|
||||||
) -> anyhow::Result<(cargo_metadata::Metadata, Option<anyhow::Error>)> {
|
) -> anyhow::Result<(cargo_metadata::Metadata, Option<anyhow::Error>)> {
|
||||||
let targets = find_list_of_build_targets(config, cargo_toml, sysroot);
|
|
||||||
|
|
||||||
let cargo = sysroot.tool(Tool::Cargo);
|
let cargo = sysroot.tool(Tool::Cargo);
|
||||||
let mut meta = MetadataCommand::new();
|
let mut meta = MetadataCommand::new();
|
||||||
meta.cargo_path(cargo.get_program());
|
meta.cargo_path(cargo.get_program());
|
||||||
|
@ -319,12 +329,9 @@ impl CargoWorkspace {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !targets.is_empty() {
|
if !config.targets.is_empty() {
|
||||||
other_options.append(
|
other_options.extend(
|
||||||
&mut targets
|
config.targets.iter().flat_map(|it| ["--filter-platform".to_owned(), it.clone()]),
|
||||||
.into_iter()
|
|
||||||
.flat_map(|target| ["--filter-platform".to_owned(), target])
|
|
||||||
.collect(),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// The manifest is a rust file, so this means its a script manifest
|
// The manifest is a rust file, so this means its a script manifest
|
||||||
|
@ -596,79 +603,3 @@ impl CargoWorkspace {
|
||||||
self.is_virtual_workspace
|
self.is_virtual_workspace
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_list_of_build_targets(
|
|
||||||
config: &CargoConfig,
|
|
||||||
cargo_toml: &ManifestPath,
|
|
||||||
sysroot: &Sysroot,
|
|
||||||
) -> Vec<String> {
|
|
||||||
if let Some(target) = &config.target {
|
|
||||||
return [target.into()].to_vec();
|
|
||||||
}
|
|
||||||
|
|
||||||
let build_targets = cargo_config_build_target(cargo_toml, &config.extra_env, sysroot);
|
|
||||||
if !build_targets.is_empty() {
|
|
||||||
return build_targets;
|
|
||||||
}
|
|
||||||
|
|
||||||
rustc_discover_host_triple(cargo_toml, &config.extra_env, sysroot).into_iter().collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn rustc_discover_host_triple(
|
|
||||||
cargo_toml: &ManifestPath,
|
|
||||||
extra_env: &FxHashMap<String, String>,
|
|
||||||
sysroot: &Sysroot,
|
|
||||||
) -> Option<String> {
|
|
||||||
let mut rustc = sysroot.tool(Tool::Rustc);
|
|
||||||
rustc.envs(extra_env);
|
|
||||||
rustc.current_dir(cargo_toml.parent()).arg("-vV");
|
|
||||||
tracing::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_owned())
|
|
||||||
} else {
|
|
||||||
// If we fail to resolve the host platform, it's not the end of the world.
|
|
||||||
tracing::info!("rustc -vV did not report host platform, got:\n{}", stdout);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
tracing::warn!("Failed to discover host platform: {}", e);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cargo_config_build_target(
|
|
||||||
cargo_toml: &ManifestPath,
|
|
||||||
extra_env: &FxHashMap<String, String>,
|
|
||||||
sysroot: &Sysroot,
|
|
||||||
) -> Vec<String> {
|
|
||||||
let mut cargo_config = sysroot.tool(Tool::Cargo);
|
|
||||||
cargo_config.envs(extra_env);
|
|
||||||
cargo_config
|
|
||||||
.current_dir(cargo_toml.parent())
|
|
||||||
.args(["-Z", "unstable-options", "config", "get", "build.target"])
|
|
||||||
.env("RUSTC_BOOTSTRAP", "1");
|
|
||||||
// if successful we receive `build.target = "target-triple"`
|
|
||||||
// or `build.target = ["<target 1>", ..]`
|
|
||||||
tracing::debug!("Discovering cargo config target by {:?}", cargo_config);
|
|
||||||
utf8_stdout(cargo_config).map(parse_output_cargo_config_build_target).unwrap_or_default()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_output_cargo_config_build_target(stdout: String) -> Vec<String> {
|
|
||||||
let trimmed = stdout.trim_start_matches("build.target = ").trim_matches('"');
|
|
||||||
|
|
||||||
if !trimmed.starts_with('[') {
|
|
||||||
return [trimmed.to_owned()].to_vec();
|
|
||||||
}
|
|
||||||
|
|
||||||
let res = serde_json::from_str(trimmed);
|
|
||||||
if let Err(e) = &res {
|
|
||||||
tracing::warn!("Failed to parse `build.target` as an array of target: {}`", e);
|
|
||||||
}
|
|
||||||
res.unwrap_or_default()
|
|
||||||
}
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ pub mod project_json;
|
||||||
mod rustc_cfg;
|
mod rustc_cfg;
|
||||||
mod sysroot;
|
mod sysroot;
|
||||||
pub mod target_data_layout;
|
pub mod target_data_layout;
|
||||||
|
mod target_triple;
|
||||||
mod workspace;
|
mod workspace;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -42,8 +43,8 @@ use rustc_hash::FxHashSet;
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
build_dependencies::WorkspaceBuildScripts,
|
build_dependencies::WorkspaceBuildScripts,
|
||||||
cargo_workspace::{
|
cargo_workspace::{
|
||||||
CargoConfig, CargoFeatures, CargoWorkspace, Package, PackageData, PackageDependency,
|
CargoConfig, CargoFeatures, CargoMetadataConfig, CargoWorkspace, Package, PackageData,
|
||||||
RustLibSource, Target, TargetData, TargetKind,
|
PackageDependency, RustLibSource, Target, TargetData, TargetKind,
|
||||||
},
|
},
|
||||||
manifest_path::ManifestPath,
|
manifest_path::ManifestPath,
|
||||||
project_json::{ProjectJson, ProjectJsonData},
|
project_json::{ProjectJson, ProjectJsonData},
|
||||||
|
@ -241,9 +242,14 @@ fn parse_cfg(s: &str) -> Result<cfg::CfgAtom, String> {
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum SysrootQueryMetadata {
|
pub enum SysrootQueryMetadata {
|
||||||
#[default]
|
CargoMetadata(CargoMetadataConfig),
|
||||||
CargoMetadata,
|
|
||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for SysrootQueryMetadata {
|
||||||
|
fn default() -> Self {
|
||||||
|
SysrootQueryMetadata::CargoMetadata(Default::default())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -14,7 +14,10 @@ use paths::{AbsPath, AbsPathBuf, Utf8PathBuf};
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
use toolchain::{probe_for_binary, Tool};
|
use toolchain::{probe_for_binary, Tool};
|
||||||
|
|
||||||
use crate::{utf8_stdout, CargoConfig, CargoWorkspace, ManifestPath, SysrootQueryMetadata};
|
use crate::{
|
||||||
|
cargo_workspace::CargoMetadataConfig, utf8_stdout, CargoWorkspace, ManifestPath,
|
||||||
|
SysrootQueryMetadata,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct Sysroot {
|
pub struct Sysroot {
|
||||||
|
@ -126,7 +129,7 @@ impl Sysroot {
|
||||||
pub fn discover(
|
pub fn discover(
|
||||||
dir: &AbsPath,
|
dir: &AbsPath,
|
||||||
extra_env: &FxHashMap<String, String>,
|
extra_env: &FxHashMap<String, String>,
|
||||||
sysroot_query_metadata: SysrootQueryMetadata,
|
sysroot_query_metadata: &SysrootQueryMetadata,
|
||||||
) -> Sysroot {
|
) -> Sysroot {
|
||||||
let sysroot_dir = discover_sysroot_dir(dir, extra_env);
|
let sysroot_dir = discover_sysroot_dir(dir, extra_env);
|
||||||
let sysroot_src_dir = sysroot_dir.as_ref().ok().map(|sysroot_dir| {
|
let sysroot_src_dir = sysroot_dir.as_ref().ok().map(|sysroot_dir| {
|
||||||
|
@ -139,7 +142,7 @@ impl Sysroot {
|
||||||
current_dir: &AbsPath,
|
current_dir: &AbsPath,
|
||||||
extra_env: &FxHashMap<String, String>,
|
extra_env: &FxHashMap<String, String>,
|
||||||
sysroot_src_dir: AbsPathBuf,
|
sysroot_src_dir: AbsPathBuf,
|
||||||
sysroot_query_metadata: SysrootQueryMetadata,
|
sysroot_query_metadata: &SysrootQueryMetadata,
|
||||||
) -> Sysroot {
|
) -> Sysroot {
|
||||||
let sysroot_dir = discover_sysroot_dir(current_dir, extra_env);
|
let sysroot_dir = discover_sysroot_dir(current_dir, extra_env);
|
||||||
Sysroot::load_core_check(
|
Sysroot::load_core_check(
|
||||||
|
@ -151,7 +154,7 @@ impl Sysroot {
|
||||||
|
|
||||||
pub fn discover_sysroot_src_dir(
|
pub fn discover_sysroot_src_dir(
|
||||||
sysroot_dir: AbsPathBuf,
|
sysroot_dir: AbsPathBuf,
|
||||||
sysroot_query_metadata: SysrootQueryMetadata,
|
sysroot_query_metadata: &SysrootQueryMetadata,
|
||||||
) -> Sysroot {
|
) -> Sysroot {
|
||||||
let sysroot_src_dir = discover_sysroot_src_dir(&sysroot_dir)
|
let sysroot_src_dir = discover_sysroot_src_dir(&sysroot_dir)
|
||||||
.ok_or_else(|| format_err!("can't find standard library sources in {sysroot_dir}"));
|
.ok_or_else(|| format_err!("can't find standard library sources in {sysroot_dir}"));
|
||||||
|
@ -205,7 +208,7 @@ impl Sysroot {
|
||||||
pub fn load(
|
pub fn load(
|
||||||
sysroot_dir: Option<AbsPathBuf>,
|
sysroot_dir: Option<AbsPathBuf>,
|
||||||
sysroot_src_dir: Option<AbsPathBuf>,
|
sysroot_src_dir: Option<AbsPathBuf>,
|
||||||
sysroot_query_metadata: SysrootQueryMetadata,
|
sysroot_query_metadata: &SysrootQueryMetadata,
|
||||||
) -> Sysroot {
|
) -> Sysroot {
|
||||||
Self::load_core_check(sysroot_dir.map(Ok), sysroot_src_dir.map(Ok), sysroot_query_metadata)
|
Self::load_core_check(sysroot_dir.map(Ok), sysroot_src_dir.map(Ok), sysroot_query_metadata)
|
||||||
}
|
}
|
||||||
|
@ -213,7 +216,7 @@ impl Sysroot {
|
||||||
fn load_core_check(
|
fn load_core_check(
|
||||||
sysroot_dir: Option<Result<AbsPathBuf, anyhow::Error>>,
|
sysroot_dir: Option<Result<AbsPathBuf, anyhow::Error>>,
|
||||||
sysroot_src_dir: Option<Result<AbsPathBuf, anyhow::Error>>,
|
sysroot_src_dir: Option<Result<AbsPathBuf, anyhow::Error>>,
|
||||||
sysroot_query_metadata: SysrootQueryMetadata,
|
sysroot_query_metadata: &SysrootQueryMetadata,
|
||||||
) -> Sysroot {
|
) -> Sysroot {
|
||||||
let mut sysroot = Self::load_(sysroot_dir, sysroot_src_dir, sysroot_query_metadata);
|
let mut sysroot = Self::load_(sysroot_dir, sysroot_src_dir, sysroot_query_metadata);
|
||||||
if sysroot.error.is_none() {
|
if sysroot.error.is_none() {
|
||||||
|
@ -241,7 +244,7 @@ impl Sysroot {
|
||||||
fn load_(
|
fn load_(
|
||||||
sysroot_dir: Option<Result<AbsPathBuf, anyhow::Error>>,
|
sysroot_dir: Option<Result<AbsPathBuf, anyhow::Error>>,
|
||||||
sysroot_src_dir: Option<Result<AbsPathBuf, anyhow::Error>>,
|
sysroot_src_dir: Option<Result<AbsPathBuf, anyhow::Error>>,
|
||||||
sysroot_query_metadata: SysrootQueryMetadata,
|
sysroot_query_metadata: &SysrootQueryMetadata,
|
||||||
) -> Sysroot {
|
) -> Sysroot {
|
||||||
let sysroot_dir = match sysroot_dir {
|
let sysroot_dir = match sysroot_dir {
|
||||||
Some(Ok(sysroot_dir)) => Some(sysroot_dir),
|
Some(Ok(sysroot_dir)) => Some(sysroot_dir),
|
||||||
|
@ -274,13 +277,16 @@ impl Sysroot {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if sysroot_query_metadata == SysrootQueryMetadata::CargoMetadata {
|
if let SysrootQueryMetadata::CargoMetadata(cargo_config) = sysroot_query_metadata {
|
||||||
let library_manifest =
|
let library_manifest =
|
||||||
ManifestPath::try_from(sysroot_src_dir.join("Cargo.toml")).unwrap();
|
ManifestPath::try_from(sysroot_src_dir.join("Cargo.toml")).unwrap();
|
||||||
if fs::metadata(&library_manifest).is_ok() {
|
if fs::metadata(&library_manifest).is_ok() {
|
||||||
if let Some(sysroot) =
|
if let Some(sysroot) = Self::load_library_via_cargo(
|
||||||
Self::load_library_via_cargo(library_manifest, &sysroot_dir, &sysroot_src_dir)
|
library_manifest,
|
||||||
{
|
&sysroot_dir,
|
||||||
|
&sysroot_src_dir,
|
||||||
|
cargo_config,
|
||||||
|
) {
|
||||||
return sysroot;
|
return sysroot;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -341,9 +347,10 @@ impl Sysroot {
|
||||||
library_manifest: ManifestPath,
|
library_manifest: ManifestPath,
|
||||||
sysroot_dir: &Option<AbsPathBuf>,
|
sysroot_dir: &Option<AbsPathBuf>,
|
||||||
sysroot_src_dir: &AbsPathBuf,
|
sysroot_src_dir: &AbsPathBuf,
|
||||||
|
cargo_config: &CargoMetadataConfig,
|
||||||
) -> Option<Sysroot> {
|
) -> Option<Sysroot> {
|
||||||
tracing::debug!("Loading library metadata: {library_manifest}");
|
tracing::debug!("Loading library metadata: {library_manifest}");
|
||||||
let mut cargo_config = CargoConfig::default();
|
let mut cargo_config = cargo_config.clone();
|
||||||
// the sysroot uses `public-dependency`, so we make cargo think it's a nightly
|
// the sysroot uses `public-dependency`, so we make cargo think it's a nightly
|
||||||
cargo_config.extra_env.insert(
|
cargo_config.extra_env.insert(
|
||||||
"__CARGO_TEST_CHANNEL_OVERRIDE_DO_NOT_USE_THIS".to_owned(),
|
"__CARGO_TEST_CHANNEL_OVERRIDE_DO_NOT_USE_THIS".to_owned(),
|
||||||
|
|
82
crates/project-model/src/target_triple.rs
Normal file
82
crates/project-model/src/target_triple.rs
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
//! Runs `rustc --print -vV` to get the host target.
|
||||||
|
use anyhow::Context;
|
||||||
|
use rustc_hash::FxHashMap;
|
||||||
|
use toolchain::Tool;
|
||||||
|
|
||||||
|
use crate::{utf8_stdout, ManifestPath, Sysroot};
|
||||||
|
|
||||||
|
pub(super) enum TargetTipleConfig<'a> {
|
||||||
|
#[expect(dead_code)]
|
||||||
|
Rustc(&'a Sysroot),
|
||||||
|
Cargo(&'a Sysroot, &'a ManifestPath),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn get(
|
||||||
|
config: TargetTipleConfig<'_>,
|
||||||
|
target: Option<&str>,
|
||||||
|
extra_env: &FxHashMap<String, String>,
|
||||||
|
) -> anyhow::Result<Vec<String>> {
|
||||||
|
if let Some(target) = target {
|
||||||
|
return Ok(vec![target.to_owned()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
let sysroot = match config {
|
||||||
|
TargetTipleConfig::Cargo(sysroot, cargo_toml) => {
|
||||||
|
match cargo_config_build_target(cargo_toml, extra_env, sysroot) {
|
||||||
|
Ok(it) => return Ok(it),
|
||||||
|
Err(e) => {
|
||||||
|
tracing::warn!("failed to run `cargo rustc --print cfg`, falling back to invoking rustc directly: {e}");
|
||||||
|
sysroot
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TargetTipleConfig::Rustc(sysroot) => sysroot,
|
||||||
|
};
|
||||||
|
rustc_discover_host_triple(extra_env, sysroot).map(|it| vec![it])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rustc_discover_host_triple(
|
||||||
|
extra_env: &FxHashMap<String, String>,
|
||||||
|
sysroot: &Sysroot,
|
||||||
|
) -> anyhow::Result<String> {
|
||||||
|
let mut rustc = sysroot.tool(Tool::Rustc);
|
||||||
|
rustc.envs(extra_env);
|
||||||
|
rustc.arg("-vV");
|
||||||
|
tracing::debug!("Discovering host platform by {:?}", rustc);
|
||||||
|
let stdout = utf8_stdout(rustc).context("Failed to discover host platform")?;
|
||||||
|
let field = "host: ";
|
||||||
|
let target = stdout.lines().find_map(|l| l.strip_prefix(field));
|
||||||
|
if let Some(target) = target {
|
||||||
|
Ok(target.to_owned())
|
||||||
|
} else {
|
||||||
|
// If we fail to resolve the host platform, it's not the end of the world.
|
||||||
|
Err(anyhow::format_err!("rustc -vV did not report host platform, got:\n{}", stdout))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cargo_config_build_target(
|
||||||
|
cargo_toml: &ManifestPath,
|
||||||
|
extra_env: &FxHashMap<String, String>,
|
||||||
|
sysroot: &Sysroot,
|
||||||
|
) -> anyhow::Result<Vec<String>> {
|
||||||
|
let mut cargo_config = sysroot.tool(Tool::Cargo);
|
||||||
|
cargo_config.envs(extra_env);
|
||||||
|
cargo_config
|
||||||
|
.current_dir(cargo_toml.parent())
|
||||||
|
.args(["-Z", "unstable-options", "config", "get", "build.target"])
|
||||||
|
.env("RUSTC_BOOTSTRAP", "1");
|
||||||
|
// if successful we receive `build.target = "target-triple"`
|
||||||
|
// or `build.target = ["<target 1>", ..]`
|
||||||
|
tracing::debug!("Discovering cargo config target by {:?}", cargo_config);
|
||||||
|
utf8_stdout(cargo_config).and_then(parse_output_cargo_config_build_target)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_output_cargo_config_build_target(stdout: String) -> anyhow::Result<Vec<String>> {
|
||||||
|
let trimmed = stdout.trim_start_matches("build.target = ").trim_matches('"');
|
||||||
|
|
||||||
|
if !trimmed.starts_with('[') {
|
||||||
|
return Ok([trimmed.to_owned()].to_vec());
|
||||||
|
}
|
||||||
|
|
||||||
|
serde_json::from_str(trimmed).context("Failed to parse `build.target` as an array of target")
|
||||||
|
}
|
|
@ -117,7 +117,7 @@ fn get_fake_sysroot() -> Sysroot {
|
||||||
// fake sysroot, so we give them both the same path:
|
// fake sysroot, so we give them both the same path:
|
||||||
let sysroot_dir = AbsPathBuf::assert(sysroot_path);
|
let sysroot_dir = AbsPathBuf::assert(sysroot_path);
|
||||||
let sysroot_src_dir = sysroot_dir.clone();
|
let sysroot_src_dir = sysroot_dir.clone();
|
||||||
Sysroot::load(Some(sysroot_dir), Some(sysroot_src_dir), SysrootQueryMetadata::CargoMetadata)
|
Sysroot::load(Some(sysroot_dir), Some(sysroot_src_dir), &SysrootQueryMetadata::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rooted_project_json(data: ProjectJsonData) -> ProjectJson {
|
fn rooted_project_json(data: ProjectJsonData) -> ProjectJson {
|
||||||
|
@ -232,7 +232,7 @@ fn smoke_test_real_sysroot_cargo() {
|
||||||
let sysroot = Sysroot::discover(
|
let sysroot = Sysroot::discover(
|
||||||
AbsPath::assert(Utf8Path::new(env!("CARGO_MANIFEST_DIR"))),
|
AbsPath::assert(Utf8Path::new(env!("CARGO_MANIFEST_DIR"))),
|
||||||
&Default::default(),
|
&Default::default(),
|
||||||
SysrootQueryMetadata::CargoMetadata,
|
&SysrootQueryMetadata::default(),
|
||||||
);
|
);
|
||||||
assert!(matches!(sysroot.mode(), SysrootMode::Workspace(_)));
|
assert!(matches!(sysroot.mode(), SysrootMode::Workspace(_)));
|
||||||
let project_workspace = ProjectWorkspace {
|
let project_workspace = ProjectWorkspace {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
//! metadata` or `rust-project.json`) into representation stored in the salsa
|
//! metadata` or `rust-project.json`) into representation stored in the salsa
|
||||||
//! database -- `CrateGraph`.
|
//! database -- `CrateGraph`.
|
||||||
|
|
||||||
use std::{collections::VecDeque, fmt, fs, iter, sync};
|
use std::{collections::VecDeque, fmt, fs, iter, ops::Deref, sync};
|
||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use base_db::{
|
use base_db::{
|
||||||
|
@ -22,12 +22,13 @@ use triomphe::Arc;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
build_dependencies::BuildScriptOutput,
|
build_dependencies::BuildScriptOutput,
|
||||||
cargo_workspace::{DepKind, PackageData, RustLibSource},
|
cargo_workspace::{CargoMetadataConfig, DepKind, PackageData, RustLibSource},
|
||||||
env::{cargo_config_env, inject_cargo_env, inject_cargo_package_env, inject_rustc_tool_env},
|
env::{cargo_config_env, inject_cargo_env, inject_cargo_package_env, inject_rustc_tool_env},
|
||||||
project_json::{Crate, CrateArrayIdx},
|
project_json::{Crate, CrateArrayIdx},
|
||||||
rustc_cfg::{self, RustcCfgConfig},
|
rustc_cfg::{self, RustcCfgConfig},
|
||||||
sysroot::{SysrootCrate, SysrootMode},
|
sysroot::{SysrootCrate, SysrootMode},
|
||||||
target_data_layout::{self, RustcDataLayoutConfig},
|
target_data_layout::{self, RustcDataLayoutConfig},
|
||||||
|
target_triple::{self, TargetTipleConfig},
|
||||||
utf8_stdout, CargoConfig, CargoWorkspace, CfgOverrides, InvocationStrategy, ManifestPath,
|
utf8_stdout, CargoConfig, CargoWorkspace, CfgOverrides, InvocationStrategy, ManifestPath,
|
||||||
Package, ProjectJson, ProjectManifest, Sysroot, TargetData, TargetKind, WorkspaceBuildScripts,
|
Package, ProjectJson, ProjectManifest, Sysroot, TargetData, TargetKind, WorkspaceBuildScripts,
|
||||||
};
|
};
|
||||||
|
@ -220,28 +221,31 @@ impl ProjectWorkspace {
|
||||||
ProjectWorkspace::load_detached_file(rust_file, config)?
|
ProjectWorkspace::load_detached_file(rust_file, config)?
|
||||||
}
|
}
|
||||||
ProjectManifest::CargoToml(cargo_toml) => {
|
ProjectManifest::CargoToml(cargo_toml) => {
|
||||||
|
// FIXME: Split sysroot discovery from sysroot loading, as to load the sysroot we
|
||||||
|
// want to pass the analysis target, but to discover the target we need to know the
|
||||||
|
// sysroot location so we know which cargo to use
|
||||||
let sysroot = match (&config.sysroot, &config.sysroot_src) {
|
let sysroot = match (&config.sysroot, &config.sysroot_src) {
|
||||||
(Some(RustLibSource::Discover), None) => Sysroot::discover(
|
(Some(RustLibSource::Discover), None) => Sysroot::discover(
|
||||||
cargo_toml.parent(),
|
cargo_toml.parent(),
|
||||||
&config.extra_env,
|
&config.extra_env,
|
||||||
config.sysroot_query_metadata,
|
&config.sysroot_query_metadata,
|
||||||
),
|
),
|
||||||
(Some(RustLibSource::Discover), Some(sysroot_src)) => {
|
(Some(RustLibSource::Discover), Some(sysroot_src)) => {
|
||||||
Sysroot::discover_with_src_override(
|
Sysroot::discover_with_src_override(
|
||||||
cargo_toml.parent(),
|
cargo_toml.parent(),
|
||||||
&config.extra_env,
|
&config.extra_env,
|
||||||
sysroot_src.clone(),
|
sysroot_src.clone(),
|
||||||
config.sysroot_query_metadata,
|
&config.sysroot_query_metadata,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
(Some(RustLibSource::Path(path)), None) => Sysroot::discover_sysroot_src_dir(
|
(Some(RustLibSource::Path(path)), None) => Sysroot::discover_sysroot_src_dir(
|
||||||
path.clone(),
|
path.clone(),
|
||||||
config.sysroot_query_metadata,
|
&config.sysroot_query_metadata,
|
||||||
),
|
),
|
||||||
(Some(RustLibSource::Path(sysroot)), Some(sysroot_src)) => Sysroot::load(
|
(Some(RustLibSource::Path(sysroot)), Some(sysroot_src)) => Sysroot::load(
|
||||||
Some(sysroot.clone()),
|
Some(sysroot.clone()),
|
||||||
Some(sysroot_src.clone()),
|
Some(sysroot_src.clone()),
|
||||||
config.sysroot_query_metadata,
|
&config.sysroot_query_metadata,
|
||||||
),
|
),
|
||||||
(None, _) => Sysroot::empty(),
|
(None, _) => Sysroot::empty(),
|
||||||
};
|
};
|
||||||
|
@ -257,15 +261,22 @@ impl ProjectWorkspace {
|
||||||
}
|
}
|
||||||
None => Err(None),
|
None => Err(None),
|
||||||
};
|
};
|
||||||
|
let targets = target_triple::get(
|
||||||
|
TargetTipleConfig::Cargo(&sysroot, cargo_toml),
|
||||||
|
config.target.as_deref(),
|
||||||
|
&config.extra_env,
|
||||||
|
)
|
||||||
|
.unwrap_or_default();
|
||||||
let rustc = rustc_dir.and_then(|rustc_dir| {
|
let rustc = rustc_dir.and_then(|rustc_dir| {
|
||||||
info!(workspace = %cargo_toml, rustc_dir = %rustc_dir, "Using rustc source");
|
info!(workspace = %cargo_toml, rustc_dir = %rustc_dir, "Using rustc source");
|
||||||
match CargoWorkspace::fetch_metadata(
|
match CargoWorkspace::fetch_metadata(
|
||||||
&rustc_dir,
|
&rustc_dir,
|
||||||
cargo_toml.parent(),
|
cargo_toml.parent(),
|
||||||
&CargoConfig {
|
&CargoMetadataConfig {
|
||||||
features: crate::CargoFeatures::default(),
|
features: crate::CargoFeatures::default(),
|
||||||
..config.clone()
|
targets: targets.clone(),
|
||||||
|
extra_args: config.extra_args.clone(),
|
||||||
|
extra_env: config.extra_env.clone(),
|
||||||
},
|
},
|
||||||
&sysroot,
|
&sysroot,
|
||||||
false,
|
false,
|
||||||
|
@ -301,7 +312,7 @@ impl ProjectWorkspace {
|
||||||
"cargo ",
|
"cargo ",
|
||||||
)?;
|
)?;
|
||||||
let rustc_cfg = rustc_cfg::get(
|
let rustc_cfg = rustc_cfg::get(
|
||||||
config.target.as_deref(),
|
targets.first().map(Deref::deref),
|
||||||
&config.extra_env,
|
&config.extra_env,
|
||||||
RustcCfgConfig::Cargo(&sysroot, cargo_toml),
|
RustcCfgConfig::Cargo(&sysroot, cargo_toml),
|
||||||
);
|
);
|
||||||
|
@ -309,7 +320,7 @@ impl ProjectWorkspace {
|
||||||
let cfg_overrides = config.cfg_overrides.clone();
|
let cfg_overrides = config.cfg_overrides.clone();
|
||||||
let data_layout = target_data_layout::get(
|
let data_layout = target_data_layout::get(
|
||||||
RustcDataLayoutConfig::Cargo(&sysroot, cargo_toml),
|
RustcDataLayoutConfig::Cargo(&sysroot, cargo_toml),
|
||||||
config.target.as_deref(),
|
targets.first().map(Deref::deref),
|
||||||
&config.extra_env,
|
&config.extra_env,
|
||||||
);
|
);
|
||||||
if let Err(e) = &data_layout {
|
if let Err(e) = &data_layout {
|
||||||
|
@ -319,7 +330,12 @@ impl ProjectWorkspace {
|
||||||
let (meta, error) = CargoWorkspace::fetch_metadata(
|
let (meta, error) = CargoWorkspace::fetch_metadata(
|
||||||
cargo_toml,
|
cargo_toml,
|
||||||
cargo_toml.parent(),
|
cargo_toml.parent(),
|
||||||
config,
|
&CargoMetadataConfig {
|
||||||
|
features: config.features.clone(),
|
||||||
|
targets,
|
||||||
|
extra_args: config.extra_args.clone(),
|
||||||
|
extra_env: config.extra_env.clone(),
|
||||||
|
},
|
||||||
&sysroot,
|
&sysroot,
|
||||||
false,
|
false,
|
||||||
progress,
|
progress,
|
||||||
|
@ -360,7 +376,7 @@ impl ProjectWorkspace {
|
||||||
let sysroot = Sysroot::load(
|
let sysroot = Sysroot::load(
|
||||||
project_json.sysroot.clone(),
|
project_json.sysroot.clone(),
|
||||||
project_json.sysroot_src.clone(),
|
project_json.sysroot_src.clone(),
|
||||||
config.sysroot_query_metadata,
|
&config.sysroot_query_metadata,
|
||||||
);
|
);
|
||||||
let cfg_config = RustcCfgConfig::Rustc(&sysroot);
|
let cfg_config = RustcCfgConfig::Rustc(&sysroot);
|
||||||
let data_layout_config = RustcDataLayoutConfig::Rustc(&sysroot);
|
let data_layout_config = RustcDataLayoutConfig::Rustc(&sysroot);
|
||||||
|
@ -398,10 +414,10 @@ impl ProjectWorkspace {
|
||||||
let dir = detached_file.parent();
|
let dir = detached_file.parent();
|
||||||
let sysroot = match &config.sysroot {
|
let sysroot = match &config.sysroot {
|
||||||
Some(RustLibSource::Path(path)) => {
|
Some(RustLibSource::Path(path)) => {
|
||||||
Sysroot::discover_sysroot_src_dir(path.clone(), config.sysroot_query_metadata)
|
Sysroot::discover_sysroot_src_dir(path.clone(), &config.sysroot_query_metadata)
|
||||||
}
|
}
|
||||||
Some(RustLibSource::Discover) => {
|
Some(RustLibSource::Discover) => {
|
||||||
Sysroot::discover(dir, &config.extra_env, config.sysroot_query_metadata)
|
Sysroot::discover(dir, &config.extra_env, &config.sysroot_query_metadata)
|
||||||
}
|
}
|
||||||
None => Sysroot::empty(),
|
None => Sysroot::empty(),
|
||||||
};
|
};
|
||||||
|
@ -415,6 +431,12 @@ impl ProjectWorkspace {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let targets = target_triple::get(
|
||||||
|
TargetTipleConfig::Cargo(&sysroot, detached_file),
|
||||||
|
config.target.as_deref(),
|
||||||
|
&config.extra_env,
|
||||||
|
)
|
||||||
|
.unwrap_or_default();
|
||||||
let rustc_cfg = rustc_cfg::get(None, &config.extra_env, RustcCfgConfig::Rustc(&sysroot));
|
let rustc_cfg = rustc_cfg::get(None, &config.extra_env, RustcCfgConfig::Rustc(&sysroot));
|
||||||
let data_layout = target_data_layout::get(
|
let data_layout = target_data_layout::get(
|
||||||
RustcDataLayoutConfig::Rustc(&sysroot),
|
RustcDataLayoutConfig::Rustc(&sysroot),
|
||||||
|
@ -422,16 +444,27 @@ impl ProjectWorkspace {
|
||||||
&config.extra_env,
|
&config.extra_env,
|
||||||
);
|
);
|
||||||
|
|
||||||
let cargo_script =
|
let cargo_script = CargoWorkspace::fetch_metadata(
|
||||||
CargoWorkspace::fetch_metadata(detached_file, dir, config, &sysroot, false, &|_| ())
|
detached_file,
|
||||||
.ok()
|
dir,
|
||||||
.map(|(ws, error)| {
|
&CargoMetadataConfig {
|
||||||
(
|
features: config.features.clone(),
|
||||||
CargoWorkspace::new(ws, detached_file.clone()),
|
targets,
|
||||||
WorkspaceBuildScripts::default(),
|
extra_args: config.extra_args.clone(),
|
||||||
error.map(Arc::new),
|
extra_env: config.extra_env.clone(),
|
||||||
)
|
},
|
||||||
});
|
&sysroot,
|
||||||
|
false,
|
||||||
|
&|_| (),
|
||||||
|
)
|
||||||
|
.ok()
|
||||||
|
.map(|(ws, error)| {
|
||||||
|
(
|
||||||
|
CargoWorkspace::new(ws, detached_file.clone()),
|
||||||
|
WorkspaceBuildScripts::default(),
|
||||||
|
error.map(Arc::new),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
let cargo_config_extra_env = cargo_config_env(detached_file, &config.extra_env, &sysroot);
|
let cargo_config_extra_env = cargo_config_env(detached_file, &config.extra_env, &sysroot);
|
||||||
Ok(ProjectWorkspace {
|
Ok(ProjectWorkspace {
|
||||||
|
|
|
@ -10,7 +10,7 @@ extern crate rustc_driver as _;
|
||||||
|
|
||||||
mod rustc_wrapper;
|
mod rustc_wrapper;
|
||||||
|
|
||||||
use std::{env, fs, path::PathBuf, process::ExitCode, sync::Arc, thread::sleep};
|
use std::{env, fs, path::PathBuf, process::ExitCode, sync::Arc};
|
||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use lsp_server::Connection;
|
use lsp_server::Connection;
|
||||||
|
@ -100,7 +100,7 @@ fn wait_for_debugger() {
|
||||||
// SAFETY: WinAPI generated code that is defensively marked `unsafe` but
|
// SAFETY: WinAPI generated code that is defensively marked `unsafe` but
|
||||||
// in practice can not be used in an unsafe way.
|
// in practice can not be used in an unsafe way.
|
||||||
while unsafe { IsDebuggerPresent() } == 0 {
|
while unsafe { IsDebuggerPresent() } == 0 {
|
||||||
sleep(std::time::Duration::from_millis(100));
|
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
@ -109,7 +109,7 @@ fn wait_for_debugger() {
|
||||||
let mut d = 4;
|
let mut d = 4;
|
||||||
while d == 4 {
|
while d == 4 {
|
||||||
d = 4;
|
d = 4;
|
||||||
sleep(std::time::Duration::from_millis(100));
|
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,10 @@ use itertools::Itertools;
|
||||||
use load_cargo::{load_workspace, LoadCargoConfig, ProcMacroServerChoice};
|
use load_cargo::{load_workspace, LoadCargoConfig, ProcMacroServerChoice};
|
||||||
use oorandom::Rand32;
|
use oorandom::Rand32;
|
||||||
use profile::{Bytes, StopWatch};
|
use profile::{Bytes, StopWatch};
|
||||||
use project_model::{CargoConfig, CfgOverrides, ProjectManifest, ProjectWorkspace, RustLibSource};
|
use project_model::{
|
||||||
|
CargoConfig, CargoMetadataConfig, CfgOverrides, ProjectManifest, ProjectWorkspace,
|
||||||
|
RustLibSource,
|
||||||
|
};
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
use syntax::{AstNode, SyntaxNode};
|
use syntax::{AstNode, SyntaxNode};
|
||||||
|
@ -68,7 +71,9 @@ impl flags::AnalysisStats {
|
||||||
},
|
},
|
||||||
sysroot_query_metadata: match self.no_query_sysroot_metadata {
|
sysroot_query_metadata: match self.no_query_sysroot_metadata {
|
||||||
true => project_model::SysrootQueryMetadata::None,
|
true => project_model::SysrootQueryMetadata::None,
|
||||||
false => project_model::SysrootQueryMetadata::CargoMetadata,
|
false => project_model::SysrootQueryMetadata::CargoMetadata(
|
||||||
|
CargoMetadataConfig::default(),
|
||||||
|
),
|
||||||
},
|
},
|
||||||
all_targets: true,
|
all_targets: true,
|
||||||
set_test: !self.no_test,
|
set_test: !self.no_test,
|
||||||
|
|
|
@ -77,7 +77,7 @@ impl Tester {
|
||||||
let sysroot = Sysroot::discover(
|
let sysroot = Sysroot::discover(
|
||||||
tmp_file.parent().unwrap(),
|
tmp_file.parent().unwrap(),
|
||||||
&cargo_config.extra_env,
|
&cargo_config.extra_env,
|
||||||
SysrootQueryMetadata::CargoMetadata,
|
&SysrootQueryMetadata::CargoMetadata(Default::default()),
|
||||||
);
|
);
|
||||||
let data_layout = target_data_layout::get(
|
let data_layout = target_data_layout::get(
|
||||||
RustcDataLayoutConfig::Rustc(&sysroot),
|
RustcDataLayoutConfig::Rustc(&sysroot),
|
||||||
|
|
|
@ -21,8 +21,8 @@ use ide_db::{
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use paths::{Utf8Path, Utf8PathBuf};
|
use paths::{Utf8Path, Utf8PathBuf};
|
||||||
use project_model::{
|
use project_model::{
|
||||||
CargoConfig, CargoFeatures, ProjectJson, ProjectJsonData, ProjectJsonFromCommand,
|
CargoConfig, CargoFeatures, CargoMetadataConfig, ProjectJson, ProjectJsonData,
|
||||||
ProjectManifest, RustLibSource,
|
ProjectJsonFromCommand, ProjectManifest, RustLibSource,
|
||||||
};
|
};
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
use semver::Version;
|
use semver::Version;
|
||||||
|
@ -1862,7 +1862,12 @@ impl Config {
|
||||||
sysroot,
|
sysroot,
|
||||||
sysroot_query_metadata: match self.cargo_sysrootQueryMetadata(None) {
|
sysroot_query_metadata: match self.cargo_sysrootQueryMetadata(None) {
|
||||||
SysrootQueryMetadata::CargoMetadata => {
|
SysrootQueryMetadata::CargoMetadata => {
|
||||||
project_model::SysrootQueryMetadata::CargoMetadata
|
project_model::SysrootQueryMetadata::CargoMetadata(CargoMetadataConfig {
|
||||||
|
features: Default::default(),
|
||||||
|
targets: self.cargo_target(source_root).clone().into_iter().collect(),
|
||||||
|
extra_args: Default::default(),
|
||||||
|
extra_env: Default::default(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
SysrootQueryMetadata::None => project_model::SysrootQueryMetadata::None,
|
SysrootQueryMetadata::None => project_model::SysrootQueryMetadata::None,
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in a new issue