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 toolchain::Tool;
use crate::{utf8_stdout, ManifestPath, Sysroot, SysrootQueryMetadata};
use crate::{CfgOverrides, InvocationStrategy};
use crate::{ManifestPath, Sysroot, SysrootQueryMetadata};
/// [`CargoWorkspace`] represents the logical structure of, well, a Cargo
/// 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
#[derive(Deserialize, Default)]
struct PackageMetadata {
@ -265,7 +277,7 @@ impl CargoWorkspace {
pub fn fetch_metadata(
cargo_toml: &ManifestPath,
current_dir: &AbsPath,
config: &CargoConfig,
config: &CargoMetadataConfig,
sysroot: &Sysroot,
locked: bool,
progress: &dyn Fn(String),
@ -276,14 +288,12 @@ impl CargoWorkspace {
fn fetch_metadata_(
cargo_toml: &ManifestPath,
current_dir: &AbsPath,
config: &CargoConfig,
config: &CargoMetadataConfig,
sysroot: &Sysroot,
locked: bool,
no_deps: bool,
progress: &dyn Fn(String),
) -> 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 mut meta = MetadataCommand::new();
meta.cargo_path(cargo.get_program());
@ -319,12 +329,9 @@ impl CargoWorkspace {
}
}
if !targets.is_empty() {
other_options.append(
&mut targets
.into_iter()
.flat_map(|target| ["--filter-platform".to_owned(), target])
.collect(),
if !config.targets.is_empty() {
other_options.extend(
config.targets.iter().flat_map(|it| ["--filter-platform".to_owned(), it.clone()]),
);
}
// The manifest is a rust file, so this means its a script manifest
@ -596,79 +603,3 @@ impl CargoWorkspace {
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()
}