diff --git a/Cargo.lock b/Cargo.lock index 4a39ee141e6..625fa028e6d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -588,7 +588,7 @@ dependencies = [ [[package]] name = "crates-io" -version = "0.38.1" +version = "0.39.0" dependencies = [ "curl", "percent-encoding", diff --git a/Cargo.toml b/Cargo.toml index 2fb58d71eea..9f46bd019ef 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,7 @@ cargo-util = { version = "0.2.6", path = "crates/cargo-util" } cargo_metadata = "0.14.0" clap = "4.3.23" core-foundation = { version = "0.9.3", features = ["mac_os_10_7_support"] } -crates-io = { version = "0.38.0", path = "crates/crates-io" } +crates-io = { version = "0.39.0", path = "crates/crates-io" } criterion = { version = "0.5.1", features = ["html_reports"] } curl = "0.4.44" curl-sys = "0.4.65" diff --git a/benches/benchsuite/benches/resolve.rs b/benches/benchsuite/benches/resolve.rs index d03cd620e27..e235441e1e2 100644 --- a/benches/benchsuite/benches/resolve.rs +++ b/benches/benchsuite/benches/resolve.rs @@ -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/cargo-test-support/src/registry.rs b/crates/cargo-test-support/src/registry.rs index 27c31965657..8ab44f4ad5f 100644 --- a/crates/cargo-test-support/src/registry.rs +++ b/crates/cargo-test-support/src/registry.rs @@ -549,7 +549,9 @@ pub struct Dependency { name: String, vers: String, kind: String, - artifact: Option<(String, Option)>, + artifact: Option, + bindep_target: Option, + lib: bool, target: Option, features: Vec, registry: Option, @@ -1409,13 +1411,20 @@ impl Package { (true, Some("alternative")) => None, _ => panic!("registry_dep currently only supports `alternative`"), }; + let artifact = if let Some(artifact) = &dep.artifact { + serde_json::json!([artifact]) + } else { + serde_json::json!(null) + }; serde_json::json!({ "name": dep.name, "req": dep.vers, "features": dep.features, "default_features": true, "target": dep.target, - "artifact": dep.artifact, + "artifact": artifact, + "bindep_target": dep.bindep_target, + "lib": dep.lib, "optional": dep.optional, "kind": dep.kind, "registry": registry_url, @@ -1536,11 +1545,14 @@ impl Package { "#, target, kind, dep.name, dep.vers )); - if let Some((artifact, target)) = &dep.artifact { + if let Some(artifact) = &dep.artifact { manifest.push_str(&format!("artifact = \"{}\"\n", artifact)); - if let Some(target) = &target { - manifest.push_str(&format!("target = \"{}\"\n", target)) - } + } + if let Some(target) = &dep.bindep_target { + manifest.push_str(&format!("target = \"{}\"\n", target)); + } + if dep.lib { + manifest.push_str("lib = true\n"); } if let Some(registry) = &dep.registry { assert_eq!(registry, "alternative"); @@ -1617,6 +1629,8 @@ impl Dependency { vers: vers.to_string(), kind: "normal".to_string(), artifact: None, + bindep_target: None, + lib: false, target: None, features: Vec::new(), package: None, @@ -1646,7 +1660,8 @@ impl Dependency { /// Change the artifact to be of the given kind, like "bin", or "staticlib", /// along with a specific target triple if provided. pub fn artifact(&mut self, kind: &str, target: Option) -> &mut Self { - self.artifact = Some((kind.to_string(), target)); + self.artifact = Some(kind.to_string()); + self.bindep_target = target; self } diff --git a/crates/crates-io/Cargo.toml b/crates/crates-io/Cargo.toml index c9ed50a1ab2..d06dacdfa43 100644 --- a/crates/crates-io/Cargo.toml +++ b/crates/crates-io/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "crates-io" -version = "0.38.1" +version = "0.39.0" rust-version.workspace = true edition.workspace = true license.workspace = true diff --git a/crates/crates-io/lib.rs b/crates/crates-io/lib.rs index 6ce39cefd4b..344e6e5c33f 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 == false } #[derive(Deserialize)] diff --git a/src/cargo/core/compiler/build_context/target_info.rs b/src/cargo/core/compiler/build_context/target_info.rs index 754adcf3cd0..7c02d9009ef 100644 --- a/src/cargo/core/compiler/build_context/target_info.rs +++ b/src/cargo/core/compiler/build_context/target_info.rs @@ -948,7 +948,7 @@ impl<'cfg> RustcTargetData<'cfg> { } /// 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<()> { + pub 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 diff --git a/src/cargo/core/compiler/standard_lib.rs b/src/cargo/core/compiler/standard_lib.rs index c456c58d530..b76c395b87e 100644 --- a/src/cargo/core/compiler/standard_lib.rs +++ b/src/cargo/core/compiler/standard_lib.rs @@ -62,7 +62,7 @@ pub(crate) fn std_crates(config: &Config, units: Option<&[Unit]>) -> Option( ws: &Workspace<'cfg>, - target_data: &RustcTargetData<'cfg>, + target_data: &mut RustcTargetData<'cfg>, build_config: &BuildConfig, crates: &[String], ) -> CargoResult<(PackageSet<'cfg>, Resolve, ResolvedFeatures)> { diff --git a/src/cargo/core/dependency.rs b/src/cargo/core/dependency.rs index c8fee6262ec..2a7255c7f22 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/resolver/features.rs b/src/cargo/core/resolver/features.rs index 4518f9fe7cf..b3ece7d05ab 100644 --- a/src/cargo/core/resolver/features.rs +++ b/src/cargo/core/resolver/features.rs @@ -45,7 +45,8 @@ use crate::core::resolver::{Resolve, ResolveBehavior}; use crate::core::{FeatureValue, PackageId, PackageIdSpec, PackageSet, Workspace}; use crate::util::interning::InternedString; use crate::util::CargoResult; -use anyhow::bail; +use anyhow::{bail, Context}; +use itertools::Itertools; use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use std::rc::Rc; @@ -408,7 +409,7 @@ pub type DiffMap = BTreeMap>; /// [module-level documentation]: crate::core::resolver::features pub struct FeatureResolver<'a, 'cfg> { ws: &'a Workspace<'cfg>, - target_data: &'a RustcTargetData<'cfg>, + target_data: &'a mut RustcTargetData<'cfg>, /// The platforms to build for, requested by the user. requested_targets: &'a [CompileKind], resolve: &'a Resolve, @@ -445,7 +446,7 @@ impl<'a, 'cfg> FeatureResolver<'a, 'cfg> { /// with the result. pub fn resolve( ws: &Workspace<'cfg>, - target_data: &RustcTargetData<'cfg>, + target_data: &'a mut RustcTargetData<'cfg>, resolve: &Resolve, package_set: &'a PackageSet<'cfg>, cli_features: &CliFeatures, @@ -544,7 +545,7 @@ impl<'a, 'cfg> FeatureResolver<'a, 'cfg> { // features that enable other features. return Ok(()); } - for (dep_pkg_id, deps) in self.deps(pkg_id, fk) { + for (dep_pkg_id, deps) in self.deps(pkg_id, fk)? { for (dep, dep_fk) in deps { if dep.is_optional() { // Optional dependencies are enabled in `activate_fv` when @@ -647,7 +648,7 @@ impl<'a, 'cfg> FeatureResolver<'a, 'cfg> { .deferred_weak_dependencies .remove(&(pkg_id, fk, dep_name)); // Activate the optional dep. - for (dep_pkg_id, deps) in self.deps(pkg_id, fk) { + for (dep_pkg_id, deps) in self.deps(pkg_id, fk)? { for (dep, dep_fk) in deps { if dep.name_in_toml() != dep_name { continue; @@ -681,7 +682,7 @@ impl<'a, 'cfg> FeatureResolver<'a, 'cfg> { dep_feature: InternedString, weak: bool, ) -> CargoResult<()> { - for (dep_pkg_id, deps) in self.deps(pkg_id, fk) { + for (dep_pkg_id, deps) in self.deps(pkg_id, fk)? { for (dep, dep_fk) in deps { if dep.name_in_toml() != dep_name { continue; @@ -777,12 +778,17 @@ impl<'a, 'cfg> FeatureResolver<'a, 'cfg> { /// Returns the dependencies for a package, filtering out inactive targets. fn deps( - &self, + &mut self, pkg_id: PackageId, fk: FeaturesFor, - ) -> Vec<(PackageId, Vec<(&'a Dependency, FeaturesFor)>)> { + ) -> CargoResult)>> { // Helper for determining if a platform is activated. - let platform_activated = |dep: &Dependency| -> bool { + fn platform_activated( + dep: &Dependency, + fk: FeaturesFor, + target_data: &RustcTargetData<'_>, + requested_targets: &[CompileKind], + ) -> bool { // We always count platforms as activated if the target stems from an artifact // dependency's target specification. This triggers in conjunction with // `[target.'cfg(ā€¦)'.dependencies]` manifest sections. @@ -791,18 +797,17 @@ impl<'a, 'cfg> FeatureResolver<'a, 'cfg> { // We always care about build-dependencies, and they are always // Host. If we are computing dependencies "for a build script", // even normal dependencies are host-only. - self.target_data - .dep_platform_activated(dep, CompileKind::Host) + target_data.dep_platform_activated(dep, CompileKind::Host) } - (_, FeaturesFor::NormalOrDev) => self - .requested_targets + (_, FeaturesFor::NormalOrDev) => requested_targets .iter() - .any(|kind| self.target_data.dep_platform_activated(dep, *kind)), - (_, FeaturesFor::ArtifactDep(target)) => self - .target_data - .dep_platform_activated(dep, CompileKind::Target(target)), + .any(|kind| target_data.dep_platform_activated(dep, *kind)), + (_, FeaturesFor::ArtifactDep(target)) => { + target_data.dep_platform_activated(dep, CompileKind::Target(target)) + } } - }; + } + self.resolve .deps(pkg_id) .map(|(dep_id, deps)| { @@ -811,7 +816,12 @@ impl<'a, 'cfg> FeatureResolver<'a, 'cfg> { .filter(|dep| { if dep.platform().is_some() && self.opts.ignore_inactive_targets - && !platform_activated(dep) + && !platform_activated( + dep, + fk, + self.target_data, + self.requested_targets, + ) { return false; } @@ -820,7 +830,9 @@ impl<'a, 'cfg> FeatureResolver<'a, 'cfg> { } true }) - .flat_map(|dep| { + .collect_vec() // collect because the next closure mutably borrows `self.target_data` + .into_iter() + .map(|dep| { // Each `dep`endency can be built for multiple targets. For one, it // may be a library target which is built as initially configured // by `fk`. If it appears as build dependency, it must be built @@ -852,28 +864,52 @@ impl<'a, 'cfg> FeatureResolver<'a, 'cfg> { }; // `artifact_target_keys` are produced to fulfil the needs of artifacts that have a target specification. - let artifact_target_keys = dep.artifact().map(|artifact| { - ( - artifact.is_lib(), - artifact.target().map(|target| match target { - ArtifactTarget::Force(target) => { - vec![FeaturesFor::ArtifactDep(target)] - } - ArtifactTarget::BuildDependencyAssumeTarget => self - .requested_targets - .iter() - .map(|kind| match kind { - CompileKind::Host => { - let host_triple = self.target_data.rustc.host; - CompileTarget::new(&host_triple).unwrap() - } - CompileKind::Target(target) => *target, + let artifact_target_keys = dep + .artifact() + .map(|artifact| { + let host_triple = self.target_data.rustc.host; + // not all targets may be queried before resolution since artifact dependencies + // and per-pkg-targets are not immediately known. + let mut activate_target = |target| { + let name = dep.name_in_toml(); + self.target_data + .merge_compile_kind(CompileKind::Target(target)) + .with_context(|| format!("failed to determine target information for target `{target}`.\n \ + Artifact dependency `{name}` in package `{pkg_id}` requires building for `{target}`", target = target.rustc_target())) + }; + CargoResult::Ok(( + artifact.is_lib(), + artifact + .target() + .map(|target| { + CargoResult::Ok(match target { + ArtifactTarget::Force(target) => { + activate_target(target)?; + vec![FeaturesFor::ArtifactDep(target)] + } + // FIXME: this needs to interact with the `default-target` and `forced-target` values + // of the dependency + ArtifactTarget::BuildDependencyAssumeTarget => self + .requested_targets + .iter() + .map(|kind| match kind { + CompileKind::Host => { + CompileTarget::new(&host_triple) + .unwrap() + } + CompileKind::Target(target) => *target, + }) + .map(|target| { + activate_target(target)?; + Ok(FeaturesFor::ArtifactDep(target)) + }) + .collect::>()?, + }) }) - .map(FeaturesFor::ArtifactDep) - .collect(), - }), - ) - }); + .transpose()?, + )) + }) + .transpose()?; let dep_fks = match artifact_target_keys { // The artifact is also a library and does specify custom @@ -893,12 +929,13 @@ impl<'a, 'cfg> FeatureResolver<'a, 'cfg> { // Use the standard feature key without any alteration. Some((_, None)) | None => vec![lib_fk], }; - dep_fks.into_iter().map(move |dep_fk| (dep, dep_fk)) + Ok(dep_fks.into_iter().map(move |dep_fk| (dep, dep_fk))) }) - .collect::>(); - (dep_id, deps) + .flatten_ok() + .collect::>>()?; + Ok((dep_id, deps)) }) - .filter(|(_id, deps)| !deps.is_empty()) + .filter(|res| res.as_ref().map_or(true, |(_id, deps)| !deps.is_empty())) .collect() } diff --git a/src/cargo/ops/cargo_compile/mod.rs b/src/cargo/ops/cargo_compile/mod.rs index 1247ceda700..6cf385b0a41 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 { 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 0e678d61c6b..cd884ae7c12 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/publish.rs b/src/cargo/ops/registry/publish.rs index 40ca9fd16f5..c5539825d3c 100644 --- a/src/cargo/ops/registry/publish.rs +++ b/src/cargo/ops/registry/publish.rs @@ -353,6 +353,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 6246311a5c5..f7251c46f8d 100644 --- a/src/cargo/ops/resolve.rs +++ b/src/cargo/ops/resolve.rs @@ -124,7 +124,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 RustcTargetData<'cfg>, requested_targets: &[CompileKind], cli_features: &CliFeatures, specs: &[PackageIdSpec], 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 05bfe71af05..6424af3140c 100644 --- a/src/cargo/sources/registry/index.rs +++ b/src/cargo/sources/registry/index.rs @@ -85,7 +85,7 @@ //! [`RemoteRegistry`]: super::remote::RemoteRegistry //! [`Dependency`]: crate::core::Dependency -use crate::core::dependency::DepKind; +use crate::core::dependency::{Artifact, DepKind}; use crate::core::Dependency; use crate::core::{PackageId, SourceId, Summary}; use crate::sources::registry::{LoadResponse, RegistryData}; @@ -313,6 +313,9 @@ pub struct IndexPackage<'a> { /// /// Version `2` schema adds the `features2` field. /// + /// Version `3` schema adds `artifact`, `bindep_targes`, and `lib` for + /// artifact dependencies support. + /// /// This provides a method to safely introduce changes to index entries /// and allow older versions of cargo to ignore newer entries it doesn't /// understand. This is honored as of 1.51, so unfortunately older @@ -356,6 +359,10 @@ struct RegistryDependency<'a> { /// /// [RFC 1977]: https://rust-lang.github.io/rfcs/1977-public-private-dependencies.html public: Option, + artifact: Option>>, + bindep_target: Option>, + #[serde(default)] + lib: bool, } impl<'cfg> RegistryIndex<'cfg> { @@ -409,6 +416,8 @@ impl<'cfg> RegistryIndex<'cfg> { where 'a: 'b, { + let bindeps = self.config.cli_unstable().bindeps; + let source_id = self.source_id; // First up parse what summaries we have available. @@ -434,7 +443,9 @@ impl<'cfg> RegistryIndex<'cfg> { } }) .filter(move |is| { - if is.v > INDEX_V_MAX { + if is.v == 3 && bindeps { + true + } else if is.v > INDEX_V_MAX { debug!( "unsupported schema version {} ({} {})", is.v, @@ -947,6 +958,9 @@ impl<'a> RegistryDependency<'a> { registry, package, public, + artifact, + bindep_target, + lib, } = self; let id = if let Some(registry) = ®istry { @@ -986,6 +1000,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 2f88478a059..7037ff429b4 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -3287,7 +3287,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..64aa9d8afbc 100644 --- a/tests/testsuite/artifact_dep.rs +++ b/tests/testsuite/artifact_dep.rs @@ -1445,13 +1445,7 @@ foo v0.0.0 ([CWD]) ) .run(); } - -// TODO: Fix this potentially by reverting 887562bfeb8c540594d7d08e6e9a4ab7eb255865 which adds artifact information to the registry -// followed by 0ff93733626f7cbecaf9dce9ab62b4ced0be088e which picks it up. -// For reference, see comments by ehuss https://github.com/rust-lang/cargo/pull/9992#discussion_r801086315 and -// joshtriplett https://github.com/rust-lang/cargo/pull/9992#issuecomment-1033394197 . #[cargo_test] -#[ignore = "broken, need artifact info in index"] fn targets_are_picked_up_from_non_workspace_artifact_deps() { if cross_compile::disabled() { return; @@ -1464,6 +1458,7 @@ fn targets_are_picked_up_from_non_workspace_artifact_deps() { let mut dep = registry::Dependency::new("artifact", "1.0.0"); Package::new("uses-artifact", "1.0.0") + .schema_version(3) .file( "src/lib.rs", r#"pub fn uses_artifact() { let _b = include_bytes!(env!("CARGO_BIN_FILE_ARTIFACT")); }"#, @@ -1495,6 +1490,127 @@ fn targets_are_picked_up_from_non_workspace_artifact_deps() { .run(); } +#[cargo_test] +fn index_version_filtering() { + if cross_compile::disabled() { + return; + } + let target = cross_compile::alternate(); + + Package::new("artifact", "1.0.0") + .file("src/main.rs", r#"fn main() {}"#) + .file("src/lib.rs", r#"pub fn lib() {}"#) + .publish(); + + let mut dep = registry::Dependency::new("artifact", "1.0.0"); + + Package::new("bar", "1.0.0").publish(); + Package::new("bar", "1.0.1") + .schema_version(3) + .add_dep(dep.artifact("bin", Some(target.to_string()))) + .publish(); + + // Verify that without `-Zbindeps` that it does not use 1.0.1. + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + + [dependencies] + bar = "1.0" + "#, + ) + .file("src/lib.rs", "") + .build(); + + p.cargo("tree") + .with_stdout("foo v0.1.0 [..]\nā””ā”€ā”€ bar v1.0.0") + .run(); + + // And with -Zbindeps it can use 1.0.1. + p.cargo("update -Zbindeps") + .masquerade_as_nightly_cargo(&["bindeps"]) + .with_stderr( + "\ +[UPDATING] [..] +[ADDING] artifact v1.0.0 +[UPDATING] bar v1.0.0 -> v1.0.1", + ) + .run(); + + // And without -Zbindeps, now that 1.0.1 is in Cargo.lock, it should fail. + p.cargo("check") + .with_status(101) + .with_stderr( + "\ +[UPDATING] [..] +error: failed to select a version for the requirement `bar = \"^1.0\"` (locked to 1.0.1) +candidate versions found which didn't match: 1.0.0 +location searched: [..] +required by package `foo v0.1.0 [..]` +perhaps a crate was updated and forgotten to be re-vendored?", + ) + .run(); +} + +// FIXME: `download_accessible` should work properly for artifact dependencies +#[cargo_test] +#[ignore = "broken, needs download_accessible fix"] +fn proc_macro_in_artifact_dep() { + // Forcing FeatureResolver to check a proc-macro for a dependency behind a + // target dependency. + if cross_compile::disabled() { + return; + } + Package::new("pm", "1.0.0") + .file("src/lib.rs", "") + .file( + "Cargo.toml", + r#" + [package] + name = "pm" + version = "1.0.0" + + [lib] + proc-macro = true + + "#, + ) + .publish(); + let alternate = cross_compile::alternate(); + Package::new("bin-uses-pm", "1.0.0") + .target_dep("pm", "1.0", alternate) + .file("src/main.rs", "fn main() {}") + .publish(); + // Simulate a network error downloading the proc-macro. + std::fs::remove_file(cargo_test_support::paths::root().join("dl/pm/1.0.0/download")).unwrap(); + let p = project() + .file( + "Cargo.toml", + &format!( + r#" + [package] + name = "foo" + version = "0.1.0" + edition = "2021" + + [dependencies] + bin-uses-pm = {{ version = "1.0", artifact = "bin", target = "{alternate}"}} + "# + ), + ) + .file("src/lib.rs", "") + .build(); + + p.cargo("check -Z bindeps") + .masquerade_as_nightly_cargo(&["bindeps"]) + .with_stderr("") + .run(); +} + #[cargo_test] fn allow_dep_renames_with_multiple_versions() { Package::new("bar", "1.0.0") @@ -1926,15 +2042,23 @@ 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 +3018,8 @@ 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 determine target information for target `custom-target`.\n \ + Artifact dependency `baz` in package `bar v0.0.0 [..]` requires building for `custom-target`", ) .with_status(101) .run();