From c8da40f8bdb243f1ad85eaa0076e0f699e044877 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Fri, 3 Dec 2021 10:45:59 +0000 Subject: [PATCH 1/4] Implement depend-defaults --- include/vcpkg/dependencies.h | 9 +- include/vcpkg/packagespec.h | 10 ++ include/vcpkg/sourceparagraph.h | 1 + src/vcpkg-test/dependencies.cpp | 275 ++++++++++++++++++++++---------- src/vcpkg-test/manifests.cpp | 31 ++-- src/vcpkg-test/plan.cpp | 62 ++++++- src/vcpkg/dependencies.cpp | 53 +++--- src/vcpkg/install.cpp | 20 +-- src/vcpkg/packagespec.cpp | 23 +++ src/vcpkg/sourceparagraph.cpp | 13 +- 10 files changed, 367 insertions(+), 130 deletions(-) diff --git a/include/vcpkg/dependencies.h b/include/vcpkg/dependencies.h index 70b2e91774..2fcf3aa0f5 100644 --- a/include/vcpkg/dependencies.h +++ b/include/vcpkg/dependencies.h @@ -203,6 +203,12 @@ namespace vcpkg::Dependencies std::vector features, CMakeVars::CMakeVarProvider& var_provider); + enum class DependDefaults + { + NO, + YES, + }; + ExpectedS create_versioned_install_plan(const PortFileProvider::IVersionedPortfileProvider& vprovider, const PortFileProvider::IBaselineProvider& bprovider, const PortFileProvider::IOverlayProvider& oprovider, @@ -211,7 +217,8 @@ namespace vcpkg::Dependencies const std::vector& overrides, const PackageSpec& toplevel, Triplet host_triplet, - UnsupportedPortAction unsupported_port_action); + UnsupportedPortAction unsupported_port_action, + DependDefaults depend_defaults); void print_plan(const ActionPlan& action_plan, const bool is_recursive = true, const Path& builtin_ports_dir = {}); } diff --git a/include/vcpkg/packagespec.h b/include/vcpkg/packagespec.h index 8929e2cedd..bd2b14e338 100644 --- a/include/vcpkg/packagespec.h +++ b/include/vcpkg/packagespec.h @@ -112,6 +112,14 @@ namespace vcpkg std::vector to_feature_specs(const std::vector& default_features, const std::vector& all_features) const; + void to_feature_specs(std::vector& out, + const std::vector& default_features, + const std::vector& all_features) const; + + /// Splats out individual FeatureSpec's into out. If "core" is missing, adds "core". + /// @param with_defaults also add "default" if "core" is missing + void expand_to(std::vector& out, bool with_defaults) const; + static ExpectedS from_string(const std::string& spec_as_string, Triplet default_triplet); bool operator==(const FullPackageSpec& o) const @@ -157,6 +165,8 @@ namespace vcpkg Json::Object extra_info; + FullPackageSpec to_full_spec(Triplet target, Triplet host) const; + friend bool operator==(const Dependency& lhs, const Dependency& rhs); friend bool operator!=(const Dependency& lhs, const Dependency& rhs) { return !(lhs == rhs); } }; diff --git a/include/vcpkg/sourceparagraph.h b/include/vcpkg/sourceparagraph.h index 8eb41dbf8b..18d4df389f 100644 --- a/include/vcpkg/sourceparagraph.h +++ b/include/vcpkg/sourceparagraph.h @@ -62,6 +62,7 @@ namespace vcpkg Versions::Scheme version_scheme = Versions::Scheme::String; std::string version; int port_version = 0; + bool depend_defaults = true; std::vector description; std::vector summary; std::vector maintainers; diff --git a/src/vcpkg-test/dependencies.cpp b/src/vcpkg-test/dependencies.cpp index e36e9b1cb3..7785897c3d 100644 --- a/src/vcpkg-test/dependencies.cpp +++ b/src/vcpkg-test/dependencies.cpp @@ -85,6 +85,7 @@ struct MockVersionedPortfileProvider : PortFileProvider::IVersionedPortfileProvi } }; +using Dependencies::DependDefaults; using Versions::Constraint; using Versions::Scheme; @@ -99,16 +100,16 @@ T unwrap(ExpectedS e) return std::move(*e.get()); } -static void check_name_and_version(const Dependencies::InstallPlanAction& ipa, - StringLiteral name, - Versions::Version v, - std::initializer_list features = {}) +static void check_name_and_features(const Dependencies::InstallPlanAction& ipa, + StringLiteral name, + std::initializer_list features) { CHECK(ipa.spec.name() == name); CHECK(ipa.source_control_file_and_location.has_value()); - CHECK(ipa.feature_list.size() == features.size() + 1); { INFO("ipa.feature_list = [" << Strings::join(", ", ipa.feature_list) << "]"); + INFO("features = [" << Strings::join(", ", features) << "]"); + CHECK(ipa.feature_list.size() == features.size() + 1); for (auto&& f : features) { INFO("f = \"" << f.c_str() << "\""); @@ -116,6 +117,14 @@ static void check_name_and_version(const Dependencies::InstallPlanAction& ipa, } CHECK(Util::find(ipa.feature_list, "core") != ipa.feature_list.end()); } +} + +static void check_name_and_version(const Dependencies::InstallPlanAction& ipa, + StringLiteral name, + Versions::Version v, + std::initializer_list features = {}) +{ + check_name_and_features(ipa, name, features); if (auto scfl = ipa.source_control_file_and_location.get()) { CHECK(scfl->source_control_file->core_paragraph->version == v.text()); @@ -201,6 +210,8 @@ struct MockOverlayProvider : PortFileProvider::IOverlayProvider return it->second; } + SourceControlFileAndLocation& emplace(const std::string& name) { return emplace(name, {"1", 0}); } + virtual void load_all_control_files(std::map&) const override { Checks::unreachable(VCPKG_LINE_INFO); @@ -228,30 +239,51 @@ static ExpectedS create_versioned_install_plan( overrides, toplevel, Test::ARM_UWP, - Dependencies::UnsupportedPortAction::Error); + Dependencies::UnsupportedPortAction::Error, + DependDefaults::YES); } -namespace vcpkg::Dependencies +static ExpectedS create_versioned_install_plan( + const PortFileProvider::IVersionedPortfileProvider& provider, + const PortFileProvider::IBaselineProvider& bprovider, + const PortFileProvider::IOverlayProvider& oprovider, + const CMakeVars::CMakeVarProvider& var_provider, + const std::vector& deps, + const std::vector& overrides, + const PackageSpec& toplevel) { - static ExpectedS create_versioned_install_plan( - const PortFileProvider::IVersionedPortfileProvider& provider, - const PortFileProvider::IBaselineProvider& bprovider, - const PortFileProvider::IOverlayProvider& oprovider, - const CMakeVars::CMakeVarProvider& var_provider, - const std::vector& deps, - const std::vector& overrides, - const PackageSpec& toplevel) - { - return vcpkg::Dependencies::create_versioned_install_plan(provider, - bprovider, - oprovider, - var_provider, - deps, - overrides, - toplevel, - Test::ARM_UWP, - Dependencies::UnsupportedPortAction::Error); - } + return vcpkg::Dependencies::create_versioned_install_plan(provider, + bprovider, + oprovider, + var_provider, + deps, + overrides, + toplevel, + Test::ARM_UWP, + Dependencies::UnsupportedPortAction::Error, + Dependencies::DependDefaults::YES); +} + +static ExpectedS create_versioned_install_plan( + const PortFileProvider::IOverlayProvider& oprovider, + const std::vector& deps, + const PackageSpec& toplevel, + DependDefaults depend_defaults) +{ + MockVersionedPortfileProvider vp; + MockCMakeVarProvider var_provider; + MockBaselineProvider bp; + + return vcpkg::Dependencies::create_versioned_install_plan(vp, + bp, + oprovider, + var_provider, + deps, + {}, + toplevel, + Test::ARM_UWP, + Dependencies::UnsupportedPortAction::Error, + depend_defaults); } TEST_CASE ("basic version install single", "[versionplan]") @@ -1487,6 +1519,83 @@ TEST_CASE ("version install default features", "[versionplan]") check_name_and_version(install_plan.install_actions[0], "a", {"1", 0}, {"x"}); } +TEST_CASE ("version install depend-defaults", "[versionplan]") +{ + MockOverlayProvider op; + auto& a_scf = op.emplace("a"); + a_scf.source_control_file->core_paragraph->dependencies.push_back(Dependency{"b"}); + auto& b_scf = op.emplace("b"); + b_scf.source_control_file->core_paragraph->default_features.emplace_back("0"); + b_scf.source_control_file->feature_paragraphs.emplace_back(make_fpgh("0")); + auto& c_scf = op.emplace("c"); + auto& c0 = c_scf.source_control_file->feature_paragraphs.emplace_back(make_fpgh("0")); + c0->dependencies.push_back(Dependency{"b"}); + + auto& d_scf = op.emplace("d"); + d_scf.source_control_file->core_paragraph->dependencies.push_back(Dependency{"b", {"core"}}); + + auto& e_scf = op.emplace("e"); + e_scf.source_control_file->core_paragraph->dependencies.push_back(Dependency{"b"}); + e_scf.source_control_file->core_paragraph->depend_defaults = false; + + SECTION ("toplevel depend-defaults true") + { + auto install_plan = + unwrap(create_versioned_install_plan(op, {Dependency{"b"}}, toplevel_spec(), DependDefaults::YES)); + REQUIRE(install_plan.size() == 1); + check_name_and_features(install_plan.install_actions[0], "b", {"0"}); + } + + SECTION ("toplevel depend-defaults false") + { + auto install_plan = + unwrap(create_versioned_install_plan(op, {Dependency{"b"}}, toplevel_spec(), DependDefaults::NO)); + REQUIRE(install_plan.size() == 1); + check_name_and_features(install_plan.install_actions[0], "b", {}); + + // a -> b[default], so depend-defaults should not suppress it + install_plan = + unwrap(create_versioned_install_plan(op, {Dependency{"a"}}, toplevel_spec(), DependDefaults::NO)); + REQUIRE(install_plan.size() == 2); + check_name_and_features(install_plan.install_actions[0], "b", {"0"}); + } + + SECTION ("toplevel depend-defaults true (transitive)") + { + auto install_plan = + unwrap(create_versioned_install_plan(op, {Dependency{"d"}}, toplevel_spec(), DependDefaults::YES)); + REQUIRE(install_plan.size() == 2); + check_name_and_features(install_plan.install_actions[0], "b", {"0"}); + } + + SECTION ("toplevel depend-defaults false (transitive)") + { + auto install_plan = + unwrap(create_versioned_install_plan(op, {Dependency{"d"}}, toplevel_spec(), DependDefaults::NO)); + REQUIRE(install_plan.size() == 2); + check_name_and_features(install_plan.install_actions[0], "b", {}); + } + + SECTION ("transitive depend-defaults false") + { + SECTION ("toplevel false") + { + auto install_plan = + unwrap(create_versioned_install_plan(op, {Dependency{"e"}}, toplevel_spec(), DependDefaults::NO)); + REQUIRE(install_plan.size() == 2); + check_name_and_features(install_plan.install_actions[0], "b", {}); + } + + SECTION ("toplevel core") + { + auto install_plan = unwrap(create_versioned_install_plan( + op, {Dependency{"e"}, Dependency{"b", {"core"}}}, toplevel_spec(), DependDefaults::YES)); + REQUIRE(install_plan.size() == 2); + check_name_and_features(install_plan.install_actions[0], "b", {}); + } + } +} + TEST_CASE ("version dont install default features", "[versionplan]") { MockVersionedPortfileProvider vp; @@ -1932,8 +2041,8 @@ TEST_CASE ("version overlay ports", "[versionplan]") { const MockBaselineProvider empty_bp; - auto install_plan = unwrap(Dependencies::create_versioned_install_plan( - vp, empty_bp, oprovider, var_provider, {{"a"}}, {}, toplevel_spec())); + auto install_plan = + unwrap(create_versioned_install_plan(vp, empty_bp, oprovider, var_provider, {{"a"}}, {}, toplevel_spec())); REQUIRE(install_plan.size() == 1); check_name_and_version(install_plan.install_actions[0], "a", {"overlay", 0}); @@ -1941,8 +2050,8 @@ TEST_CASE ("version overlay ports", "[versionplan]") SECTION ("transitive") { - auto install_plan = unwrap( - Dependencies::create_versioned_install_plan(vp, bp, oprovider, var_provider, {{"b"}}, {}, toplevel_spec())); + auto install_plan = + unwrap(create_versioned_install_plan(vp, bp, oprovider, var_provider, {{"b"}}, {}, toplevel_spec())); REQUIRE(install_plan.size() == 2); check_name_and_version(install_plan.install_actions[0], "a", {"overlay", 0}); @@ -1951,8 +2060,8 @@ TEST_CASE ("version overlay ports", "[versionplan]") SECTION ("transitive constraint") { - auto install_plan = unwrap( - Dependencies::create_versioned_install_plan(vp, bp, oprovider, var_provider, {{"c"}}, {}, toplevel_spec())); + auto install_plan = + unwrap(create_versioned_install_plan(vp, bp, oprovider, var_provider, {{"c"}}, {}, toplevel_spec())); REQUIRE(install_plan.size() == 2); check_name_and_version(install_plan.install_actions[0], "a", {"overlay", 0}); @@ -1961,59 +2070,59 @@ TEST_CASE ("version overlay ports", "[versionplan]") SECTION ("none") { - auto install_plan = unwrap( - Dependencies::create_versioned_install_plan(vp, bp, oprovider, var_provider, {{"a"}}, {}, toplevel_spec())); + auto install_plan = + unwrap(create_versioned_install_plan(vp, bp, oprovider, var_provider, {{"a"}}, {}, toplevel_spec())); REQUIRE(install_plan.size() == 1); check_name_and_version(install_plan.install_actions[0], "a", {"overlay", 0}); } SECTION ("constraint") { - auto install_plan = unwrap(Dependencies::create_versioned_install_plan( - vp, - bp, - oprovider, - var_provider, - { - Dependency{"a", {}, {}, {Constraint::Type::Minimum, "1", 1}}, - }, - {}, - toplevel_spec())); + auto install_plan = + unwrap(create_versioned_install_plan(vp, + bp, + oprovider, + var_provider, + { + Dependency{"a", {}, {}, {Constraint::Type::Minimum, "1", 1}}, + }, + {}, + toplevel_spec())); REQUIRE(install_plan.size() == 1); check_name_and_version(install_plan.install_actions[0], "a", {"overlay", 0}); } SECTION ("constraint+override") { - auto install_plan = unwrap(Dependencies::create_versioned_install_plan( - vp, - bp, - oprovider, - var_provider, - { - Dependency{"a", {}, {}, {Constraint::Type::Minimum, "1", 1}}, - }, - { - DependencyOverride{"a", "2", 0}, - }, - toplevel_spec())); + auto install_plan = + unwrap(create_versioned_install_plan(vp, + bp, + oprovider, + var_provider, + { + Dependency{"a", {}, {}, {Constraint::Type::Minimum, "1", 1}}, + }, + { + DependencyOverride{"a", "2", 0}, + }, + toplevel_spec())); REQUIRE(install_plan.size() == 1); check_name_and_version(install_plan.install_actions[0], "a", {"overlay", 0}); } SECTION ("override") { - auto install_plan = unwrap(Dependencies::create_versioned_install_plan(vp, - bp, - oprovider, - var_provider, - { - Dependency{"a"}, - }, - { - DependencyOverride{"a", "2", 0}, - }, - toplevel_spec())); + auto install_plan = unwrap(create_versioned_install_plan(vp, + bp, + oprovider, + var_provider, + { + Dependency{"a"}, + }, + { + DependencyOverride{"a", "2", 0}, + }, + toplevel_spec())); REQUIRE(install_plan.size() == 1); check_name_and_version(install_plan.install_actions[0], "a", {"overlay", 0}); @@ -2042,12 +2151,12 @@ TEST_CASE ("respect supports expression", "[versionplan]") { // override from non supported to supported version MockOverlayProvider oprovider; - install_plan = Dependencies::create_versioned_install_plan( + install_plan = create_versioned_install_plan( vp, bp, oprovider, var_provider, {Dependency{"a"}}, {DependencyOverride{"a", "1", 1}}, toplevel_spec()); CHECK(install_plan.has_value()); // override from supported to non supported version bp.v["a"] = {"1", 1}; - install_plan = Dependencies::create_versioned_install_plan( + install_plan = create_versioned_install_plan( vp, bp, oprovider, var_provider, {Dependency{"a"}}, {DependencyOverride{"a", "1", 0}}, toplevel_spec()); CHECK_FALSE(install_plan.has_value()); } @@ -2080,23 +2189,23 @@ TEST_CASE ("respect supports expressions of features", "[versionplan]") { // override from non supported to supported version MockOverlayProvider oprovider; - install_plan = Dependencies::create_versioned_install_plan(vp, - bp, - oprovider, - var_provider, - {Dependency{"a", {"x"}}}, - {DependencyOverride{"a", "1", 1}}, - toplevel_spec()); + install_plan = create_versioned_install_plan(vp, + bp, + oprovider, + var_provider, + {Dependency{"a", {"x"}}}, + {DependencyOverride{"a", "1", 1}}, + toplevel_spec()); CHECK(install_plan.has_value()); // override from supported to non supported version bp.v["a"] = {"1", 1}; - install_plan = Dependencies::create_versioned_install_plan(vp, - bp, - oprovider, - var_provider, - {Dependency{"a", {"x"}}}, - {DependencyOverride{"a", "1", 0}}, - toplevel_spec()); + install_plan = create_versioned_install_plan(vp, + bp, + oprovider, + var_provider, + {Dependency{"a", {"x"}}}, + {DependencyOverride{"a", "1", 0}}, + toplevel_spec()); CHECK_FALSE(install_plan.has_value()); } } diff --git a/src/vcpkg-test/manifests.cpp b/src/vcpkg-test/manifests.cpp index e5da304be6..1ee3c7d17e 100644 --- a/src/vcpkg-test/manifests.cpp +++ b/src/vcpkg-test/manifests.cpp @@ -59,6 +59,7 @@ TEST_CASE ("manifest construct minimum", "[manifests]") REQUIRE(pgh.core_paragraph->name == "zlib"); REQUIRE(pgh.core_paragraph->version == "1.2.8"); + REQUIRE(pgh.core_paragraph->depend_defaults == true); REQUIRE(pgh.core_paragraph->maintainers.empty()); REQUIRE(pgh.core_paragraph->contacts.is_empty()); REQUIRE(pgh.core_paragraph->summary.empty()); @@ -716,31 +717,32 @@ TEST_CASE ("manifest construct maximum", "[manifests]") "summary": "d", "description": "d", "builtin-baseline": "123", + "depend-defaults": false, "dependencies": ["bd"], "default-features": ["df"], "features": { "iroh" : { "$comment": "hello", - "description": "zuko's uncle", - "dependencies": [ - "firebending", - { - "name": "order.white-lotus", - "features": [ "the-ancient-ways" ], - "platform": "!(windows & arm)" + "description": "zuko's uncle", + "dependencies": [ + "firebending", + { + "name": "order.white-lotus", + "features": [ "the-ancient-ways" ], + "platform": "!(windows & arm)" }, { "$extra": [], "$my": [], "name": "tea" - } - ] - }, - "zuko": { - "description": ["son of the fire lord", "firebending 師父"], - "supports": "!(windows & arm)" - } + } + ] + }, + "zuko": { + "description": ["son of the fire lord", "firebending 師父"], + "supports": "!(windows & arm)" } + } })json"; auto object = parse_json_object(raw); auto res = SourceControlFile::parse_manifest_object("", object); @@ -766,6 +768,7 @@ TEST_CASE ("manifest construct maximum", "[manifests]") REQUIRE(contact_a_aa->string() == "aa"); REQUIRE(pgh.core_paragraph->summary.size() == 1); REQUIRE(pgh.core_paragraph->summary[0] == "d"); + REQUIRE(pgh.core_paragraph->depend_defaults == false); REQUIRE(pgh.core_paragraph->description.size() == 1); REQUIRE(pgh.core_paragraph->description[0] == "d"); REQUIRE(pgh.core_paragraph->dependencies.size() == 1); diff --git a/src/vcpkg-test/plan.cpp b/src/vcpkg-test/plan.cpp index b9fd772a42..a4e006c15c 100644 --- a/src/vcpkg-test/plan.cpp +++ b/src/vcpkg-test/plan.cpp @@ -791,8 +791,8 @@ TEST_CASE ("install with default features", "[plan]") FullPackageSpec{b_spec, {"core"}}, }; - auto install_plan = Dependencies::create_feature_install_plan( - map_port, var_provider, full_package_specs, StatusParagraphs(std::move(status_db))); + auto install_plan = + Dependencies::create_feature_install_plan(map_port, var_provider, full_package_specs, status_db); // Install "a" and indicate that "b" should not install default features REQUIRE(install_plan.size() == 3); @@ -801,6 +801,64 @@ TEST_CASE ("install with default features", "[plan]") features_check(install_plan.install_actions.at(1), "a", {"0", "core"}); } +TEST_CASE ("install with depend-defaults false", "[plan]") +{ + StatusParagraphs status_db; + + PackageSpecMap spec_map; + auto a_spec = spec_map.emplace("a", "b"); + auto b_spec = spec_map.emplace("b", "", {{"0", ""}}, {"0"}); + auto c_spec = spec_map.emplace("c", "", {{"0", "b"}}, {"0"}); + + PortFileProvider::MapPortFileProvider map_port{spec_map.map}; + MockCMakeVarProvider var_provider; + + std::vector full_package_specs{ + FullPackageSpec{a_spec}, + FullPackageSpec{b_spec, {"core"}}, + }; + + std::vector full_package_specs2{ + FullPackageSpec{c_spec}, + FullPackageSpec{b_spec, {"core"}}, + }; + + // Install "a" and then "b" _should_ install default features + SECTION ("depend-defaults true from core") + { + auto install_plan = Dependencies::create_feature_install_plan(map_port, var_provider, full_package_specs, {}); + REQUIRE(install_plan.size() == 2); + features_check(install_plan.install_actions.at(0), "b", {"0", "core"}); + features_check(install_plan.install_actions.at(1), "a", {"core"}); + } + + SECTION ("depend-defaults true from feature") + { + auto install_plan = Dependencies::create_feature_install_plan(map_port, var_provider, full_package_specs2, {}); + REQUIRE(install_plan.size() == 2); + features_check(install_plan.install_actions.at(0), "b", {"0", "core"}); + features_check(install_plan.install_actions.at(1), "c", {"0", "core"}); + } + + // now, disable the implicit default dependency from `a` and `c[0]` + SECTION ("depend-defaults false from core") + { + spec_map.map["a"].source_control_file->core_paragraph->depend_defaults = false; + auto install_plan = Dependencies::create_feature_install_plan(map_port, var_provider, full_package_specs, {}); + REQUIRE(install_plan.size() == 2); + features_check(install_plan.install_actions.at(0), "b", {"core"}); + features_check(install_plan.install_actions.at(1), "a", {"core"}); + } + SECTION ("depend-defaults false from feature") + { + spec_map.map["c"].source_control_file->core_paragraph->depend_defaults = false; + auto install_plan = Dependencies::create_feature_install_plan(map_port, var_provider, full_package_specs2, {}); + REQUIRE(install_plan.size() == 2); + features_check(install_plan.install_actions.at(0), "b", {"core"}); + features_check(install_plan.install_actions.at(1), "c", {"0", "core"}); + } +} + TEST_CASE ("upgrade with default features 1", "[plan]") { std::vector> pghs; diff --git a/src/vcpkg/dependencies.cpp b/src/vcpkg/dependencies.cpp index 909ef6f528..87bb170ce9 100644 --- a/src/vcpkg/dependencies.cpp +++ b/src/vcpkg/dependencies.cpp @@ -93,13 +93,15 @@ namespace vcpkg::Dependencies std::vector& out_new_dependencies, Triplet host_triplet) { + const auto& scfl = get_scfl_or_exit(); + ClusterInstallInfo& info = m_install_info.value_or_exit(VCPKG_LINE_INFO); if (feature == "default") { if (!info.defaults_requested) { info.defaults_requested = true; - for (auto&& f : get_scfl_or_exit().source_control_file->core_paragraph->default_features) + for (auto&& f : scfl.source_control_file->core_paragraph->default_features) out_new_dependencies.emplace_back(m_spec, f); } return; @@ -112,7 +114,7 @@ namespace vcpkg::Dependencies } auto maybe_vars = var_provider.get_dep_info_vars(m_spec); Optional&> maybe_qualified_deps = - get_scfl_or_exit().source_control_file->find_dependencies_for_feature(feature); + scfl.source_control_file->find_dependencies_for_feature(feature); if (!maybe_qualified_deps.has_value()) { Checks::exit_with_message( @@ -120,6 +122,8 @@ namespace vcpkg::Dependencies } const std::vector* qualified_deps = &maybe_qualified_deps.value_or_exit(VCPKG_LINE_INFO); + const auto depend_defaults = scfl.source_control_file->core_paragraph->depend_defaults; + std::vector dep_list; if (auto vars = maybe_vars.get()) { @@ -128,7 +132,7 @@ namespace vcpkg::Dependencies for (auto&& fspec : fullspec_list) { - Util::Vectors::append(&dep_list, fspec.to_feature_specs({"default"}, {"default"})); + fspec.expand_to(dep_list, depend_defaults); } Util::sort_unique_erase(dep_list); @@ -141,10 +145,7 @@ namespace vcpkg::Dependencies { if (dep.platform.is_empty()) { - auto t = dep.host ? host_triplet : m_spec.triplet(); - Util::Vectors::append(&dep_list, - FullPackageSpec({dep.name, t}, dep.features) - .to_feature_specs({"default"}, {"default"})); + dep.to_full_spec(m_spec.triplet(), host_triplet).expand_to(dep_list, depend_defaults); } else { @@ -1270,12 +1271,14 @@ namespace vcpkg::Dependencies const IBaselineProvider& base_provider, const PortFileProvider::IOverlayProvider& oprovider, const CMakeVars::CMakeVarProvider& var_provider, - Triplet host_triplet) + Triplet host_triplet, + DependDefaults depend_defaults) : m_ver_provider(ver_provider) , m_base_provider(base_provider) , m_o_provider(oprovider) , m_var_provider(var_provider) , m_host_triplet(host_triplet) + , m_depend_defaults(depend_defaults == DependDefaults::YES) { } @@ -1292,6 +1295,7 @@ namespace vcpkg::Dependencies const PortFileProvider::IOverlayProvider& m_o_provider; const CMakeVars::CMakeVarProvider& m_var_provider; const Triplet m_host_triplet; + const bool m_depend_defaults; struct DepSpec { @@ -1337,7 +1341,7 @@ namespace vcpkg::Dependencies Optional> semver; Optional> date; std::set requested_features; - bool default_features = true; + bool default_features; bool user_requested = false; VersionSchemeInfo* get_node(const Versions::Version& ver); @@ -1349,7 +1353,7 @@ namespace vcpkg::Dependencies // replaces the current entry for the scheme VersionSchemeInfo& emplace_node(Versions::Scheme scheme, const Versions::Version& ver); - PackageNode() = default; + explicit PackageNode(bool default_features) : default_features(default_features) { } PackageNode(const PackageNode&) = delete; PackageNode(PackageNode&&) = default; PackageNode& operator=(const PackageNode&) = delete; @@ -1389,6 +1393,7 @@ namespace vcpkg::Dependencies // the following functions will add stuff recursively void require_dependency(std::pair& ref, const Dependency& dep, + bool depend_defaults, const std::string& origin); void require_port_version(std::pair& graph_entry, const Versions::Version& ver, @@ -1577,7 +1582,10 @@ namespace vcpkg::Dependencies } else { - require_dependency(dep_node, dep, ref.first.name()); + require_dependency(dep_node, + dep, + vsi.scfl->source_control_file->core_paragraph->depend_defaults, + ref.first.name()); } p.first->second.emplace_back(dep_spec, "core"); @@ -1590,6 +1598,7 @@ namespace vcpkg::Dependencies void VersionedPackageGraph::require_dependency(std::pair& ref, const Dependency& dep, + bool depend_defaults, const std::string& origin) { auto maybe_overlay = m_o_provider.get_control_file(ref.first.name()); @@ -1624,7 +1633,7 @@ namespace vcpkg::Dependencies require_port_feature(ref, f, origin); } - if (Util::find(dep.features, StringView{"core"}) == dep.features.end()) + if (depend_defaults && Util::find(dep.features, StringView{"core"}) == dep.features.end()) { require_port_defaults(ref, origin); } @@ -1742,7 +1751,12 @@ namespace vcpkg::Dependencies std::pair& VersionedPackageGraph::emplace_package( const PackageSpec& spec) { - return *m_graph.emplace(spec, PackageNode{}).first; + auto it = m_graph.find(spec); + if (it == m_graph.end()) + { + return *m_graph.emplace(spec, m_depend_defaults).first; + } + return *it; } Optional VersionedPackageGraph::dep_to_version(const std::string& name, @@ -1961,7 +1975,7 @@ namespace vcpkg::Dependencies const Versions::Version& new_ver, const PackageSpec& origin, View features) -> Optional { - auto&& node = m_graph[spec]; + auto&& node = emplace_package(spec).second; auto overlay = m_o_provider.get_control_file(spec.name()); auto over_it = m_overrides.find(spec.name()); @@ -2125,8 +2139,10 @@ namespace vcpkg::Dependencies auto& back = stack.back(); if (back.deps.empty()) { - emitted[back.ipa.spec] = m_graph[back.ipa.spec].get_node( - to_version(*back.ipa.source_control_file_and_location.get()->source_control_file)); + emitted[back.ipa.spec] = + emplace_package(back.ipa.spec) + .second.get_node( + to_version(*back.ipa.source_control_file_and_location.get()->source_control_file)); ret.install_actions.push_back(std::move(back.ipa)); stack.pop_back(); } @@ -2153,9 +2169,10 @@ namespace vcpkg::Dependencies const std::vector& overrides, const PackageSpec& toplevel, Triplet host_triplet, - UnsupportedPortAction unsupported_port_action) + UnsupportedPortAction unsupported_port_action, + DependDefaults depend_defaults) { - VersionedPackageGraph vpg(provider, bprovider, oprovider, var_provider, host_triplet); + VersionedPackageGraph vpg(provider, bprovider, oprovider, var_provider, host_triplet, depend_defaults); for (auto&& o : overrides) vpg.add_override(o.name, {o.version, o.port_version}); vpg.add_roots(deps, toplevel); diff --git a/src/vcpkg/install.cpp b/src/vcpkg/install.cpp index d6a70ff5b9..cb781124c7 100644 --- a/src/vcpkg/install.cpp +++ b/src/vcpkg/install.cpp @@ -1008,15 +1008,17 @@ namespace vcpkg::Install } auto oprovider = PortFileProvider::make_overlay_provider(paths, extended_overlay_ports); PackageSpec toplevel{manifest_scf.core_paragraph->name, default_triplet}; - auto install_plan = Dependencies::create_versioned_install_plan(*verprovider, - *baseprovider, - *oprovider, - var_provider, - dependencies, - manifest_scf.core_paragraph->overrides, - toplevel, - host_triplet, - unsupported_port_action) + auto install_plan = Dependencies::create_versioned_install_plan( + *verprovider, + *baseprovider, + *oprovider, + var_provider, + dependencies, + manifest_scf.core_paragraph->overrides, + toplevel, + host_triplet, + unsupported_port_action, + Util::Enum::to_enum(manifest_scf.core_paragraph->depend_defaults)) .value_or_exit(VCPKG_LINE_INFO); for (const auto& warning : install_plan.warnings) { diff --git a/src/vcpkg/packagespec.cpp b/src/vcpkg/packagespec.cpp index 14692d8f2a..80b32f9c78 100644 --- a/src/vcpkg/packagespec.cpp +++ b/src/vcpkg/packagespec.cpp @@ -59,6 +59,24 @@ namespace vcpkg return feature_specs; } + void FullPackageSpec::expand_to(std::vector& out, bool with_defaults) const + { + bool core = false; + for (auto&& feature : features) + { + out.emplace_back(package_spec, feature); + core = core || feature == "core"; + } + if (!core) + { + out.emplace_back(package_spec, "core"); + if (with_defaults) + { + out.emplace_back(package_spec, "default"); + } + } + } + ExpectedS FullPackageSpec::from_string(const std::string& spec_as_string, Triplet default_triplet) { return parse_qualified_specifier(spec_as_string) @@ -267,6 +285,11 @@ namespace vcpkg } bool operator!=(const DependencyConstraint& lhs, const DependencyConstraint& rhs); + FullPackageSpec Dependency::to_full_spec(Triplet target, Triplet host_triplet) const + { + return FullPackageSpec({name, host ? host_triplet : target}, features); + } + bool operator==(const Dependency& lhs, const Dependency& rhs) { if (lhs.name != rhs.name) return false; diff --git a/src/vcpkg/sourceparagraph.cpp b/src/vcpkg/sourceparagraph.cpp index 9ce20de376..5634670b67 100644 --- a/src/vcpkg/sourceparagraph.cpp +++ b/src/vcpkg/sourceparagraph.cpp @@ -872,12 +872,13 @@ namespace vcpkg constexpr static StringLiteral DEV_DEPENDENCIES = "dev-dependencies"; constexpr static StringLiteral FEATURES = "features"; constexpr static StringLiteral DEFAULT_FEATURES = "default-features"; + constexpr static StringLiteral DEPEND_DEFAULTS = "depend-defaults"; constexpr static StringLiteral SUPPORTS = "supports"; constexpr static StringLiteral OVERRIDES = "overrides"; constexpr static StringLiteral BUILTIN_BASELINE = "builtin-baseline"; constexpr static StringLiteral VCPKG_CONFIGURATION = "vcpkg-configuration"; - virtual Span valid_fields() const override + virtual View valid_fields() const override { static const StringView u[] = { NAME, @@ -889,6 +890,7 @@ namespace vcpkg DOCUMENTATION, LICENSE, DEPENDENCIES, + DEPEND_DEFAULTS, DEV_DEPENDENCIES, FEATURES, DEFAULT_FEATURES, @@ -925,6 +927,7 @@ namespace vcpkg spgh->version_scheme = schemed_version.scheme; spgh->port_version = schemed_version.versiont.port_version(); + r.optional_object_field(obj, DEPEND_DEFAULTS, spgh->depend_defaults, Json::BooleanDeserializer::instance); r.optional_object_field(obj, MAINTAINERS, spgh->maintainers, Json::ParagraphDeserializer::instance); r.optional_object_field(obj, CONTACTS, spgh->contacts, ContactsDeserializer::instance); r.optional_object_field(obj, SUMMARY, spgh->summary, Json::ParagraphDeserializer::instance); @@ -1304,8 +1307,7 @@ namespace vcpkg { if (dep.platform.evaluate(cmake_vars)) { - Triplet t = dep.host ? host : target; - ret.emplace_back(FullPackageSpec({dep.name, t}, dep.features)); + ret.emplace_back(dep.to_full_spec(target, host)); } } return ret; @@ -1461,6 +1463,11 @@ namespace vcpkg Json::Value::string(scf.core_paragraph->builtin_baseline.value_or_exit(VCPKG_LINE_INFO))); } + if (!scf.core_paragraph->depend_defaults || debug) + { + obj.insert(ManifestDeserializer::DEPEND_DEFAULTS, Json::Value::boolean(false)); + } + if (!scf.core_paragraph->dependencies.empty() || debug) { auto& deps = obj.insert(ManifestDeserializer::DEPENDENCIES, Json::Array()); From 02a21330ccfdfd58969940db90db284f14b65e18 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Thu, 17 Feb 2022 23:30:07 +0000 Subject: [PATCH 2/4] Fixup after merge --- include/vcpkg/base/jsonreader.h | 18 ++++++++++++ include/vcpkg/packagespec.h | 1 + src/vcpkg-test/dependencies.cpp | 2 -- src/vcpkg-test/plan.cpp | 19 ++++++++++-- src/vcpkg/dependencies.cpp | 16 ++++++---- src/vcpkg/packagespec.cpp | 52 ++++----------------------------- src/vcpkg/sourceparagraph.cpp | 7 +---- 7 files changed, 53 insertions(+), 62 deletions(-) diff --git a/include/vcpkg/base/jsonreader.h b/include/vcpkg/base/jsonreader.h index 7e285108cd..f503202699 100644 --- a/include/vcpkg/base/jsonreader.h +++ b/include/vcpkg/base/jsonreader.h @@ -160,6 +160,24 @@ namespace vcpkg::Json } } + // returns whether key \in obj + template + bool optional_object_field(const Object& obj, + StringView key, + Optional& place, + IDeserializer& visitor) + { + if (auto value = obj.get(key)) + { + visit_in_key(*value, key, place.emplace(), visitor); + return true; + } + else + { + return false; + } + } + template Optional visit(const Value& value, IDeserializer& visitor) { diff --git a/include/vcpkg/packagespec.h b/include/vcpkg/packagespec.h index a9b9ee6cbf..9ac80629a9 100644 --- a/include/vcpkg/packagespec.h +++ b/include/vcpkg/packagespec.h @@ -153,6 +153,7 @@ namespace vcpkg PlatformExpression::Expr platform; DependencyConstraint constraint; bool host = false; + Optional default_features; Json::Object extra_info; diff --git a/src/vcpkg-test/dependencies.cpp b/src/vcpkg-test/dependencies.cpp index bfff2bab52..ae73c2361c 100644 --- a/src/vcpkg-test/dependencies.cpp +++ b/src/vcpkg-test/dependencies.cpp @@ -93,8 +93,6 @@ struct MockVersionedPortfileProvider : PortFileProvider::IVersionedPortfileProvi }; using Dependencies::DependDefaults; -using Versions::Constraint; -using Versions::Scheme; template T unwrap(ExpectedS e) diff --git a/src/vcpkg-test/plan.cpp b/src/vcpkg-test/plan.cpp index 108e3ccae9..fc255c8273 100644 --- a/src/vcpkg-test/plan.cpp +++ b/src/vcpkg-test/plan.cpp @@ -764,20 +764,27 @@ TEST_CASE ("install with depend-defaults false", "[plan]") auto a_spec = spec_map.emplace("a", "b"); auto b_spec = spec_map.emplace("b", "", {{"0", ""}}, {"0"}); auto c_spec = spec_map.emplace("c", "", {{"0", "b"}}, {"0"}); + auto d_spec = spec_map.emplace("d", "b"); + spec_map.map["d"].source_control_file->core_paragraph->depend_defaults = false; + spec_map.map["d"].source_control_file->core_paragraph->dependencies[0].default_features = true; PortFileProvider::MapPortFileProvider map_port{spec_map.map}; MockCMakeVarProvider var_provider; std::vector full_package_specs{ - FullPackageSpec{a_spec}, + FullPackageSpec{a_spec, {"core"}}, FullPackageSpec{b_spec, {"core"}}, }; std::vector full_package_specs2{ - FullPackageSpec{c_spec}, + FullPackageSpec{c_spec, {"default", "core"}}, FullPackageSpec{b_spec, {"core"}}, }; + std::vector full_package_specs_d{ + FullPackageSpec{d_spec, {"core"}}, + }; + // Install "a" and then "b" _should_ install default features SECTION ("depend-defaults true from core") { @@ -795,6 +802,14 @@ TEST_CASE ("install with depend-defaults false", "[plan]") features_check(install_plan.install_actions.at(1), "c", {"0", "core"}); } + SECTION ("depend-defaults false overridden from dependency") + { + auto install_plan = Dependencies::create_feature_install_plan(map_port, var_provider, full_package_specs_d, {}); + REQUIRE(install_plan.size() == 2); + features_check(install_plan.install_actions.at(0), "b", {"0", "core"}); + features_check(install_plan.install_actions.at(1), "d", {"core"}); + } + // now, disable the implicit default dependency from `a` and `c[0]` SECTION ("depend-defaults false from core") { diff --git a/src/vcpkg/dependencies.cpp b/src/vcpkg/dependencies.cpp index fe0159c6ce..50c7497fc9 100644 --- a/src/vcpkg/dependencies.cpp +++ b/src/vcpkg/dependencies.cpp @@ -129,12 +129,16 @@ namespace vcpkg::Dependencies if (auto vars = maybe_vars.get()) { // Qualified dependency resolution is available - auto fullspec_list = filter_dependencies( - *qualified_deps, m_spec.triplet(), host_triplet, *vars, ImplicitDefault::YES); + auto fullspec_list = + filter_dependencies(*qualified_deps, + m_spec.triplet(), + host_triplet, + *vars, + depend_defaults ? ImplicitDefault::YES : ImplicitDefault::NO); for (auto&& fspec : fullspec_list) { - fspec.expand_fspecs_to(dep_list, depend_defaults); + fspec.expand_fspecs_to(dep_list); } Util::sort_unique_erase(dep_list); @@ -147,8 +151,10 @@ namespace vcpkg::Dependencies { if (dep.platform.is_empty()) { - dep.to_full_spec(m_spec.triplet(), host_triplet, ImplicitDefault::YES) - .expand_fspecs_to(dep_list, depend_defaults); + dep.to_full_spec(m_spec.triplet(), + host_triplet, + depend_defaults ? ImplicitDefault::YES : ImplicitDefault::NO) + .expand_fspecs_to(dep_list); } else { diff --git a/src/vcpkg/packagespec.cpp b/src/vcpkg/packagespec.cpp index aa202919d6..c6eb994bd2 100644 --- a/src/vcpkg/packagespec.cpp +++ b/src/vcpkg/packagespec.cpp @@ -26,44 +26,6 @@ namespace vcpkg { out.emplace_back(package_spec, feature); } - - return feature_specs; - } - - void FullPackageSpec::expand_to(std::vector& out, bool with_defaults) const - { - bool core = false; - for (auto&& feature : features) - { - out.emplace_back(package_spec, feature); - core = core || feature == "core"; - } - if (!core) - { - out.emplace_back(package_spec, "core"); - if (with_defaults) - { - out.emplace_back(package_spec, "default"); - } - } - } - - ExpectedS FullPackageSpec::from_string(const std::string& spec_as_string, Triplet default_triplet) - { - return parse_qualified_specifier(spec_as_string) - .then([&](ParsedQualifiedSpecifier&& p) -> ExpectedS { - if (p.platform) - return "Error: platform specifier not allowed in this context: " + spec_as_string + "\n"; - auto triplet = p.triplet ? Triplet::from_canonical_name(std::move(*p.triplet.get())) : default_triplet; - return FullPackageSpec({p.name, triplet}, p.features.value_or({})); - }); - } - - std::vector PackageSpec::to_package_specs(const std::vector& ports, Triplet triplet) - { - return Util::fmap(ports, [&](const std::string& spec_as_string) -> PackageSpec { - return {spec_as_string, triplet}; - }); } const std::string& PackageSpec::name() const { return this->m_name; } @@ -86,7 +48,7 @@ namespace vcpkg "Error: Platform qualifier is not allowed in this context"); DECLARE_AND_REGISTER_MESSAGE(IllegalFeatures, (), "", "Error: List of features is not allowed in this contect"); - static InternalFeatureSet normalize_feature_list(View fs, ImplicitDefault id) + static InternalFeatureSet normalize_feature_list(View fs, bool implicit_default) { InternalFeatureSet ret; bool core = false; @@ -102,7 +64,7 @@ namespace vcpkg if (!core) { ret.emplace_back("core"); - if (id == ImplicitDefault::YES) + if (implicit_default) { ret.emplace_back("default"); } @@ -119,7 +81,7 @@ namespace vcpkg const Triplet t = triplet ? Triplet::from_canonical_name(*triplet.get()) : default_triplet; const View fs = !features.get() ? View{} : *features.get(); - return FullPackageSpec{{name, t}, normalize_feature_list(fs, id)}; + return FullPackageSpec{{name, t}, normalize_feature_list(fs, id == ImplicitDefault::YES)}; } ExpectedS ParsedQualifiedSpecifier::to_package_spec(Triplet default_triplet) const @@ -324,12 +286,8 @@ namespace vcpkg FullPackageSpec Dependency::to_full_spec(Triplet target, Triplet host_triplet, ImplicitDefault id) const { - return FullPackageSpec{{name, host ? host_triplet : target}, normalize_feature_list(features, id)}; - } - - FullPackageSpec Dependency::to_full_spec(Triplet target, Triplet host_triplet) const - { - return FullPackageSpec({name, host ? host_triplet : target}, features); + return FullPackageSpec{{name, host ? host_triplet : target}, + normalize_feature_list(features, default_features.value_or(id == ImplicitDefault::YES))}; } bool operator==(const Dependency& lhs, const Dependency& rhs) diff --git a/src/vcpkg/sourceparagraph.cpp b/src/vcpkg/sourceparagraph.cpp index 199779ae51..5edc00266a 100644 --- a/src/vcpkg/sourceparagraph.cpp +++ b/src/vcpkg/sourceparagraph.cpp @@ -561,12 +561,7 @@ namespace vcpkg r.required_object_field(type_name(), obj, NAME, dep.name, Json::PackageNameDeserializer::instance); r.optional_object_field(obj, FEATURES, dep.features, arr_id_d); - bool default_features = true; - r.optional_object_field(obj, DEFAULT_FEATURES, default_features, Json::BooleanDeserializer::instance); - if (!default_features) - { - dep.features.push_back("core"); - } + r.optional_object_field(obj, DEFAULT_FEATURES, dep.default_features, Json::BooleanDeserializer::instance); r.optional_object_field(obj, HOST, dep.host, Json::BooleanDeserializer::instance); r.optional_object_field(obj, PLATFORM, dep.platform, PlatformExprDeserializer::instance); From 4542303d49c3f516ebcb435979d2ec331fa9d9af Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Fri, 18 Feb 2022 00:50:51 +0000 Subject: [PATCH 3/4] Fix serialization error --- src/vcpkg/sourceparagraph.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/vcpkg/sourceparagraph.cpp b/src/vcpkg/sourceparagraph.cpp index 5edc00266a..79a9012da1 100644 --- a/src/vcpkg/sourceparagraph.cpp +++ b/src/vcpkg/sourceparagraph.cpp @@ -1520,7 +1520,7 @@ namespace vcpkg static bool is_dependency_trivial(const Dependency& dep) { return dep.features.empty() && dep.platform.is_empty() && dep.extra_info.is_empty() && - dep.constraint.type == VersionConstraintKind::None && !dep.host; + dep.constraint.type == VersionConstraintKind::None && !dep.host && !dep.default_features.has_value(); } static Json::Object serialize_manifest_impl(const SourceControlFile& scf, bool debug) @@ -1584,11 +1584,16 @@ namespace vcpkg auto features_copy = dep.features; auto core_it = std::find(features_copy.begin(), features_copy.end(), "core"); + auto default_features = dep.default_features; if (core_it != features_copy.end()) { - dep_obj.insert(DependencyDeserializer::DEFAULT_FEATURES, Json::Value::boolean(false)); + default_features = false; features_copy.erase(core_it); } + if (auto b = default_features.get()) + { + dep_obj.insert(DependencyDeserializer::DEFAULT_FEATURES, Json::Value::boolean(*b)); + } serialize_optional_array(dep_obj, DependencyDeserializer::FEATURES, features_copy); serialize_optional_string(dep_obj, DependencyDeserializer::PLATFORM, to_string(dep.platform)); From e337036b4d299413968e6660066527a9b0a64052 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Fri, 18 Feb 2022 18:22:16 +0000 Subject: [PATCH 4/4] Fix e2e test break --- include/vcpkg/packagespec.h | 3 +++ src/vcpkg-test/dependencies.cpp | 38 +++++++++++++++++++++++++++++---- src/vcpkg/sourceparagraph.cpp | 24 +++++++++++++++++++++ 3 files changed, 61 insertions(+), 4 deletions(-) diff --git a/include/vcpkg/packagespec.h b/include/vcpkg/packagespec.h index 9ac80629a9..f5942ec0e4 100644 --- a/include/vcpkg/packagespec.h +++ b/include/vcpkg/packagespec.h @@ -149,6 +149,9 @@ namespace vcpkg struct Dependency { std::string name; + + // When created through parsing a manifest, `features` will be pre-normalized (containing 'core' and 'default' + // as appropriate) std::vector features; PlatformExpression::Expr platform; DependencyConstraint constraint; diff --git a/src/vcpkg-test/dependencies.cpp b/src/vcpkg-test/dependencies.cpp index ae73c2361c..05dedbaca0 100644 --- a/src/vcpkg-test/dependencies.cpp +++ b/src/vcpkg-test/dependencies.cpp @@ -1548,11 +1548,41 @@ TEST_CASE ("version install default features", "[versionplan]") MockBaselineProvider bp; bp.v["a"] = {"1", 0}; - auto install_plan = - unwrap(create_versioned_install_plan(vp, bp, var_provider, {Dependency{"a"}}, {}, toplevel_spec())); + SECTION ("toplevel requires defaults") + { + auto install_plan = + unwrap(create_versioned_install_plan(vp, bp, var_provider, {Dependency{"a"}}, {}, toplevel_spec())); - REQUIRE(install_plan.size() == 1); - check_name_and_version(install_plan.install_actions[0], "a", {"1", 0}, {"x"}); + REQUIRE(install_plan.size() == 1); + check_name_and_version(install_plan.install_actions[0], "a", {"1", 0}, {"x"}); + } + + SECTION ("default-features false") + { + auto install_plan = unwrap(create_versioned_install_plan( + vp, bp, var_provider, {Dependency{"a", {"core"}, {}, {}, false, false}}, {}, toplevel_spec())); + + REQUIRE(install_plan.size() == 1); + check_name_and_version(install_plan.install_actions[0], "a", {"1", 0}, {}); + } + + SECTION ("default-features true") + { + auto install_plan = unwrap(create_versioned_install_plan( + vp, bp, var_provider, {Dependency{"a", {"core", "default"}, {}, {}, false, false}}, {}, toplevel_spec())); + + REQUIRE(install_plan.size() == 1); + check_name_and_version(install_plan.install_actions[0], "a", {"1", 0}, {"x"}); + } + + SECTION ("default-features true 2") + { + auto install_plan = unwrap(create_versioned_install_plan( + vp, bp, var_provider, {Dependency{"a", {"core", "default"}, {}, {}, false, true}}, {}, toplevel_spec())); + + REQUIRE(install_plan.size() == 1); + check_name_and_version(install_plan.install_actions[0], "a", {"1", 0}, {"x"}); + } } TEST_CASE ("version install depend-defaults", "[versionplan]") diff --git a/src/vcpkg/sourceparagraph.cpp b/src/vcpkg/sourceparagraph.cpp index 79a9012da1..bd3d6ece73 100644 --- a/src/vcpkg/sourceparagraph.cpp +++ b/src/vcpkg/sourceparagraph.cpp @@ -1178,6 +1178,30 @@ namespace vcpkg Checks::exit_with_message(VCPKG_LINE_INFO, maybe_error->error); } + // This ugly fixup is needed because Dependency is serving two roles: one as a parse tree (context + // dependent) and another as a context-free description of a package dependency. This fixup applies the + // context from the parent SourceControlFile onto all child Dependencies. + auto fixup_dependencies = [&spgh](Span deps) { + for (auto&& dep : deps) + { + auto it = Util::find(dep.features, "core"); + if (it == dep.features.end()) + { + dep.features.push_back("core"); + it = Util::find(dep.features, "default"); + if (dep.default_features.value_or(spgh->depend_defaults) && it == dep.features.end()) + { + dep.features.push_back("default"); + } + } + } + }; + fixup_dependencies(spgh->dependencies); + for (auto&& fpgh : control_file->feature_paragraphs) + { + fixup_dependencies(fpgh->dependencies); + } + return std::move(control_file); // gcc-7 bug workaround redundant move }