3 //! This is a new feature resolver that runs independently of the main
4 //! dependency resolver. It is enabled when the user specifies `resolver =
5 //! "2"` in `Cargo.toml`.
7 //! One of its key characteristics is that it can avoid unifying features for
8 //! shared dependencies in some situations. See `FeatureOpts` for the
9 //! different behaviors that can be enabled. If no extra options are enabled,
10 //! then it should behave exactly the same as the dependency resolver's
11 //! feature resolution. This can be verified by setting the
12 //! `__CARGO_FORCE_NEW_FEATURES=compare` environment variable and running
13 //! Cargo's test suite (or building other projects), and checking if it
14 //! panics. Note: the `features2` tests will fail because they intentionally
15 //! compare the old vs new behavior, so forcing the old behavior will
16 //! naturally fail the tests.
18 //! The preferred way to engage this new resolver is via
19 //! `resolve_ws_with_opts`.
21 //! This does not *replace* feature resolution in the dependency resolver, but
22 //! instead acts as a second pass which can *narrow* the features selected in
23 //! the dependency resolver. The dependency resolver still needs to do its own
24 //! feature resolution in order to avoid selecting optional dependencies that
25 //! are never enabled. The dependency resolver could, in theory, just assume
26 //! all optional dependencies on all packages are enabled (and remove all
27 //! knowledge of features), but that could introduce new requirements that
28 //! might change old behavior or cause conflicts. Maybe some day in the future
29 //! we could experiment with that, but it seems unlikely to work or be all
32 //! There are many assumptions made about the dependency resolver. This
33 //! feature resolver assumes validation has already been done on the feature
34 //! maps, and doesn't do any validation itself. It assumes dev-dependencies
35 //! within a dependency have been removed. There are probably other
36 //! assumptions that I am forgetting.
38 use crate::core
::compiler
::{CompileKind, RustcTargetData}
;
39 use crate::core
::dependency
::{DepKind, Dependency}
;
40 use crate::core
::resolver
::types
::FeaturesSet
;
41 use crate::core
::resolver
::{Resolve, ResolveBehavior}
;
42 use crate::core
::{FeatureValue, PackageId, PackageIdSpec, PackageSet, Workspace}
;
43 use crate::util
::interning
::InternedString
;
44 use crate::util
::CargoResult
;
46 use std
::collections
::{BTreeMap, BTreeSet, HashMap, HashSet}
;
49 /// Map of activated features.
51 /// The key is `(PackageId, bool)` where the bool is `true` if these
52 /// are features for a build dependency or proc-macro.
53 type ActivateMap
= HashMap
<(PackageId
, bool
), BTreeSet
<InternedString
>>;
55 /// Set of all activated features for all packages in the resolve graph.
56 pub struct ResolvedFeatures
{
57 activated_features
: ActivateMap
,
58 /// Optional dependencies that should be built.
60 /// The value is the `name_in_toml` of the dependencies.
61 activated_dependencies
: ActivateMap
,
62 /// This is only here for legacy support when the new resolver is not enabled.
64 /// This is the set of features enabled for each package.
65 legacy_features
: Option
<HashMap
<PackageId
, Vec
<InternedString
>>>,
66 /// This is only here for legacy support when the new resolver is not enabled.
68 /// This is the set of optional dependencies enabled for each package.
69 legacy_dependencies
: Option
<HashMap
<PackageId
, HashSet
<InternedString
>>>,
73 /// Options for how the feature resolver works.
75 pub struct FeatureOpts
{
76 /// Use the new resolver instead of the old one.
78 /// Build deps and proc-macros will not share share features with other dep kinds.
79 decouple_host_deps
: bool
,
80 /// Dev dep features will not be activated unless needed.
81 decouple_dev_deps
: bool
,
82 /// Targets that are not in use will not activate features.
83 ignore_inactive_targets
: bool
,
84 /// If enabled, compare against old resolver (for testing).
88 /// Flag to indicate if Cargo is building *any* dev units (tests, examples, etc.).
90 /// This disables decoupling of dev dependencies. It may be possible to relax
91 /// this in the future, but it will require significant changes to how unit
92 /// dependencies are computed, and can result in longer build times with
93 /// `cargo test` because the lib may need to be built 3 times instead of
95 #[derive(Copy, Clone, PartialEq)]
96 pub enum HasDevUnits
{
101 /// Flag to indicate that target-specific filtering should be disabled.
102 #[derive(Copy, Clone, PartialEq)]
103 pub enum ForceAllTargets
{
108 /// Flag to indicate if features are requested for a build dependency or not.
109 #[derive(Copy, Clone, Debug, PartialEq)]
110 pub enum FeaturesFor
{
112 /// Build dependency or proc-macro.
117 pub fn from_for_host(for_host
: bool
) -> FeaturesFor
{
121 FeaturesFor
::NormalOrDev
129 has_dev_units
: HasDevUnits
,
130 force_all_targets
: ForceAllTargets
,
131 ) -> CargoResult
<FeatureOpts
> {
132 let mut opts
= FeatureOpts
::default();
133 let unstable_flags
= ws
.config().cli_unstable();
134 let mut enable
= |feat_opts
: &Vec
<String
>| {
135 opts
.new_resolver
= true;
136 for opt
in feat_opts
{
138 "build_dep" | "host_dep" => opts
.decouple_host_deps
= true,
139 "dev_dep" => opts
.decouple_dev_deps
= true,
140 "itarget" => opts
.ignore_inactive_targets
= true,
142 opts
.decouple_host_deps
= true;
143 opts
.decouple_dev_deps
= true;
144 opts
.ignore_inactive_targets
= true;
146 "compare" => opts
.compare
= true,
147 "ws" => unimplemented
!(),
148 s
=> bail
!("-Zfeatures flag `{}` is not supported", s
),
153 if let Some(feat_opts
) = unstable_flags
.features
.as_ref() {
156 match ws
.resolve_behavior() {
157 ResolveBehavior
::V1
=> {}
158 ResolveBehavior
::V2
=> {
159 enable(&vec
!["all".to_string()]).unwrap();
162 // This env var is intended for testing only.
163 if let Ok(env_opts
) = std
::env
::var("__CARGO_FORCE_NEW_FEATURES") {
165 opts
.new_resolver
= true;
167 let env_opts
= env_opts
.split('
,'
).map(|s
| s
.to_string()).collect();
171 if let HasDevUnits
::Yes
= has_dev_units
{
172 // Dev deps cannot be decoupled when they are in use.
173 opts
.decouple_dev_deps
= false;
175 if let ForceAllTargets
::Yes
= force_all_targets
{
176 opts
.ignore_inactive_targets
= false;
178 if unstable_flags
.weak_dep_features
{
179 // Force this ON because it only works with the new resolver.
180 opts
.new_resolver
= true;
185 /// Creates a new FeatureOpts for the given behavior.
186 pub fn new_behavior(behavior
: ResolveBehavior
, has_dev_units
: HasDevUnits
) -> FeatureOpts
{
188 ResolveBehavior
::V1
=> FeatureOpts
::default(),
189 ResolveBehavior
::V2
=> FeatureOpts
{
191 decouple_host_deps
: true,
192 decouple_dev_deps
: has_dev_units
== HasDevUnits
::No
,
193 ignore_inactive_targets
: true,
200 /// Features flags requested for a package.
202 /// This should be cheap and fast to clone, it is used in the resolver for
205 /// This is split into enum variants because the resolver needs to handle
206 /// features coming from different places (command-line and dependency
207 /// declarations), but those different places have different constraints on
208 /// which syntax is allowed. This helps ensure that every place dealing with
209 /// features is properly handling those syntax restrictions.
210 #[derive(Debug, Clone, Eq, PartialEq, Hash)]
211 pub enum RequestedFeatures
{
212 /// Features requested on the command-line with flags.
213 CliFeatures(CliFeatures
),
214 /// Features specified in a dependency declaration.
216 /// The `features` dependency field.
217 features
: FeaturesSet
,
218 /// The `default-features` dependency field.
219 uses_default_features
: bool
,
223 /// Features specified on the command-line.
224 #[derive(Debug, Clone, Eq, PartialEq, Hash)]
225 pub struct CliFeatures
{
226 /// Features from the `--features` flag.
227 pub features
: Rc
<BTreeSet
<FeatureValue
>>,
228 /// The `--all-features` flag.
229 pub all_features
: bool
,
230 /// Inverse of `--no-default-features` flag.
231 pub uses_default_features
: bool
,
235 /// Creates a new CliFeatures from the given command-line flags.
236 pub fn from_command_line(
239 uses_default_features
: bool
,
240 ) -> CargoResult
<CliFeatures
> {
241 let features
= Rc
::new(CliFeatures
::split_features(features
));
242 // Some early validation to ensure correct syntax.
243 for feature
in features
.iter() {
245 // Maybe call validate_feature_name here once it is an error?
246 FeatureValue
::Feature(_
) => {}
247 FeatureValue
::Dep { .. }
248 | FeatureValue
::DepFeature
{
252 "feature `{}` is not allowed to use explicit `dep:` syntax",
256 FeatureValue
::DepFeature { dep_feature, .. }
=> {
257 if dep_feature
.contains('
/'
) {
258 bail
!("multiple slashes in feature `{}` is not allowed", feature
);
266 uses_default_features
,
270 /// Creates a new CliFeatures with the given `all_features` setting.
271 pub fn new_all(all_features
: bool
) -> CliFeatures
{
273 features
: Rc
::new(BTreeSet
::new()),
275 uses_default_features
: true,
279 fn split_features(features
: &[String
]) -> BTreeSet
<FeatureValue
> {
282 .flat_map(|s
| s
.split_whitespace())
283 .flat_map(|s
| s
.split('
,'
))
284 .filter(|s
| !s
.is_empty())
285 .map(InternedString
::new
)
286 .map(FeatureValue
::new
)
291 impl ResolvedFeatures
{
292 /// Returns the list of features that are enabled for the given package.
293 pub fn activated_features(
296 features_for
: FeaturesFor
,
297 ) -> Vec
<InternedString
> {
298 self.activated_features_int(pkg_id
, features_for
)
299 .expect("activated_features for invalid package")
302 /// Returns if the given dependency should be included.
304 /// This handles dependencies disabled via `cfg` expressions and optional
305 /// dependencies which are not enabled.
306 pub fn is_dep_activated(
309 features_for
: FeaturesFor
,
310 dep_name
: InternedString
,
312 if let Some(legacy
) = &self.legacy_dependencies
{
315 .map(|deps
| deps
.contains(&dep_name
))
318 let is_build
= self.opts
.decouple_host_deps
&& features_for
== FeaturesFor
::HostDep
;
319 self.activated_dependencies
320 .get(&(pkg_id
, is_build
))
321 .map(|deps
| deps
.contains(&dep_name
))
326 /// Variant of `activated_features` that returns `None` if this is
327 /// not a valid pkg_id/is_build combination. Used in places which do
328 /// not know which packages are activated (like `cargo clean`).
329 pub fn activated_features_unverified(
332 features_for
: FeaturesFor
,
333 ) -> Option
<Vec
<InternedString
>> {
334 self.activated_features_int(pkg_id
, features_for
).ok()
337 fn activated_features_int(
340 features_for
: FeaturesFor
,
341 ) -> CargoResult
<Vec
<InternedString
>> {
342 if let Some(legacy
) = &self.legacy_features
{
343 Ok(legacy
.get(&pkg_id
).map_or_else(Vec
::new
, |v
| v
.clone()))
345 let is_build
= self.opts
.decouple_host_deps
&& features_for
== FeaturesFor
::HostDep
;
346 if let Some(fs
) = self.activated_features
.get(&(pkg_id
, is_build
)) {
347 Ok(fs
.iter().cloned().collect())
349 bail
!("features did not find {:?} {:?}", pkg_id
, is_build
)
354 /// Compares the result against the original resolver behavior.
356 /// Used by `cargo fix --edition` to display any differences.
357 pub fn compare_legacy(&self, legacy
: &ResolvedFeatures
) -> FeatureDifferences
{
358 let legacy_features
= legacy
.legacy_features
.as_ref().unwrap();
362 .filter_map(|((pkg_id
, for_host
), new_features
)| {
363 let old_features
= match legacy_features
.get(pkg_id
) {
364 Some(feats
) => feats
.iter().cloned().collect(),
365 None
=> BTreeSet
::new(),
367 // The new resolver should never add features.
368 assert_eq
!(new_features
.difference(&old_features
).next(), None
);
369 let removed_features
: BTreeSet
<_
> =
370 old_features
.difference(new_features
).cloned().collect();
371 if removed_features
.is_empty() {
374 Some(((*pkg_id
, *for_host
), removed_features
))
378 let legacy_deps
= legacy
.legacy_dependencies
.as_ref().unwrap();
379 let optional_deps
= self
380 .activated_dependencies
382 .filter_map(|((pkg_id
, for_host
), new_deps
)| {
383 let old_deps
= match legacy_deps
.get(pkg_id
) {
384 Some(deps
) => deps
.iter().cloned().collect(),
385 None
=> BTreeSet
::new(),
387 // The new resolver should never add dependencies.
388 assert_eq
!(new_deps
.difference(&old_deps
).next(), None
);
389 let removed_deps
: BTreeSet
<_
> = old_deps
.difference(new_deps
).cloned().collect();
390 if removed_deps
.is_empty() {
393 Some(((*pkg_id
, *for_host
), removed_deps
))
404 /// Map of differences.
406 /// Key is `(pkg_id, for_host)`. Value is a set of features or dependencies removed.
407 pub type DiffMap
= BTreeMap
<(PackageId
, bool
), BTreeSet
<InternedString
>>;
409 /// Differences between resolvers.
410 pub struct FeatureDifferences
{
411 pub features
: DiffMap
,
412 pub optional_deps
: DiffMap
,
415 pub struct FeatureResolver
<'a
, 'cfg
> {
416 ws
: &'a Workspace
<'cfg
>,
417 target_data
: &'a RustcTargetData
<'cfg
>,
418 /// The platforms to build for, requested by the user.
419 requested_targets
: &'a
[CompileKind
],
420 resolve
: &'a Resolve
,
421 package_set
: &'a PackageSet
<'cfg
>,
422 /// Options that change how the feature resolver operates.
424 /// Map of features activated for each package.
425 activated_features
: ActivateMap
,
426 /// Map of optional dependencies activated for each package.
427 activated_dependencies
: ActivateMap
,
428 /// Keeps track of which packages have had its dependencies processed.
429 /// Used to avoid cycles, and to speed up processing.
430 processed_deps
: HashSet
<(PackageId
, bool
)>,
431 /// If this is `true`, then `for_host` needs to be tracked while
432 /// traversing the graph.
434 /// This is only here to avoid calling `is_proc_macro` when all feature
435 /// options are disabled (because `is_proc_macro` can trigger downloads).
436 /// This has to be separate from `FeatureOpts.decouple_host_deps` because
437 /// `for_host` tracking is also needed for `itarget` to work properly.
438 track_for_host
: bool
,
439 /// `dep_name?/feat_name` features that will be activated if `dep_name` is
442 /// The key is the `(package, for_host, dep_name)` of the package whose
443 /// dependency will trigger the addition of new features. The value is the
444 /// set of `(feature, dep_prefix)` features to activate (`dep_prefix` is a
445 /// bool that indicates if `dep:` prefix was used).
446 deferred_weak_dependencies
:
447 HashMap
<(PackageId
, bool
, InternedString
), HashSet
<(InternedString
, bool
)>>,
450 impl<'a
, 'cfg
> FeatureResolver
<'a
, 'cfg
> {
451 /// Runs the resolution algorithm and returns a new `ResolvedFeatures`
454 ws
: &Workspace
<'cfg
>,
455 target_data
: &RustcTargetData
<'cfg
>,
457 package_set
: &'a PackageSet
<'cfg
>,
458 cli_features
: &CliFeatures
,
459 specs
: &[PackageIdSpec
],
460 requested_targets
: &[CompileKind
],
462 ) -> CargoResult
<ResolvedFeatures
> {
463 use crate::util
::profile
;
464 let _p
= profile
::start("resolve features");
466 if !opts
.new_resolver
{
468 return Ok(ResolvedFeatures
{
469 activated_features
: HashMap
::new(),
470 activated_dependencies
: HashMap
::new(),
471 legacy_features
: Some(resolve
.features_clone()),
472 legacy_dependencies
: Some(compute_legacy_deps(resolve
)),
476 let track_for_host
= opts
.decouple_host_deps
|| opts
.ignore_inactive_targets
;
477 let mut r
= FeatureResolver
{
484 activated_features
: HashMap
::new(),
485 activated_dependencies
: HashMap
::new(),
486 processed_deps
: HashSet
::new(),
488 deferred_weak_dependencies
: HashMap
::new(),
490 r
.do_resolve(specs
, cli_features
)?
;
491 log
::debug
!("features={:#?}", r
.activated_features
);
495 Ok(ResolvedFeatures
{
496 activated_features
: r
.activated_features
,
497 activated_dependencies
: r
.activated_dependencies
,
498 legacy_features
: None
,
499 legacy_dependencies
: None
,
504 /// Performs the process of resolving all features for the resolve graph.
507 specs
: &[PackageIdSpec
],
508 cli_features
: &CliFeatures
,
509 ) -> CargoResult
<()> {
510 let member_features
= self.ws
.members_with_features(specs
, cli_features
)?
;
511 for (member
, cli_features
) in &member_features
{
512 let fvs
= self.fvs_from_requested(member
.package_id(), cli_features
);
513 let for_host
= self.track_for_host
&& self.is_proc_macro(member
.package_id());
514 self.activate_pkg(member
.package_id(), for_host
, &fvs
)?
;
516 // Also activate without for_host. This is needed if the
517 // proc-macro includes other targets (like binaries or tests),
518 // or running in `cargo test`. Note that in a workspace, if
519 // the proc-macro is selected on the command like (like with
520 // `--workspace`), this forces feature unification with normal
521 // dependencies. This is part of the bigger problem where
522 // features depend on which packages are built.
523 self.activate_pkg(member
.package_id(), false, &fvs
)?
;
533 fvs
: &[FeatureValue
],
534 ) -> CargoResult
<()> {
535 log
::trace
!("activate_pkg {} {}", pkg_id
.name(), for_host
);
536 // Add an empty entry to ensure everything is covered. This is intended for
537 // finding bugs where the resolver missed something it should have visited.
538 // Remove this in the future if `activated_features` uses an empty default.
539 self.activated_features
540 .entry((pkg_id
, self.opts
.decouple_host_deps
&& for_host
))
541 .or_insert_with(BTreeSet
::new
);
543 self.activate_fv(pkg_id
, for_host
, fv
)?
;
545 if !self.processed_deps
.insert((pkg_id
, for_host
)) {
546 // Already processed dependencies. There's no need to process them
547 // again. This is primarily to avoid cycles, but also helps speed
550 // This is safe because if another package comes along and adds a
551 // feature on this package, it will immediately add it (in
552 // `activate_fv`), and recurse as necessary right then and there.
553 // For example, consider we've already processed our dependencies,
554 // and another package comes along and enables one of our optional
555 // dependencies, it will do so immediately in the
556 // `FeatureValue::DepFeature` branch, and then immediately
557 // recurse into that optional dependency. This also holds true for
558 // features that enable other features.
561 for (dep_pkg_id
, deps
) in self.deps(pkg_id
, for_host
) {
562 for (dep
, dep_for_host
) in deps
{
563 if dep
.is_optional() {
564 // Optional dependencies are enabled in `activate_fv` when
565 // a feature enables it.
568 // Recurse into the dependency.
569 let fvs
= self.fvs_from_dependency(dep_pkg_id
, dep
);
570 self.activate_pkg(dep_pkg_id
, dep_for_host
, &fvs
)?
;
576 /// Activate a single FeatureValue for a package.
582 ) -> CargoResult
<()> {
583 log
::trace
!("activate_fv {} {} {}", pkg_id
.name(), for_host
, fv
);
585 FeatureValue
::Feature(f
) => {
586 self.activate_rec(pkg_id
, for_host
, *f
)?
;
588 FeatureValue
::Dep { dep_name }
=> {
589 self.activate_dependency(pkg_id
, for_host
, *dep_name
)?
;
591 FeatureValue
::DepFeature
{
597 self.activate_dep_feature(
610 /// Activate the given feature for the given package, and then recursively
611 /// activate any other features that feature enables.
616 feature_to_enable
: InternedString
,
617 ) -> CargoResult
<()> {
619 "activate_rec {} {} feat={}",
626 .entry((pkg_id
, self.opts
.decouple_host_deps
&& for_host
))
627 .or_insert_with(BTreeSet
::new
);
628 if !enabled
.insert(feature_to_enable
) {
632 let summary
= self.resolve
.summary(pkg_id
);
633 let feature_map
= summary
.features();
634 let fvs
= match feature_map
.get(&feature_to_enable
) {
637 // TODO: this should only happen for optional dependencies.
638 // Other cases should be validated by Summary's `build_feature_map`.
639 // Figure out some way to validate this assumption.
641 "pkg {:?} does not define feature {}",
649 self.activate_fv(pkg_id
, for_host
, fv
)?
;
654 /// Activate a dependency (`dep:dep_name` syntax).
655 fn activate_dependency(
659 dep_name
: InternedString
,
660 ) -> CargoResult
<()> {
661 // Mark this dependency as activated.
662 let save_for_host
= self.opts
.decouple_host_deps
&& for_host
;
663 self.activated_dependencies
664 .entry((pkg_id
, save_for_host
))
667 // Check for any deferred features.
669 .deferred_weak_dependencies
670 .remove(&(pkg_id
, for_host
, dep_name
));
671 // Activate the optional dep.
672 for (dep_pkg_id
, deps
) in self.deps(pkg_id
, for_host
) {
673 for (dep
, dep_for_host
) in deps
{
674 if dep
.name_in_toml() != dep_name
{
677 if let Some(to_enable
) = &to_enable
{
678 for (dep_feature
, dep_prefix
) in to_enable
{
680 "activate deferred {} {} -> {}/{}",
687 self.activate_rec(pkg_id
, for_host
, dep_name
)?
;
689 let fv
= FeatureValue
::new(*dep_feature
);
690 self.activate_fv(dep_pkg_id
, dep_for_host
, &fv
)?
;
693 let fvs
= self.fvs_from_dependency(dep_pkg_id
, dep
);
694 self.activate_pkg(dep_pkg_id
, dep_for_host
, &fvs
)?
;
700 /// Activate a feature within a dependency (`dep_name/feat_name` syntax).
701 fn activate_dep_feature(
705 dep_name
: InternedString
,
706 dep_feature
: InternedString
,
709 ) -> CargoResult
<()> {
710 for (dep_pkg_id
, deps
) in self.deps(pkg_id
, for_host
) {
711 for (dep
, dep_for_host
) in deps
{
712 if dep
.name_in_toml() != dep_name
{
715 if dep
.is_optional() {
716 let save_for_host
= self.opts
.decouple_host_deps
&& for_host
;
719 .activated_dependencies
720 .get(&(pkg_id
, save_for_host
))
721 .map(|deps
| deps
.contains(&dep_name
))
724 // This is weak, but not yet activated. Defer in case
725 // something comes along later and enables it.
727 "deferring feature {} {} -> {}/{}",
733 self.deferred_weak_dependencies
734 .entry((pkg_id
, for_host
, dep_name
))
736 .insert((dep_feature
, dep_prefix
));
740 // Activate the dependency on self.
741 let fv
= FeatureValue
::Dep { dep_name }
;
742 self.activate_fv(pkg_id
, for_host
, &fv
)?
;
744 // To retain compatibility with old behavior,
745 // this also enables a feature of the same
747 self.activate_rec(pkg_id
, for_host
, dep_name
)?
;
750 // Activate the feature on the dependency.
751 let fv
= FeatureValue
::new(dep_feature
);
752 self.activate_fv(dep_pkg_id
, dep_for_host
, &fv
)?
;
758 /// Returns Vec of FeatureValues from a Dependency definition.
759 fn fvs_from_dependency(&self, dep_id
: PackageId
, dep
: &Dependency
) -> Vec
<FeatureValue
> {
760 let summary
= self.resolve
.summary(dep_id
);
761 let feature_map
= summary
.features();
762 let mut result
: Vec
<FeatureValue
> = dep
765 .map(|f
| FeatureValue
::new(*f
))
767 let default = InternedString
::new("default");
768 if dep
.uses_default_features() && feature_map
.contains_key(&default) {
769 result
.push(FeatureValue
::Feature(default));
774 /// Returns Vec of FeatureValues from a set of command-line features.
775 fn fvs_from_requested(
778 cli_features
: &CliFeatures
,
779 ) -> Vec
<FeatureValue
> {
780 let summary
= self.resolve
.summary(pkg_id
);
781 let feature_map
= summary
.features();
782 if cli_features
.all_features
{
785 .map(|k
| FeatureValue
::Feature(*k
))
788 let mut result
: Vec
<FeatureValue
> = cli_features
.features
.iter().cloned().collect();
789 let default = InternedString
::new("default");
790 if cli_features
.uses_default_features
&& feature_map
.contains_key(&default) {
791 result
.push(FeatureValue
::Feature(default));
797 /// Returns the dependencies for a package, filtering out inactive targets.
802 ) -> Vec
<(PackageId
, Vec
<(&'a Dependency
, bool
)>)> {
803 // Helper for determining if a platform is activated.
804 let platform_activated
= |dep
: &Dependency
| -> bool
{
805 // We always care about build-dependencies, and they are always
806 // Host. If we are computing dependencies "for a build script",
807 // even normal dependencies are host-only.
808 if for_host
|| dep
.is_build() {
811 .dep_platform_activated(dep
, CompileKind
::Host
);
813 // Not a build dependency, and not for a build script, so must be Target.
814 self.requested_targets
816 .any(|kind
| self.target_data
.dep_platform_activated(dep
, *kind
))
820 .map(|(dep_id
, deps
)| {
824 if dep
.platform().is_some()
825 && self.opts
.ignore_inactive_targets
826 && !platform_activated(dep
)
830 if self.opts
.decouple_dev_deps
&& dep
.kind() == DepKind
::Development
{
836 let dep_for_host
= self.track_for_host
837 && (for_host
|| dep
.is_build() || self.is_proc_macro(dep_id
));
840 .collect
::<Vec
<_
>>();
843 .filter(|(_id
, deps
)| !deps
.is_empty())
847 /// Compare the activated features to the resolver. Used for testing.
849 let mut found
= false;
850 for ((pkg_id
, dep_kind
), features
) in &self.activated_features
{
851 let r_features
= self.resolve
.features(*pkg_id
);
852 if !r_features
.iter().eq(features
.iter()) {
853 crate::drop_eprintln
!(
855 "{}/{:?} features mismatch\nresolve: {:?}\nnew: {:?}\n",
865 panic
!("feature mismatch");
869 fn is_proc_macro(&self, package_id
: PackageId
) -> bool
{
872 .expect("packages downloaded")
877 /// Computes a map of PackageId to the set of optional dependencies that are
878 /// enabled for that dep (when the new resolver is not enabled).
879 fn compute_legacy_deps(resolve
: &Resolve
) -> HashMap
<PackageId
, HashSet
<InternedString
>> {
880 let mut result
: HashMap
<PackageId
, HashSet
<InternedString
>> = HashMap
::new();
881 for pkg_id
in resolve
.iter() {
882 for (_dep_id
, deps
) in resolve
.deps(pkg_id
) {
884 if dep
.is_optional() {
885 result
.entry(pkg_id
).or_default().insert(dep
.name_in_toml());