Cleanup target fetching for cargo metadata

This commit is contained in:
Lukas Wirth 2024-12-24 17:21:46 +01:00
parent 633a10cb58
commit 029261f9cc
10 changed files with 209 additions and 140 deletions

View file

@ -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()
}

View file

@ -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())
}
}

View file

@ -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(),

View 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")
}

View file

@ -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 {

View file

@ -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 {

View file

@ -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));
} }
} }
} }

View file

@ -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,

View file

@ -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),

View file

@ -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,
}, },