Skip to content

Commit a79aa3a

Browse files
committed
Auto merge of #8987 - jonhoo:metadata-target-filtering, r=ehuss
Make cargo metadata and tree respect target Previously, the `metadata` and `tree` subcommands would download dependencies for all targets, regardless of whether those targets were actually enabled. This PR updates them so that they only download the same dependencies that building would do with the requested target(s). `cargo metadata` still includes all targets by default; you can only opt _out_ using `--filter-platform`. Ideally it should use `--target` the same way `tree` does, but it's too late to change that now. Fixes #8981.
2 parents 0877f61 + 260a355 commit a79aa3a

File tree

10 files changed

+101
-51
lines changed

10 files changed

+101
-51
lines changed

src/cargo/core/compiler/standard_lib.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use crate::core::compiler::UnitInterner;
44
use crate::core::compiler::{CompileKind, CompileMode, RustcTargetData, Unit};
55
use crate::core::profiles::{Profiles, UnitFor};
6-
use crate::core::resolver::features::{FeaturesFor, ResolvedFeatures};
6+
use crate::core::resolver::features::{FeaturesFor, RequestedFeatures, ResolvedFeatures};
77
use crate::core::resolver::{HasDevUnits, ResolveOpts};
88
use crate::core::{Dependency, PackageId, PackageSet, Resolve, SourceId, Workspace};
99
use crate::ops::{self, Packages};
@@ -109,8 +109,10 @@ pub fn resolve_std<'cfg>(
109109
};
110110
// dev_deps setting shouldn't really matter here.
111111
let opts = ResolveOpts::new(
112-
/*dev_deps*/ false, &features, /*all_features*/ false,
113-
/*uses_default_features*/ false,
112+
/*dev_deps*/ false,
113+
RequestedFeatures::from_command_line(
114+
&features, /*all_features*/ false, /*uses_default_features*/ false,
115+
),
114116
);
115117
let resolve = ops::resolve_ws_with_opts(
116118
&std_ws,

src/cargo/core/package.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,10 @@ impl<'cfg> PackageSet<'cfg> {
434434
self.packages.keys().cloned()
435435
}
436436

437+
pub fn packages<'a>(&'a self) -> impl Iterator<Item = &'a Package> + 'a {
438+
self.packages.values().filter_map(|p| p.borrow())
439+
}
440+
437441
pub fn enable_download<'a>(&'a self) -> CargoResult<Downloads<'a, 'cfg>> {
438442
assert!(!self.downloading.replace(true));
439443
let timeout = ops::HttpTimeout::new(self.config)?;

src/cargo/core/resolver/types.rs

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -147,20 +147,8 @@ impl ResolveOpts {
147147
}
148148
}
149149

150-
pub fn new(
151-
dev_deps: bool,
152-
features: &[String],
153-
all_features: bool,
154-
uses_default_features: bool,
155-
) -> ResolveOpts {
156-
ResolveOpts {
157-
dev_deps,
158-
features: RequestedFeatures::from_command_line(
159-
features,
160-
all_features,
161-
uses_default_features,
162-
),
163-
}
150+
pub fn new(dev_deps: bool, features: RequestedFeatures) -> ResolveOpts {
151+
ResolveOpts { dev_deps, features }
164152
}
165153
}
166154

src/cargo/ops/cargo_compile.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ use crate::core::compiler::{BuildConfig, BuildContext, Compilation, Context};
3333
use crate::core::compiler::{CompileKind, CompileMode, CompileTarget, RustcTargetData, Unit};
3434
use crate::core::compiler::{DefaultExecutor, Executor, UnitInterner};
3535
use crate::core::profiles::{Profiles, UnitFor};
36-
use crate::core::resolver::features::{self, FeaturesFor};
36+
use crate::core::resolver::features::{self, FeaturesFor, RequestedFeatures};
3737
use crate::core::resolver::{HasDevUnits, Resolve, ResolveOpts};
3838
use crate::core::{FeatureValue, Package, PackageSet, Shell, Summary, Target};
3939
use crate::core::{PackageId, PackageIdSpec, TargetKind, Workspace};
@@ -336,7 +336,10 @@ pub fn create_bcx<'a, 'cfg>(
336336

337337
let specs = spec.to_package_id_specs(ws)?;
338338
let dev_deps = ws.require_optional_deps() || filter.need_dev_deps(build_config.mode);
339-
let opts = ResolveOpts::new(dev_deps, features, all_features, !no_default_features);
339+
let opts = ResolveOpts::new(
340+
dev_deps,
341+
RequestedFeatures::from_command_line(features, all_features, !no_default_features),
342+
);
340343
let has_dev_units = if filter.need_dev_deps(build_config.mode) {
341344
HasDevUnits::Yes
342345
} else {

src/cargo/ops/cargo_doc.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::core::compiler::RustcTargetData;
2-
use crate::core::resolver::{HasDevUnits, ResolveOpts};
2+
use crate::core::resolver::{features::RequestedFeatures, HasDevUnits, ResolveOpts};
33
use crate::core::{Shell, Workspace};
44
use crate::ops;
55
use crate::util::CargoResult;
@@ -21,9 +21,11 @@ pub fn doc(ws: &Workspace<'_>, options: &DocOptions) -> CargoResult<()> {
2121
let specs = options.compile_opts.spec.to_package_id_specs(ws)?;
2222
let opts = ResolveOpts::new(
2323
/*dev_deps*/ true,
24-
&options.compile_opts.features,
25-
options.compile_opts.all_features,
26-
!options.compile_opts.no_default_features,
24+
RequestedFeatures::from_command_line(
25+
&options.compile_opts.features,
26+
options.compile_opts.all_features,
27+
!options.compile_opts.no_default_features,
28+
),
2729
);
2830
let target_data = RustcTargetData::new(ws, &options.compile_opts.build_config.requested_kinds)?;
2931
let ws_resolve = ops::resolve_ws_with_opts(

src/cargo/ops/cargo_output_metadata.rs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::core::compiler::{CompileKind, RustcTargetData};
22
use crate::core::dependency::DepKind;
33
use crate::core::package::SerializedPackage;
4-
use crate::core::resolver::{HasDevUnits, Resolve, ResolveOpts};
4+
use crate::core::resolver::{features::RequestedFeatures, HasDevUnits, Resolve, ResolveOpts};
55
use crate::core::{Dependency, Package, PackageId, Workspace};
66
use crate::ops::{self, Packages};
77
use crate::util::interning::InternedString;
@@ -115,28 +115,33 @@ fn build_resolve_graph(
115115
let target_data = RustcTargetData::new(ws, &requested_kinds)?;
116116
// Resolve entire workspace.
117117
let specs = Packages::All.to_package_id_specs(ws)?;
118-
let resolve_opts = ResolveOpts::new(
119-
/*dev_deps*/ true,
118+
let requested_features = RequestedFeatures::from_command_line(
120119
&metadata_opts.features,
121120
metadata_opts.all_features,
122121
!metadata_opts.no_default_features,
123122
);
123+
let resolve_opts = ResolveOpts::new(/*dev_deps*/ true, requested_features.clone());
124+
let force_all = if metadata_opts.filter_platforms.is_empty() {
125+
crate::core::resolver::features::ForceAllTargets::Yes
126+
} else {
127+
crate::core::resolver::features::ForceAllTargets::No
128+
};
129+
130+
// Note that even with --filter-platform we end up downloading host dependencies as well,
131+
// as that is the behavior of download_accessible.
124132
let ws_resolve = ops::resolve_ws_with_opts(
125133
ws,
126134
&target_data,
127135
&requested_kinds,
128136
&resolve_opts,
129137
&specs,
130138
HasDevUnits::Yes,
131-
crate::core::resolver::features::ForceAllTargets::No,
139+
force_all,
132140
)?;
133-
// Download all Packages. This is needed to serialize the information
134-
// for every package. In theory this could honor target filtering,
135-
// but that would be somewhat complex.
141+
136142
let package_map: BTreeMap<PackageId, Package> = ws_resolve
137143
.pkg_set
138-
.get_many(ws_resolve.pkg_set.package_ids())?
139-
.into_iter()
144+
.packages()
140145
// This is a little lazy, but serde doesn't handle Rc fields very well.
141146
.map(|pkg| (pkg.package_id(), Package::clone(pkg)))
142147
.collect();

src/cargo/ops/tree/graph.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,13 @@ fn add_pkg(
351351
true
352352
})
353353
.collect();
354+
355+
// This dependency is eliminated from the dependency tree under
356+
// the current target and feature set.
357+
if deps.is_empty() {
358+
continue;
359+
}
360+
354361
deps.sort_unstable_by_key(|dep| dep.name_in_toml());
355362
let dep_pkg = graph.package_map[&dep_id];
356363

src/cargo/ops/tree/mod.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
use self::format::Pattern;
44
use crate::core::compiler::{CompileKind, RustcTargetData};
55
use crate::core::dependency::DepKind;
6-
use crate::core::resolver::{ForceAllTargets, HasDevUnits, ResolveOpts};
6+
use crate::core::resolver::{
7+
features::RequestedFeatures, ForceAllTargets, HasDevUnits, ResolveOpts,
8+
};
79
use crate::core::{Package, PackageId, PackageIdSpec, Workspace};
810
use crate::ops::{self, Packages};
911
use crate::util::{CargoResult, Config};
@@ -136,12 +138,12 @@ pub fn build_and_print(ws: &Workspace<'_>, opts: &TreeOptions) -> CargoResult<()
136138
let requested_kinds = CompileKind::from_requested_targets(ws.config(), &requested_targets)?;
137139
let target_data = RustcTargetData::new(ws, &requested_kinds)?;
138140
let specs = opts.packages.to_package_id_specs(ws)?;
139-
let resolve_opts = ResolveOpts::new(
140-
/*dev_deps*/ true,
141+
let requested_features = RequestedFeatures::from_command_line(
141142
&opts.features,
142143
opts.all_features,
143144
!opts.no_default_features,
144145
);
146+
let resolve_opts = ResolveOpts::new(/*dev_deps*/ true, requested_features.clone());
145147
let has_dev = if opts
146148
.edge_kinds
147149
.contains(&EdgeKind::Dep(DepKind::Development))
@@ -164,13 +166,10 @@ pub fn build_and_print(ws: &Workspace<'_>, opts: &TreeOptions) -> CargoResult<()
164166
has_dev,
165167
force_all,
166168
)?;
167-
// Download all Packages. Some display formats need to display package metadata.
168-
// This may trigger some unnecessary downloads, but trying to figure out a
169-
// minimal set would be difficult.
169+
170170
let package_map: HashMap<PackageId, &Package> = ws_resolve
171171
.pkg_set
172-
.get_many(ws_resolve.pkg_set.package_ids())?
173-
.into_iter()
172+
.packages()
174173
.map(|pkg| (pkg.package_id(), pkg))
175174
.collect();
176175

tests/testsuite/features2.rs

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2214,29 +2214,19 @@ fn minimal_download() {
22142214
.run();
22152215
clear();
22162216

2217-
// This disables itarget, but leaves decouple_dev_deps enabled. However,
2218-
// `cargo tree` downloads everything anyways. Ideally `cargo tree` should
2219-
// be a little smarter, but that would make it a bit more complicated. The
2220-
// two "Downloading" lines are because `download_accessible` doesn't
2221-
// download enough (`cargo tree` really wants everything). Again, that
2222-
// could be cleaner, but is difficult.
2217+
// This disables itarget, but leaves decouple_dev_deps enabled.
22232218
p.cargo("tree -e normal --target=all -Zfeatures=all")
22242219
.masquerade_as_nightly_cargo()
22252220
.with_stderr_unordered(
22262221
"\
22272222
[DOWNLOADING] crates ...
2228-
[DOWNLOADING] crates ...
22292223
[DOWNLOADED] normal v1.0.0 [..]
2230-
[DOWNLOADED] dev_dep v1.0.0 [..]
22312224
[DOWNLOADED] normal_pm v1.0.0 [..]
22322225
[DOWNLOADED] build_dep v1.0.0 [..]
2233-
[DOWNLOADED] dev_dep_pm v1.0.0 [..]
22342226
[DOWNLOADED] build_dep_pm v1.0.0 [..]
22352227
[DOWNLOADED] itarget_normal v1.0.0 [..]
2236-
[DOWNLOADED] itarget_dev_dep v1.0.0 [..]
22372228
[DOWNLOADED] itarget_normal_pm v1.0.0 [..]
22382229
[DOWNLOADED] itarget_build_dep v1.0.0 [..]
2239-
[DOWNLOADED] itarget_dev_dep_pm v1.0.0 [..]
22402230
[DOWNLOADED] itarget_build_dep_pm v1.0.0 [..]
22412231
",
22422232
)

tests/testsuite/metadata.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
//! Tests for the `cargo metadata` command.
22
3+
use cargo_test_support::install::cargo_home;
4+
use cargo_test_support::paths::CargoPathExt;
35
use cargo_test_support::registry::Package;
46
use cargo_test_support::{basic_bin_manifest, basic_lib_manifest, main_file, project, rustc_host};
57

@@ -2343,8 +2345,27 @@ fn filter_platform() {
23432345
.replace("$ALT_TRIPLE", alt_target)
23442346
.replace("$HOST_TRIPLE", &rustc_host());
23452347

2348+
// We're going to be checking that we don't download excessively,
2349+
// so we need to ensure that downloads will happen.
2350+
let clear = || {
2351+
cargo_home().join("registry/cache").rm_rf();
2352+
cargo_home().join("registry/src").rm_rf();
2353+
p.build_dir().rm_rf();
2354+
};
2355+
23462356
// Normal metadata, no filtering, returns *everything*.
23472357
p.cargo("metadata")
2358+
.with_stderr_unordered(
2359+
"\
2360+
[UPDATING] [..]
2361+
[WARNING] please specify `--format-version` flag explicitly to avoid compatibility problems
2362+
[DOWNLOADING] crates ...
2363+
[DOWNLOADED] normal-dep v0.0.1 [..]
2364+
[DOWNLOADED] host-dep v0.0.1 [..]
2365+
[DOWNLOADED] alt-dep v0.0.1 [..]
2366+
[DOWNLOADED] cfg-dep v0.0.1 [..]
2367+
",
2368+
)
23482369
.with_json(
23492370
&r#"
23502371
{
@@ -2454,10 +2475,20 @@ fn filter_platform() {
24542475
.replace("$FOO", &foo),
24552476
)
24562477
.run();
2478+
clear();
24572479

24582480
// Filter on alternate, removes cfg and host.
24592481
p.cargo("metadata --filter-platform")
24602482
.arg(alt_target)
2483+
.with_stderr_unordered(
2484+
"\
2485+
[WARNING] please specify `--format-version` flag explicitly to avoid compatibility problems
2486+
[DOWNLOADING] crates ...
2487+
[DOWNLOADED] normal-dep v0.0.1 [..]
2488+
[DOWNLOADED] host-dep v0.0.1 [..]
2489+
[DOWNLOADED] alt-dep v0.0.1 [..]
2490+
",
2491+
)
24612492
.with_json(
24622493
&r#"
24632494
{
@@ -2526,10 +2557,19 @@ fn filter_platform() {
25262557
.replace("$FOO", &foo),
25272558
)
25282559
.run();
2560+
clear();
25292561

25302562
// Filter on host, removes alt and cfg.
25312563
p.cargo("metadata --filter-platform")
25322564
.arg(rustc_host())
2565+
.with_stderr_unordered(
2566+
"\
2567+
[WARNING] please specify `--format-version` flag explicitly to avoid compatibility problems
2568+
[DOWNLOADING] crates ...
2569+
[DOWNLOADED] normal-dep v0.0.1 [..]
2570+
[DOWNLOADED] host-dep v0.0.1 [..]
2571+
",
2572+
)
25332573
.with_json(
25342574
&r#"
25352575
{
@@ -2598,11 +2638,21 @@ fn filter_platform() {
25982638
.replace("$FOO", &foo),
25992639
)
26002640
.run();
2641+
clear();
26012642

26022643
// Filter host with cfg, removes alt only
26032644
p.cargo("metadata --filter-platform")
26042645
.arg(rustc_host())
26052646
.env("RUSTFLAGS", "--cfg=foobar")
2647+
.with_stderr_unordered(
2648+
"\
2649+
[WARNING] please specify `--format-version` flag explicitly to avoid compatibility problems
2650+
[DOWNLOADING] crates ...
2651+
[DOWNLOADED] normal-dep v0.0.1 [..]
2652+
[DOWNLOADED] host-dep v0.0.1 [..]
2653+
[DOWNLOADED] cfg-dep v0.0.1 [..]
2654+
",
2655+
)
26062656
.with_json(
26072657
&r#"
26082658
{

0 commit comments

Comments
 (0)