Don't use $CARGO_BUILD_TARGET in cargo metadata

This commit fixes a (five year old!) regression in `cargo metadata`
where if `--filter-platform` isn't explicitly specified it will
accidentally read `$CARGO_BUILD_TARGET` (or `build.target`
configuration) and use that as the default `--filter-platform`. The
reason for this is that the calculation for targets changed in #8167
and while the shared function makes sense for other commands such as
`cargo build` the targets have a different meaning in `cargo metadata`
so a slightly different set of functionality is desired.

This commit fixes the issue by introducing a new constructor for the
list of `CompileKind` variants where the fallback of "if nothing is
specified" is explicitly chosen.
This commit is contained in:
Alex Crichton 2025-03-05 20:11:41 -08:00
parent 2da492b8e5
commit 70dc4d8331
4 changed files with 48 additions and 9 deletions

View File

@ -29,6 +29,20 @@ pub enum CompileKind {
Target(CompileTarget),
}
/// Fallback behavior in the
/// [`CompileKind::from_requested_targets_with_fallback`] function when
/// no targets are specified.
pub enum CompileKindFallback {
/// The build configuration is consulted to find the default target, such as
/// `$CARGO_BUILD_TARGET` or reading `build.target`.
BuildConfig,
/// Only the host should be returned when targets aren't explicitly
/// specified. This is used by `cargo metadata` for example where "only
/// host" has a special meaning in terms of the returned metadata.
JustHost,
}
impl CompileKind {
pub fn is_host(&self) -> bool {
matches!(self, CompileKind::Host)
@ -53,6 +67,21 @@ impl CompileKind {
pub fn from_requested_targets(
gctx: &GlobalContext,
targets: &[String],
) -> CargoResult<Vec<CompileKind>> {
CompileKind::from_requested_targets_with_fallback(
gctx,
targets,
CompileKindFallback::BuildConfig,
)
}
/// Same as [`CompileKind::from_requested_targets`] except that if `targets`
/// doesn't explicitly mention anything the behavior of what to return is
/// controlled by the `fallback` argument.
pub fn from_requested_targets_with_fallback(
gctx: &GlobalContext,
targets: &[String],
fallback: CompileKindFallback,
) -> CargoResult<Vec<CompileKind>> {
let dedup = |targets: &[String]| {
Ok(targets
@ -70,9 +99,11 @@ impl CompileKind {
return dedup(targets);
}
let kinds = match &gctx.build_config()?.target {
None => Ok(vec![CompileKind::Host]),
Some(build_target_config) => dedup(&build_target_config.values(gctx)?),
let kinds = match (fallback, &gctx.build_config()?.target) {
(_, None) | (CompileKindFallback::JustHost, _) => Ok(vec![CompileKind::Host]),
(CompileKindFallback::BuildConfig, Some(build_target_config)) => {
dedup(&build_target_config.values(gctx)?)
}
};
kinds

View File

@ -76,7 +76,7 @@ pub use self::build_context::{
use self::build_plan::BuildPlan;
pub use self::build_runner::{BuildRunner, Metadata, UnitHash};
pub use self::compilation::{Compilation, Doctest, UnitOutput};
pub use self::compile_kind::{CompileKind, CompileTarget};
pub use self::compile_kind::{CompileKind, CompileKindFallback, CompileTarget};
pub use self::crate_type::CrateType;
pub use self::custom_build::LinkArgTarget;
pub use self::custom_build::{BuildOutput, BuildScriptOutputs, BuildScripts};

View File

@ -1,5 +1,5 @@
use crate::core::compiler::artifact::match_artifacts_kind_with_targets;
use crate::core::compiler::{CompileKind, RustcTargetData};
use crate::core::compiler::{CompileKind, CompileKindFallback, RustcTargetData};
use crate::core::dependency::DepKind;
use crate::core::package::SerializedPackage;
use crate::core::resolver::{features::CliFeatures, HasDevUnits, Resolve};
@ -132,8 +132,16 @@ fn build_resolve_graph(
) -> CargoResult<(Vec<SerializedPackage>, MetadataResolve)> {
// TODO: Without --filter-platform, features are being resolved for `host` only.
// How should this work?
let requested_kinds =
CompileKind::from_requested_targets(ws.gctx(), &metadata_opts.filter_platforms)?;
//
// Otherwise note that "just host" is used as the fallback here if
// `filter_platforms` is empty to intentionally avoid reading
// `$CARGO_BUILD_TARGET` (or `build.target`) which makes sense for other
// subcommands like `cargo build` but does not fit with this command.
let requested_kinds = CompileKind::from_requested_targets_with_fallback(
ws.gctx(),
&metadata_opts.filter_platforms,
CompileKindFallback::JustHost,
)?;
let mut target_data = RustcTargetData::new(ws, &requested_kinds)?;
// Resolve entire workspace.
let specs = Packages::All(Vec::new()).to_package_id_specs(ws)?;

View File

@ -4980,8 +4980,8 @@ fn metadata_ignores_build_target_configuration() -> anyhow::Result<()> {
.env("CARGO_BUILD_TARGET", rustc_host())
.exec_with_output()?;
assert!(
output1.stdout != output2.stdout,
"metadata should change when `CARGO_BUILD_TARGET` is set",
output1.stdout == output2.stdout,
"metadata should not change when `CARGO_BUILD_TARGET` is set",
);
Ok(())
}