-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Open
Labels
A-featuresArea: features — conditional compilationArea: features — conditional compilationC-feature-requestCategory: proposal for a feature. Before PR, ping rust-lang/cargo if this is not `Feature accepted`Category: proposal for a feature. Before PR, ping rust-lang/cargo if this is not `Feature accepted`PerformanceGotta go fast!Gotta go fast!S-needs-designStatus: Needs someone to work further on the design for the feature or fix. NOT YET accepted.Status: Needs someone to work further on the design for the feature or fix. NOT YET accepted.
Description
Problem
Cargo's resolver has 3 phases, narrowing down the packages used at each step
- Resolve for lockfile
- Resolve for target and some other settings
- Resolve features
Resolving of features requires downloading and parsing all packages from step (2)
cargo/src/cargo/ops/resolve.rs
Lines 259 to 309 in 02bcdd2
| pkg_set.download_accessible( | |
| &resolved_with_overrides, | |
| &member_ids, | |
| has_dev_units, | |
| requested_targets, | |
| target_data, | |
| force_all_targets, | |
| )?; | |
| let mut specs_and_features = Vec::new(); | |
| for specs in individual_specs { | |
| let feature_opts = FeatureOpts::new(ws, has_dev_units, force_all_targets)?; | |
| // We want to narrow the features to the current specs so that stuff like `cargo check -p a | |
| // -p b -F a/a,b/b` works and the resolver does not contain that `a` does not have feature | |
| // `b` and vice-versa. However, resolver v1 needs to see even features of unselected | |
| // packages turned on if it was because of working directory being inside the unselected | |
| // package, because they might turn on a feature of a selected package. | |
| let narrowed_features = match feature_unification { | |
| FeatureUnification::Package => { | |
| let mut narrowed_features = cli_features.clone(); | |
| let enabled_features = members_with_features | |
| .iter() | |
| .filter_map(|(package, cli_features)| { | |
| specs | |
| .iter() | |
| .any(|spec| spec.matches(package.package_id())) | |
| .then_some(cli_features.features.iter()) | |
| }) | |
| .flatten() | |
| .cloned() | |
| .collect(); | |
| narrowed_features.features = Rc::new(enabled_features); | |
| Cow::Owned(narrowed_features) | |
| } | |
| FeatureUnification::Selected | FeatureUnification::Workspace => { | |
| Cow::Borrowed(cli_features) | |
| } | |
| }; | |
| let resolved_features = FeatureResolver::resolve( | |
| ws, | |
| target_data, | |
| &resolved_with_overrides, | |
| &pkg_set, | |
| &*narrowed_features, | |
| &specs, | |
| requested_targets, | |
| feature_opts, | |
| )?; |
so we can then know what proc macros there are
cargo/src/cargo/core/resolver/features.rs
Lines 951 to 970 in 02bcdd2
| /// Whether the given package has any proc macro target, including proc-macro examples. | |
| fn has_any_proc_macro(&self, package_id: PackageId) -> bool { | |
| self.package_set | |
| .get_one(package_id) | |
| .expect("packages downloaded") | |
| .proc_macro() | |
| } | |
| /// Whether the given package is a proc macro lib target. | |
| /// | |
| /// This is useful for checking if a dependency is a proc macro, | |
| /// as it is not possible to depend on a non-lib target as a proc-macro. | |
| fn has_proc_macro_lib(&self, package_id: PackageId) -> bool { | |
| self.package_set | |
| .get_one(package_id) | |
| .expect("packages downloaded") | |
| .library() | |
| .map(|lib| lib.proc_macro()) | |
| .unwrap_or_default() | |
| } |
so we can know whether a package and its features are being resolved for the host-platform or target-platform
Without this, resolving of features could operate on the Index and we could download packages after step 3, reducing how many we download.
Problems with this:
- Network, file IO, and CPU performance in downloading and parsing more manifests than needed
- This makes a plumbing command for a feature resolver take in a lot more input than it would otherwise need, slowing down the plumbing command operations
- The plumbing commands are also providing light on how ways we might be able to better isolate cargo's architecture for easier maintainability and contributor approachability
See also
cargo builddownloads unrelated dependencies even when target has been specified and nobuild.rs#11352- cargo forgets why it downloaded a package #9222
Proposed Solution
- Add proc macro information to the Index Summary
- Have crates.io backfill this Summary entry
Open question
- How do we deal with non-backfilled data, like third-party registries
Notes
No response
Metadata
Metadata
Assignees
Labels
A-featuresArea: features — conditional compilationArea: features — conditional compilationC-feature-requestCategory: proposal for a feature. Before PR, ping rust-lang/cargo if this is not `Feature accepted`Category: proposal for a feature. Before PR, ping rust-lang/cargo if this is not `Feature accepted`PerformanceGotta go fast!Gotta go fast!S-needs-designStatus: Needs someone to work further on the design for the feature or fix. NOT YET accepted.Status: Needs someone to work further on the design for the feature or fix. NOT YET accepted.