diff --git a/docs/vcpkg.schema.json b/docs/vcpkg.schema.json index 261bdbfb93..7aafb10073 100644 --- a/docs/vcpkg.schema.json +++ b/docs/vcpkg.schema.json @@ -80,6 +80,11 @@ } } }, + "depend-defaults": { + "description": "The default value for the default-features field of a dependency", + "type": "boolean", + "default": true + }, "default-features": { "description": "Features enabled by default with the package.", "type": "array", diff --git a/include/vcpkg/base/contractual-constants.h b/include/vcpkg/base/contractual-constants.h index 1dd7d6fbc9..85a24743ec 100644 --- a/include/vcpkg/base/contractual-constants.h +++ b/include/vcpkg/base/contractual-constants.h @@ -38,6 +38,7 @@ namespace vcpkg inline constexpr StringLiteral JsonIdDefaultTriplet = "default-triplet"; inline constexpr StringLiteral JsonIdDemands = "demands"; inline constexpr StringLiteral JsonIdDependencies = "dependencies"; + inline constexpr StringLiteral JsonIdDependDefaults = "depend-defaults"; inline constexpr StringLiteral JsonIdDescription = "description"; inline constexpr StringLiteral JsonIdDetectedCIEnvironment = "detected-ci-environment"; inline constexpr StringLiteral JsonIdDetector = "detector"; diff --git a/include/vcpkg/dependencies.h b/include/vcpkg/dependencies.h index 994952581f..16fc057b31 100644 --- a/include/vcpkg/dependencies.h +++ b/include/vcpkg/dependencies.h @@ -130,13 +130,15 @@ namespace vcpkg const Path& packages_dir, UnsupportedPortAction action, UseHeadVersion use_head_version_if_user_requested, - Editable editable_if_user_requested) + Editable editable_if_user_requested, + ImplicitDefault implicit_default = ImplicitDefault::Yes) : randomizer(randomizer) , host_triplet(host_triplet) , packages_dir(packages_dir) , unsupported_port_action(action) , use_head_version_if_user_requested(use_head_version_if_user_requested) , editable_if_user_requested(editable_if_user_requested) + , implicit_default(implicit_default) { } @@ -146,6 +148,7 @@ namespace vcpkg UnsupportedPortAction unsupported_port_action; UseHeadVersion use_head_version_if_user_requested; Editable editable_if_user_requested; + ImplicitDefault implicit_default; }; struct CreateUpgradePlanOptions @@ -165,6 +168,7 @@ namespace vcpkg Triplet host_triplet; Path packages_dir; UnsupportedPortAction unsupported_port_action; + ImplicitDefault implicit_default; }; struct RemovePlan diff --git a/include/vcpkg/sourceparagraph.h b/include/vcpkg/sourceparagraph.h index d5b200931a..54cb530df8 100644 --- a/include/vcpkg/sourceparagraph.h +++ b/include/vcpkg/sourceparagraph.h @@ -113,6 +113,7 @@ namespace vcpkg std::string name; VersionScheme version_scheme = VersionScheme::String; Version version; + 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 4a5e3457e1..8598718922 100644 --- a/src/vcpkg-test/dependencies.cpp +++ b/src/vcpkg-test/dependencies.cpp @@ -97,6 +97,7 @@ static void check_name_and_features(const InstallPlanAction& ipa, std::initializer_list features) { CHECK(ipa.spec.name() == name); + INFO("spec.name: " << name); CHECK(ipa.source_control_file_and_location.has_value()); { INFO("ipa.feature_list = [" << Strings::join(", ", ipa.feature_list) << "]"); @@ -220,15 +221,20 @@ static ExpectedL create_versioned_install_plan(const IVersionedPortf const std::vector& overrides, const PackageSpec& toplevel) { - return create_versioned_install_plan( - provider, - bprovider, - s_empty_mock_overlay, - var_provider, - deps, - overrides, - toplevel, - {nullptr, Test::ARM_UWP, "pkgs", UnsupportedPortAction::Error, UseHeadVersion::No, Editable::No}); + return create_versioned_install_plan(provider, + bprovider, + s_empty_mock_overlay, + var_provider, + deps, + overrides, + toplevel, + {nullptr, + Test::ARM_UWP, + "pkgs", + UnsupportedPortAction::Error, + UseHeadVersion::No, + Editable::No, + ImplicitDefault::Yes}); } static ExpectedL create_versioned_install_plan(const IVersionedPortfileProvider& provider, @@ -239,15 +245,45 @@ static ExpectedL create_versioned_install_plan(const IVersionedPortf const std::vector& overrides, const PackageSpec& toplevel) { - return create_versioned_install_plan( - provider, - bprovider, - oprovider, - var_provider, - deps, - overrides, - toplevel, - {nullptr, Test::ARM_UWP, "pkgs", UnsupportedPortAction::Error, UseHeadVersion::No, Editable::No}); + return create_versioned_install_plan(provider, + bprovider, + oprovider, + var_provider, + deps, + overrides, + toplevel, + {nullptr, + Test::ARM_UWP, + "pkgs", + UnsupportedPortAction::Error, + UseHeadVersion::No, + Editable::No, + ImplicitDefault::Yes}); +} + +static ExpectedL create_versioned_install_plan(const IOverlayProvider& oprovider, + const std::vector& deps, + const PackageSpec& toplevel, + ImplicitDefault implicit_default) +{ + MockVersionedPortfileProvider vp; + MockCMakeVarProvider var_provider; + MockBaselineProvider bp; + + return vcpkg::create_versioned_install_plan(vp, + bp, + oprovider, + var_provider, + deps, + {}, + toplevel, + {nullptr, + Test::ARM_UWP, + "pkgs", + UnsupportedPortAction::Error, + UseHeadVersion::No, + Editable::No, + implicit_default}); } TEST_CASE ("basic version install single", "[versionplan]") @@ -1630,11 +1666,85 @@ TEST_CASE ("version install default features", "[versionplan]") MockBaselineProvider bp; bp.v["a"] = {"1", 0}; - WITH_EXPECTED(install_plan, - create_versioned_install_plan(vp, bp, var_provider, {Dependency{"a"}}, {}, toplevel_spec())); + SECTION ("toplevel requires defaults") + { + WITH_EXPECTED(install_plan, + 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 = + create_versioned_install_plan(vp, bp, var_provider, {CoreDependency{"a"}}, {}, toplevel_spec()) + .value_or_exit(VCPKG_LINE_INFO); + + REQUIRE(install_plan.size() == 1); + check_name_and_version(install_plan.install_actions[0], "a", {"1", 0}, {}); + } + + SECTION ("default-features true") + { + auto install_plan = create_versioned_install_plan(vp, bp, var_provider, {Dependency{"a"}}, {}, toplevel_spec()) + .value_or_exit(VCPKG_LINE_INFO); + + 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 = create_versioned_install_plan(vp, bp, var_provider, {Dependency{"a"}}, {}, toplevel_spec()) + .value_or_exit(VCPKG_LINE_INFO); + + 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]") +{ + // Dependencies: + // b has default feature '0' + // a -> b[core] + // c -> b[default] + + MockOverlayProvider op; + auto& a_scf = op.emplace("a"); + a_scf.source_control_file->core_paragraph->dependencies.push_back(CoreDependency{"b"}); + auto& b_scf = op.emplace("b"); + b_scf.source_control_file->core_paragraph->default_features.push_back({"0"}); + b_scf.source_control_file->feature_paragraphs.emplace_back(make_fpgh("0")); + auto& d_scf = op.emplace("c"); + d_scf.source_control_file->core_paragraph->dependencies.push_back(Dependency{"b"}); + + SECTION ("toplevel ImplicitDefault::Yes") + { + auto install_plan = create_versioned_install_plan(op, {Dependency{"a"}}, toplevel_spec(), ImplicitDefault::Yes) + .value_or_exit(VCPKG_LINE_INFO); + REQUIRE(install_plan.size() == 2); + check_name_and_features(install_plan.install_actions[0], "b", {"0"}); + check_name_and_features(install_plan.install_actions[1], "a", {}); + } + + SECTION ("toplevel ImplicitDefault::No") + { + auto install_plan = create_versioned_install_plan(op, {Dependency{"a"}}, toplevel_spec(), ImplicitDefault::No) + .value_or_exit(VCPKG_LINE_INFO); + REQUIRE(install_plan.size() == 2); + + check_name_and_features(install_plan.install_actions[0], "b", {}); + check_name_and_features(install_plan.install_actions[1], "a", {}); + + // c -> b[default], so depend-defaults should not suppress it + install_plan = create_versioned_install_plan(op, {Dependency{"c"}}, toplevel_spec(), ImplicitDefault::No) + .value_or_exit(VCPKG_LINE_INFO); + REQUIRE(install_plan.size() == 2); + check_name_and_features(install_plan.install_actions[0], "b", {"0"}); + check_name_and_features(install_plan.install_actions[1], "c", {}); + } } TEST_CASE ("version dont install default features", "[versionplan]") diff --git a/src/vcpkg-test/manifests.cpp b/src/vcpkg-test/manifests.cpp index bbb20e0712..5172a278c0 100644 --- a/src/vcpkg-test/manifests.cpp +++ b/src/vcpkg-test/manifests.cpp @@ -97,6 +97,7 @@ TEST_CASE ("manifest construct minimum", "[manifests]") REQUIRE(pgh.to_name() == "zlib"); REQUIRE(pgh.to_version_scheme() == VersionScheme::String); REQUIRE(pgh.to_version() == Version{"1.2.8", 0}); + 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()); @@ -1060,6 +1061,68 @@ TEST_CASE ("manifest construct maximum", "[manifests]") check_json_eq_ordered(serialize_manifest(pgh), object); } +TEST_CASE ("SourceParagraph manifest depend-default", "[manifests]") +{ + auto json = parse_json_object(R"json({ + "name": "zlib", + "version-string": "1.2.8", + "depend-defaults": false, + "dependencies": [ + "y", + {"name": "z", "host": true}, + {"name": "z2", "host": true, "default-features": true} + ], + "features": { + "t": { + "description": "", + "dependencies": ["z"] + } + } + })json"); + SECTION ("depend-defaults: false") + { + auto m_pgh = test_parse_port_manifest(json); + REQUIRE(m_pgh.has_value()); + auto& pgh = **m_pgh.get(); + REQUIRE(pgh.core_paragraph->depend_defaults == false); + REQUIRE(pgh.core_paragraph->dependencies.size() == 3); + REQUIRE(pgh.core_paragraph->dependencies[0].name == "y"); + REQUIRE(pgh.core_paragraph->dependencies[0].default_features == false); + REQUIRE(pgh.core_paragraph->dependencies[1].name == "z"); + REQUIRE(pgh.core_paragraph->dependencies[1].default_features == false); + REQUIRE(pgh.core_paragraph->dependencies[2].name == "z2"); + REQUIRE(pgh.core_paragraph->dependencies[2].default_features == true); + + REQUIRE(pgh.feature_paragraphs.size() == 1); + REQUIRE(pgh.feature_paragraphs[0]->dependencies[0].name == "z"); + REQUIRE(pgh.feature_paragraphs[0]->dependencies[0].default_features == false); + check_json_eq_ordered(serialize_manifest(pgh), json); + } + SECTION ("depend-defaults: true") + { + json.remove("depend-defaults"); + json["dependencies"].array(VCPKG_LINE_INFO)[2].object(VCPKG_LINE_INFO)["default-features"] = + Json::Value::boolean(false); + auto m_pgh = test_parse_port_manifest(json); + REQUIRE(m_pgh.has_value()); + auto& pgh = **m_pgh.get(); + + REQUIRE(pgh.core_paragraph->depend_defaults == true); + REQUIRE(pgh.core_paragraph->dependencies.size() == 3); + REQUIRE(pgh.core_paragraph->dependencies[0].name == "y"); + REQUIRE(pgh.core_paragraph->dependencies[0].default_features == true); + REQUIRE(pgh.core_paragraph->dependencies[1].name == "z"); + REQUIRE(pgh.core_paragraph->dependencies[1].default_features == true); + REQUIRE(pgh.core_paragraph->dependencies[2].name == "z2"); + REQUIRE(pgh.core_paragraph->dependencies[2].default_features == false); + + REQUIRE(pgh.feature_paragraphs.size() == 1); + REQUIRE(pgh.feature_paragraphs[0]->dependencies[0].name == "z"); + REQUIRE(pgh.feature_paragraphs[0]->dependencies[0].default_features == true); + check_json_eq_ordered(serialize_manifest(pgh), json); + } +} + TEST_CASE ("SourceParagraph manifest two dependencies", "[manifests]") { auto m_pgh = test_parse_port_manifest(R"json({ diff --git a/src/vcpkg-test/plan.cpp b/src/vcpkg-test/plan.cpp index 7c3b06e7a3..5ffa63e527 100644 --- a/src/vcpkg-test/plan.cpp +++ b/src/vcpkg-test/plan.cpp @@ -60,11 +60,16 @@ static void remove_plan_check(RemovePlanAction& plan, std::string pkg_name, Trip static ActionPlan create_feature_install_plan(const PortFileProvider& port_provider, const CMakeVars::CMakeVarProvider& var_provider, View specs, - const StatusParagraphs& status_db) + const StatusParagraphs& status_db, + ImplicitDefault implicit_defaults = ImplicitDefault::Yes) { - const CreateInstallPlanOptions create_options{ - nullptr, Test::X64_ANDROID, "pkg", UnsupportedPortAction::Error, UseHeadVersion::No, Editable::No}; - + const CreateInstallPlanOptions create_options{nullptr, + Test::X64_ANDROID, + "pkg", + UnsupportedPortAction::Error, + UseHeadVersion::No, + Editable::No, + implicit_defaults}; return create_feature_install_plan(port_provider, var_provider, specs, status_db, create_options); } @@ -820,6 +825,69 @@ TEST_CASE ("install with default features", "[plan]") features_check(install_plan.install_actions.at(1), "a", {"0", "core"}); } +TEST_CASE ("install with ImplicitDefault::NO", "[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"}); + + MapPortFileProvider map_port{spec_map.map}; + MockCMakeVarProvider var_provider; + + std::vector full_package_specs{ + FullPackageSpec{a_spec, {"core"}}, + FullPackageSpec{b_spec, {"core"}}, + }; + + std::vector full_package_specs2{ + FullPackageSpec{c_spec, {"default", "core"}}, + FullPackageSpec{b_spec, {"core"}}, + }; + + // Install "a" and then "b" _should_ install default features + SECTION ("depend-defaults true from core") + { + auto install_plan = + create_feature_install_plan(map_port, var_provider, full_package_specs, {}, ImplicitDefault::No); + 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 = + create_feature_install_plan(map_port, var_provider, full_package_specs2, {}, ImplicitDefault::No); + 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 default dependency from `a` and `c[0]` + spec_map.map["a"].source_control_file->core_paragraph->dependencies.at(0).default_features = false; + spec_map.map["c"].source_control_file->feature_paragraphs.at(0)->dependencies.at(0).default_features = false; + SECTION ("depend-defaults false from core") + { + auto install_plan = + create_feature_install_plan(map_port, var_provider, full_package_specs, {}, ImplicitDefault::No); + 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 = + create_feature_install_plan(map_port, var_provider, full_package_specs2, {}, ImplicitDefault::No); + 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/commands.install.cpp b/src/vcpkg/commands.install.cpp index 5f750f3658..7c24b5db79 100644 --- a/src/vcpkg/commands.install.cpp +++ b/src/vcpkg/commands.install.cpp @@ -1125,12 +1125,12 @@ namespace vcpkg keep_going, }; - const CreateInstallPlanOptions create_options{nullptr, - host_triplet, - paths.packages(), - unsupported_port_action, - Util::Enum::to_enum(use_head_version), - Util::Enum::to_enum(is_editable)}; + CreateInstallPlanOptions create_options{nullptr, + host_triplet, + paths.packages(), + unsupported_port_action, + Util::Enum::to_enum(use_head_version), + Util::Enum::to_enum(is_editable)}; auto var_provider_storage = CMakeVars::make_triplet_cmake_var_provider(paths); auto& var_provider = *var_provider_storage; @@ -1244,6 +1244,8 @@ namespace vcpkg extended_overlay_ports.emplace_back(paths.builtin_ports_directory()); } + create_options.implicit_default = + (manifest_scf->core_paragraph->depend_defaults ? ImplicitDefault::Yes : ImplicitDefault::No); auto oprovider = make_manifest_provider(fs, extended_overlay_ports, manifest->path, std::move(manifest_scf)); auto install_plan = create_versioned_install_plan(*verprovider, diff --git a/src/vcpkg/dependencies.cpp b/src/vcpkg/dependencies.cpp index bfdd903138..2003354d9c 100644 --- a/src/vcpkg/dependencies.cpp +++ b/src/vcpkg/dependencies.cpp @@ -1356,6 +1356,7 @@ namespace vcpkg const CMakeVars::CMakeVarProvider& var_provider, const PackageSpec& toplevel, Triplet host_triplet, + ImplicitDefault implicit_default, const Path& packages_dir) : m_ver_provider(ver_provider) , m_base_provider(base_provider) @@ -1363,6 +1364,7 @@ namespace vcpkg , m_var_provider(var_provider) , m_toplevel(toplevel) , m_host_triplet(host_triplet) + , m_implicit_default(implicit_default) , m_packages_dir(packages_dir) { } @@ -1382,6 +1384,7 @@ namespace vcpkg const CMakeVars::CMakeVarProvider& m_var_provider; const PackageSpec& m_toplevel; const Triplet m_host_triplet; + const ImplicitDefault m_implicit_default; const Path m_packages_dir; struct DepSpec @@ -1681,8 +1684,10 @@ namespace vcpkg } } - it->second.default_features = default_features_mask; - // Note that if top-level doesn't also mark that reference as `[core]`, defaults will be re-engaged. + // Implicit defaults are disabled if spec has been mentioned at top-level. + // Note that if top-level doesn't also mark that reference as `[core]` and ImplicitDefault::YES, defaults + // will be re-engaged. + it->second.default_features = (m_implicit_default == ImplicitDefault::Yes) && default_features_mask; it->second.requested_features.insert(FeatureNameCore.to_string()); require_scfl(*it, it->second.scfl, origin); @@ -2052,8 +2057,14 @@ namespace vcpkg const PackageSpec& toplevel, const CreateInstallPlanOptions& options) { - VersionedPackageGraph vpg( - provider, bprovider, oprovider, var_provider, toplevel, options.host_triplet, options.packages_dir); + VersionedPackageGraph vpg(provider, + bprovider, + oprovider, + var_provider, + toplevel, + options.host_triplet, + options.implicit_default, + options.packages_dir); for (auto&& o : overrides) { vpg.add_override(o.name, o.version); diff --git a/src/vcpkg/sourceparagraph.cpp b/src/vcpkg/sourceparagraph.cpp index 1a581431ab..e80f79ef8c 100644 --- a/src/vcpkg/sourceparagraph.cpp +++ b/src/vcpkg/sourceparagraph.cpp @@ -618,6 +618,8 @@ namespace vcpkg struct DependencyDeserializer final : Json::IDeserializer { + explicit DependencyDeserializer(bool depends_defaults) : depends_defaults(depends_defaults) { } + bool depends_defaults; virtual LocalizedString type_name() const override { return msg::format(msgADependency); } virtual Span valid_fields() const override @@ -636,13 +638,17 @@ namespace vcpkg virtual Optional visit_string(Json::Reader& r, StringView sv) const override { - return Json::PackageNameDeserializer::instance.visit_string(r, sv).map( - [](std::string&& name) { return Dependency{std::move(name)}; }); + return Json::PackageNameDeserializer::instance.visit_string(r, sv).map([this](std::string&& name) { + Dependency dep{std::move(name)}; + dep.default_features = depends_defaults; + return dep; + }); } virtual Optional visit_object(Json::Reader& r, const Json::Object& obj) const override { Dependency dep; + dep.default_features = depends_defaults; for (const auto& el : obj) { @@ -679,25 +685,20 @@ namespace vcpkg return dep; } - - static DependencyDeserializer instance; }; - DependencyDeserializer DependencyDeserializer::instance; struct DependencyArrayDeserializer final : Json::IDeserializer> { + explicit DependencyArrayDeserializer(bool depends_defaults) : depends_defaults(depends_defaults) { } + bool depends_defaults; virtual LocalizedString type_name() const override { return msg::format(msgAnArrayOfDependencies); } virtual Optional> visit_array(Json::Reader& r, const Json::Array& arr) const override { - return r.array_elements(arr, DependencyDeserializer::instance); + return r.array_elements(arr, DependencyDeserializer{depends_defaults}); } - - static const DependencyArrayDeserializer instance; }; - const DependencyArrayDeserializer DependencyArrayDeserializer::instance; - struct DependencyOverrideDeserializer final : Json::IDeserializer { virtual LocalizedString type_name() const override { return msg::format(msgAnOverride); } @@ -1002,6 +1003,8 @@ namespace vcpkg // `ArrayFeatureDeserializer` is used for the former, `FeatureDeserializer` is used for the latter. struct FeatureDeserializer final : Json::IDeserializer> { + explicit FeatureDeserializer(bool depends_defaults) : depends_defaults(depends_defaults) { } + bool depends_defaults; virtual LocalizedString type_name() const override { return msg::format(msgAFeature); } virtual Span valid_fields() const override @@ -1025,7 +1028,7 @@ namespace vcpkg r.required_object_field( type_name(), obj, JsonIdDescription, feature->description, Json::ParagraphDeserializer::instance); r.optional_object_field( - obj, JsonIdDependencies, feature->dependencies, DependencyArrayDeserializer::instance); + obj, JsonIdDependencies, feature->dependencies, DependencyArrayDeserializer{depends_defaults}); r.optional_object_field( obj, JsonIdSupports, feature->supports_expression, PlatformExprDeserializer::instance); std::string license; @@ -1036,12 +1039,8 @@ namespace vcpkg return std::move(feature); // gcc-7 bug workaround redundant move } - - static const FeatureDeserializer instance; }; - const FeatureDeserializer FeatureDeserializer::instance; - struct FeaturesObject { std::vector> feature_paragraphs; @@ -1050,6 +1049,8 @@ namespace vcpkg struct FeaturesFieldDeserializer final : Json::IDeserializer { + explicit FeaturesFieldDeserializer(bool depends_defaults) : depends_defaults(depends_defaults) { } + bool depends_defaults; virtual LocalizedString type_name() const override { return msg::format(msgASetOfFeatures); } virtual Span valid_fields() const override { return {}; } @@ -1072,7 +1073,7 @@ namespace vcpkg continue; } std::unique_ptr v; - r.visit_in_key(pr.second, pr.first, v, FeatureDeserializer::instance); + r.visit_in_key(pr.second, pr.first, v, FeatureDeserializer{depends_defaults}); if (v) { v->name = pr.first.to_string(); @@ -1082,12 +1083,8 @@ namespace vcpkg return std::move(res); // gcc-7 bug workaround redundant move } - - static const FeaturesFieldDeserializer instance; }; - const FeaturesFieldDeserializer FeaturesFieldDeserializer::instance; - struct ContactsDeserializer final : Json::IDeserializer { virtual LocalizedString type_name() const override { return msg::format(msgADictionaryOfContacts); } @@ -1134,6 +1131,7 @@ namespace vcpkg JsonIdDocumentation, JsonIdLicense, JsonIdDependencies, + JsonIdDependDefaults, JsonIdFeatures, JsonIdDefaultFeatures, JsonIdSupports, @@ -1160,6 +1158,8 @@ namespace vcpkg } } + r.optional_object_field( + obj, JsonIdDependDefaults, spgh.depend_defaults, Json::BooleanDeserializer::instance); r.optional_object_field(obj, JsonIdMaintainers, spgh.maintainers, Json::ParagraphDeserializer::instance); r.optional_object_field(obj, JsonIdContacts, spgh.contacts, ContactsDeserializer::instance); r.optional_object_field(obj, JsonIdSummary, spgh.summary, Json::ParagraphDeserializer::instance); @@ -1173,7 +1173,8 @@ namespace vcpkg spgh.license = {std::move(license)}; } - r.optional_object_field(obj, JsonIdDependencies, spgh.dependencies, DependencyArrayDeserializer::instance); + r.optional_object_field( + obj, JsonIdDependencies, spgh.dependencies, DependencyArrayDeserializer{spgh.depend_defaults}); r.optional_object_field( obj, JsonIdOverrides, spgh.overrides, DependencyOverrideArrayDeserializer::instance); @@ -1188,7 +1189,7 @@ namespace vcpkg obj, JsonIdDefaultFeatures, spgh.default_features, DefaultFeatureArrayDeserializer::instance); FeaturesObject features_tmp; - r.optional_object_field(obj, JsonIdFeatures, features_tmp, FeaturesFieldDeserializer::instance); + r.optional_object_field(obj, JsonIdFeatures, features_tmp, FeaturesFieldDeserializer{spgh.depend_defaults}); control_file->feature_paragraphs = std::move(features_tmp.feature_paragraphs); control_file->extra_features_info = std::move(features_tmp.extra_features_info); @@ -1587,10 +1588,10 @@ namespace vcpkg return ret; } - static bool is_dependency_trivial(const Dependency& dep) + static bool is_dependency_trivial(const Dependency& dep, bool depend_defaults) { - return dep.features.empty() && dep.default_features && dep.platform.is_empty() && dep.extra_info.is_empty() && - dep.constraint.type == VersionConstraintKind::None && !dep.host; + return dep.features.empty() && dep.default_features == depend_defaults && dep.platform.is_empty() && + dep.extra_info.is_empty() && dep.constraint.type == VersionConstraintKind::None && !dep.host; } Json::Object serialize_manifest(const SourceControlFile& scf) @@ -1644,7 +1645,7 @@ namespace vcpkg } }; auto serialize_dependency = [&](Json::Array& arr, const Dependency& dep) { - if (is_dependency_trivial(dep)) + if (is_dependency_trivial(dep, scf.core_paragraph->depend_defaults)) { arr.push_back(Json::Value::string(dep.name)); } @@ -1659,9 +1660,9 @@ namespace vcpkg dep_obj.insert(JsonIdName, dep.name); if (dep.host) dep_obj.insert(JsonIdHost, Json::Value::boolean(true)); - if (!dep.default_features) + if (dep.default_features != scf.core_paragraph->depend_defaults) { - dep_obj.insert(JsonIdDefaultFeatures, Json::Value::boolean(false)); + dep_obj.insert(JsonIdDefaultFeatures, Json::Value::boolean(dep.default_features)); } serialize_dependency_features(dep_obj, JsonIdFeatures, dep.features); serialize_optional_string(dep_obj, JsonIdPlatform, to_string(dep.platform)); @@ -1727,6 +1728,11 @@ namespace vcpkg Json::Value::string(scf.core_paragraph->builtin_baseline.value_or_exit(VCPKG_LINE_INFO))); } + if (!scf.core_paragraph->depend_defaults) + { + obj.insert(JsonIdDependDefaults, Json::Value::boolean(false)); + } + if (!scf.core_paragraph->dependencies.empty()) { auto& deps = obj.insert(JsonIdDependencies, Json::Array());