[vcpkg] Added parser support for 'Supports' field
MODIFY
include/SourceParagraph.h
include/SourceParagraph.h
#pragma once
+#include "vcpkg_System.h"
#include "vcpkg_expected.h"
+
+#include <string>
#include <unordered_map>
#include <vector>
@@ -38,6 +41,7 @@ namespace vcpkg
std::string version;
std::string description;
std::string maintainer;
+ std::vector<std::string> supports;
std::vector<Dependency> depends;
};
@@ -47,5 +51,36 @@ namespace vcpkg
std::vector<std::string> filter_dependencies(const std::vector<Dependency>& deps, const Triplet& t);
std::vector<Dependency> expand_qualified_dependencies(const std::vector<std::string>& depends);
- std::vector<std::string> parse_depends(const std::string& depends_string);
+ std::vector<std::string> parse_comma_list(const std::string& str);
+
+ struct Supports
+ {
+ static ExpectedT<Supports, std::vector<std::string>> parse(const std::vector<std::string>& strs);
+
+ using Architecture = System::CPUArchitecture;
+
+ enum class Platform
+ {
+ WINDOWS,
+ UWP,
+ };
+ enum class Linkage
+ {
+ DYNAMIC,
+ STATIC,
+ };
+ enum class ToolsetVersion
+ {
+ V140,
+ V141,
+ };
+
+ bool supports(Architecture arch, Platform plat, Linkage crt, ToolsetVersion tools);
+
+ private:
+ std::vector<Architecture> architectures;
+ std::vector<Platform> platforms;
+ std::vector<Linkage> crt_linkages;
+ std::vector<ToolsetVersion> toolsets;
+ };
}

MODIFY
include/vcpkg_Util.h
include/vcpkg_Util.h
@@ -34,6 +34,12 @@ namespace vcpkg::Util
cont.erase(std::remove_if(cont.begin(), cont.end(), pred), cont.end());
}
+ template<class Container, class V>
+ auto find(const Container& cont, V&& v)
+ {
+ return std::find(cont.cbegin(), cont.cend(), v);
+ }
+
template<class Container, class Pred>
auto find_if(const Container& cont, Pred pred)
{

MODIFY
src/BinaryParagraph.cpp
src/BinaryParagraph.cpp
@@ -42,7 +42,7 @@ namespace vcpkg
Checks::check_exit(VCPKG_LINE_INFO, multi_arch == "same", "Multi-Arch must be 'same' but was %s", multi_arch);
std::string deps = details::remove_optional_field(&fields, BinaryParagraphOptionalField::DEPENDS);
- this->depends = parse_depends(deps);
+ this->depends = parse_comma_list(deps);
}
BinaryParagraph::BinaryParagraph(const SourceParagraph& spgh, const Triplet& triplet)

MODIFY
src/SourceParagraph.cpp
src/SourceParagraph.cpp
#include "vcpkg_Checks.h"
#include "vcpkg_Maps.h"
#include "vcpkg_System.h"
+#include "vcpkg_Util.h"
#include "vcpkg_expected.h"
#include "vcpkglib_helpers.h"
@@ -23,6 +24,7 @@ namespace vcpkg
static const std::string DESCRIPTION = "Description";
static const std::string MAINTAINER = "Maintainer";
static const std::string BUILD_DEPENDS = "Build-Depends";
+ static const std::string SUPPORTS = "Supports";
}
static const std::vector<std::string>& get_list_of_valid_fields()
@@ -32,7 +34,8 @@ namespace vcpkg
SourceParagraphOptionalField::DESCRIPTION,
SourceParagraphOptionalField::MAINTAINER,
- SourceParagraphOptionalField::BUILD_DEPENDS};
+ SourceParagraphOptionalField::BUILD_DEPENDS,
+ SourceParagraphOptionalField::SUPPORTS};
return valid_fields;
}
@@ -72,7 +75,10 @@ namespace vcpkg
sparagraph.maintainer = details::remove_optional_field(&fields, SourceParagraphOptionalField::MAINTAINER);
std::string deps = details::remove_optional_field(&fields, SourceParagraphOptionalField::BUILD_DEPENDS);
- sparagraph.depends = expand_qualified_dependencies(parse_depends(deps));
+ sparagraph.depends = expand_qualified_dependencies(parse_comma_list(deps));
+
+ std::string sups = details::remove_optional_field(&fields, SourceParagraphOptionalField::SUPPORTS);
+ sparagraph.supports = parse_comma_list(sups);
if (!fields.empty())
{
@@ -89,7 +95,7 @@ namespace vcpkg
std::vector<Dependency> vcpkg::expand_qualified_dependencies(const std::vector<std::string>& depends)
{
- auto convert = [&](const std::string& depend_string) -> Dependency {
+ return Util::fmap(depends, [&](const std::string& depend_string) -> Dependency {
auto pos = depend_string.find(' ');
if (pos == std::string::npos) return {depend_string, ""};
// expect of the form "\w+ \[\w+\]"
@@ -102,21 +108,12 @@ namespace vcpkg
}
dep.qualifier = depend_string.substr(pos + 2, depend_string.size() - pos - 3);
return dep;
- };
-
- std::vector<vcpkg::Dependency> ret;
-
- for (auto&& depend_string : depends)
- {
- ret.push_back(convert(depend_string));
+ });
}
- return ret;
- }
-
- std::vector<std::string> parse_depends(const std::string& depends_string)
+ std::vector<std::string> parse_comma_list(const std::string& str)
{
- if (depends_string.empty())
+ if (str.empty())
{
return {};
}
@@ -126,17 +123,17 @@ namespace vcpkg
size_t cur = 0;
do
{
- auto pos = depends_string.find(',', cur);
+ auto pos = str.find(',', cur);
if (pos == std::string::npos)
{
- out.push_back(depends_string.substr(cur));
+ out.push_back(str.substr(cur));
break;
}
- out.push_back(depends_string.substr(cur, pos - cur));
+ out.push_back(str.substr(cur, pos - cur));
// skip comma and space
++pos;
- if (depends_string[pos] == ' ')
+ if (str[pos] == ' ')
{
++pos;
}
@@ -161,4 +158,49 @@ namespace vcpkg
}
const std::string& to_string(const Dependency& dep) { return dep.name; }
+
+ ExpectedT<Supports, std::vector<std::string>> Supports::parse(const std::vector<std::string>& strs)
+ {
+ Supports ret;
+ std::vector<std::string> unrecognized;
+
+ for (auto&& str : strs)
+ {
+ if (str == "x64")
+ ret.architectures.push_back(Architecture::X64);
+ else if (str == "x86")
+ ret.architectures.push_back(Architecture::X86);
+ else if (str == "arm")
+ ret.architectures.push_back(Architecture::ARM);
+ else if (str == "windows")
+ ret.platforms.push_back(Platform::WINDOWS);
+ else if (str == "uwp")
+ ret.platforms.push_back(Platform::UWP);
+ else if (str == "v140")
+ ret.toolsets.push_back(ToolsetVersion::V140);
+ else if (str == "v141")
+ ret.toolsets.push_back(ToolsetVersion::V141);
+ else if (str == "crt-static")
+ ret.crt_linkages.push_back(Linkage::STATIC);
+ else if (str == "crt-dynamic")
+ ret.crt_linkages.push_back(Linkage::DYNAMIC);
+ else
+ unrecognized.push_back(str);
+ }
+
+ if (unrecognized.empty())
+ return std::move(ret);
+ else
+ return std::move(unrecognized);
+ }
+
+ bool Supports::supports(Architecture arch, Platform plat, Linkage crt, ToolsetVersion tools)
+ {
+ auto is_in_or_empty = [](auto v, auto&& c) -> bool { return c.empty() || c.end() != Util::find(c, v); };
+ if (!is_in_or_empty(arch, architectures)) return false;
+ if (!is_in_or_empty(plat, platforms)) return false;
+ if (!is_in_or_empty(crt, crt_linkages)) return false;
+ if (!is_in_or_empty(tools, toolsets)) return false;
+ return true;
+ }
}

MODIFY
src/tests_dependencies.cpp
src/tests_dependencies.cpp
@@ -15,7 +15,7 @@ namespace UnitTest1
{
TEST_METHOD(parse_depends_one)
{
- auto v = expand_qualified_dependencies(parse_depends("libA [windows]"));
+ auto v = expand_qualified_dependencies(parse_comma_list("libA [windows]"));
Assert::AreEqual(size_t(1), v.size());
Assert::AreEqual("libA", v[0].name.c_str());
Assert::AreEqual("windows", v[0].qualifier.c_str());
@@ -23,7 +23,7 @@ namespace UnitTest1
TEST_METHOD(filter_depends)
{
- auto deps = expand_qualified_dependencies(parse_depends("libA [windows], libB, libC [uwp]"));
+ auto deps = expand_qualified_dependencies(parse_comma_list("libA [windows], libB, libC [uwp]"));
auto v = filter_dependencies(deps, Triplet::X64_WINDOWS);
Assert::AreEqual(size_t(2), v.size());
Assert::AreEqual("libA", v[0].c_str());
@@ -35,4 +35,65 @@ namespace UnitTest1
Assert::AreEqual("libC", v2[1].c_str());
}
};
+
+ class SupportsTests : public TestClass<SupportsTests>
+ {
+ TEST_METHOD(parse_supports_all)
+ {
+ auto v = Supports::parse({
+ "x64", "x86", "arm", "windows", "uwp", "v140", "v141", "crt-static", "crt-dynamic",
+ });
+ Assert::AreNotEqual(uintptr_t(0), uintptr_t(v.get()));
+
+ Assert::IsTrue(v.get()->supports(System::CPUArchitecture::X64,
+ Supports::Platform::UWP,
+ Supports::Linkage::DYNAMIC,
+ Supports::ToolsetVersion::V140));
+ Assert::IsTrue(v.get()->supports(System::CPUArchitecture::ARM,
+ Supports::Platform::WINDOWS,
+ Supports::Linkage::STATIC,
+ Supports::ToolsetVersion::V141));
+ }
+
+ TEST_METHOD(parse_supports_invalid)
+ {
+ auto v = Supports::parse({"arm64"});
+ Assert::AreEqual(uintptr_t(0), uintptr_t(v.get()));
+ Assert::AreEqual(size_t(1), v.error().size());
+ Assert::AreEqual("arm64", v.error()[0].c_str());
+ }
+
+ TEST_METHOD(parse_supports_case_sensitive)
+ {
+ auto v = Supports::parse({"Windows"});
+ Assert::AreEqual(uintptr_t(0), uintptr_t(v.get()));
+ Assert::AreEqual(size_t(1), v.error().size());
+ Assert::AreEqual("Windows", v.error()[0].c_str());
+ }
+
+ TEST_METHOD(parse_supports_some)
+ {
+ auto v = Supports::parse({
+ "x64", "x86", "windows",
+ });
+ Assert::AreNotEqual(uintptr_t(0), uintptr_t(v.get()));
+
+ Assert::IsTrue(v.get()->supports(System::CPUArchitecture::X64,
+ Supports::Platform::WINDOWS,
+ Supports::Linkage::DYNAMIC,
+ Supports::ToolsetVersion::V140));
+ Assert::IsFalse(v.get()->supports(System::CPUArchitecture::ARM,
+ Supports::Platform::WINDOWS,
+ Supports::Linkage::DYNAMIC,
+ Supports::ToolsetVersion::V140));
+ Assert::IsFalse(v.get()->supports(System::CPUArchitecture::X64,
+ Supports::Platform::UWP,
+ Supports::Linkage::DYNAMIC,
+ Supports::ToolsetVersion::V140));
+ Assert::IsTrue(v.get()->supports(System::CPUArchitecture::X64,
+ Supports::Platform::WINDOWS,
+ Supports::Linkage::STATIC,
+ Supports::ToolsetVersion::V141));
+ }
+ };
}

MODIFY
src/tests_paragraph.cpp
src/tests_paragraph.cpp
@@ -40,7 +40,12 @@ namespace UnitTest1
TEST_METHOD(SourceParagraph_Construct_Maximum)
{
auto m_pgh = vcpkg::SourceParagraph::parse_control_file({
- {"Source", "s"}, {"Version", "v"}, {"Maintainer", "m"}, {"Description", "d"}, {"Build-Depends", "bd"},
+ {"Source", "s"},
+ {"Version", "v"},
+ {"Maintainer", "m"},
+ {"Description", "d"},
+ {"Build-Depends", "bd"},
+ {"Supports", "x64"},
});
Assert::IsTrue(m_pgh.has_value());
auto& pgh = *m_pgh.get();
@@ -51,6 +56,8 @@ namespace UnitTest1
Assert::AreEqual("d", pgh.description.c_str());
Assert::AreEqual(size_t(1), pgh.depends.size());
Assert::AreEqual("bd", pgh.depends[0].name.c_str());
+ Assert::AreEqual(size_t(1), pgh.supports.size());
+ Assert::AreEqual("x64", pgh.supports[0].c_str());
}
TEST_METHOD(SourceParagraph_Two_Depends)
@@ -80,6 +87,20 @@ namespace UnitTest1
Assert::AreEqual("xyz", pgh.depends[2].name.c_str());
}
+ TEST_METHOD(SourceParagraph_Three_Supports)
+ {
+ auto m_pgh = vcpkg::SourceParagraph::parse_control_file({
+ {"Source", "zlib"}, {"Version", "1.2.8"}, {"Supports", "x64, windows, uwp"},
+ });
+ Assert::IsTrue(m_pgh.has_value());
+ auto& pgh = *m_pgh.get();
+
+ Assert::AreEqual(size_t(3), pgh.supports.size());
+ Assert::AreEqual("x64", pgh.supports[0].c_str());
+ Assert::AreEqual("windows", pgh.supports[1].c_str());
+ Assert::AreEqual("uwp", pgh.supports[2].c_str());
+ }
+
TEST_METHOD(SourceParagraph_Construct_Qualified_Depends)
{
auto m_pgh = vcpkg::SourceParagraph::parse_control_file({

[vcpkg] Added parser support for 'Supports' field