From d23edf66ca16f746da8420f1caced6ef17613901 Mon Sep 17 00:00:00 2001 From: Serhii Plyhun Date: Thu, 8 Nov 2018 15:24:40 +0100 Subject: [PATCH 1/8] An attempt to implement #1197 --- src/cargo/core/compiler/build_context/mod.rs | 20 +- src/cargo/core/compiler/context/mod.rs | 6 +- .../compiler/context/unit_dependencies.rs | 15 +- src/cargo/core/compiler/custom_build.rs | 2 +- src/cargo/core/compiler/mod.rs | 12 +- src/cargo/core/dependency.rs | 8 +- src/cargo/core/resolver/context.rs | 89 ++++---- src/cargo/core/resolver/mod.rs | 2 +- src/cargo/core/resolver/resolve.rs | 21 +- src/cargo/core/summary.rs | 16 +- src/cargo/ops/cargo_compile.rs | 4 +- src/cargo/ops/cargo_output_metadata.rs | 2 +- src/cargo/ops/registry.rs | 2 +- src/cargo/sources/registry/index.rs | 3 +- src/cargo/util/cfg.rs | 6 + src/cargo/util/mod.rs | 2 +- src/cargo/util/toml/mod.rs | 33 ++- tests/testsuite/cfg_features.rs | 192 ++++++++++++++++++ tests/testsuite/main.rs | 1 + tests/testsuite/support/resolver.rs | 8 +- 20 files changed, 342 insertions(+), 102 deletions(-) create mode 100644 tests/testsuite/cfg_features.rs diff --git a/src/cargo/core/compiler/build_context/mod.rs b/src/cargo/core/compiler/build_context/mod.rs index 358751c7f07..4235b28399f 100644 --- a/src/cargo/core/compiler/build_context/mod.rs +++ b/src/cargo/core/compiler/build_context/mod.rs @@ -7,7 +7,7 @@ use core::profiles::Profiles; use core::{Dependency, Workspace}; use core::{PackageId, PackageSet, Resolve}; use util::errors::CargoResult; -use util::{profile, Cfg, CfgExpr, Config, Rustc}; +use util::{profile, Cfg, CfgExpr, Config, Rustc, Platform}; use super::{BuildConfig, BuildOutput, Kind, Unit}; @@ -90,13 +90,11 @@ impl<'a, 'cfg> BuildContext<'a, 'cfg> { pub fn extern_crate_name(&self, unit: &Unit<'a>, dep: &Unit<'a>) -> CargoResult { self.resolve.extern_crate_name(unit.pkg.package_id(), dep.pkg.package_id(), dep.target) } - - /// Whether a dependency should be compiled for the host or target platform, + + /// Whether a given platform matches the host or target platform, /// specified by `Kind`. - pub fn dep_platform_activated(&self, dep: &Dependency, kind: Kind) -> bool { - // If this dependency is only available for certain platforms, - // make sure we're only enabling it for that platform. - let platform = match dep.platform() { + pub fn platform_activated(&self, platform: Option<&Platform>, kind: Kind) -> bool { + let platform = match platform { Some(p) => p, None => return true, }; @@ -107,6 +105,14 @@ impl<'a, 'cfg> BuildContext<'a, 'cfg> { platform.matches(name, info.cfg()) } + /// Whether a dependency should be compiled for the host or target platform, + /// specified by `Kind`. + pub fn dep_platform_activated(&self, dep: &Dependency, kind: Kind) -> bool { + // If this dependency is only available for certain platforms, + // make sure we're only enabling it for that platform. + self.platform_activated(dep.platform(), kind) + } + /// Get the user-specified linker for a particular host or target pub fn linker(&self, kind: Kind) -> Option<&Path> { self.target_config(kind).linker.as_ref().map(|s| s.as_ref()) diff --git a/src/cargo/core/compiler/context/mod.rs b/src/cargo/core/compiler/context/mod.rs index a5b6231e86a..dffc33a5283 100644 --- a/src/cargo/core/compiler/context/mod.rs +++ b/src/cargo/core/compiler/context/mod.rs @@ -268,7 +268,8 @@ impl<'a, 'cfg> Context<'a, 'cfg> { }); } - let feats = self.bcx.resolve.features(unit.pkg.package_id()); + let bcx = self.bcx; + let feats = bcx.resolve.features(unit.pkg.package_id()); if !feats.is_empty() { self.compilation .cfgs @@ -276,7 +277,8 @@ impl<'a, 'cfg> Context<'a, 'cfg> { .or_insert_with(|| { feats .iter() - .map(|feat| format!("feature=\"{}\"", feat)) + .filter(|feat| bcx.platform_activated(feat.1.as_ref(), unit.kind)) + .map(|feat| format!("feature=\"{}\"", feat.0)) .collect() }); } diff --git a/src/cargo/core/compiler/context/unit_dependencies.rs b/src/cargo/core/compiler/context/unit_dependencies.rs index c7050e348ec..262f941b8d1 100644 --- a/src/cargo/core/compiler/context/unit_dependencies.rs +++ b/src/cargo/core/compiler/context/unit_dependencies.rs @@ -150,10 +150,15 @@ fn compute_deps<'a, 'cfg, 'tmp>( // If the dependency is optional, then we're only activating it // if the corresponding feature was activated - if dep.is_optional() && - !bcx.resolve.features(id).contains(&*dep.name_in_toml()) - { - return false; + if dep.is_optional() { + // Same for features this dependency is referenced + if let Some(platform) = bcx.resolve.features(id).get(&*dep.name_in_toml()) { + if !bcx.platform_activated(platform.as_ref(), unit.kind) { + return false; + } + } else { + return false; + } } // If we've gotten past all that, then this dependency is @@ -216,7 +221,7 @@ fn compute_deps<'a, 'cfg, 'tmp>( t.is_bin() && // Skip binaries with required features that have not been selected. t.required_features().unwrap_or(&no_required_features).iter().all(|f| { - bcx.resolve.features(id).contains(f) + bcx.resolve.features(id).contains_key(f) && bcx.platform_activated(bcx.resolve.features(id).get(f).unwrap().as_ref(), unit.kind) }) }) .map(|t| { diff --git a/src/cargo/core/compiler/custom_build.rs b/src/cargo/core/compiler/custom_build.rs index 58bdd7c76a4..fc3018d738a 100644 --- a/src/cargo/core/compiler/custom_build.rs +++ b/src/cargo/core/compiler/custom_build.rs @@ -187,7 +187,7 @@ fn build_work<'a, 'cfg>(cx: &mut Context<'a, 'cfg>, unit: &Unit<'a>) -> CargoRes // Be sure to pass along all enabled features for this package, this is the // last piece of statically known information that we have. for feat in bcx.resolve.features(unit.pkg.package_id()).iter() { - cmd.env(&format!("CARGO_FEATURE_{}", super::envify(feat)), "1"); + cmd.env(&format!("CARGO_FEATURE_{}", super::envify(feat.0)), "1"); } let mut cfg_map = HashMap::new(); diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index 1b31e736433..a4d012e8221 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -389,7 +389,7 @@ fn link_targets<'a, 'cfg>( let features = bcx.resolve .features_sorted(&package_id) .into_iter() - .map(|s| s.to_owned()) + .map(|s| s.0.to_owned()) .collect(); let json_messages = bcx.build_config.json_messages(); let mut target = unit.target.clone(); @@ -606,7 +606,10 @@ fn rustdoc<'a, 'cfg>(cx: &mut Context<'a, 'cfg>, unit: &Unit<'a>) -> CargoResult rustdoc.arg("-o").arg(doc_dir); for feat in bcx.resolve.features_sorted(unit.pkg.package_id()) { - rustdoc.arg("--cfg").arg(&format!("feature=\"{}\"", feat)); + if !bcx.platform_activated(feat.1, unit.kind) { + continue; + } + rustdoc.arg("--cfg").arg(&format!("feature=\"{}\"", feat.0)); } add_error_format(bcx, &mut rustdoc); @@ -840,7 +843,10 @@ fn build_base_args<'a, 'cfg>( // rustc-caching strategies like sccache are able to cache more, so sort the // feature list here. for feat in bcx.resolve.features_sorted(unit.pkg.package_id()) { - cmd.arg("--cfg").arg(&format!("feature=\"{}\"", feat)); + if !bcx.platform_activated(feat.1, unit.kind) { + continue; + } + cmd.arg("--cfg").arg(&format!("feature=\"{}\"", feat.0)); } match cx.files().metadata(unit) { diff --git a/src/cargo/core/dependency.rs b/src/cargo/core/dependency.rs index f96c2069136..7682c720dee 100644 --- a/src/cargo/core/dependency.rs +++ b/src/cargo/core/dependency.rs @@ -8,7 +8,7 @@ use serde::ser; use core::{PackageId, SourceId, Summary}; use core::interning::InternedString; -use util::{Cfg, CfgExpr, Config}; +use util::{Cfg, Config, Platform}; use util::errors::{CargoError, CargoResult, CargoResultExt}; /// Information about a dependency requested by a Cargo manifest. @@ -39,12 +39,6 @@ struct Inner { platform: Option, } -#[derive(Eq, PartialEq, Hash, Ord, PartialOrd, Clone, Debug)] -pub enum Platform { - Name(String), - Cfg(CfgExpr), -} - #[derive(Serialize)] struct SerializedDependency<'a> { name: &'a str, diff --git a/src/cargo/core/resolver/context.rs b/src/cargo/core/resolver/context.rs index b39bbd18f39..9f15e0917be 100644 --- a/src/cargo/core/resolver/context.rs +++ b/src/cargo/core/resolver/context.rs @@ -4,7 +4,7 @@ use std::rc::Rc; use core::interning::InternedString; use core::{Dependency, FeatureValue, PackageId, SourceId, Summary}; use util::CargoResult; -use util::Graph; +use util::{Platform, Graph}; use super::types::RegistryQueryer; use super::types::{ActivateResult, ConflictReason, DepInfo, GraphNode, Method, RcList}; @@ -23,7 +23,7 @@ pub struct Context { // switch to persistent hash maps if we can at some point or otherwise // make these much cheaper to clone in general. pub activations: Activations, - pub resolve_features: HashMap>>, + pub resolve_features: HashMap>>>, pub links: HashMap, // These are two cheaply-cloneable lists (O(1) clone) which are effectively @@ -88,8 +88,8 @@ impl Context { let has_default_feature = summary.features().contains_key("default"); Ok(match self.resolve_features.get(id) { Some(prev) => { - features.iter().all(|f| prev.contains(f)) - && (!use_default || prev.contains("default") || !has_default_feature) + features.iter().all(|f| prev.contains_key(f)) + && (!use_default || prev.contains_key("default") || !has_default_feature) } None => features.is_empty() && (!use_default || !has_default_feature), }) @@ -113,7 +113,7 @@ impl Context { .into_iter() .map(|(dep, features)| { let candidates = registry.query(&dep)?; - Ok((dep, candidates, Rc::new(features))) + Ok((dep, candidates, Rc::new(features.iter().map(|(k,_)| *k).collect()))) }) .collect::>>()?; @@ -159,7 +159,7 @@ impl Context { parent: Option<&Summary>, s: &'b Summary, method: &'b Method, - ) -> ActivateResult)>> { + ) -> ActivateResult)>)>> { let dev_deps = match *method { Method::Everything => true, Method::Required { dev_deps, .. } => dev_deps, @@ -210,7 +210,8 @@ impl Context { ); } } - ret.push((dep.clone(), base)); + // TODO danger => dep platform is copied to the feature platform! + ret.push((dep.clone(), base.into_iter().map(|f| (f, dep.platform().cloned())).collect())); } // Any entries in `reqs.dep` which weren't used are bugs in that the @@ -245,11 +246,11 @@ impl Context { let set = Rc::make_mut( self.resolve_features .entry(pkgid.clone()) - .or_insert_with(|| Rc::new(HashSet::new())), + .or_insert_with(|| Rc::new(HashMap::new())), ); - for feature in reqs.used { - set.insert(feature); + for (k, v) in reqs.used { + set.insert(k, v); } } @@ -297,8 +298,8 @@ fn build_requirements<'a, 'b: 'a>( | Method::Required { all_features: true, .. } => { - for key in s.features().keys() { - reqs.require_feature(*key)?; + for (key, (platform, _)) in s.features().iter() { + reqs.require_feature(*key, platform.as_ref())?; } for dep in s.dependencies().iter().filter(|d| d.is_optional()) { reqs.require_dependency(dep.name_in_toml()); @@ -309,8 +310,15 @@ fn build_requirements<'a, 'b: 'a>( features: requested, .. } => { - for &f in requested.iter() { - reqs.require_value(&FeatureValue::new(f, s))?; + for item in requested.iter() { + reqs.require_value( + &FeatureValue::new(*item, s), + if let Some((platform, _)) = s.features().get(item) { + platform.as_ref() + } else { + None + } + )?; } } } @@ -320,8 +328,8 @@ fn build_requirements<'a, 'b: 'a>( uses_default_features: true, .. } => { - if s.features().contains_key("default") { - reqs.require_feature(InternedString::new("default"))?; + if let Some((platform,_)) = s.features().get("default") { + reqs.require_feature(InternedString::new("default"), platform.as_ref())?; } } Method::Required { @@ -343,8 +351,8 @@ struct Requirements<'a> { // The used features set is the set of features which this local package had // enabled, which is later used when compiling to instruct the code what // features were enabled. - used: HashSet, - visited: HashSet, + used: HashMap>, + visited: HashMap>, } impl<'r> Requirements<'r> { @@ -352,13 +360,13 @@ impl<'r> Requirements<'r> { Requirements { summary, deps: HashMap::new(), - used: HashSet::new(), - visited: HashSet::new(), + used: HashMap::new(), + visited: HashMap::new(), } } - fn require_crate_feature(&mut self, package: InternedString, feat: InternedString) { - self.used.insert(package); + fn require_crate_feature(&mut self, package: InternedString, feat: InternedString, platform: Option<&Platform>) { + self.used.insert(package, platform.cloned()); self.deps .entry(package) .or_insert((false, Vec::new())) @@ -366,50 +374,59 @@ impl<'r> Requirements<'r> { .push(feat); } - fn seen(&mut self, feat: InternedString) -> bool { - if self.visited.insert(feat) { - self.used.insert(feat); - false - } else { + fn seen(&mut self, feat: InternedString, platform: Option<&Platform>) -> bool { + if self.visited.get(&feat).is_some() { true + } else { + self.used.insert(feat, platform.cloned()); + false } } fn require_dependency(&mut self, pkg: InternedString) { - if self.seen(pkg) { + if self.seen(pkg, None) { return; } self.deps.entry(pkg).or_insert((false, Vec::new())).0 = true; } - fn require_feature(&mut self, feat: InternedString) -> CargoResult<()> { - if feat.is_empty() || self.seen(feat) { + fn require_feature(&mut self, feat: InternedString, platform: Option<&Platform>) -> CargoResult<()> { + if feat.is_empty() || self.seen(feat, platform) { return Ok(()); } for fv in self .summary .features() .get(feat.as_str()) - .expect("must be a valid feature") + .expect("must be a valid feature").1.as_slice() { - match *fv { + match fv { FeatureValue::Feature(ref dep_feat) if **dep_feat == *feat => bail!( "Cyclic feature dependency: feature `{}` depends on itself", feat ), _ => {} } - self.require_value(fv)?; + let platform = if let FeatureValue::Feature(feature) = fv { + if let Some((platform, _)) = self.summary.features().get(feature) { + platform.as_ref() + } else { + platform + } + } else { + platform.clone() + }; + self.require_value(&fv, platform)?; } Ok(()) } - fn require_value<'f>(&mut self, fv: &'f FeatureValue) -> CargoResult<()> { + fn require_value<'f>(&mut self, fv: &'f FeatureValue, platform: Option<&Platform>) -> CargoResult<()> { match fv { - FeatureValue::Feature(feat) => self.require_feature(*feat)?, + FeatureValue::Feature(feat) => self.require_feature(*feat, platform)?, FeatureValue::Crate(dep) => self.require_dependency(*dep), FeatureValue::CrateFeature(dep, dep_feat) => { - self.require_crate_feature(*dep, *dep_feat) + self.require_crate_feature(*dep, *dep_feat, platform) } }; Ok(()) diff --git a/src/cargo/core/resolver/mod.rs b/src/cargo/core/resolver/mod.rs index d1b3fe878ce..4d75960c322 100644 --- a/src/cargo/core/resolver/mod.rs +++ b/src/cargo/core/resolver/mod.rs @@ -133,7 +133,7 @@ pub fn resolve( cx.resolve_replacements(), cx.resolve_features .iter() - .map(|(k, v)| (k.clone(), v.iter().map(|x| x.to_string()).collect())) + .map(|(k, v)| (k.clone(), v.iter().map(|(k, v)| (k.to_string(), v.clone())).collect())) .collect(), cksums, BTreeMap::new(), diff --git a/src/cargo/core/resolver/resolve.rs b/src/cargo/core/resolver/resolve.rs index dff80107f07..400502bdf3e 100644 --- a/src/cargo/core/resolver/resolve.rs +++ b/src/cargo/core/resolver/resolve.rs @@ -1,14 +1,13 @@ use std::borrow::Borrow; -use std::collections::{HashMap, HashSet}; +use std::collections::{HashMap, BTreeMap}; use std::fmt; use std::hash::Hash; -use std::iter::FromIterator; use url::Url; use core::{Dependency, PackageId, PackageIdSpec, Summary, Target}; use util::errors::CargoResult; -use util::Graph; +use util::{Graph, Platform}; use super::encode::Metadata; @@ -25,8 +24,8 @@ pub struct Resolve { graph: Graph>, replacements: HashMap, reverse_replacements: HashMap, - empty_features: HashSet, - features: HashMap>, + empty_features: HashMap>, + features: HashMap>>, checksums: HashMap>, metadata: Metadata, unused_patches: Vec, @@ -36,7 +35,7 @@ impl Resolve { pub fn new( graph: Graph>, replacements: HashMap, - features: HashMap>, + features: HashMap>>, checksums: HashMap>, metadata: Metadata, unused_patches: Vec, @@ -52,7 +51,7 @@ impl Resolve { checksums, metadata, unused_patches, - empty_features: HashSet::new(), + empty_features: HashMap::new(), reverse_replacements, } } @@ -193,14 +192,12 @@ unable to verify that `{0}` is the same as when the lockfile was generated &self.replacements } - pub fn features(&self, pkg: &PackageId) -> &HashSet { + pub fn features(&self, pkg: &PackageId) -> &HashMap> { self.features.get(pkg).unwrap_or(&self.empty_features) } - pub fn features_sorted(&self, pkg: &PackageId) -> Vec<&str> { - let mut v = Vec::from_iter(self.features(pkg).iter().map(|s| s.as_ref())); - v.sort_unstable(); - v + pub fn features_sorted(&self, pkg: &PackageId) -> BTreeMap<&str, Option<&Platform>> { + self.features(pkg).iter().map(|(k, v)| (k.as_str(), v.as_ref())).collect() } pub fn query(&self, spec: &str) -> CargoResult<&PackageId> { diff --git a/src/cargo/core/summary.rs b/src/cargo/core/summary.rs index 727bcdb4f51..d29b06b5a9f 100644 --- a/src/cargo/core/summary.rs +++ b/src/cargo/core/summary.rs @@ -10,7 +10,7 @@ use core::interning::InternedString; use core::{Dependency, PackageId, SourceId}; use semver::Version; -use util::CargoResult; +use util::{Platform, CargoResult}; /// Subset of a `Manifest`. Contains only the most important information about /// a package. @@ -35,7 +35,7 @@ impl Summary { pub fn new( pkg_id: PackageId, dependencies: Vec, - features: &BTreeMap>>, + features: &BTreeMap, Vec>)>, links: Option>, namespaced_features: bool, ) -> CargoResult @@ -139,7 +139,7 @@ impl PartialEq for Summary { // Checks features for errors, bailing out a CargoResult:Err if invalid, // and creates FeatureValues for each feature. fn build_feature_map( - features: &BTreeMap>>, + features: &BTreeMap, Vec>)>, dependencies: &[Dependency], namespaced: bool, ) -> CargoResult @@ -189,10 +189,10 @@ where K: Borrow + Ord + Display { }; let mut values = vec![]; - for dep in list { + for dep in list.1.as_slice() { let val = FeatureValue::build( InternedString::new(dep.as_ref()), - |fs| features.contains_key(fs.as_str()), + |fs| features.contains_key(fs.as_str()), namespaced, ); @@ -227,7 +227,7 @@ where K: Borrow + Ord + Display { // we don't have to do so here. (&Feature(feat), _, true) => { if namespaced && !features.contains_key(&*feat) { - map.insert(feat, vec![FeatureValue::Crate(feat)]); + map.insert(feat, (list.0.clone(), vec![FeatureValue::Crate(feat)])); } } // If features are namespaced and the value is not defined as a feature @@ -321,7 +321,7 @@ where K: Borrow + Ord + Display { ) } - map.insert(InternedString::new(feature.borrow()), values); + map.insert(InternedString::new(feature.borrow()), (list.0.clone(), values)); } Ok(map) } @@ -398,4 +398,4 @@ impl Serialize for FeatureValue { } } -pub type FeatureMap = BTreeMap>; +pub type FeatureMap = BTreeMap, Vec)>; diff --git a/src/cargo/ops/cargo_compile.rs b/src/cargo/ops/cargo_compile.rs index 0f9264e990e..15453686724 100644 --- a/src/cargo/ops/cargo_compile.rs +++ b/src/cargo/ops/cargo_compile.rs @@ -718,13 +718,13 @@ fn resolve_all_features( resolve_with_overrides: &Resolve, package_id: &PackageId, ) -> HashSet { - let mut features = resolve_with_overrides.features(package_id).clone(); + let mut features = resolve_with_overrides.features(package_id).keys().cloned().collect::>(); // Include features enabled for use by dependencies so targets can also use them with the // required-features field when deciding whether to be built or skipped. for (dep, _) in resolve_with_overrides.deps(package_id) { for feature in resolve_with_overrides.features(dep) { - features.insert(dep.name().to_string() + "/" + feature); + features.insert(dep.name().to_string() + "/" + feature.0); } } diff --git a/src/cargo/ops/cargo_output_metadata.rs b/src/cargo/ops/cargo_output_metadata.rs index da6462bb6f0..bf4dee4f7e4 100644 --- a/src/cargo/ops/cargo_output_metadata.rs +++ b/src/cargo/ops/cargo_output_metadata.rs @@ -128,6 +128,6 @@ where Dep { name, pkg } }) .collect(), - features: resolve.features_sorted(id), + features: resolve.features_sorted(id).keys().cloned().collect(), })) } diff --git a/src/cargo/ops/registry.rs b/src/cargo/ops/registry.rs index 34c8fa0bbe4..a3e3e29111d 100644 --- a/src/cargo/ops/registry.rs +++ b/src/cargo/ops/registry.rs @@ -219,7 +219,7 @@ fn transmit( .map(|(feat, values)| { ( feat.to_string(), - values.iter().map(|fv| fv.to_string(&summary)).collect(), + values.1.iter().map(|fv| fv.to_string(&summary)).collect(), ) }) .collect::>>(); diff --git a/src/cargo/sources/registry/index.rs b/src/cargo/sources/registry/index.rs index e9db7cfd10e..b730c5ebdcf 100644 --- a/src/cargo/sources/registry/index.rs +++ b/src/cargo/sources/registry/index.rs @@ -253,7 +253,8 @@ impl<'cfg> RegistryIndex<'cfg> { .into_iter() .map(|dep| dep.into_dep(&self.source_id)) .collect::>>()?; - let summary = Summary::new(pkgid, deps, &features, links, false)?; + let ftrs = features.iter().map(|(k, v)| (k.clone(), (None, v.clone()))).collect(); + let summary = Summary::new(pkgid, deps, &ftrs, links, false)?; let summary = summary.set_checksum(cksum.clone()); self.hashes .entry(name.as_str()) diff --git a/src/cargo/util/cfg.rs b/src/cargo/util/cfg.rs index 877452c8ff0..9f8b9aee3e0 100644 --- a/src/cargo/util/cfg.rs +++ b/src/cargo/util/cfg.rs @@ -4,6 +4,12 @@ use std::fmt; use util::{CargoError, CargoResult}; +#[derive(Eq, PartialEq, Hash, Ord, PartialOrd, Clone, Debug)] +pub enum Platform { + Name(String), + Cfg(CfgExpr), +} + #[derive(Eq, PartialEq, Hash, Ord, PartialOrd, Clone, Debug)] pub enum Cfg { Name(String), diff --git a/src/cargo/util/mod.rs b/src/cargo/util/mod.rs index c18914954f6..a2434a35778 100644 --- a/src/cargo/util/mod.rs +++ b/src/cargo/util/mod.rs @@ -1,6 +1,6 @@ use std::time::Duration; -pub use self::cfg::{Cfg, CfgExpr}; +pub use self::cfg::{Cfg, CfgExpr, Platform}; pub use self::config::{homedir, Config, ConfigValue}; pub use self::dependency_queue::{DependencyQueue, Dirty, Fresh, Freshness}; pub use self::errors::{CargoError, CargoResult, CargoResultExt, CliResult, Test}; diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index 4f42a7335c4..c17a0365a47 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -12,7 +12,7 @@ use serde_ignored; use toml; use url::Url; -use core::dependency::{Kind, Platform}; +use core::dependency::Kind; use core::manifest::{LibKind, ManifestMetadata, TargetSourcePath, Warnings}; use core::profiles::Profiles; use core::{Dependency, Manifest, PackageId, Summary, Target}; @@ -21,7 +21,7 @@ use core::{GitReference, PackageIdSpec, SourceId, WorkspaceConfig, WorkspaceRoot use sources::{CRATES_IO_INDEX, CRATES_IO_REGISTRY}; use util::errors::{CargoError, CargoResult, CargoResultExt}; use util::paths; -use util::{self, Config, ToUrl}; +use util::{self, Config, ToUrl, Platform}; mod targets; use self::targets::targets; @@ -719,6 +719,7 @@ impl TomlManifest { Ok(( k.clone(), TomlPlatform { + features: v.features.clone(), dependencies: map_deps(config, v.dependencies.as_ref())?, dev_dependencies: map_deps( config, @@ -865,6 +866,7 @@ impl TomlManifest { } let mut deps = Vec::new(); + let mut ftrs = BTreeMap::new(); let replace; let patch; @@ -897,6 +899,21 @@ impl TomlManifest { Ok(()) } + fn process_features( + ftrs: &mut BTreeMap, Vec)>, + new_ftrs: Option<&BTreeMap>>, + platform: Option<&Platform> + ) -> CargoResult<()> { + let features = match new_ftrs { + Some(features) => features, + None => return Ok(()), + }; + for (n, v) in features.iter() { + ftrs.insert(n.clone(), (platform.cloned(), v.clone())); + } + + Ok(()) + } // Collect the deps process_dependencies(&mut cx, me.dependencies.as_ref(), None)?; @@ -910,6 +927,7 @@ impl TomlManifest { .as_ref() .or_else(|| me.build_dependencies2.as_ref()); process_dependencies(&mut cx, build_deps, Some(Kind::Build))?; + process_features(&mut ftrs, me.features.as_ref(), None)?; for (name, platform) in me.target.iter().flat_map(|t| t) { cx.platform = Some(name.parse()?); @@ -924,6 +942,7 @@ impl TomlManifest { .as_ref() .or_else(|| platform.dev_dependencies2.as_ref()); process_dependencies(&mut cx, dev_deps, Some(Kind::Development))?; + process_features(&mut ftrs, platform.features.as_ref(), cx.platform.as_ref())?; } replace = me.replace(&mut cx)?; @@ -955,14 +974,7 @@ impl TomlManifest { let summary = Summary::new( pkgid, deps, - &me.features - .as_ref() - .map(|x| { - x.iter() - .map(|(k, v)| (k.as_str(), v.iter().collect())) - .collect() - }) - .unwrap_or_else(BTreeMap::new), + &ftrs, project.links.as_ref().map(|x| x.as_str()), project.namespaced_features.unwrap_or(false), )?; @@ -1450,6 +1462,7 @@ impl ser::Serialize for PathValue { /// Corresponds to a `target` entry, but `TomlTarget` is already used. #[derive(Serialize, Deserialize, Debug)] struct TomlPlatform { + features: Option>>, dependencies: Option>, #[serde(rename = "build-dependencies")] build_dependencies: Option>, diff --git a/tests/testsuite/cfg_features.rs b/tests/testsuite/cfg_features.rs new file mode 100644 index 00000000000..e0bf5d42960 --- /dev/null +++ b/tests/testsuite/cfg_features.rs @@ -0,0 +1,192 @@ +use support::project; + +#[test] +fn syntax() { + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "a" + version = "0.0.1" + authors = [] + + [target.'cfg(unix)'.features] + b = [] + [target.'cfg(windows)'.features] + b = [] + "#, + ).file("src/lib.rs", r#" + pub fn bb() {} + "#).build(); + p.cargo("build") + .with_stderr( + "\ +[COMPILING] a v0.0.1 ([CWD]) +[FINISHED] dev [unoptimized + debuginfo] target(s) in [..] +", + ).run(); +} + +#[test] +fn include_by_param() { + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "a" + version = "0.0.1" + authors = [] + + [target.'cfg(unix)'.features] + b = [] + [target.'cfg(windows)'.features] + c = [] + "#, + ).file("src/lib.rs", r#" + #[cfg(feature = "b")] + pub const BB: usize = 0; + #[cfg(feature = "c")] + pub const BB: usize = 1; + + pub fn bb() -> Result<(), ()> { if BB > 0 { Ok(()) } else { Err(()) } } + "#).build(); + p.cargo(format!("build --features {}", if cfg!(unix) { "b" } else { "c" }).as_str()) + .with_stderr( + "\ +[COMPILING] a v0.0.1 ([CWD]) +[FINISHED] dev [unoptimized + debuginfo] target(s) in [..] +", + ).run(); +} + +#[test] +fn dont_include_by_platform() { + let other_family = if cfg!(unix) { "windows" } else { "unix" }; + let p = project() + .file( + "Cargo.toml", + &format!( + r#" + [package] + name = "a" + version = "0.0.1" + authors = [] + + [target.'cfg({})'.features] + b = [] + "#, + other_family + ), + ).file("src/lib.rs", r#" + #[cfg(feature = "b")] + pub const BB: usize = 0; + + pub fn bb() { let _ = BB; } + "#).build(); + p.cargo("build --features b -vv") + .with_status(101) + .with_stderr_contains( + "\ +error[E0425]: cannot find value `BB` in this scope", + ).run(); +} + +#[test] +fn dont_include_by_param() { + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "a" + version = "0.0.1" + authors = [] + + [target.'cfg(unix)'.features] + b = [] + [target.'cfg(windows)'.features] + c = [] + "#, + ).file("src/lib.rs", r#" + #[cfg(feature = "b")] + pub const BB: usize = 0; + #[cfg(feature = "c")] + pub const BB: usize = 1; + + pub fn bb() -> Result<(), ()> { if BB > 0 { Ok(()) } else { Err(()) } } + "#).build(); + p.cargo("build -v") + .with_status(101) + .with_stderr_contains( + "\ +error[E0425]: cannot find value `BB` in this scope", + ).run(); +} + +#[test] +fn dont_include_default() { + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "a" + version = "0.0.1" + authors = [] + + [target.'cfg(unix)'.features] + b = [] + + [features] + default = ["b"] + "#, + ).file("src/lib.rs", r#" + #[cfg(feature = "b")] + pub const BB: usize = 0; + + pub fn bb() { let _ = BB; } + "#).build(); + p.cargo("build -v") + .with_status(101) + .with_stderr_contains( + "\ +error[E0425]: cannot find value `BB` in this scope", + ).run(); +} + +// https://github.com/rust-lang/cargo/issues/5313 +#[test] +#[cfg(all( + target_arch = "x86_64", + target_os = "linux", + target_env = "gnu" +))] +fn cfg_looks_at_rustflags_for_target() { + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "a" + version = "0.0.1" + authors = [] + + [target.'cfg(with_b)'.features] + b = [] + "#, + ).file( + "src/main.rs", + r#" + #[cfg(with_b)] + pub const BB: usize = 0; + + fn main() { let _ = BB; } + "#, + ).build(); + + p.cargo("build --target x86_64-unknown-linux-gnu") + .env("RUSTFLAGS", "--cfg with_b") + .run(); +} diff --git a/tests/testsuite/main.rs b/tests/testsuite/main.rs index 4131b1fb4c8..257e043d0fd 100644 --- a/tests/testsuite/main.rs +++ b/tests/testsuite/main.rs @@ -41,6 +41,7 @@ mod cargo_alias_config; mod cargo_command; mod cargo_features; mod cfg; +mod cfg_features; mod check; mod clean; mod concurrent; diff --git a/tests/testsuite/support/resolver.rs b/tests/testsuite/support/resolver.rs index 583617363c6..eaa7fdc7f30 100644 --- a/tests/testsuite/support/resolver.rs +++ b/tests/testsuite/support/resolver.rs @@ -9,7 +9,7 @@ use cargo::core::resolver::{self, Method}; use cargo::core::source::{GitReference, SourceId}; use cargo::core::Resolve; use cargo::core::{Dependency, PackageId, Registry, Summary}; -use cargo::util::{CargoResult, Config, ToUrl}; +use cargo::util::{CargoResult, Config, ToUrl, Platform}; use proptest::collection::{btree_map, vec}; use proptest::prelude::*; @@ -100,7 +100,7 @@ pub fn resolve_with_config_raw( let summary = Summary::new( pkg.clone(), deps, - &BTreeMap::>::new(), + &BTreeMap::, Vec)>::new(), None::, false, ) @@ -194,7 +194,7 @@ pub fn pkg_dep(name: T, dep: Vec) -> Summary { Summary::new( name.to_pkgid(), dep, - &BTreeMap::>::new(), + &BTreeMap::, Vec)>::new(), link, false, ) @@ -222,7 +222,7 @@ pub fn pkg_loc(name: &str, loc: &str) -> Summary { Summary::new( pkg_id_loc(name, loc), Vec::new(), - &BTreeMap::>::new(), + &BTreeMap::, Vec)>::new(), link, false, ) From 75b4095adb2215aa4cad315f369428bc9b7bd814 Mon Sep 17 00:00:00 2001 From: Serhii Plyhun Date: Thu, 8 Nov 2018 17:26:23 +0100 Subject: [PATCH 2/8] cargo metadata ops fix --- src/cargo/core/mod.rs | 2 +- src/cargo/core/package.rs | 11 ++++++++--- src/cargo/core/resolver/context.rs | 2 +- src/cargo/core/summary.rs | 1 + 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/cargo/core/mod.rs b/src/cargo/core/mod.rs index 3312ba3458c..019b265c434 100644 --- a/src/cargo/core/mod.rs +++ b/src/cargo/core/mod.rs @@ -14,7 +14,7 @@ pub use self::registry::Registry; pub use self::resolver::Resolve; pub use self::shell::{Shell, Verbosity}; pub use self::source::{GitReference, Source, SourceId, SourceMap}; -pub use self::summary::{FeatureMap, FeatureValue, Summary}; +pub use self::summary::{FeatureMap, RefFeatureMap, FeatureValue, Summary}; pub use self::workspace::{Members, Workspace, WorkspaceConfig, WorkspaceRootConfig}; pub mod compiler; diff --git a/src/cargo/core/package.rs b/src/cargo/core/package.rs index 171ac27e33e..6f8bb7ebb18 100644 --- a/src/cargo/core/package.rs +++ b/src/cargo/core/package.rs @@ -17,7 +17,7 @@ use serde::ser; use toml; use core::{Dependency, Manifest, PackageId, SourceId, Target}; -use core::{FeatureMap, SourceMap, Summary}; +use core::{RefFeatureMap, SourceMap, Summary}; use core::source::MaybePackage; use core::interning::InternedString; use ops; @@ -49,7 +49,7 @@ struct SerializedPackage<'a> { source: &'a SourceId, dependencies: &'a [Dependency], targets: Vec<&'a Target>, - features: &'a FeatureMap, + features: RefFeatureMap<'a>, manifest_path: &'a str, metadata: Option<&'a toml::Value>, authors: &'a [String], @@ -78,6 +78,11 @@ impl ser::Serialize for Package { let keywords = manmeta.keywords.as_ref(); let readme = manmeta.readme.as_ref().map(String::as_ref); let repository = manmeta.repository.as_ref().map(String::as_ref); + let features = summary + .features() + .iter() + .map(|(k, (_, v))| (*k, v.as_slice())) + .collect::(); // Filter out metabuild targets. They are an internal implementation // detail that is probably not relevant externally. There's also not a // real path to show in `src_path`, and this avoids changing the format. @@ -98,7 +103,7 @@ impl ser::Serialize for Package { source: summary.source_id(), dependencies: summary.dependencies(), targets, - features: summary.features(), + features, manifest_path: &self.manifest_path.display().to_string(), metadata: self.manifest.custom_metadata(), authors, diff --git a/src/cargo/core/resolver/context.rs b/src/cargo/core/resolver/context.rs index f1d98f9f76c..c228cbdbb77 100644 --- a/src/cargo/core/resolver/context.rs +++ b/src/cargo/core/resolver/context.rs @@ -376,7 +376,7 @@ impl<'r> Requirements<'r> { } fn seen(&mut self, feat: InternedString, platform: Option<&Platform>) -> bool { - if self.visited.get(&feat).is_some() { + if self.visited.insert(feat, platform.cloned()).is_some() { true } else { self.used.insert(feat, platform.cloned()); diff --git a/src/cargo/core/summary.rs b/src/cargo/core/summary.rs index d29b06b5a9f..8722f90673b 100644 --- a/src/cargo/core/summary.rs +++ b/src/cargo/core/summary.rs @@ -399,3 +399,4 @@ impl Serialize for FeatureValue { } pub type FeatureMap = BTreeMap, Vec)>; +pub type RefFeatureMap<'a> = BTreeMap; From 9ae818b36c52542edda8f685bd450be81eb89aed Mon Sep 17 00:00:00 2001 From: Serhii Plyhun Date: Fri, 9 Nov 2018 10:12:25 +0100 Subject: [PATCH 3/8] cfg_features::dont_include_default works on Unix --- tests/testsuite/cfg_features.rs | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/tests/testsuite/cfg_features.rs b/tests/testsuite/cfg_features.rs index e0bf5d42960..9e8c180f46a 100644 --- a/tests/testsuite/cfg_features.rs +++ b/tests/testsuite/cfg_features.rs @@ -127,21 +127,23 @@ error[E0425]: cannot find value `BB` in this scope", #[test] fn dont_include_default() { + let other_family = if cfg!(unix) { "windows" } else { "unix" }; let p = project() .file( "Cargo.toml", - r#" - [package] - name = "a" - version = "0.0.1" - authors = [] - - [target.'cfg(unix)'.features] - b = [] - - [features] - default = ["b"] - "#, + &format!(r#" + [package] + name = "a" + version = "0.0.1" + authors = [] + + [target.'cfg({})'.features] + b = [] + + [features] + default = ["b"] + "#, + other_family), ).file("src/lib.rs", r#" #[cfg(feature = "b")] pub const BB: usize = 0; From 0fd8ca232e0912bc9869b50ea567055ac922e5f9 Mon Sep 17 00:00:00 2001 From: snuk182 Date: Thu, 3 Jan 2019 21:26:03 +0100 Subject: [PATCH 4/8] Elided lifetimes do not work anymore --- src/cargo/core/package.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cargo/core/package.rs b/src/cargo/core/package.rs index 762a9cae981..710e6d768cd 100644 --- a/src/cargo/core/package.rs +++ b/src/cargo/core/package.rs @@ -95,7 +95,7 @@ impl ser::Serialize for Package { .features() .iter() .map(|(k, (_, v))| (*k, v.as_slice())) - .collect::(); + .collect::>(); // Filter out metabuild targets. They are an internal implementation // detail that is probably not relevant externally. There's also not a // real path to show in `src_path`, and this avoids changing the format. From cdc81558aefb1b02fc5feed7b6a7b4c08cc2f7a1 Mon Sep 17 00:00:00 2001 From: snuk182 Date: Sat, 5 Jan 2019 08:48:29 +0100 Subject: [PATCH 5/8] Build fixed --- src/cargo/core/dependency.rs | 50 +----------------------------------- src/cargo/core/mod.rs | 2 +- src/cargo/core/package.rs | 11 +++----- src/cargo/core/summary.rs | 1 - src/cargo/util/cfg.rs | 48 ++++++++++++++++++++++++++++++++++ src/cargo/util/toml/mod.rs | 2 +- 6 files changed, 54 insertions(+), 60 deletions(-) diff --git a/src/cargo/core/dependency.rs b/src/cargo/core/dependency.rs index da22d67fa3e..c9470a0c6e0 100644 --- a/src/cargo/core/dependency.rs +++ b/src/cargo/core/dependency.rs @@ -1,6 +1,4 @@ -use std::fmt; use std::rc::Rc; -use std::str::FromStr; use log::trace; use semver::ReqParseError; @@ -12,7 +10,7 @@ use url::Url; use crate::core::interning::InternedString; use crate::core::{PackageId, SourceId, Summary}; use crate::util::errors::{CargoResult, CargoResultExt}; -use crate::util::{Cfg, CfgExpr, Config}; +use crate::util::{Platform, Config}; /// Information about a dependency requested by a Cargo manifest. /// Cheap to copy. @@ -432,49 +430,3 @@ impl Dependency { } } } - -impl Platform { - pub fn matches(&self, name: &str, cfg: Option<&[Cfg]>) -> bool { - match *self { - Platform::Name(ref p) => p == name, - Platform::Cfg(ref p) => match cfg { - Some(cfg) => p.matches(cfg), - None => false, - }, - } - } -} - -impl ser::Serialize for Platform { - fn serialize(&self, s: S) -> Result - where - S: ser::Serializer, - { - self.to_string().serialize(s) - } -} - -impl FromStr for Platform { - type Err = failure::Error; - - fn from_str(s: &str) -> CargoResult { - if s.starts_with("cfg(") && s.ends_with(')') { - let s = &s[4..s.len() - 1]; - let p = s.parse().map(Platform::Cfg).chain_err(|| { - failure::format_err!("failed to parse `{}` as a cfg expression", s) - })?; - Ok(p) - } else { - Ok(Platform::Name(s.to_string())) - } - } -} - -impl fmt::Display for Platform { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - Platform::Name(ref n) => n.fmt(f), - Platform::Cfg(ref e) => write!(f, "cfg({})", e), - } - } -} diff --git a/src/cargo/core/mod.rs b/src/cargo/core/mod.rs index e1f70d4dc77..f94291f74e9 100644 --- a/src/cargo/core/mod.rs +++ b/src/cargo/core/mod.rs @@ -12,7 +12,7 @@ pub use self::registry::Registry; pub use self::resolver::Resolve; pub use self::shell::{Shell, Verbosity}; pub use self::source::{GitReference, Source, SourceId, SourceMap}; -pub use self::summary::{FeatureMap, RefFeatureMap, FeatureValue, Summary}; +pub use self::summary::{FeatureMap, FeatureValue, Summary}; pub use self::workspace::{Members, Workspace, WorkspaceConfig, WorkspaceRootConfig}; pub mod compiler; diff --git a/src/cargo/core/package.rs b/src/cargo/core/package.rs index 429e2064542..e1a0be576b4 100644 --- a/src/cargo/core/package.rs +++ b/src/cargo/core/package.rs @@ -20,7 +20,7 @@ use serde::Serialize; use crate::core::interning::InternedString; use crate::core::source::MaybePackage; use crate::core::{Dependency, Manifest, PackageId, SourceId, Target}; -use crate::core::{RefFeatureMap, SourceMap, Summary}; +use crate::core::{FeatureMap, SourceMap, Summary}; use crate::ops; use crate::util::errors::{CargoResult, CargoResultExt, HttpNot200}; use crate::util::network::Retry; @@ -62,8 +62,8 @@ struct SerializedPackage<'a> { source: SourceId, dependencies: &'a [Dependency], targets: Vec<&'a Target>, - features: RefFeatureMap<'a>, - manifest_path: &'a str, + features: &'a FeatureMap, + manifest_path: &'a Path, metadata: Option<&'a toml::Value>, authors: &'a [String], categories: &'a [String], @@ -92,11 +92,6 @@ impl ser::Serialize for Package { let keywords = manmeta.keywords.as_ref(); let readme = manmeta.readme.as_ref().map(String::as_ref); let repository = manmeta.repository.as_ref().map(String::as_ref); - let features = summary - .features() - .iter() - .map(|(k, (_, v))| (*k, v.as_slice())) - .collect::>(); // Filter out metabuild targets. They are an internal implementation // detail that is probably not relevant externally. There's also not a // real path to show in `src_path`, and this avoids changing the format. diff --git a/src/cargo/core/summary.rs b/src/cargo/core/summary.rs index d36aec742bf..9e9c3ec9d6b 100644 --- a/src/cargo/core/summary.rs +++ b/src/cargo/core/summary.rs @@ -409,4 +409,3 @@ impl Serialize for FeatureValue { } pub type FeatureMap = BTreeMap, Vec)>; -pub type RefFeatureMap<'a> = BTreeMap; diff --git a/src/cargo/util/cfg.rs b/src/cargo/util/cfg.rs index be6453cb26b..8dcee7a62a6 100644 --- a/src/cargo/util/cfg.rs +++ b/src/cargo/util/cfg.rs @@ -1,8 +1,10 @@ use std::fmt; use std::iter; use std::str::{self, FromStr}; +use serde::ser; use crate::util::CargoResult; +use crate::util::errors::CargoResultExt; #[derive(Eq, PartialEq, Hash, Ord, PartialOrd, Clone, Debug)] pub enum Platform { @@ -10,6 +12,52 @@ pub enum Platform { Cfg(CfgExpr), } +impl Platform { + pub fn matches(&self, name: &str, cfg: Option<&[Cfg]>) -> bool { + match *self { + Platform::Name(ref p) => p == name, + Platform::Cfg(ref p) => match cfg { + Some(cfg) => p.matches(cfg), + None => false, + }, + } + } +} + +impl ser::Serialize for Platform { + fn serialize(&self, s: S) -> Result + where + S: ser::Serializer, + { + self.to_string().serialize(s) + } +} + +impl FromStr for Platform { + type Err = failure::Error; + + fn from_str(s: &str) -> CargoResult { + if s.starts_with("cfg(") && s.ends_with(')') { + let s = &s[4..s.len() - 1]; + let p = s.parse().map(Platform::Cfg).chain_err(|| { + failure::format_err!("failed to parse `{}` as a cfg expression", s) + })?; + Ok(p) + } else { + Ok(Platform::Name(s.to_string())) + } + } +} + +impl fmt::Display for Platform { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + Platform::Name(ref n) => n.fmt(f), + Platform::Cfg(ref e) => write!(f, "cfg({})", e), + } + } +} + #[derive(Eq, PartialEq, Hash, Ord, PartialOrd, Clone, Debug)] pub enum Cfg { Name(String), diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index 1d4e78c9682..3f103a80f90 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -21,7 +21,7 @@ use crate::core::{GitReference, PackageIdSpec, SourceId, WorkspaceConfig, Worksp use crate::sources::{CRATES_IO_INDEX, CRATES_IO_REGISTRY}; use crate::util::errors::{CargoResult, CargoResultExt, ManifestError}; use crate::util::paths; -use crate::util::{self, validate_package_name, Config, ToUrl}; +use crate::util::{self, validate_package_name, Config, ToUrl, Platform}; mod targets; use self::targets::targets; From 06ec94f67c768f65db535984bc91f0194aa27df3 Mon Sep 17 00:00:00 2001 From: Serhii Plyhun Date: Mon, 7 Jan 2019 12:02:38 +0100 Subject: [PATCH 6/8] Get RefFeatureMap back for JSON output compatibility. --- src/cargo/core/mod.rs | 2 +- src/cargo/core/package.rs | 11 ++++++++--- src/cargo/core/summary.rs | 1 + 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/cargo/core/mod.rs b/src/cargo/core/mod.rs index f94291f74e9..e1f70d4dc77 100644 --- a/src/cargo/core/mod.rs +++ b/src/cargo/core/mod.rs @@ -12,7 +12,7 @@ pub use self::registry::Registry; pub use self::resolver::Resolve; pub use self::shell::{Shell, Verbosity}; pub use self::source::{GitReference, Source, SourceId, SourceMap}; -pub use self::summary::{FeatureMap, FeatureValue, Summary}; +pub use self::summary::{FeatureMap, RefFeatureMap, FeatureValue, Summary}; pub use self::workspace::{Members, Workspace, WorkspaceConfig, WorkspaceRootConfig}; pub mod compiler; diff --git a/src/cargo/core/package.rs b/src/cargo/core/package.rs index e1a0be576b4..f45a3df807e 100644 --- a/src/cargo/core/package.rs +++ b/src/cargo/core/package.rs @@ -20,7 +20,7 @@ use serde::Serialize; use crate::core::interning::InternedString; use crate::core::source::MaybePackage; use crate::core::{Dependency, Manifest, PackageId, SourceId, Target}; -use crate::core::{FeatureMap, SourceMap, Summary}; +use crate::core::{RefFeatureMap, SourceMap, Summary}; use crate::ops; use crate::util::errors::{CargoResult, CargoResultExt, HttpNot200}; use crate::util::network::Retry; @@ -62,7 +62,7 @@ struct SerializedPackage<'a> { source: SourceId, dependencies: &'a [Dependency], targets: Vec<&'a Target>, - features: &'a FeatureMap, + features: RefFeatureMap<'a>, manifest_path: &'a Path, metadata: Option<&'a toml::Value>, authors: &'a [String], @@ -92,6 +92,11 @@ impl ser::Serialize for Package { let keywords = manmeta.keywords.as_ref(); let readme = manmeta.readme.as_ref().map(String::as_ref); let repository = manmeta.repository.as_ref().map(String::as_ref); + let features = summary + .features() + .iter() + .map(|(k, (_, v))| (*k, v.as_slice())) + .collect::>(); // Filter out metabuild targets. They are an internal implementation // detail that is probably not relevant externally. There's also not a // real path to show in `src_path`, and this avoids changing the format. @@ -112,7 +117,7 @@ impl ser::Serialize for Package { source: summary.source_id(), dependencies: summary.dependencies(), targets, - features: summary.features(), + features, manifest_path: &self.manifest_path, metadata: self.manifest.custom_metadata(), authors, diff --git a/src/cargo/core/summary.rs b/src/cargo/core/summary.rs index 9e9c3ec9d6b..d36aec742bf 100644 --- a/src/cargo/core/summary.rs +++ b/src/cargo/core/summary.rs @@ -409,3 +409,4 @@ impl Serialize for FeatureValue { } pub type FeatureMap = BTreeMap, Vec)>; +pub type RefFeatureMap<'a> = BTreeMap; From fdc96d73586f10cf35f2e18adadd63389fbdc239 Mon Sep 17 00:00:00 2001 From: Serhii Plyhun Date: Fri, 1 Mar 2019 17:07:17 +0100 Subject: [PATCH 7/8] Test types fix --- tests/testsuite/support/resolver.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/testsuite/support/resolver.rs b/tests/testsuite/support/resolver.rs index 4f24f541f9f..8d8131e9bce 100644 --- a/tests/testsuite/support/resolver.rs +++ b/tests/testsuite/support/resolver.rs @@ -237,7 +237,7 @@ pub fn remove_dep(sum: &Summary, ind: usize) -> Summary { Summary::new( sum.package_id(), deps, - &BTreeMap::>::new(), + &BTreeMap::, Vec)>::new(), sum.links().map(|a| a.as_str()), sum.namespaced_features(), ) From e4109696163126f12eb33bc52393373f1f05c066 Mon Sep 17 00:00:00 2001 From: Serhii Plyhun Date: Mon, 8 Apr 2019 21:42:03 +0200 Subject: [PATCH 8/8] Resolver warning fixed --- src/cargo/core/resolver/resolve.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/cargo/core/resolver/resolve.rs b/src/cargo/core/resolver/resolve.rs index c47c71b7eb5..6b3630d8267 100644 --- a/src/cargo/core/resolver/resolve.rs +++ b/src/cargo/core/resolver/resolve.rs @@ -1,7 +1,6 @@ use std::borrow::Borrow; use std::collections::{HashMap, BTreeMap}; use std::fmt; -use std::iter::FromIterator; use url::Url;