Skip to content

Commit 9c55462

Browse files
authored
Merge pull request rust-lang#18754 from Veykril/push-zkkzxrsxnqnm
Cleanup target fetching for cargo metadata
2 parents 8bfb2fe + 4be8178 commit 9c55462

File tree

10 files changed

+209
-140
lines changed

10 files changed

+209
-140
lines changed

src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs

Lines changed: 18 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ use serde_json::from_value;
1313
use span::Edition;
1414
use toolchain::Tool;
1515

16-
use crate::{utf8_stdout, ManifestPath, Sysroot, SysrootQueryMetadata};
1716
use crate::{CfgOverrides, InvocationStrategy};
17+
use crate::{ManifestPath, Sysroot, SysrootQueryMetadata};
1818

1919
/// [`CargoWorkspace`] represents the logical structure of, well, a Cargo
2020
/// workspace. It pretty closely mirrors `cargo metadata` output.
@@ -251,6 +251,18 @@ impl TargetKind {
251251
}
252252
}
253253

254+
#[derive(Default, Clone, Debug, PartialEq, Eq)]
255+
pub struct CargoMetadataConfig {
256+
/// List of features to activate.
257+
pub features: CargoFeatures,
258+
/// rustc targets
259+
pub targets: Vec<String>,
260+
/// Extra args to pass to the cargo command.
261+
pub extra_args: Vec<String>,
262+
/// Extra env vars to set when invoking the cargo command
263+
pub extra_env: FxHashMap<String, String>,
264+
}
265+
254266
// Deserialize helper for the cargo metadata
255267
#[derive(Deserialize, Default)]
256268
struct PackageMetadata {
@@ -265,7 +277,7 @@ impl CargoWorkspace {
265277
pub fn fetch_metadata(
266278
cargo_toml: &ManifestPath,
267279
current_dir: &AbsPath,
268-
config: &CargoConfig,
280+
config: &CargoMetadataConfig,
269281
sysroot: &Sysroot,
270282
locked: bool,
271283
progress: &dyn Fn(String),
@@ -276,14 +288,12 @@ impl CargoWorkspace {
276288
fn fetch_metadata_(
277289
cargo_toml: &ManifestPath,
278290
current_dir: &AbsPath,
279-
config: &CargoConfig,
291+
config: &CargoMetadataConfig,
280292
sysroot: &Sysroot,
281293
locked: bool,
282294
no_deps: bool,
283295
progress: &dyn Fn(String),
284296
) -> anyhow::Result<(cargo_metadata::Metadata, Option<anyhow::Error>)> {
285-
let targets = find_list_of_build_targets(config, cargo_toml, sysroot);
286-
287297
let cargo = sysroot.tool(Tool::Cargo);
288298
let mut meta = MetadataCommand::new();
289299
meta.cargo_path(cargo.get_program());
@@ -319,12 +329,9 @@ impl CargoWorkspace {
319329
}
320330
}
321331

322-
if !targets.is_empty() {
323-
other_options.append(
324-
&mut targets
325-
.into_iter()
326-
.flat_map(|target| ["--filter-platform".to_owned(), target])
327-
.collect(),
332+
if !config.targets.is_empty() {
333+
other_options.extend(
334+
config.targets.iter().flat_map(|it| ["--filter-platform".to_owned(), it.clone()]),
328335
);
329336
}
330337
// The manifest is a rust file, so this means its a script manifest
@@ -596,79 +603,3 @@ impl CargoWorkspace {
596603
self.is_virtual_workspace
597604
}
598605
}
599-
600-
fn find_list_of_build_targets(
601-
config: &CargoConfig,
602-
cargo_toml: &ManifestPath,
603-
sysroot: &Sysroot,
604-
) -> Vec<String> {
605-
if let Some(target) = &config.target {
606-
return [target.into()].to_vec();
607-
}
608-
609-
let build_targets = cargo_config_build_target(cargo_toml, &config.extra_env, sysroot);
610-
if !build_targets.is_empty() {
611-
return build_targets;
612-
}
613-
614-
rustc_discover_host_triple(cargo_toml, &config.extra_env, sysroot).into_iter().collect()
615-
}
616-
617-
fn rustc_discover_host_triple(
618-
cargo_toml: &ManifestPath,
619-
extra_env: &FxHashMap<String, String>,
620-
sysroot: &Sysroot,
621-
) -> Option<String> {
622-
let mut rustc = sysroot.tool(Tool::Rustc);
623-
rustc.envs(extra_env);
624-
rustc.current_dir(cargo_toml.parent()).arg("-vV");
625-
tracing::debug!("Discovering host platform by {:?}", rustc);
626-
match utf8_stdout(rustc) {
627-
Ok(stdout) => {
628-
let field = "host: ";
629-
let target = stdout.lines().find_map(|l| l.strip_prefix(field));
630-
if let Some(target) = target {
631-
Some(target.to_owned())
632-
} else {
633-
// If we fail to resolve the host platform, it's not the end of the world.
634-
tracing::info!("rustc -vV did not report host platform, got:\n{}", stdout);
635-
None
636-
}
637-
}
638-
Err(e) => {
639-
tracing::warn!("Failed to discover host platform: {}", e);
640-
None
641-
}
642-
}
643-
}
644-
645-
fn cargo_config_build_target(
646-
cargo_toml: &ManifestPath,
647-
extra_env: &FxHashMap<String, String>,
648-
sysroot: &Sysroot,
649-
) -> Vec<String> {
650-
let mut cargo_config = sysroot.tool(Tool::Cargo);
651-
cargo_config.envs(extra_env);
652-
cargo_config
653-
.current_dir(cargo_toml.parent())
654-
.args(["-Z", "unstable-options", "config", "get", "build.target"])
655-
.env("RUSTC_BOOTSTRAP", "1");
656-
// if successful we receive `build.target = "target-triple"`
657-
// or `build.target = ["<target 1>", ..]`
658-
tracing::debug!("Discovering cargo config target by {:?}", cargo_config);
659-
utf8_stdout(cargo_config).map(parse_output_cargo_config_build_target).unwrap_or_default()
660-
}
661-
662-
fn parse_output_cargo_config_build_target(stdout: String) -> Vec<String> {
663-
let trimmed = stdout.trim_start_matches("build.target = ").trim_matches('"');
664-
665-
if !trimmed.starts_with('[') {
666-
return [trimmed.to_owned()].to_vec();
667-
}
668-
669-
let res = serde_json::from_str(trimmed);
670-
if let Err(e) = &res {
671-
tracing::warn!("Failed to parse `build.target` as an array of target: {}`", e);
672-
}
673-
res.unwrap_or_default()
674-
}

src/tools/rust-analyzer/crates/project-model/src/lib.rs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ pub mod project_json;
2323
mod rustc_cfg;
2424
mod sysroot;
2525
pub mod target_data_layout;
26+
mod target_triple;
2627
mod workspace;
2728

2829
#[cfg(test)]
@@ -42,8 +43,8 @@ use rustc_hash::FxHashSet;
4243
pub use crate::{
4344
build_dependencies::WorkspaceBuildScripts,
4445
cargo_workspace::{
45-
CargoConfig, CargoFeatures, CargoWorkspace, Package, PackageData, PackageDependency,
46-
RustLibSource, Target, TargetData, TargetKind,
46+
CargoConfig, CargoFeatures, CargoMetadataConfig, CargoWorkspace, Package, PackageData,
47+
PackageDependency, RustLibSource, Target, TargetData, TargetKind,
4748
},
4849
manifest_path::ManifestPath,
4950
project_json::{ProjectJson, ProjectJsonData},
@@ -241,9 +242,14 @@ fn parse_cfg(s: &str) -> Result<cfg::CfgAtom, String> {
241242
Ok(res)
242243
}
243244

244-
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
245+
#[derive(Clone, Debug, PartialEq, Eq)]
245246
pub enum SysrootQueryMetadata {
246-
#[default]
247-
CargoMetadata,
247+
CargoMetadata(CargoMetadataConfig),
248248
None,
249249
}
250+
251+
impl Default for SysrootQueryMetadata {
252+
fn default() -> Self {
253+
SysrootQueryMetadata::CargoMetadata(Default::default())
254+
}
255+
}

src/tools/rust-analyzer/crates/project-model/src/sysroot.rs

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@ use paths::{AbsPath, AbsPathBuf, Utf8PathBuf};
1414
use rustc_hash::FxHashMap;
1515
use toolchain::{probe_for_binary, Tool};
1616

17-
use crate::{utf8_stdout, CargoConfig, CargoWorkspace, ManifestPath, SysrootQueryMetadata};
17+
use crate::{
18+
cargo_workspace::CargoMetadataConfig, utf8_stdout, CargoWorkspace, ManifestPath,
19+
SysrootQueryMetadata,
20+
};
1821

1922
#[derive(Debug, Clone, PartialEq, Eq)]
2023
pub struct Sysroot {
@@ -126,7 +129,7 @@ impl Sysroot {
126129
pub fn discover(
127130
dir: &AbsPath,
128131
extra_env: &FxHashMap<String, String>,
129-
sysroot_query_metadata: SysrootQueryMetadata,
132+
sysroot_query_metadata: &SysrootQueryMetadata,
130133
) -> Sysroot {
131134
let sysroot_dir = discover_sysroot_dir(dir, extra_env);
132135
let sysroot_src_dir = sysroot_dir.as_ref().ok().map(|sysroot_dir| {
@@ -139,7 +142,7 @@ impl Sysroot {
139142
current_dir: &AbsPath,
140143
extra_env: &FxHashMap<String, String>,
141144
sysroot_src_dir: AbsPathBuf,
142-
sysroot_query_metadata: SysrootQueryMetadata,
145+
sysroot_query_metadata: &SysrootQueryMetadata,
143146
) -> Sysroot {
144147
let sysroot_dir = discover_sysroot_dir(current_dir, extra_env);
145148
Sysroot::load_core_check(
@@ -151,7 +154,7 @@ impl Sysroot {
151154

152155
pub fn discover_sysroot_src_dir(
153156
sysroot_dir: AbsPathBuf,
154-
sysroot_query_metadata: SysrootQueryMetadata,
157+
sysroot_query_metadata: &SysrootQueryMetadata,
155158
) -> Sysroot {
156159
let sysroot_src_dir = discover_sysroot_src_dir(&sysroot_dir)
157160
.ok_or_else(|| format_err!("can't find standard library sources in {sysroot_dir}"));
@@ -205,15 +208,15 @@ impl Sysroot {
205208
pub fn load(
206209
sysroot_dir: Option<AbsPathBuf>,
207210
sysroot_src_dir: Option<AbsPathBuf>,
208-
sysroot_query_metadata: SysrootQueryMetadata,
211+
sysroot_query_metadata: &SysrootQueryMetadata,
209212
) -> Sysroot {
210213
Self::load_core_check(sysroot_dir.map(Ok), sysroot_src_dir.map(Ok), sysroot_query_metadata)
211214
}
212215

213216
fn load_core_check(
214217
sysroot_dir: Option<Result<AbsPathBuf, anyhow::Error>>,
215218
sysroot_src_dir: Option<Result<AbsPathBuf, anyhow::Error>>,
216-
sysroot_query_metadata: SysrootQueryMetadata,
219+
sysroot_query_metadata: &SysrootQueryMetadata,
217220
) -> Sysroot {
218221
let mut sysroot = Self::load_(sysroot_dir, sysroot_src_dir, sysroot_query_metadata);
219222
if sysroot.error.is_none() {
@@ -241,7 +244,7 @@ impl Sysroot {
241244
fn load_(
242245
sysroot_dir: Option<Result<AbsPathBuf, anyhow::Error>>,
243246
sysroot_src_dir: Option<Result<AbsPathBuf, anyhow::Error>>,
244-
sysroot_query_metadata: SysrootQueryMetadata,
247+
sysroot_query_metadata: &SysrootQueryMetadata,
245248
) -> Sysroot {
246249
let sysroot_dir = match sysroot_dir {
247250
Some(Ok(sysroot_dir)) => Some(sysroot_dir),
@@ -274,13 +277,16 @@ impl Sysroot {
274277
}
275278
}
276279
};
277-
if sysroot_query_metadata == SysrootQueryMetadata::CargoMetadata {
280+
if let SysrootQueryMetadata::CargoMetadata(cargo_config) = sysroot_query_metadata {
278281
let library_manifest =
279282
ManifestPath::try_from(sysroot_src_dir.join("Cargo.toml")).unwrap();
280283
if fs::metadata(&library_manifest).is_ok() {
281-
if let Some(sysroot) =
282-
Self::load_library_via_cargo(library_manifest, &sysroot_dir, &sysroot_src_dir)
283-
{
284+
if let Some(sysroot) = Self::load_library_via_cargo(
285+
library_manifest,
286+
&sysroot_dir,
287+
&sysroot_src_dir,
288+
cargo_config,
289+
) {
284290
return sysroot;
285291
}
286292
}
@@ -341,9 +347,10 @@ impl Sysroot {
341347
library_manifest: ManifestPath,
342348
sysroot_dir: &Option<AbsPathBuf>,
343349
sysroot_src_dir: &AbsPathBuf,
350+
cargo_config: &CargoMetadataConfig,
344351
) -> Option<Sysroot> {
345352
tracing::debug!("Loading library metadata: {library_manifest}");
346-
let mut cargo_config = CargoConfig::default();
353+
let mut cargo_config = cargo_config.clone();
347354
// the sysroot uses `public-dependency`, so we make cargo think it's a nightly
348355
cargo_config.extra_env.insert(
349356
"__CARGO_TEST_CHANNEL_OVERRIDE_DO_NOT_USE_THIS".to_owned(),
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
//! Runs `rustc --print -vV` to get the host target.
2+
use anyhow::Context;
3+
use rustc_hash::FxHashMap;
4+
use toolchain::Tool;
5+
6+
use crate::{utf8_stdout, ManifestPath, Sysroot};
7+
8+
pub(super) enum TargetTipleConfig<'a> {
9+
#[expect(dead_code)]
10+
Rustc(&'a Sysroot),
11+
Cargo(&'a Sysroot, &'a ManifestPath),
12+
}
13+
14+
pub(super) fn get(
15+
config: TargetTipleConfig<'_>,
16+
target: Option<&str>,
17+
extra_env: &FxHashMap<String, String>,
18+
) -> anyhow::Result<Vec<String>> {
19+
if let Some(target) = target {
20+
return Ok(vec![target.to_owned()]);
21+
}
22+
23+
let sysroot = match config {
24+
TargetTipleConfig::Cargo(sysroot, cargo_toml) => {
25+
match cargo_config_build_target(cargo_toml, extra_env, sysroot) {
26+
Ok(it) => return Ok(it),
27+
Err(e) => {
28+
tracing::warn!("failed to run `cargo rustc --print cfg`, falling back to invoking rustc directly: {e}");
29+
sysroot
30+
}
31+
}
32+
}
33+
TargetTipleConfig::Rustc(sysroot) => sysroot,
34+
};
35+
rustc_discover_host_triple(extra_env, sysroot).map(|it| vec![it])
36+
}
37+
38+
fn rustc_discover_host_triple(
39+
extra_env: &FxHashMap<String, String>,
40+
sysroot: &Sysroot,
41+
) -> anyhow::Result<String> {
42+
let mut rustc = sysroot.tool(Tool::Rustc);
43+
rustc.envs(extra_env);
44+
rustc.arg("-vV");
45+
tracing::debug!("Discovering host platform by {:?}", rustc);
46+
let stdout = utf8_stdout(rustc).context("Failed to discover host platform")?;
47+
let field = "host: ";
48+
let target = stdout.lines().find_map(|l| l.strip_prefix(field));
49+
if let Some(target) = target {
50+
Ok(target.to_owned())
51+
} else {
52+
// If we fail to resolve the host platform, it's not the end of the world.
53+
Err(anyhow::format_err!("rustc -vV did not report host platform, got:\n{}", stdout))
54+
}
55+
}
56+
57+
fn cargo_config_build_target(
58+
cargo_toml: &ManifestPath,
59+
extra_env: &FxHashMap<String, String>,
60+
sysroot: &Sysroot,
61+
) -> anyhow::Result<Vec<String>> {
62+
let mut cargo_config = sysroot.tool(Tool::Cargo);
63+
cargo_config.envs(extra_env);
64+
cargo_config
65+
.current_dir(cargo_toml.parent())
66+
.args(["-Z", "unstable-options", "config", "get", "build.target"])
67+
.env("RUSTC_BOOTSTRAP", "1");
68+
// if successful we receive `build.target = "target-triple"`
69+
// or `build.target = ["<target 1>", ..]`
70+
tracing::debug!("Discovering cargo config target by {:?}", cargo_config);
71+
utf8_stdout(cargo_config).and_then(parse_output_cargo_config_build_target)
72+
}
73+
74+
fn parse_output_cargo_config_build_target(stdout: String) -> anyhow::Result<Vec<String>> {
75+
let trimmed = stdout.trim_start_matches("build.target = ").trim_matches('"');
76+
77+
if !trimmed.starts_with('[') {
78+
return Ok([trimmed.to_owned()].to_vec());
79+
}
80+
81+
serde_json::from_str(trimmed).context("Failed to parse `build.target` as an array of target")
82+
}

src/tools/rust-analyzer/crates/project-model/src/tests.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ fn get_fake_sysroot() -> Sysroot {
117117
// fake sysroot, so we give them both the same path:
118118
let sysroot_dir = AbsPathBuf::assert(sysroot_path);
119119
let sysroot_src_dir = sysroot_dir.clone();
120-
Sysroot::load(Some(sysroot_dir), Some(sysroot_src_dir), SysrootQueryMetadata::CargoMetadata)
120+
Sysroot::load(Some(sysroot_dir), Some(sysroot_src_dir), &SysrootQueryMetadata::default())
121121
}
122122

123123
fn rooted_project_json(data: ProjectJsonData) -> ProjectJson {
@@ -232,7 +232,7 @@ fn smoke_test_real_sysroot_cargo() {
232232
let sysroot = Sysroot::discover(
233233
AbsPath::assert(Utf8Path::new(env!("CARGO_MANIFEST_DIR"))),
234234
&Default::default(),
235-
SysrootQueryMetadata::CargoMetadata,
235+
&SysrootQueryMetadata::default(),
236236
);
237237
assert!(matches!(sysroot.mode(), SysrootMode::Workspace(_)));
238238
let project_workspace = ProjectWorkspace {

0 commit comments

Comments
 (0)