diff --git a/include/vcpkg/packagespec.h b/include/vcpkg/packagespec.h
index 44b1fbab36..444051005a 100644
--- a/include/vcpkg/packagespec.h
+++ b/include/vcpkg/packagespec.h
@@ -62,7 +62,7 @@ namespace vcpkg
{
FeatureSpec(const PackageSpec& spec, const std::string& feature) : m_spec(spec), m_feature(feature) { }
- const std::string& name() const { return m_spec.name(); }
+ const std::string& port() const { return m_spec.name(); }
const std::string& feature() const { return m_feature; }
Triplet triplet() const { return m_spec.triplet(); }
@@ -73,8 +73,8 @@ namespace vcpkg
bool operator<(const FeatureSpec& other) const
{
- if (name() < other.name()) return true;
- if (name() > other.name()) return false;
+ if (port() < other.port()) return true;
+ if (port() > other.port()) return false;
if (feature() < other.feature()) return true;
if (feature() > other.feature()) return false;
return triplet() < other.triplet();
@@ -82,7 +82,7 @@ namespace vcpkg
bool operator==(const FeatureSpec& other) const
{
- return triplet() == other.triplet() && name() == other.name() && feature() == other.feature();
+ return triplet() == other.triplet() && port() == other.port() && feature() == other.feature();
}
bool operator!=(const FeatureSpec& other) const { return !(*this == other); }
diff --git a/include/vcpkg/statusparagraphs.h b/include/vcpkg/statusparagraphs.h
index 8fd85b4e05..bbf70f7b04 100644
--- a/include/vcpkg/statusparagraphs.h
+++ b/include/vcpkg/statusparagraphs.h
@@ -28,7 +28,7 @@ namespace vcpkg
/// Find the StatusParagraph for given feature spec.
/// Feature specification to find the status paragraph for
/// Iterator for found spec
- const_iterator find(const FeatureSpec& spec) const { return find(spec.name(), spec.triplet(), spec.feature()); }
+ const_iterator find(const FeatureSpec& spec) const { return find(spec.port(), spec.triplet(), spec.feature()); }
/// Find a StatusParagraph by name, triplet and feature.
/// Package name
diff --git a/src/vcpkg/build.cpp b/src/vcpkg/build.cpp
index f822b4db16..498fbb72e7 100644
--- a/src/vcpkg/build.cpp
+++ b/src/vcpkg/build.cpp
@@ -1221,7 +1221,7 @@ namespace vcpkg::Build
{
for (const FeatureSpec& fspec : kv.second)
{
- if (!status_db.is_installed(fspec) && !(fspec.name() == name && fspec.triplet() == spec.triplet()))
+ if (!status_db.is_installed(fspec) && !(fspec.port() == name && fspec.triplet() == spec.triplet()))
{
missing_fspecs.emplace_back(fspec);
}
diff --git a/src/vcpkg/dependencies.cpp b/src/vcpkg/dependencies.cpp
index abc2cd79ee..6fb89de069 100644
--- a/src/vcpkg/dependencies.cpp
+++ b/src/vcpkg/dependencies.cpp
@@ -243,7 +243,7 @@ namespace vcpkg::Dependencies
Checks::check_maybe_upgrade(VCPKG_LINE_INFO,
maybe_paragraph.has_value(),
"Package %s does not have a %s feature",
- spec.name(),
+ spec.port(),
spec.feature());
return maybe_paragraph.get()->supports_expression;
@@ -858,7 +858,7 @@ namespace vcpkg::Dependencies
Checks::check_maybe_upgrade(VCPKG_LINE_INFO,
maybe_paragraph.has_value(),
"Package %s does not have a %s feature",
- spec.name(),
+ spec.port(),
spec.feature());
paragraph_depends = &maybe_paragraph.value_or_exit(VCPKG_LINE_INFO).dependencies;
has_supports = !maybe_paragraph.get()->supports_expression.is_empty();
@@ -882,7 +882,7 @@ namespace vcpkg::Dependencies
m_var_provider.get_dep_info_vars(spec.spec()).value_or_exit(VCPKG_LINE_INFO)))
{
const auto msg = Strings::format("%s[%s] is only supported on '%s'",
- spec.name(),
+ spec.port(),
spec.feature(),
to_string(*supports_expression.get()));
if (unsupported_port_action == UnsupportedPortAction::Error)
@@ -1300,9 +1300,8 @@ namespace vcpkg::Dependencies
std::vector features;
};
- // This object contains the current version within a given column.
- // Each "string" scheme text is treated as a separate column
- // "relaxed" versions all share the same column
+ // This object contains the current version within a given version scheme (except for the "string" scheme,
+ // there we save an object for every version)
struct VersionSchemeInfo
{
Versions::Scheme scheme;
@@ -1310,6 +1309,7 @@ namespace vcpkg::Dependencies
Versions::Version version;
// This tracks a list of constraint sources for debugging purposes
std::vector origins;
+ // mapping from feature name -> dependencies of this feature
std::map> deps;
bool is_less_than(const Versions::Version& new_ver) const;
@@ -1317,16 +1317,36 @@ namespace vcpkg::Dependencies
struct PackageNode
{
+ // Mapping from version to the newest version in the corresponding version scheme
+ // For example, given the versions:
+ // - "version-string": "1.0.0"
+ // - "version": "1.0.1"
+ // - "version": "1.0.2"
+ // you'd have a map:
+ // {
+ // "1.0.0": { "version-string": "1.0.0" },
+ // "1.0.1": { "version": "1.0.2" },
+ // "1.0.2": { "version": "1.0.2" }
+ // }
std::map vermap;
+ // We don't know how to compare "version-string" versions, so keep all the versions separately
std::map exacts;
+ // for each version type besides string (relaxed, semver, date), we only track the latest version
+ // required
Optional> relaxed;
Optional> semver;
Optional> date;
- std::set features;
+ std::set requested_features;
bool default_features = true;
bool user_requested = false;
VersionSchemeInfo* get_node(const Versions::Version& ver);
+ // Adds the version to the version resolver:
+ // - for string version schemes, just adds the newer version to the set
+ // - for non-string version schemes:
+ // - if the scheme doesn't exist in the set, adds the version to the set
+ // - if the scheme already exists in the set, and the version is newer than the existing entry,
+ // replaces the current entry for the scheme
VersionSchemeInfo& emplace_node(Versions::Scheme scheme, const Versions::Version& ver);
PackageNode() = default;
@@ -1357,24 +1377,25 @@ namespace vcpkg::Dependencies
}
};
+ // the roots of the dependency graph (given in the manifest file)
std::vector m_roots;
+ // mapping from portname -> version. "overrides" field in manifest file
std::map m_overrides;
+ // mapping from { package specifier -> node containing resolution information for that package }
std::map m_graph;
std::pair& emplace_package(const PackageSpec& spec);
- void add_constraint(std::pair& ref,
- const Dependency& dep,
- const std::string& origin);
- void add_constraint(std::pair& ref,
- const Versions::Version& ver,
- const std::string& origin);
- void add_constraint(std::pair& ref,
- const std::string& feature,
- const std::string& origin);
-
- void add_constraint_default_features(std::pair& ref,
- const std::string& origin);
+ // the following 4 functions will add stuff recursivly
+ void require_dependency(std::pair& ref,
+ const Dependency& dep,
+ const std::string& origin);
+ void require_port_version(std::pair& graph_entry,
+ const Versions::Version& ver,
+ const std::string& origin);
+ void require_port_feature(std::pair& ref,
+ const std::string& feature,
+ const std::string& origin);
void add_feature_to(std::pair& ref,
VersionSchemeInfo& vsi,
@@ -1549,12 +1570,12 @@ namespace vcpkg::Dependencies
// this is a feature dependency for oneself
for (auto&& f : dep.features)
{
- add_constraint(ref, f, ref.first.name());
+ require_port_feature(ref, f, ref.first.name());
}
}
else
{
- add_constraint(dep_node, dep, ref.first.name());
+ require_dependency(dep_node, dep, ref.first.name());
}
p.first->second.emplace_back(dep_spec, "core");
@@ -1565,36 +1586,20 @@ namespace vcpkg::Dependencies
}
}
- void VersionedPackageGraph::add_constraint_default_features(std::pair& ref,
- const std::string& origin)
- {
- (void)origin;
- if (!ref.second.default_features)
- {
- ref.second.default_features = true;
- ref.second.foreach_vsi([this, &ref](VersionSchemeInfo& vsi) {
- for (auto&& f : vsi.scfl->source_control_file->core_paragraph->default_features)
- {
- this->add_feature_to(ref, vsi, f);
- }
- });
- }
- }
-
- void VersionedPackageGraph::add_constraint(std::pair& ref,
- const Dependency& dep,
- const std::string& origin)
+ void VersionedPackageGraph::require_dependency(std::pair& ref,
+ const Dependency& dep,
+ const std::string& origin)
{
auto maybe_overlay = m_o_provider.get_control_file(ref.first.name());
auto over_it = m_overrides.find(ref.first.name());
if (auto p_overlay = maybe_overlay.get())
{
auto overlay_version = to_version(*p_overlay->source_control_file);
- add_constraint(ref, overlay_version, origin);
+ require_port_version(ref, overlay_version, origin);
}
else if (over_it != m_overrides.end())
{
- add_constraint(ref, over_it->second, origin);
+ require_port_version(ref, over_it->second, origin);
}
else
{
@@ -1603,84 +1608,89 @@ namespace vcpkg::Dependencies
if (auto dv = dep_ver.get())
{
- add_constraint(ref, *dv, origin);
+ require_port_version(ref, *dv, origin);
}
if (auto bv = base_ver.get())
{
- add_constraint(ref, *bv, origin);
+ require_port_version(ref, *bv, origin);
}
}
for (auto&& f : dep.features)
{
- add_constraint(ref, f, origin);
+ require_port_feature(ref, f, origin);
}
}
- void VersionedPackageGraph::add_constraint(std::pair& ref,
- const Versions::Version& version,
- const std::string& origin)
+ void VersionedPackageGraph::require_port_version(std::pair& graph_entry,
+ const Versions::Version& version,
+ const std::string& origin)
{
ExpectedS maybe_scfl;
- auto maybe_overlay = m_o_provider.get_control_file(ref.first.name());
+ // if this port is an overlay port, ignore the given version and use the version from the overlay
+ auto maybe_overlay = m_o_provider.get_control_file(graph_entry.first.name());
if (auto p_overlay = maybe_overlay.get())
{
auto overlay_version = to_version(*p_overlay->source_control_file);
+ // If the original request did not match the overlay version, restart this function to operate on the
+ // overlay version
if (version != overlay_version)
{
- return add_constraint(ref, overlay_version, origin);
+ return require_port_version(graph_entry, overlay_version, origin);
}
maybe_scfl = *p_overlay;
}
else
{
- auto over_it = m_overrides.find(ref.first.name());
+ // if there is a override, ignore the given version and use the version from the override
+ auto over_it = m_overrides.find(graph_entry.first.name());
if (over_it != m_overrides.end() && over_it->second != version)
{
- return add_constraint(ref, over_it->second, origin);
+ return require_port_version(graph_entry, over_it->second, origin);
}
- maybe_scfl = m_ver_provider.get_control_file({ref.first.name(), version});
+ maybe_scfl = m_ver_provider.get_control_file({graph_entry.first.name(), version});
}
if (auto p_scfl = maybe_scfl.get())
{
- auto& exact_ref =
- ref.second.emplace_node(p_scfl->source_control_file->core_paragraph->version_scheme, version);
- exact_ref.origins.push_back(origin);
-
+ auto& versioned_graph_entry = graph_entry.second.emplace_node(
+ p_scfl->source_control_file->core_paragraph->version_scheme, version);
+ versioned_graph_entry.origins.push_back(origin);
+ // Use the new source control file if we currently don't have one or the new one is newer
bool replace;
- if (exact_ref.scfl == nullptr)
+ if (versioned_graph_entry.scfl == nullptr)
{
replace = true;
}
- else if (exact_ref.scfl == p_scfl)
+ else if (versioned_graph_entry.scfl == p_scfl)
{
replace = false;
}
else
{
- replace = exact_ref.is_less_than(version);
+ replace = versioned_graph_entry.is_less_than(version);
}
if (replace)
{
- exact_ref.scfl = p_scfl;
- exact_ref.version = to_version(*p_scfl->source_control_file);
- exact_ref.deps.clear();
+ versioned_graph_entry.scfl = p_scfl;
+ versioned_graph_entry.version = to_version(*p_scfl->source_control_file);
+ versioned_graph_entry.deps.clear();
- add_feature_to(ref, exact_ref, "core");
+ // add all dependencies to the graph
+ add_feature_to(graph_entry, versioned_graph_entry, "core");
- for (auto&& f : ref.second.features)
+ for (auto&& f : graph_entry.second.requested_features)
{
- add_feature_to(ref, exact_ref, f);
+ add_feature_to(graph_entry, versioned_graph_entry, f);
}
- if (ref.second.default_features)
+ if (graph_entry.second.default_features)
{
for (auto&& f : p_scfl->source_control_file->core_paragraph->default_features)
{
- add_feature_to(ref, exact_ref, f);
+ add_feature_to(graph_entry, versioned_graph_entry, f);
}
}
}
@@ -1691,11 +1701,11 @@ namespace vcpkg::Dependencies
}
}
- void VersionedPackageGraph::add_constraint(std::pair& ref,
- const std::string& feature,
- const std::string& origin)
+ void VersionedPackageGraph::require_port_feature(std::pair& ref,
+ const std::string& feature,
+ const std::string& origin)
{
- auto inserted = ref.second.features.emplace(feature).second;
+ auto inserted = ref.second.requested_features.emplace(feature).second;
if (inserted)
{
ref.second.foreach_vsi(
@@ -1767,6 +1777,11 @@ namespace vcpkg::Dependencies
const auto& vars = m_var_provider.get_dep_info_vars(toplevel).value_or_exit(VCPKG_LINE_INFO);
std::vector active_deps;
+ // First add all top level packages to ensure the default_features is set to false before recursing into the
+ // individual packages. Otherwise, a case like:
+ // A -> B, C[core]
+ // B -> C
+ // could install the default features of C. (A is the manifest/vcpkg.json)
for (auto&& dep : deps)
{
if (!dep.platform.evaluate(vars)) continue;
@@ -1796,12 +1811,12 @@ namespace vcpkg::Dependencies
{
auto ver = to_version(*p_overlay->source_control_file);
m_roots.push_back(DepSpec{spec, ver, dep.features});
- add_constraint(node, ver, toplevel.name());
+ require_port_version(node, ver, toplevel.name());
}
else if (over_it != m_overrides.end())
{
m_roots.push_back(DepSpec{spec, over_it->second, dep.features});
- add_constraint(node, over_it->second, toplevel.name());
+ require_port_version(node, over_it->second, toplevel.name());
}
else
{
@@ -1824,13 +1839,13 @@ namespace vcpkg::Dependencies
*p_base_ver);
if (r == VerComp::lt)
{
- add_constraint(node, *p_base_ver, "baseline");
- add_constraint(node, *p_dep_ver, toplevel.name());
+ require_port_version(node, *p_base_ver, "baseline");
+ require_port_version(node, *p_dep_ver, toplevel.name());
}
else
{
- add_constraint(node, *p_dep_ver, toplevel.name());
- add_constraint(node, *p_base_ver, "baseline");
+ require_port_version(node, *p_dep_ver, toplevel.name());
+ require_port_version(node, *p_base_ver, "baseline");
}
}
else
@@ -1841,13 +1856,13 @@ namespace vcpkg::Dependencies
}
else
{
- add_constraint(node, *p_dep_ver, toplevel.name());
+ require_port_version(node, *p_dep_ver, toplevel.name());
}
}
else if (auto p_base_ver = base_ver.get())
{
m_roots.push_back(DepSpec{spec, *p_base_ver, dep.features});
- add_constraint(node, *p_base_ver, toplevel.name());
+ require_port_version(node, *p_base_ver, toplevel.name());
}
else
{
@@ -1857,11 +1872,7 @@ namespace vcpkg::Dependencies
for (auto&& f : dep.features)
{
- add_constraint(node, f, toplevel.name());
- }
- if (Util::find(dep.features, "core") == dep.features.end())
- {
- add_constraint_default_features(node, toplevel.name());
+ require_port_feature(node, f, toplevel.name());
}
}
}
@@ -1919,6 +1930,7 @@ namespace vcpkg::Dependencies
};
std::vector stack;
+ // Adds a new Frame to the stack if the spec was not already added
auto push = [&emitted, this, &stack, unsupported_port_action, &ret](
const PackageSpec& spec,
const Versions::Version& new_ver,
diff --git a/src/vcpkg/packagespec.cpp b/src/vcpkg/packagespec.cpp
index 3f35e118e0..14692d8f2a 100644
--- a/src/vcpkg/packagespec.cpp
+++ b/src/vcpkg/packagespec.cpp
@@ -16,7 +16,7 @@ namespace vcpkg
void FeatureSpec::to_string(std::string& out) const
{
if (feature().empty()) return spec().to_string(out);
- Strings::append(out, name(), '[', feature(), "]:", triplet());
+ Strings::append(out, port(), '[', feature(), "]:", triplet());
}
std::vector FullPackageSpec::to_feature_specs(const std::vector& default_features,