Skip to content

Commit 1e2f8db

Browse files
committed
Auto merge of #8020 - xiongmao86:issue7853, r=ehuss
Checking for binary that is built as an implicit dependency of an integration test. When a project containing binary with required-features, the binary will only be built with the given dependency's feature is enabled. But this feature syntax is not checked when the binary is built as an implicit dependency of an integration test. This pr addresses this issue. More info is in the issue page: this pr fixes #7853.
2 parents 3342792 + 8b17895 commit 1e2f8db

File tree

4 files changed

+48
-17
lines changed

4 files changed

+48
-17
lines changed

src/cargo/core/compiler/unit_dependencies.rs

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use crate::core::profiles::{Profile, UnitFor};
2323
use crate::core::resolver::features::{FeaturesFor, ResolvedFeatures};
2424
use crate::core::resolver::Resolve;
2525
use crate::core::{InternedString, Package, PackageId, Target};
26+
use crate::ops::resolve_all_features;
2627
use crate::CargoResult;
2728
use log::trace;
2829
use std::collections::{HashMap, HashSet};
@@ -309,13 +310,20 @@ fn compute_deps<'a, 'cfg>(
309310
.targets()
310311
.iter()
311312
.filter(|t| {
312-
let no_required_features = Vec::new();
313-
314-
t.is_bin() &&
315-
// Skip binaries with required features that have not been selected.
316-
t.required_features().unwrap_or(&no_required_features).iter().all(|f| {
317-
unit.features.contains(&InternedString::new(f.as_str()))
318-
})
313+
// Skip binaries with required features that have not been selected.
314+
match t.required_features() {
315+
Some(rf) if t.is_bin() => {
316+
let features = resolve_all_features(
317+
state.resolve(),
318+
state.features(),
319+
bcx.packages,
320+
id,
321+
);
322+
rf.iter().all(|f| features.contains(f))
323+
}
324+
None if t.is_bin() => true,
325+
_ => false,
326+
}
319327
})
320328
.map(|t| {
321329
new_unit_dep(
@@ -692,16 +700,20 @@ impl<'a, 'cfg> State<'a, 'cfg> {
692700
}
693701
}
694702

703+
fn features(&self) -> &'a ResolvedFeatures {
704+
if self.is_std {
705+
self.std_features.unwrap()
706+
} else {
707+
self.usr_features
708+
}
709+
}
710+
695711
fn activated_features(
696712
&self,
697713
pkg_id: PackageId,
698714
features_for: FeaturesFor,
699715
) -> Vec<InternedString> {
700-
let features = if self.is_std {
701-
self.std_features.unwrap()
702-
} else {
703-
self.usr_features
704-
};
716+
let features = self.features();
705717
features.activated_features(pkg_id, features_for)
706718
}
707719

src/cargo/ops/cargo_compile.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -949,7 +949,7 @@ fn generate_targets<'a>(
949949
///
950950
/// Dependencies are added as `dep_name/feat_name` because `required-features`
951951
/// wants to support that syntax.
952-
fn resolve_all_features(
952+
pub fn resolve_all_features(
953953
resolve_with_overrides: &Resolve,
954954
resolved_features: &features::ResolvedFeatures,
955955
package_set: &PackageSet<'_>,

src/cargo/ops/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
pub use self::cargo_clean::{clean, CleanOptions};
2-
pub use self::cargo_compile::{compile, compile_with_exec, compile_ws, CompileOptions};
2+
pub use self::cargo_compile::{
3+
compile, compile_with_exec, compile_ws, resolve_all_features, CompileOptions,
4+
};
35
pub use self::cargo_compile::{CompileFilter, FilterRule, LibRule, Packages};
46
pub use self::cargo_doc::{doc, DocOptions};
57
pub use self::cargo_fetch::{fetch, FetchOptions};

tests/testsuite/required_features.rs

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use cargo_test_support::install::{
44
assert_has_installed_exe, assert_has_not_installed_exe, cargo_home,
55
};
66
use cargo_test_support::is_nightly;
7+
use cargo_test_support::paths::CargoPathExt;
78
use cargo_test_support::project;
89

910
#[cargo_test]
@@ -910,7 +911,17 @@ fn dep_feature_in_cmd_line() {
910911
)
911912
.file("src/main.rs", "fn main() {}")
912913
.file("examples/foo.rs", "fn main() {}")
913-
.file("tests/foo.rs", "#[test]\nfn test() {}")
914+
.file(
915+
"tests/foo.rs",
916+
r#"
917+
#[test]
918+
fn bin_is_built() {
919+
let s = format!("target/debug/foo{}", std::env::consts::EXE_SUFFIX);
920+
let p = std::path::Path::new(&s);
921+
assert!(p.exists(), "foo does not exist");
922+
}
923+
"#,
924+
)
914925
.file(
915926
"benches/foo.rs",
916927
r#"
@@ -936,7 +947,9 @@ fn dep_feature_in_cmd_line() {
936947
.file("bar/src/lib.rs", "")
937948
.build();
938949

939-
p.cargo("build").run();
950+
// This is a no-op
951+
p.cargo("build").with_stderr("[FINISHED] dev [..]").run();
952+
assert!(!p.bin("foo").is_file());
940953

941954
// bin
942955
p.cargo("build --bin=foo")
@@ -967,19 +980,23 @@ Consider enabling them by passing, e.g., `--features=\"bar/a\"`
967980
assert!(p.bin("examples/foo").is_file());
968981

969982
// test
983+
// This is a no-op, since no tests are enabled
970984
p.cargo("test")
971985
.with_stderr("[FINISHED] test [unoptimized + debuginfo] target(s) in [..]")
972986
.with_stdout("")
973987
.run();
974988

989+
// Delete the target directory so this can check if the main.rs gets built.
990+
p.build_dir().rm_rf();
975991
p.cargo("test --test=foo --features bar/a")
976992
.with_stderr(
977993
"\
994+
[COMPILING] bar v0.0.1 ([CWD]/bar)
978995
[COMPILING] foo v0.0.1 ([CWD])
979996
[FINISHED] test [unoptimized + debuginfo] target(s) in [..]
980997
[RUNNING] target/debug/deps/foo-[..][EXE]",
981998
)
982-
.with_stdout_contains("test test ... ok")
999+
.with_stdout_contains("test bin_is_built ... ok")
9831000
.run();
9841001

9851002
// bench

0 commit comments

Comments
 (0)