Skip to content

Commit d4c38af

Browse files
committed
Auto merge of #11183 - weihanglo:issue/10526, r=ehuss
artifact deps shoud works when target field specified coexists with `optional = true`
2 parents 92d8826 + 2b913b6 commit d4c38af

File tree

4 files changed

+94
-43
lines changed

4 files changed

+94
-43
lines changed

src/cargo/core/compiler/unit_dependencies.rs

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1040,6 +1040,7 @@ impl<'a, 'cfg> State<'a, 'cfg> {
10401040
}
10411041
}
10421042

1043+
/// See [`ResolvedFeatures::activated_features`].
10431044
fn activated_features(
10441045
&self,
10451046
pkg_id: PackageId,
@@ -1049,14 +1050,9 @@ impl<'a, 'cfg> State<'a, 'cfg> {
10491050
features.activated_features(pkg_id, features_for)
10501051
}
10511052

1052-
fn is_dep_activated(
1053-
&self,
1054-
pkg_id: PackageId,
1055-
features_for: FeaturesFor,
1056-
dep_name: InternedString,
1057-
) -> bool {
1058-
self.features()
1059-
.is_dep_activated(pkg_id, features_for, dep_name)
1053+
/// See [`ResolvedFeatures::is_activated`].
1054+
fn is_activated(&self, pkg_id: PackageId, features_for: FeaturesFor) -> bool {
1055+
self.features().is_activated(pkg_id, features_for)
10601056
}
10611057

10621058
fn get(&self, id: PackageId) -> &'a Package {
@@ -1071,7 +1067,7 @@ impl<'a, 'cfg> State<'a, 'cfg> {
10711067
let kind = unit.kind;
10721068
self.resolve()
10731069
.deps(pkg_id)
1074-
.filter_map(|(id, deps)| {
1070+
.filter_map(|(dep_id, deps)| {
10751071
assert!(!deps.is_empty());
10761072
let deps: Vec<_> = deps
10771073
.iter()
@@ -1103,8 +1099,8 @@ impl<'a, 'cfg> State<'a, 'cfg> {
11031099
// If this is an optional dependency, and the new feature resolver
11041100
// did not enable it, don't include it.
11051101
if dep.is_optional() {
1106-
let features_for = unit_for.map_to_features_for(dep.artifact());
1107-
if !self.is_dep_activated(pkg_id, features_for, dep.name_in_toml()) {
1102+
let dep_features_for = unit_for.map_to_features_for(dep.artifact());
1103+
if !self.is_activated(dep_id, dep_features_for) {
11081104
return false;
11091105
}
11101106
}
@@ -1117,7 +1113,7 @@ impl<'a, 'cfg> State<'a, 'cfg> {
11171113
if deps.is_empty() {
11181114
None
11191115
} else {
1120-
Some((id, deps))
1116+
Some((dep_id, deps))
11211117
}
11221118
})
11231119
.collect()

src/cargo/core/resolver/features.rs

Lines changed: 28 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,12 @@ type ActivateMap = HashMap<PackageFeaturesKey, BTreeSet<InternedString>>;
5656

5757
/// Set of all activated features for all packages in the resolve graph.
5858
pub struct ResolvedFeatures {
59-
activated_features: ActivateMap,
60-
/// Optional dependencies that should be built.
59+
/// Map of features activated for each package.
6160
///
62-
/// The value is the `name_in_toml` of the dependencies.
63-
activated_dependencies: ActivateMap,
61+
/// The presence of each key also means the package itself is activated,
62+
/// even its associated set contains no features.
63+
activated_features: ActivateMap,
64+
/// Options that change how the feature resolver operates.
6465
opts: FeatureOpts,
6566
}
6667

@@ -321,21 +322,14 @@ impl ResolvedFeatures {
321322
.expect("activated_features for invalid package")
322323
}
323324

324-
/// Returns if the given dependency should be included.
325+
/// Asks the resolved features if the given package should be included.
325326
///
326-
/// This handles dependencies disabled via `cfg` expressions and optional
327-
/// dependencies which are not enabled.
328-
pub fn is_dep_activated(
329-
&self,
330-
pkg_id: PackageId,
331-
features_for: FeaturesFor,
332-
dep_name: InternedString,
333-
) -> bool {
334-
let key = features_for.apply_opts(&self.opts);
335-
self.activated_dependencies
336-
.get(&(pkg_id, key))
337-
.map(|deps| deps.contains(&dep_name))
338-
.unwrap_or(false)
327+
/// One scenario to use this function is to deteremine a optional dependency
328+
/// should be built or not.
329+
pub fn is_activated(&self, pkg_id: PackageId, features_for: FeaturesFor) -> bool {
330+
log::trace!("is_activated {} {features_for}", pkg_id.name());
331+
self.activated_features_unverified(pkg_id, features_for.apply_opts(&self.opts))
332+
.is_some()
339333
}
340334

341335
/// Variant of `activated_features` that returns `None` if this is
@@ -415,8 +409,14 @@ pub struct FeatureResolver<'a, 'cfg> {
415409
/// Options that change how the feature resolver operates.
416410
opts: FeatureOpts,
417411
/// Map of features activated for each package.
412+
///
413+
/// The presence of each key also means the package itself is activated,
414+
/// even its associated set contains no features.
418415
activated_features: ActivateMap,
419416
/// Map of optional dependencies activated for each package.
417+
///
418+
/// The key is the package having their dependencies activated.
419+
/// The value comes from `dep_name` part of the feature syntax `dep:dep_name`.
420420
activated_dependencies: ActivateMap,
421421
/// Keeps track of which packages have had its dependencies processed.
422422
/// Used to avoid cycles, and to speed up processing.
@@ -475,7 +475,6 @@ impl<'a, 'cfg> FeatureResolver<'a, 'cfg> {
475475
}
476476
Ok(ResolvedFeatures {
477477
activated_features: r.activated_features,
478-
activated_dependencies: r.activated_dependencies,
479478
opts: r.opts,
480479
})
481480
}
@@ -507,20 +506,24 @@ impl<'a, 'cfg> FeatureResolver<'a, 'cfg> {
507506
Ok(())
508507
}
509508

510-
/// Activates [`FeatureValue`]s on the given package.
509+
/// Activates a list of [`FeatureValue`] for a given package.
511510
///
512-
/// This is the main entrance into the recursion of feature activation
513-
/// for a package.
511+
/// This is the main entrance into the recursion of feature activation for a package.
512+
/// Other `activate_*` functions would be called inside this function accordingly.
514513
fn activate_pkg(
515514
&mut self,
516515
pkg_id: PackageId,
517516
fk: FeaturesFor,
518517
fvs: &[FeatureValue],
519518
) -> CargoResult<()> {
520519
log::trace!("activate_pkg {} {}", pkg_id.name(), fk);
521-
// Add an empty entry to ensure everything is covered. This is intended for
522-
// finding bugs where the resolver missed something it should have visited.
523-
// Remove this in the future if `activated_features` uses an empty default.
520+
// Cargo must insert an empty set here as the presence of an (empty) set
521+
// also means that the dependency is activated.
522+
// This `is_activated` behavior for dependencies was previously depends on field
523+
// `activated_dependencies`, which is less useful after rust-lang/cargo#11183.
524+
//
525+
// That is, we may keep or remove `activated_dependencies` in the future
526+
// if figuring out it can completely be replaced with `activated_features`.
524527
self.activated_features
525528
.entry((pkg_id, fk.apply_opts(&self.opts)))
526529
.or_insert_with(BTreeSet::new);

src/cargo/ops/tree/graph.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -365,11 +365,7 @@ fn add_pkg(
365365
if dep.is_optional() {
366366
// If the new feature resolver does not enable this
367367
// optional dep, then don't use it.
368-
if !resolved_features.is_dep_activated(
369-
package_id,
370-
features_for,
371-
dep.name_in_toml(),
372-
) {
368+
if !resolved_features.is_activated(dep_id, features_for) {
373369
return false;
374370
}
375371
}

tests/testsuite/artifact_dep.rs

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ fn check_with_invalid_artifact_dependency() {
2020
version = "0.0.0"
2121
authors = []
2222
resolver = "2"
23-
23+
2424
[dependencies]
2525
bar = { path = "bar/", artifact = "unknown" }
2626
"#,
@@ -2275,3 +2275,59 @@ fn build_script_features_for_shared_dependency() {
22752275
.masquerade_as_nightly_cargo(&["bindeps"])
22762276
.run();
22772277
}
2278+
2279+
#[cargo_test]
2280+
fn build_with_target_and_optional() {
2281+
// This is a incorrect behaviour got to be fixed.
2282+
// See rust-lang/cargo#10526
2283+
if cross_compile::disabled() {
2284+
return;
2285+
}
2286+
let target = cross_compile::alternate();
2287+
let p = project()
2288+
.file(
2289+
"Cargo.toml",
2290+
&r#"
2291+
[package]
2292+
name = "foo"
2293+
version = "0.0.1"
2294+
edition = "2021"
2295+
2296+
[dependencies]
2297+
d1 = { path = "d1", artifact = "bin", optional = true, target = "$TARGET" }
2298+
"#
2299+
.replace("$TARGET", target),
2300+
)
2301+
.file(
2302+
"src/main.rs",
2303+
r#"
2304+
fn main() {
2305+
let _b = include_bytes!(env!("CARGO_BIN_FILE_D1"));
2306+
}
2307+
"#,
2308+
)
2309+
.file(
2310+
"d1/Cargo.toml",
2311+
r#"
2312+
[package]
2313+
name = "d1"
2314+
version = "0.0.1"
2315+
edition = "2021"
2316+
"#,
2317+
)
2318+
.file("d1/src/main.rs", "fn main() {}")
2319+
.build();
2320+
2321+
p.cargo("build -Z bindeps -F d1 -v")
2322+
.masquerade_as_nightly_cargo(&["bindeps"])
2323+
.with_stderr(
2324+
"\
2325+
[COMPILING] d1 v0.0.1 [..]
2326+
[RUNNING] `rustc --crate-name d1 [..]--crate-type bin[..]
2327+
[COMPILING] foo v0.0.1 [..]
2328+
[RUNNING] `rustc --crate-name foo [..]--cfg[..]d1[..]
2329+
[FINISHED] dev [..]
2330+
",
2331+
)
2332+
.run();
2333+
}

0 commit comments

Comments
 (0)