diff --git a/Cargo.lock b/Cargo.lock index f37d171c549..567668123f6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -552,7 +552,7 @@ dependencies = [ [[package]] name = "crates-io" -version = "0.36.1" +version = "0.37.0" dependencies = [ "anyhow", "curl", diff --git a/Cargo.toml b/Cargo.toml index ec9f878b301..29a558ebc5f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ cargo-util = { version = "0.2.4", path = "crates/cargo-util" } cargo_metadata = "0.14.0" clap = "4.2.0" core-foundation = { version = "0.9.0", features = ["mac_os_10_7_support"] } -crates-io = { version = "0.36.1", path = "crates/crates-io" } +crates-io = { version = "0.37.0", path = "crates/crates-io" } criterion = { version = "0.3.5", features = ["html_reports"] } curl = "0.4.44" curl-sys = "0.4.63" diff --git a/benches/benchsuite/benches/resolve.rs b/benches/benchsuite/benches/resolve.rs index d03cd620e27..b2a80b0b6fb 100644 --- a/benches/benchsuite/benches/resolve.rs +++ b/benches/benchsuite/benches/resolve.rs @@ -1,5 +1,5 @@ use benchsuite::fixtures; -use cargo::core::compiler::{CompileKind, RustcTargetData}; +use cargo::core::compiler::{CompileKind, RustcTargetData, RustcTargetDataBuilder}; use cargo::core::resolver::features::{FeatureOpts, FeatureResolver}; use cargo::core::resolver::{CliFeatures, ForceAllTargets, HasDevUnits, ResolveBehavior}; use cargo::core::{PackageIdSpec, Workspace}; @@ -11,7 +11,7 @@ use std::path::Path; struct ResolveInfo<'cfg> { ws: Workspace<'cfg>, requested_kinds: [CompileKind; 1], - target_data: RustcTargetData<'cfg>, + target_data: RustcTargetDataBuilder<'cfg>, cli_features: CliFeatures, specs: Vec, has_dev_units: HasDevUnits, @@ -25,7 +25,7 @@ struct ResolveInfo<'cfg> { fn do_resolve<'cfg>(config: &'cfg Config, ws_root: &Path) -> ResolveInfo<'cfg> { let requested_kinds = [CompileKind::Host]; let ws = Workspace::new(&ws_root.join("Cargo.toml"), config).unwrap(); - let target_data = RustcTargetData::new(&ws, &requested_kinds).unwrap(); + let mut target_data = RustcTargetData::new(&ws, &requested_kinds).unwrap(); let cli_features = CliFeatures::from_command_line(&[], false, true).unwrap(); let pkgs = cargo::ops::Packages::Default; let specs = pkgs.to_package_id_specs(&ws).unwrap(); @@ -35,7 +35,7 @@ fn do_resolve<'cfg>(config: &'cfg Config, ws_root: &Path) -> ResolveInfo<'cfg> { // not confuse criterion's warmup. let ws_resolve = cargo::ops::resolve_ws_with_opts( &ws, - &target_data, + &mut target_data, &requested_kinds, &cli_features, &specs, diff --git a/crates/crates-io/Cargo.toml b/crates/crates-io/Cargo.toml index a9875d3fca5..034c2fca550 100644 --- a/crates/crates-io/Cargo.toml +++ b/crates/crates-io/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "crates-io" -version = "0.36.1" +version = "0.37.0" edition = "2021" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/cargo" diff --git a/crates/crates-io/lib.rs b/crates/crates-io/lib.rs index 243808098c4..2cc7ffadc41 100644 --- a/crates/crates-io/lib.rs +++ b/crates/crates-io/lib.rs @@ -73,6 +73,16 @@ pub struct NewCrateDependency { pub registry: Option, #[serde(skip_serializing_if = "Option::is_none")] pub explicit_name_in_toml: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub artifact: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + pub bindep_target: Option, + #[serde(default, skip_serializing_if = "is_false")] + pub lib: bool, +} + +fn is_false(&x: &bool) -> bool { + !x } #[derive(Deserialize)] diff --git a/src/cargo/core/compiler/build_context/mod.rs b/src/cargo/core/compiler/build_context/mod.rs index f35084e2b7f..89ee6de9ef4 100644 --- a/src/cargo/core/compiler/build_context/mod.rs +++ b/src/cargo/core/compiler/build_context/mod.rs @@ -14,7 +14,7 @@ use std::path::PathBuf; mod target_info; pub use self::target_info::{ - FileFlavor, FileType, RustDocFingerprint, RustcTargetData, TargetInfo, + FileFlavor, FileType, RustDocFingerprint, RustcTargetData, RustcTargetDataBuilder, TargetInfo, }; /// The build context, containing complete information needed for a build task diff --git a/src/cargo/core/compiler/build_context/target_info.rs b/src/cargo/core/compiler/build_context/target_info.rs index e6e41c5226f..2e83c9d5fa2 100644 --- a/src/cargo/core/compiler/build_context/target_info.rs +++ b/src/cargo/core/compiler/build_context/target_info.rs @@ -11,7 +11,7 @@ use crate::core::compiler::apply_env_config; use crate::core::compiler::{ BuildOutput, CompileKind, CompileMode, CompileTarget, Context, CrateType, }; -use crate::core::{Dependency, Package, Target, TargetKind, Workspace}; +use crate::core::{Dependency, Target, TargetKind, Workspace}; use crate::util::config::{Config, StringList, TargetConfig}; use crate::util::interning::InternedString; use crate::util::{CargoResult, Rustc}; @@ -21,6 +21,7 @@ use cargo_util::{paths, ProcessBuilder}; use serde::{Deserialize, Serialize}; use std::cell::RefCell; use std::collections::hash_map::{Entry, HashMap}; +use std::ops::Deref; use std::path::{Path, PathBuf}; use std::str::{self, FromStr}; @@ -850,6 +851,40 @@ fn rustflags_from_build(config: &Config, flag: Flags) -> CargoResult { + data: RustcTargetData<'cfg>, +} + +impl<'cfg> RustcTargetDataBuilder<'cfg> { + /// Insert `kind` into our `target_info` and `target_config` members if it isn't present yet. + pub fn merge_compile_kind(&mut self, kind: CompileKind) -> CargoResult<()> { + if let CompileKind::Target(target) = kind { + if !self.data.target_config.contains_key(&target) { + self.data.target_config + .insert(target, self.data.config.target_cfg_triple(target.short_name())?); + } + if !self.data.target_info.contains_key(&target) { + self.data.target_info.insert( + target, + TargetInfo::new(self.data.config, &self.data.requested_kinds, &self.data.rustc, kind)?, + ); + } + } + Ok(()) + } + + pub fn build(self) -> RustcTargetData<'cfg> { + self.data + } +} + +impl<'cfg> Deref for RustcTargetDataBuilder<'cfg> { + type Target = RustcTargetData<'cfg>; + fn deref(&self) -> &Self::Target { + &self.data + } +} + /// Collection of information about `rustc` and the host and target. pub struct RustcTargetData<'cfg> { /// Information about `rustc` itself. @@ -876,7 +911,7 @@ impl<'cfg> RustcTargetData<'cfg> { pub fn new( ws: &Workspace<'cfg>, requested_kinds: &[CompileKind], - ) -> CargoResult> { + ) -> CargoResult> { let config = ws.config(); let rustc = config.load_global_rustc(Some(ws))?; let mut target_config = HashMap::new(); @@ -900,7 +935,7 @@ impl<'cfg> RustcTargetData<'cfg> { target_config.insert(ct, config.target_cfg_triple(&rustc.host)?); }; - let mut res = RustcTargetData { + let data = RustcTargetData { rustc, config, requested_kinds: requested_kinds.into(), @@ -910,54 +945,17 @@ impl<'cfg> RustcTargetData<'cfg> { target_info, }; - // Get all kinds we currently know about. - // - // For now, targets can only ever come from the root workspace - // units and artifact dependencies, so this - // correctly represents all the kinds that can happen. When we have - // other ways for targets to appear at places that are not the root units, - // we may have to revisit this. - fn artifact_targets(package: &Package) -> impl Iterator + '_ { - package - .manifest() - .dependencies() - .iter() - .filter_map(|d| d.artifact()?.target()?.to_compile_kind()) - } - let all_kinds = requested_kinds - .iter() - .copied() - .chain(ws.members().flat_map(|p| { - p.manifest() - .default_kind() - .into_iter() - .chain(p.manifest().forced_kind()) - .chain(artifact_targets(p)) - })); - for kind in all_kinds { + let mut res = RustcTargetDataBuilder { + data + }; + + for &kind in requested_kinds { res.merge_compile_kind(kind)?; } Ok(res) } - /// Insert `kind` into our `target_info` and `target_config` members if it isn't present yet. - fn merge_compile_kind(&mut self, kind: CompileKind) -> CargoResult<()> { - if let CompileKind::Target(target) = kind { - if !self.target_config.contains_key(&target) { - self.target_config - .insert(target, self.config.target_cfg_triple(target.short_name())?); - } - if !self.target_info.contains_key(&target) { - self.target_info.insert( - target, - TargetInfo::new(self.config, &self.requested_kinds, &self.rustc, kind)?, - ); - } - } - Ok(()) - } - /// Returns a "short" name for the given kind, suitable for keying off /// configuration in Cargo or presenting to users. pub fn short_name<'a>(&'a self, kind: &'a CompileKind) -> &'a str { diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index 31e63c226b7..d771ee940a3 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -69,7 +69,7 @@ use log::{debug, trace}; pub use self::build_config::{BuildConfig, CompileMode, MessageFormat, TimingOutput}; pub use self::build_context::{ - BuildContext, FileFlavor, FileType, RustDocFingerprint, RustcTargetData, TargetInfo, + BuildContext, FileFlavor, FileType, RustDocFingerprint, RustcTargetData, RustcTargetDataBuilder, TargetInfo, }; use self::build_plan::BuildPlan; pub use self::compilation::{Compilation, Doctest, UnitOutput}; diff --git a/src/cargo/core/compiler/standard_lib.rs b/src/cargo/core/compiler/standard_lib.rs index c456c58d530..6fa531cf3d1 100644 --- a/src/cargo/core/compiler/standard_lib.rs +++ b/src/cargo/core/compiler/standard_lib.rs @@ -2,7 +2,7 @@ use crate::core::compiler::unit_dependencies::IsArtifact; use crate::core::compiler::UnitInterner; -use crate::core::compiler::{CompileKind, CompileMode, RustcTargetData, Unit}; +use crate::core::compiler::{CompileKind, CompileMode, Unit}; use crate::core::profiles::{Profiles, UnitFor}; use crate::core::resolver::features::{CliFeatures, FeaturesFor, ResolvedFeatures}; use crate::core::resolver::HasDevUnits; @@ -14,6 +14,7 @@ use std::collections::{HashMap, HashSet}; use std::path::PathBuf; use super::BuildConfig; +use super::build_context::RustcTargetDataBuilder; /// Parse the `-Zbuild-std` flag. pub fn parse_unstable_flag(value: Option<&str>) -> Vec { @@ -62,7 +63,7 @@ pub(crate) fn std_crates(config: &Config, units: Option<&[Unit]>) -> Option( ws: &Workspace<'cfg>, - target_data: &RustcTargetData<'cfg>, + target_data: &mut RustcTargetDataBuilder<'cfg>, build_config: &BuildConfig, crates: &[String], ) -> CargoResult<(PackageSet<'cfg>, Resolve, ResolvedFeatures)> { @@ -220,7 +221,7 @@ pub fn generate_std_roots( Ok(ret) } -fn detect_sysroot_src_path(target_data: &RustcTargetData<'_>) -> CargoResult { +fn detect_sysroot_src_path(target_data: &RustcTargetDataBuilder<'_>) -> CargoResult { if let Some(s) = target_data.config.get_env_os("__CARGO_TESTS_ONLY_SRC_ROOT") { return Ok(s.into()); } diff --git a/src/cargo/core/dependency.rs b/src/cargo/core/dependency.rs index 0b3aba8ada5..8ac620385d8 100644 --- a/src/cargo/core/dependency.rs +++ b/src/cargo/core/dependency.rs @@ -12,7 +12,6 @@ use crate::core::compiler::{CompileKind, CompileTarget}; use crate::core::{PackageId, SourceId, Summary}; use crate::util::errors::CargoResult; use crate::util::interning::InternedString; -use crate::util::toml::StringOrVec; use crate::util::OptVersionReq; /// Information about a dependency requested by a Cargo manifest. @@ -468,10 +467,7 @@ impl ser::Serialize for Artifact { SerializedArtifact { kinds: self.kinds(), lib: self.is_lib, - target: self.target.as_ref().map(|t| match t { - ArtifactTarget::BuildDependencyAssumeTarget => "target", - ArtifactTarget::Force(target) => target.rustc_target().as_str(), - }), + target: self.target.as_ref().map(ArtifactTarget::as_str), } .serialize(s) } @@ -479,14 +475,14 @@ impl ser::Serialize for Artifact { impl Artifact { pub(crate) fn parse( - artifacts: &StringOrVec, + artifacts: &[impl AsRef], is_lib: bool, target: Option<&str>, ) -> CargoResult { let kinds = ArtifactKind::validate( artifacts .iter() - .map(|s| ArtifactKind::parse(s)) + .map(|s| ArtifactKind::parse(s.as_ref())) .collect::, _>>()?, )?; Ok(Artifact { @@ -529,6 +525,13 @@ impl ArtifactTarget { }) } + pub fn as_str(&self) -> &str { + match self { + ArtifactTarget::BuildDependencyAssumeTarget => "target", + ArtifactTarget::Force(target) => target.rustc_target().as_str(), + } + } + pub fn to_compile_kind(&self) -> Option { self.to_compile_target().map(CompileKind::Target) } @@ -539,6 +542,7 @@ impl ArtifactTarget { ArtifactTarget::Force(target) => Some(*target), } } + pub(crate) fn to_resolved_compile_kind( &self, root_unit_compile_kind: CompileKind, @@ -575,20 +579,13 @@ impl ser::Serialize for ArtifactKind { where S: ser::Serializer, { - let out: Cow<'_, str> = match *self { - ArtifactKind::SelectedBinary(name) => format!("bin:{}", name.as_str()).into(), - _ => self.crate_type().into(), - }; - out.serialize(s) + self.as_str().serialize(s) } } impl fmt::Display for ArtifactKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(match self { - ArtifactKind::SelectedBinary(bin_name) => return write!(f, "bin:{bin_name}"), - _ => self.crate_type(), - }) + f.write_str(&self.as_str()) } } @@ -604,7 +601,14 @@ impl ArtifactKind { } } - fn parse(kind: &str) -> CargoResult { + pub fn as_str(&self) -> Cow<'static, str> { + match *self { + ArtifactKind::SelectedBinary(name) => format!("bin:{}", name.as_str()).into(), + _ => self.crate_type().into(), + } + } + + pub fn parse(kind: &str) -> CargoResult { Ok(match kind { "bin" => ArtifactKind::AllBinaries, "cdylib" => ArtifactKind::Cdylib, diff --git a/src/cargo/core/package.rs b/src/cargo/core/package.rs index 40ba9cdf894..bb8db51b720 100644 --- a/src/cargo/core/package.rs +++ b/src/cargo/core/package.rs @@ -17,7 +17,7 @@ use log::{debug, warn}; use semver::Version; use serde::Serialize; -use crate::core::compiler::{CompileKind, RustcTargetData}; +use crate::core::compiler::CompileKind; use crate::core::dependency::DepKind; use crate::core::resolver::features::ForceAllTargets; use crate::core::resolver::{HasDevUnits, Resolve}; @@ -32,6 +32,8 @@ use crate::util::network::retry::{Retry, RetryResult}; use crate::util::network::sleep::SleepTracker; use crate::util::{self, internal, Config, Progress, ProgressStyle}; +use super::compiler::build_context::RustcTargetDataBuilder; + pub const MANIFEST_PREAMBLE: &str = "\ # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # @@ -494,7 +496,7 @@ impl<'cfg> PackageSet<'cfg> { root_ids: &[PackageId], has_dev_units: HasDevUnits, requested_kinds: &[CompileKind], - target_data: &RustcTargetData<'cfg>, + target_data: &mut RustcTargetDataBuilder<'cfg>, force_all_targets: ForceAllTargets, ) -> CargoResult<()> { fn collect_used_deps( @@ -503,8 +505,9 @@ impl<'cfg> PackageSet<'cfg> { pkg_id: PackageId, has_dev_units: HasDevUnits, requested_kinds: &[CompileKind], - target_data: &RustcTargetData<'_>, + target_data: &mut RustcTargetDataBuilder<'_>, force_all_targets: ForceAllTargets, + additional_kinds: Vec, ) -> CargoResult<()> { if !used.insert(pkg_id) { return Ok(()); @@ -516,8 +519,21 @@ impl<'cfg> PackageSet<'cfg> { requested_kinds, target_data, force_all_targets, + &additional_kinds, ); - for (pkg_id, _dep) in filtered_deps { + + let deps = filtered_deps + .map(|(pkg_id, _dep, additional_kinds)| (pkg_id, additional_kinds)) + .collect::>(); + + for (pkg_id, additional_kinds) in deps { + // The dependency can specify additional targets through artifact dependencies. + // We need to run `rustc` to query the target specific configuration before we look + // at this dependency's dependencies. + for kind in &additional_kinds { + target_data.merge_compile_kind(*kind)?; + } + collect_used_deps( used, resolve, @@ -526,6 +542,7 @@ impl<'cfg> PackageSet<'cfg> { requested_kinds, target_data, force_all_targets, + additional_kinds, )?; } Ok(()) @@ -545,6 +562,7 @@ impl<'cfg> PackageSet<'cfg> { requested_kinds, target_data, force_all_targets, + Vec::new(), )?; } self.get_many(to_download.into_iter())?; @@ -560,7 +578,7 @@ impl<'cfg> PackageSet<'cfg> { root_ids: &[PackageId], has_dev_units: HasDevUnits, requested_kinds: &[CompileKind], - target_data: &RustcTargetData<'_>, + target_data: &RustcTargetDataBuilder<'_>, force_all_targets: ForceAllTargets, ) -> CargoResult<()> { let no_lib_pkgs: BTreeMap)>> = root_ids @@ -573,13 +591,14 @@ impl<'cfg> PackageSet<'cfg> { requested_kinds, target_data, force_all_targets, + &[], ) .collect(); let dep_pkgs_and_deps = dep_pkgs_to_deps .into_iter() - .filter(|(_id, deps)| deps.iter().any(|dep| dep.maybe_lib())) - .filter_map(|(dep_package_id, deps)| { + .filter(|(_id, deps, _additional_kinds)| deps.iter().any(|dep| dep.maybe_lib())) + .filter_map(|(dep_package_id, deps, _additional_kinds)| { self.get_one(dep_package_id).ok().and_then(|dep_pkg| { (!dep_pkg.targets().iter().any(|t| t.is_lib())).then(|| (dep_pkg, deps)) }) @@ -607,32 +626,54 @@ impl<'cfg> PackageSet<'cfg> { Ok(()) } + /// Returns an iterator over the dependencies of `pkg_id`, while filtering out target-specific + /// dependencies that are not enabled. Additionally returns a list of additional targets + /// specified through an artifact dependency. fn filter_deps<'a>( pkg_id: PackageId, resolve: &'a Resolve, has_dev_units: HasDevUnits, requested_kinds: &'a [CompileKind], - target_data: &'a RustcTargetData<'_>, + target_data: &'a RustcTargetDataBuilder<'_>, force_all_targets: ForceAllTargets, - ) -> impl Iterator)> + 'a { + additional_kinds: &'a [CompileKind], + ) -> impl Iterator, Vec)> + 'a { resolve .deps(pkg_id) - .filter(move |&(_id, deps)| { - deps.iter().any(|dep| { - if dep.kind() == DepKind::Development && has_dev_units == HasDevUnits::No { - return false; - } - if force_all_targets == ForceAllTargets::No { - let activated = requested_kinds - .iter() - .chain(Some(&CompileKind::Host)) - .any(|kind| target_data.dep_platform_activated(dep, *kind)); - if !activated { + .filter_map(move |(id, deps)| { + let mut deps_iter = deps + .iter() + .filter(|dep| { + if dep.kind() == DepKind::Development && has_dev_units == HasDevUnits::No { return false; } - } - true - }) + if force_all_targets == ForceAllTargets::No { + let activated = requested_kinds + .iter() + .chain(Some(&CompileKind::Host)) + .chain(additional_kinds) + .any(|kind| target_data.dep_platform_activated(dep, *kind)); + if !activated { + return false; + } + } + true + }) + .peekable(); + + if deps_iter.peek().is_some() { + Some(( + id, + deps, + deps_iter + .filter_map(|dep| dep.artifact()) + .filter_map(|artifact| artifact.target()) + .filter_map(|target| target.to_compile_kind()) + .collect(), + )) + } else { + None + } }) .into_iter() } diff --git a/src/cargo/ops/cargo_compile/mod.rs b/src/cargo/ops/cargo_compile/mod.rs index f53a9e93426..7340d397a98 100644 --- a/src/cargo/ops/cargo_compile/mod.rs +++ b/src/cargo/ops/cargo_compile/mod.rs @@ -237,7 +237,7 @@ pub fn create_bcx<'a, 'cfg>( } config.validate_term_config()?; - let target_data = RustcTargetData::new(ws, &build_config.requested_kinds)?; + let mut target_data = RustcTargetData::new(ws, &build_config.requested_kinds)?; let specs = spec.to_package_id_specs(ws)?; let has_dev_units = { @@ -263,7 +263,7 @@ pub fn create_bcx<'a, 'cfg>( }; let resolve = ops::resolve_ws_with_opts( ws, - &target_data, + &mut target_data, &build_config.requested_kinds, cli_features, &specs, @@ -279,7 +279,7 @@ pub fn create_bcx<'a, 'cfg>( let std_resolve_features = if let Some(crates) = &config.cli_unstable().build_std { let (std_package_set, std_resolve, std_features) = - standard_lib::resolve_std(ws, &target_data, &build_config, crates)?; + standard_lib::resolve_std(ws, &mut target_data, &build_config, crates)?; pkg_set.add_set(std_package_set); Some((std_resolve, std_features)) } else { @@ -535,7 +535,7 @@ pub fn create_bcx<'a, 'cfg>( build_config, profiles, extra_compiler_args, - target_data, + target_data.build(), units, unit_graph, scrape_units, diff --git a/src/cargo/ops/cargo_fetch.rs b/src/cargo/ops/cargo_fetch.rs index 273bce28492..6acdbddefb6 100644 --- a/src/cargo/ops/cargo_fetch.rs +++ b/src/cargo/ops/cargo_fetch.rs @@ -31,7 +31,7 @@ pub fn fetch<'a>( &options.targets, CompileMode::Build, )?; - let data = RustcTargetData::new(ws, &build_config.requested_kinds)?; + let mut data = RustcTargetData::new(ws, &build_config.requested_kinds)?; let mut fetched_packages = HashSet::new(); let mut deps_to_fetch = ws.members().map(|p| p.package_id()).collect::>(); let mut to_download = Vec::new(); @@ -70,7 +70,8 @@ pub fn fetch<'a>( // If -Zbuild-std was passed, download dependencies for the standard library. // We don't know ahead of time what jobs we'll be running, so tell `std_crates` that. if let Some(crates) = standard_lib::std_crates(config, None) { - let (std_package_set, _, _) = standard_lib::resolve_std(ws, &data, &build_config, &crates)?; + let (std_package_set, _, _) = + standard_lib::resolve_std(ws, &mut data, &build_config, &crates)?; packages.add_set(std_package_set); } diff --git a/src/cargo/ops/cargo_output_metadata.rs b/src/cargo/ops/cargo_output_metadata.rs index c0a63aa75a2..5ab1a419528 100644 --- a/src/cargo/ops/cargo_output_metadata.rs +++ b/src/cargo/ops/cargo_output_metadata.rs @@ -126,7 +126,7 @@ fn build_resolve_graph( // How should this work? let requested_kinds = CompileKind::from_requested_targets(ws.config(), &metadata_opts.filter_platforms)?; - let target_data = RustcTargetData::new(ws, &requested_kinds)?; + let mut target_data = RustcTargetData::new(ws, &requested_kinds)?; // Resolve entire workspace. let specs = Packages::All.to_package_id_specs(ws)?; let force_all = if metadata_opts.filter_platforms.is_empty() { @@ -139,7 +139,7 @@ fn build_resolve_graph( // as that is the behavior of download_accessible. let ws_resolve = ops::resolve_ws_with_opts( ws, - &target_data, + &mut target_data, &requested_kinds, &metadata_opts.cli_features, &specs, diff --git a/src/cargo/ops/fix.rs b/src/cargo/ops/fix.rs index be24967f8b9..080f76b3cd5 100644 --- a/src/cargo/ops/fix.rs +++ b/src/cargo/ops/fix.rs @@ -243,11 +243,12 @@ fn check_resolver_change(ws: &Workspace<'_>, opts: &FixOptions) -> CargoResult<( // 2018 without `resolver` set must be V1 assert_eq!(ws.resolve_behavior(), ResolveBehavior::V1); let specs = opts.compile_opts.spec.to_package_id_specs(ws)?; - let target_data = RustcTargetData::new(ws, &opts.compile_opts.build_config.requested_kinds)?; - let resolve_differences = |has_dev_units| -> CargoResult<(WorkspaceResolve<'_>, DiffMap)> { + let mut target_data = + RustcTargetData::new(ws, &opts.compile_opts.build_config.requested_kinds)?; + let mut resolve_differences = |has_dev_units| -> CargoResult<(WorkspaceResolve<'_>, DiffMap)> { let ws_resolve = ops::resolve_ws_with_opts( ws, - &target_data, + &mut target_data, &opts.compile_opts.build_config.requested_kinds, &opts.compile_opts.cli_features, &specs, @@ -258,7 +259,7 @@ fn check_resolver_change(ws: &Workspace<'_>, opts: &FixOptions) -> CargoResult<( let feature_opts = FeatureOpts::new_behavior(ResolveBehavior::V2, has_dev_units); let v2_features = FeatureResolver::resolve( ws, - &target_data, + &mut target_data, &ws_resolve.targeted_resolve, &ws_resolve.pkg_set, &opts.compile_opts.cli_features, diff --git a/src/cargo/ops/registry.rs b/src/cargo/ops/registry.rs index a8a2e72d744..5d9956d8464 100644 --- a/src/cargo/ops/registry.rs +++ b/src/cargo/ops/registry.rs @@ -328,6 +328,17 @@ fn transmit( .to_string(), registry: dep_registry, explicit_name_in_toml: dep.explicit_name_in_toml().map(|s| s.to_string()), + artifact: dep.artifact().map(|artifact| { + artifact + .kinds() + .iter() + .map(|x| x.as_str().into_owned()) + .collect() + }), + bindep_target: dep.artifact().and_then(|artifact| { + artifact.target().map(|target| target.as_str().to_owned()) + }), + lib: dep.artifact().map_or(false, |artifact| artifact.is_lib()), }) }) .collect::>>()?; diff --git a/src/cargo/ops/resolve.rs b/src/cargo/ops/resolve.rs index ea5eded4aa2..bacdf9be6c3 100644 --- a/src/cargo/ops/resolve.rs +++ b/src/cargo/ops/resolve.rs @@ -55,7 +55,8 @@ //! [source implementations]: crate::sources //! [`Downloads`]: crate::core::package::Downloads -use crate::core::compiler::{CompileKind, RustcTargetData}; +use crate::core::compiler::build_context::RustcTargetDataBuilder; +use crate::core::compiler::CompileKind; use crate::core::registry::{LockedPatchDependency, PackageRegistry}; use crate::core::resolver::features::{ CliFeatures, FeatureOpts, FeatureResolver, ForceAllTargets, RequestedFeatures, ResolvedFeatures, @@ -64,7 +65,7 @@ use crate::core::resolver::{ self, HasDevUnits, Resolve, ResolveOpts, ResolveVersion, VersionPreferences, }; use crate::core::summary::Summary; -use crate::core::Feature; +use crate::core::{Feature, Package}; use crate::core::{GitReference, PackageId, PackageIdSpec, PackageSet, SourceId, Workspace}; use crate::ops; use crate::sources::PathSource; @@ -124,7 +125,7 @@ pub fn resolve_ws<'a>(ws: &Workspace<'a>) -> CargoResult<(PackageSet<'a>, Resolv /// members. In this case, `opts.all_features` must be `true`. pub fn resolve_ws_with_opts<'cfg>( ws: &Workspace<'cfg>, - target_data: &RustcTargetData<'cfg>, + target_data: &mut RustcTargetDataBuilder<'cfg>, requested_targets: &[CompileKind], cli_features: &CliFeatures, specs: &[PackageIdSpec], @@ -202,6 +203,28 @@ pub fn resolve_ws_with_opts<'cfg>( force_all_targets, )?; + // After we download all the packages we need, we need to change target_data such that any + // additionally enabled targets are registered, since they could have per-pkg-target or + // artifact dependencies. + for pkg in pkg_set.packages() { + fn artifact_targets(package: &Package) -> impl Iterator + '_ { + package + .manifest() + .dependencies() + .iter() + .filter_map(|d| d.artifact()?.target()?.to_compile_kind()) + } + let kinds = pkg + .manifest() + .default_kind() + .into_iter() + .chain(pkg.manifest().forced_kind()) + .chain(artifact_targets(pkg)); + for kind in kinds { + target_data.merge_compile_kind(kind)?; + } + } + let feature_opts = FeatureOpts::new(ws, has_dev_units, force_all_targets)?; let resolved_features = FeatureResolver::resolve( ws, diff --git a/src/cargo/ops/tree/mod.rs b/src/cargo/ops/tree/mod.rs index f397b95af6f..4a7048b628a 100644 --- a/src/cargo/ops/tree/mod.rs +++ b/src/cargo/ops/tree/mod.rs @@ -135,7 +135,7 @@ pub fn build_and_print(ws: &Workspace<'_>, opts: &TreeOptions) -> CargoResult<() // TODO: Target::All is broken with -Zfeatures=itarget. To handle that properly, // `FeatureResolver` will need to be taught what "all" means. let requested_kinds = CompileKind::from_requested_targets(ws.config(), &requested_targets)?; - let target_data = RustcTargetData::new(ws, &requested_kinds)?; + let mut target_data = RustcTargetData::new(ws, &requested_kinds)?; let specs = opts.packages.to_package_id_specs(ws)?; let has_dev = if opts .edge_kinds @@ -152,7 +152,7 @@ pub fn build_and_print(ws: &Workspace<'_>, opts: &TreeOptions) -> CargoResult<() }; let ws_resolve = ops::resolve_ws_with_opts( ws, - &target_data, + &mut target_data, &requested_kinds, &opts.cli_features, &specs, diff --git a/src/cargo/sources/registry/index.rs b/src/cargo/sources/registry/index.rs index d857a053ed2..8f319b84412 100644 --- a/src/cargo/sources/registry/index.rs +++ b/src/cargo/sources/registry/index.rs @@ -206,6 +206,8 @@ impl<'cfg> RegistryIndex<'cfg> { where 'a: 'b, { + let bindeps = self.config.cli_unstable().bindeps; + let source_id = self.source_id; let config = self.config; @@ -237,6 +239,9 @@ impl<'cfg> RegistryIndex<'cfg> { }, ) .filter(move |is| { + if is.v == 3 && bindeps { + return true; + } if is.v > INDEX_V_MAX { debug!( "unsupported schema version {} ({} {})", @@ -629,7 +634,7 @@ impl<'a> SummariesCache<'a> { .get(..4) .ok_or_else(|| anyhow::anyhow!("cache expected 4 bytes for index version"))?; let index_v = u32::from_le_bytes(index_v_bytes.try_into().unwrap()); - if index_v != INDEX_V_MAX { + if index_v != INDEX_V_MAX && index_v != 3 { bail!( "index format version {} doesn't match the version I know ({})", index_v, diff --git a/src/cargo/sources/registry/mod.rs b/src/cargo/sources/registry/mod.rs index 4143ac16371..a3feaaead73 100644 --- a/src/cargo/sources/registry/mod.rs +++ b/src/cargo/sources/registry/mod.rs @@ -174,7 +174,7 @@ use semver::Version; use serde::Deserialize; use tar::Archive; -use crate::core::dependency::{DepKind, Dependency}; +use crate::core::dependency::{Artifact, DepKind, Dependency}; use crate::core::source::MaybePackage; use crate::core::{Package, PackageId, QueryKind, Source, SourceId, Summary}; use crate::sources::PathSource; @@ -363,6 +363,10 @@ struct RegistryDependency<'a> { registry: Option>, package: Option, public: Option, + artifact: Option>>, + bindep_target: Option>, + #[serde(default)] + lib: bool, } impl<'a> RegistryDependency<'a> { @@ -379,6 +383,9 @@ impl<'a> RegistryDependency<'a> { registry, package, public, + artifact, + bindep_target, + lib, } = self; let id = if let Some(registry) = ®istry { @@ -418,6 +425,11 @@ impl<'a> RegistryDependency<'a> { dep.set_registry_id(id); } + if let Some(artifacts) = artifact { + let artifact = Artifact::parse(&artifacts, lib, bindep_target.as_deref())?; + dep.set_artifact(artifact); + } + dep.set_optional(optional) .set_default_features(default_features) .set_features(features) diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index 2c213b7f5fa..94dd61c0637 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -3363,7 +3363,7 @@ impl DetailedTomlDependency

{ self.target.as_deref(), ) { if cx.config.cli_unstable().bindeps { - let artifact = Artifact::parse(artifact, is_lib, target)?; + let artifact = Artifact::parse(&artifact.0, is_lib, target)?; if dep.kind() != DepKind::Build && artifact.target() == Some(ArtifactTarget::BuildDependencyAssumeTarget) { diff --git a/tests/testsuite/artifact_dep.rs b/tests/testsuite/artifact_dep.rs index 08e413bf511..20862875876 100644 --- a/tests/testsuite/artifact_dep.rs +++ b/tests/testsuite/artifact_dep.rs @@ -1926,15 +1926,25 @@ You may press ctrl-c [..] "badges": {}, "categories": [], "deps": [{ + "artifact": [ + "bin" + ], "default_features": true, "features": [], "kind": "normal", + "lib": true, "name": "bar", "optional": false, "target": null, "version_req": "^1.0" }, { + "artifact": [ + "bin:a", + "cdylib", + "staticlib" + ], + "bindep_target": "target", "default_features": true, "features": [], "kind": "build", @@ -2894,8 +2904,11 @@ fn check_transitive_artifact_dependency_with_different_target() { p.cargo("check -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_stderr_contains( - "error: could not find specification for target `custom-target`.\n \ - Dependency `baz v0.0.0 [..]` requires to build for target `custom-target`.", + "error: failed to run `rustc` to learn about target-specific information", + ) + .with_stderr_contains( + "[..] error: Error loading target specification: Could not find specification for \ + target \"custom-target\". [..]", ) .with_status(101) .run();