aboutsummaryrefslogtreecommitdiff
path: root/toolsrc/src
diff options
context:
space:
mode:
authorWimok Nupphiboon <wimok.mok@gmail.com>2018-04-13 09:48:50 +0700
committerWimok Nupphiboon <wimok.mok@gmail.com>2018-04-13 09:48:50 +0700
commit00cdc0b10a089c6c3763f8e3c7847efac909e3fd (patch)
treedbe3d517060d68a06e7b0ac58104b0d7ea8547b6 /toolsrc/src
parent30b56c86148babd61eb6c7c2807421bdcd8d3c13 (diff)
parentdc207a2c891fe6deb2710ccde0abf48078f64fcd (diff)
downloadvcpkg-00cdc0b10a089c6c3763f8e3c7847efac909e3fd.tar.gz
vcpkg-00cdc0b10a089c6c3763f8e3c7847efac909e3fd.zip
Merge remote-tracking branch 'origin/master'
Diffstat (limited to 'toolsrc/src')
-rw-r--r--toolsrc/src/tests.plan.cpp146
-rw-r--r--toolsrc/src/vcpkg.cpp2
-rw-r--r--toolsrc/src/vcpkg/base/chrono.cpp10
-rw-r--r--toolsrc/src/vcpkg/base/cofffilereader.cpp102
-rw-r--r--toolsrc/src/vcpkg/base/files.cpp17
-rw-r--r--toolsrc/src/vcpkg/base/strings.cpp20
-rw-r--r--toolsrc/src/vcpkg/base/system.cpp46
-rw-r--r--toolsrc/src/vcpkg/binaryparagraph.cpp4
-rw-r--r--toolsrc/src/vcpkg/build.cpp98
-rw-r--r--toolsrc/src/vcpkg/commands.cache.cpp2
-rw-r--r--toolsrc/src/vcpkg/commands.ci.cpp7
-rw-r--r--toolsrc/src/vcpkg/commands.contact.cpp14
-rw-r--r--toolsrc/src/vcpkg/commands.cpp5
-rw-r--r--toolsrc/src/vcpkg/commands.create.cpp4
-rw-r--r--toolsrc/src/vcpkg/commands.dependinfo.cpp3
-rw-r--r--toolsrc/src/vcpkg/commands.edit.cpp7
-rw-r--r--toolsrc/src/vcpkg/commands.exportifw.cpp6
-rw-r--r--toolsrc/src/vcpkg/commands.fetch.cpp717
-rw-r--r--toolsrc/src/vcpkg/commands.hash.cpp222
-rw-r--r--toolsrc/src/vcpkg/commands.import.cpp2
-rw-r--r--toolsrc/src/vcpkg/commands.integrate.cpp27
-rw-r--r--toolsrc/src/vcpkg/commands.list.cpp11
-rw-r--r--toolsrc/src/vcpkg/commands.owns.cpp2
-rw-r--r--toolsrc/src/vcpkg/commands.portsdiff.cpp7
-rw-r--r--toolsrc/src/vcpkg/commands.upgrade.cpp3
-rw-r--r--toolsrc/src/vcpkg/commands.version.cpp2
-rw-r--r--toolsrc/src/vcpkg/dependencies.cpp452
-rw-r--r--toolsrc/src/vcpkg/export.cpp27
-rw-r--r--toolsrc/src/vcpkg/metrics.cpp17
-rw-r--r--toolsrc/src/vcpkg/parse.cpp1
-rw-r--r--toolsrc/src/vcpkg/postbuildlint.cpp8
-rw-r--r--toolsrc/src/vcpkg/remove.cpp4
-rw-r--r--toolsrc/src/vcpkg/statusparagraph.cpp11
-rw-r--r--toolsrc/src/vcpkg/triplet.cpp3
-rw-r--r--toolsrc/src/vcpkg/update.cpp11
-rw-r--r--toolsrc/src/vcpkg/vcpkglib.cpp24
-rw-r--r--toolsrc/src/vcpkg/vcpkgpaths.cpp659
-rw-r--r--toolsrc/src/vcpkg/versiont.cpp4
38 files changed, 1480 insertions, 1227 deletions
diff --git a/toolsrc/src/tests.plan.cpp b/toolsrc/src/tests.plan.cpp
index a99f1abb9..238aa7032 100644
--- a/toolsrc/src/tests.plan.cpp
+++ b/toolsrc/src/tests.plan.cpp
@@ -81,7 +81,7 @@ namespace UnitTest1
{
std::unordered_map<std::string, SourceControlFile> map;
Triplet triplet;
- PackageSpecMap(const Triplet& t) { triplet = t; }
+ PackageSpecMap(const Triplet& t = Triplet::X86_WINDOWS) noexcept { triplet = t; }
PackageSpec emplace(const char* name,
const char* depends = "",
@@ -105,7 +105,7 @@ namespace UnitTest1
{
std::vector<std::unique_ptr<StatusParagraph>> status_paragraphs;
- PackageSpecMap spec_map(Triplet::X86_WINDOWS);
+ PackageSpecMap spec_map;
auto spec_a = spec_map.emplace("a", "b");
auto spec_b = spec_map.emplace("b", "c");
auto spec_c = spec_map.emplace("c");
@@ -124,7 +124,7 @@ namespace UnitTest1
{
std::vector<std::unique_ptr<StatusParagraph>> status_paragraphs;
- PackageSpecMap spec_map(Triplet::X86_WINDOWS);
+ PackageSpecMap spec_map;
auto spec_a = spec_map.emplace("a", "d");
auto spec_b = spec_map.emplace("b", "d, e");
auto spec_c = spec_map.emplace("c", "e, h");
@@ -167,7 +167,7 @@ namespace UnitTest1
std::vector<std::unique_ptr<StatusParagraph>> status_paragraphs;
status_paragraphs.push_back(make_status_pgh("a"));
- PackageSpecMap spec_map(Triplet::X86_WINDOWS);
+ PackageSpecMap spec_map;
auto spec_a = FullPackageSpec{spec_map.emplace("a")};
auto install_plan =
@@ -187,7 +187,7 @@ namespace UnitTest1
{
std::vector<std::unique_ptr<StatusParagraph>> status_paragraphs;
- PackageSpecMap spec_map(Triplet::X86_WINDOWS);
+ PackageSpecMap spec_map;
auto spec_a = FullPackageSpec{spec_map.emplace("a", "b")};
auto spec_b = FullPackageSpec{spec_map.emplace("b")};
@@ -216,7 +216,7 @@ namespace UnitTest1
status_paragraphs.push_back(make_status_pgh("j", "k"));
status_paragraphs.push_back(make_status_pgh("k"));
- PackageSpecMap spec_map(Triplet::X86_WINDOWS);
+ PackageSpecMap spec_map;
auto spec_a = spec_map.emplace("a", "b, c, d, e, f, g, h, j, k");
auto spec_b = spec_map.emplace("b", "c, d, e, f, g, h, j, k");
@@ -251,7 +251,7 @@ namespace UnitTest1
status_paragraphs.push_back(make_status_pgh("b"));
status_paragraphs.push_back(make_status_feature_pgh("b", "b1"));
- PackageSpecMap spec_map(Triplet::X86_WINDOWS);
+ PackageSpecMap spec_map;
auto spec_a = FullPackageSpec{spec_map.emplace("a", "b, b[b1]", {{"a1", "b[b2]"}}), {"a1"}};
auto spec_b = FullPackageSpec{spec_map.emplace("b", "", {{"b1", ""}, {"b2", ""}, {"b3", ""}})};
@@ -271,7 +271,7 @@ namespace UnitTest1
{
std::vector<std::unique_ptr<StatusParagraph>> status_paragraphs;
- PackageSpecMap spec_map(Triplet::X86_WINDOWS);
+ PackageSpecMap spec_map;
auto spec_a = FullPackageSpec{spec_map.emplace("a", "b[b1]", {{"a1", "b[b2]"}}), {"a1"}};
auto spec_b = FullPackageSpec{spec_map.emplace("b", "", {{"b1", ""}, {"b2", ""}, {"b3", ""}})};
@@ -291,7 +291,7 @@ namespace UnitTest1
std::vector<std::unique_ptr<StatusParagraph>> status_paragraphs;
status_paragraphs.push_back(make_status_pgh("a"));
- PackageSpecMap spec_map(Triplet::X86_WINDOWS);
+ PackageSpecMap spec_map;
auto spec_a = FullPackageSpec{spec_map.emplace("a", "b", {{"a1", ""}}), {"core"}};
auto spec_b = FullPackageSpec{spec_map.emplace("b")};
@@ -315,7 +315,7 @@ namespace UnitTest1
status_paragraphs.push_back(make_status_pgh("a"));
status_paragraphs.push_back(make_status_feature_pgh("a", "a1", ""));
- PackageSpecMap spec_map(Triplet::X86_WINDOWS);
+ PackageSpecMap spec_map;
auto spec_a = FullPackageSpec{spec_map.emplace("a", "b", {{"a1", ""}})};
auto spec_b = FullPackageSpec{spec_map.emplace("b")};
@@ -334,7 +334,7 @@ namespace UnitTest1
{
std::vector<std::unique_ptr<StatusParagraph>> status_paragraphs;
- PackageSpecMap spec_map(Triplet::X86_WINDOWS);
+ PackageSpecMap spec_map;
auto spec_a =
FullPackageSpec{spec_map.emplace("a", "", {{"a1", "b[b1]"}, {"a2", "b[b2]"}, {"a3", "a[a2]"}}), {"a3"}};
@@ -355,7 +355,7 @@ namespace UnitTest1
std::vector<std::unique_ptr<StatusParagraph>> status_paragraphs;
status_paragraphs.push_back(make_status_pgh("b"));
- PackageSpecMap spec_map(Triplet::X86_WINDOWS);
+ PackageSpecMap spec_map;
auto spec_a = FullPackageSpec{spec_map.emplace("a", "b[core]"), {"core"}};
auto spec_b = FullPackageSpec{spec_map.emplace("b", "", {{"b1", ""}}), {"b1"}};
@@ -376,7 +376,7 @@ namespace UnitTest1
status_paragraphs.push_back(make_status_pgh("x", "b"));
status_paragraphs.push_back(make_status_pgh("b"));
- PackageSpecMap spec_map(Triplet::X86_WINDOWS);
+ PackageSpecMap spec_map;
auto spec_a = FullPackageSpec{spec_map.emplace("a")};
auto spec_x = FullPackageSpec{spec_map.emplace("x", "a"), {"core"}};
@@ -674,17 +674,35 @@ namespace UnitTest1
Assert::IsTrue(install_plan[0].install_action.get()->computed_dependencies == std::vector<PackageSpec>{});
}
+ TEST_METHOD(install_with_default_features)
+ {
+ std::vector<std::unique_ptr<StatusParagraph>> pghs;
+ pghs.push_back(make_status_pgh("a", ""));
+ StatusParagraphs status_db(std::move(pghs));
+
+ PackageSpecMap spec_map;
+ auto b_spec = spec_map.emplace("b", "", {{"0", ""}}, {"0"});
+ auto a_spec = spec_map.emplace("a", "b[core]", {{"0", ""}});
+
+ // Install "a" and indicate that "b" should not install default features
+ auto install_plan = Dependencies::create_feature_install_plan(
+ spec_map.map, {FeatureSpec{a_spec, "0"}, FeatureSpec{b_spec, "core"}}, status_db);
+
+ Assert::IsTrue(install_plan.size() == 3);
+ remove_plan_check(&install_plan[0], "a");
+ features_check(&install_plan[1], "b", {"core"});
+ features_check(&install_plan[2], "a", {"0", "core"});
+ }
+
TEST_METHOD(upgrade_with_default_features_1)
{
std::vector<std::unique_ptr<StatusParagraph>> pghs;
pghs.push_back(make_status_pgh("a", "", "1"));
pghs.push_back(make_status_feature_pgh("a", "0"));
- pghs.back()->package.spec =
- PackageSpec::from_name_and_triplet("a", Triplet::X86_WINDOWS).value_or_exit(VCPKG_LINE_INFO);
StatusParagraphs status_db(std::move(pghs));
// Add a port "a" of which "core" and "0" are already installed.
- PackageSpecMap spec_map(Triplet::X86_WINDOWS);
+ PackageSpecMap spec_map;
auto spec_a = spec_map.emplace("a", "", {{"0", ""}, {"1", ""}}, {"1"});
Dependencies::MapPortFileProvider provider(spec_map.map);
@@ -697,23 +715,47 @@ namespace UnitTest1
Assert::AreEqual(size_t(2), plan.size());
Assert::AreEqual("a", plan[0].spec().name().c_str());
- Assert::IsTrue(plan[0].remove_action.has_value());
-
- Assert::AreEqual("a", plan[1].spec().name().c_str());
- features_check(&plan[1], "a", {"core", "0"}, Triplet::X86_WINDOWS);
+ remove_plan_check(&plan[0], "a");
+ features_check(&plan[1], "a", {"core", "0"});
}
TEST_METHOD(upgrade_with_default_features_2)
{
std::vector<std::unique_ptr<StatusParagraph>> pghs;
- pghs.push_back(make_status_pgh("b"));
- pghs.push_back(make_status_pgh("a", "b[core]"));
- pghs.back()->package.spec =
- PackageSpec::from_name_and_triplet("a", Triplet::X64_WINDOWS).value_or_exit(VCPKG_LINE_INFO);
+ // B is currently installed _without_ default feature b0
+ pghs.push_back(make_status_pgh("b", "", "b0", "x64-windows"));
+ pghs.push_back(make_status_pgh("a", "b[core]", "", "x64-windows"));
+
+ StatusParagraphs status_db(std::move(pghs));
+
+ PackageSpecMap spec_map(Triplet::X64_WINDOWS);
+ auto spec_a = spec_map.emplace("a", "b[core]");
+ auto spec_b = spec_map.emplace("b", "", {{"b0", ""}, {"b1", ""}}, {"b0", "b1"});
+
+ Dependencies::MapPortFileProvider provider(spec_map.map);
+ Dependencies::PackageGraph graph(provider, status_db);
+
+ graph.upgrade(spec_a);
+ graph.upgrade(spec_b);
+ auto plan = graph.serialize();
+
+ // The upgrade should install the new default feature b1 but not b0
+ Assert::AreEqual(size_t(4), plan.size());
+ remove_plan_check(&plan[0], "a", Triplet::X64_WINDOWS);
+ remove_plan_check(&plan[1], "b", Triplet::X64_WINDOWS);
+ features_check(&plan[2], "b", {"core", "b1"}, Triplet::X64_WINDOWS);
+ features_check(&plan[3], "a", {"core"}, Triplet::X64_WINDOWS);
+ }
+
+ TEST_METHOD(upgrade_with_default_features_3)
+ {
+ std::vector<std::unique_ptr<StatusParagraph>> pghs;
+ // note: unrelated package due to x86 triplet
+ pghs.push_back(make_status_pgh("b", "", "", "x86-windows"));
+ pghs.push_back(make_status_pgh("a", "", "", "x64-windows"));
StatusParagraphs status_db(std::move(pghs));
- // Add a port "a" of which "core" and "0" are already installed.
PackageSpecMap spec_map(Triplet::X64_WINDOWS);
auto spec_a = spec_map.emplace("a", "b[core]");
spec_map.emplace("b", "", {{"b0", ""}, {"b1", ""}}, {"b0"});
@@ -724,17 +766,33 @@ namespace UnitTest1
graph.upgrade(spec_a);
auto plan = graph.serialize();
- // The upgrade should not install the default feature
+ // The upgrade should install the default feature
Assert::AreEqual(size_t(3), plan.size());
+ remove_plan_check(&plan[0], "a", Triplet::X64_WINDOWS);
+ features_check(&plan[1], "b", {"b0", "core"}, Triplet::X64_WINDOWS);
+ features_check(&plan[2], "a", {"core"}, Triplet::X64_WINDOWS);
+ }
- Assert::AreEqual("a", plan[0].spec().name().c_str());
- Assert::IsTrue(plan[0].remove_action.has_value());
+ TEST_METHOD(upgrade_with_new_default_feature)
+ {
+ std::vector<std::unique_ptr<StatusParagraph>> pghs;
+ pghs.push_back(make_status_pgh("a", "", "0", "x86-windows"));
- Assert::AreEqual("b", plan[1].spec().name().c_str());
- features_check(&plan[1], "b", {"b0", "core"}, Triplet::X64_WINDOWS);
+ StatusParagraphs status_db(std::move(pghs));
- Assert::AreEqual("a", plan[2].spec().name().c_str());
- features_check(&plan[2], "a", {"core"}, Triplet::X64_WINDOWS);
+ PackageSpecMap spec_map;
+ auto spec_a = spec_map.emplace("a", "", {{"0", ""}, {"1", ""}, {"2", ""}}, {"0", "1"});
+
+ Dependencies::MapPortFileProvider provider(spec_map.map);
+ Dependencies::PackageGraph graph(provider, status_db);
+
+ graph.upgrade(spec_a);
+ auto plan = graph.serialize();
+
+ // The upgrade should install the new default feature but not the old default feature 0
+ Assert::AreEqual(size_t(2), plan.size());
+ remove_plan_check(&plan[0], "a", Triplet::X86_WINDOWS);
+ features_check(&plan[1], "a", {"core", "1"}, Triplet::X86_WINDOWS);
}
TEST_METHOD(transitive_features_test)
@@ -924,7 +982,7 @@ namespace UnitTest1
pghs.push_back(make_status_pgh("a"));
StatusParagraphs status_db(std::move(pghs));
- PackageSpecMap spec_map(Triplet::X86_WINDOWS);
+ PackageSpecMap spec_map;
auto spec_a = spec_map.emplace("a");
Dependencies::MapPortFileProvider provider(spec_map.map);
@@ -948,7 +1006,7 @@ namespace UnitTest1
pghs.push_back(make_status_pgh("b", "a"));
StatusParagraphs status_db(std::move(pghs));
- PackageSpecMap spec_map(Triplet::X86_WINDOWS);
+ PackageSpecMap spec_map;
auto spec_a = spec_map.emplace("a");
spec_map.emplace("b", "a");
@@ -980,7 +1038,7 @@ namespace UnitTest1
pghs.push_back(make_status_pgh("b"));
StatusParagraphs status_db(std::move(pghs));
- PackageSpecMap spec_map(Triplet::X86_WINDOWS);
+ PackageSpecMap spec_map;
auto spec_a = spec_map.emplace("a");
spec_map.emplace("b", "a");
@@ -1004,7 +1062,7 @@ namespace UnitTest1
pghs.push_back(make_status_pgh("a"));
StatusParagraphs status_db(std::move(pghs));
- PackageSpecMap spec_map(Triplet::X86_WINDOWS);
+ PackageSpecMap spec_map;
auto spec_a = spec_map.emplace("a", "b");
spec_map.emplace("b");
@@ -1031,7 +1089,7 @@ namespace UnitTest1
pghs.push_back(make_status_feature_pgh("a", "a1"));
StatusParagraphs status_db(std::move(pghs));
- PackageSpecMap spec_map(Triplet::X86_WINDOWS);
+ PackageSpecMap spec_map;
auto spec_a = spec_map.emplace("a", "", {{"a1", ""}});
Dependencies::MapPortFileProvider provider(spec_map.map);
@@ -1057,7 +1115,7 @@ namespace UnitTest1
StatusParagraphs status_db(std::move(pghs));
// a1 was added as a default feature and should be installed in upgrade
- PackageSpecMap spec_map(Triplet::X86_WINDOWS);
+ PackageSpecMap spec_map;
auto spec_a = spec_map.emplace("a", "", {{"a1", ""}}, {"a1"});
Dependencies::MapPortFileProvider provider(spec_map.map);
@@ -1083,7 +1141,7 @@ namespace UnitTest1
pghs.push_back(make_status_feature_pgh("a", "a2", "a[a1]"));
StatusParagraphs status_db(std::move(pghs));
- PackageSpecMap spec_map(Triplet::X86_WINDOWS);
+ PackageSpecMap spec_map;
auto spec_a = spec_map.emplace("a", "", {{"a1", ""}, {"a2", "a[a1]"}});
Dependencies::MapPortFileProvider provider(spec_map.map);
@@ -1112,7 +1170,7 @@ namespace UnitTest1
pghs.push_back(make_status_pgh("a"));
StatusParagraphs status_db(std::move(pghs));
- PackageSpecMap spec_map(Triplet::X86_WINDOWS);
+ PackageSpecMap spec_map;
auto spec_a = spec_map.emplace("a");
auto plan = Dependencies::create_export_plan({spec_a}, status_db);
@@ -1129,7 +1187,7 @@ namespace UnitTest1
pghs.push_back(make_status_pgh("b", "a"));
StatusParagraphs status_db(std::move(pghs));
- PackageSpecMap spec_map(Triplet::X86_WINDOWS);
+ PackageSpecMap spec_map;
auto spec_a = spec_map.emplace("a");
auto spec_b = spec_map.emplace("b", "a");
@@ -1150,7 +1208,7 @@ namespace UnitTest1
pghs.push_back(make_status_pgh("b"));
StatusParagraphs status_db(std::move(pghs));
- PackageSpecMap spec_map(Triplet::X86_WINDOWS);
+ PackageSpecMap spec_map;
auto spec_a = spec_map.emplace("a");
auto spec_b = spec_map.emplace("b", "a");
@@ -1165,7 +1223,7 @@ namespace UnitTest1
{
StatusParagraphs status_db;
- PackageSpecMap spec_map(Triplet::X86_WINDOWS);
+ PackageSpecMap spec_map;
auto spec_a = spec_map.emplace("a");
auto plan = Dependencies::create_export_plan({spec_a}, status_db);
@@ -1183,7 +1241,7 @@ namespace UnitTest1
pghs.push_back(make_status_feature_pgh("a", "a1", "b[core]"));
StatusParagraphs status_db(std::move(pghs));
- PackageSpecMap spec_map(Triplet::X86_WINDOWS);
+ PackageSpecMap spec_map;
auto spec_a = spec_map.emplace("a", "", {{"a1", ""}});
auto plan = Dependencies::create_export_plan({spec_a}, status_db);
diff --git a/toolsrc/src/vcpkg.cpp b/toolsrc/src/vcpkg.cpp
index a65045aa8..06c99e9a8 100644
--- a/toolsrc/src/vcpkg.cpp
+++ b/toolsrc/src/vcpkg.cpp
@@ -223,6 +223,7 @@ static void load_config()
}
}
+#if defined(_WIN32)
static std::string trim_path_from_command_line(const std::string& full_command_line)
{
Checks::check_exit(
@@ -243,6 +244,7 @@ static std::string trim_path_from_command_line(const std::string& full_command_l
++it;
return std::string(it, full_command_line.cend());
}
+#endif
#if defined(_WIN32)
int wmain(const int argc, const wchar_t* const* const argv)
diff --git a/toolsrc/src/vcpkg/base/chrono.cpp b/toolsrc/src/vcpkg/base/chrono.cpp
index 00f8ba3f1..2a76f5df0 100644
--- a/toolsrc/src/vcpkg/base/chrono.cpp
+++ b/toolsrc/src/vcpkg/base/chrono.cpp
@@ -15,7 +15,7 @@ namespace vcpkg::Chrono
using std::chrono::nanoseconds;
using std::chrono::seconds;
- const double nanos_as_double = static_cast<double>(nanos.count());
+ const auto nanos_as_double = static_cast<double>(nanos.count());
if (duration_cast<hours>(nanos) > hours())
{
@@ -92,7 +92,7 @@ namespace vcpkg::Chrono
Optional<CTime> CTime::parse(CStringView str)
{
CTime ret;
- auto assigned =
+ const auto assigned =
#if defined(_WIN32)
sscanf_s
#else
@@ -117,15 +117,13 @@ namespace vcpkg::Chrono
std::string CTime::to_string() const
{
- std::array<char, 80> date;
- date.fill(0);
-
+ std::array<char, 80> date{};
strftime(&date[0], date.size(), "%Y-%m-%dT%H:%M:%S.0Z", &m_tm);
return &date[0];
}
std::chrono::system_clock::time_point CTime::to_time_point() const
{
- auto t = mktime(&m_tm);
+ const time_t t = mktime(&m_tm);
return std::chrono::system_clock::from_time_t(t);
}
}
diff --git a/toolsrc/src/vcpkg/base/cofffilereader.cpp b/toolsrc/src/vcpkg/base/cofffilereader.cpp
index 96d280108..2c09e2c19 100644
--- a/toolsrc/src/vcpkg/base/cofffilereader.cpp
+++ b/toolsrc/src/vcpkg/base/cofffilereader.cpp
@@ -2,6 +2,7 @@
#include <vcpkg/base/checks.h>
#include <vcpkg/base/cofffilereader.h>
+#include <vcpkg/base/stringliteral.h>
using namespace std;
@@ -43,21 +44,21 @@ namespace vcpkg::CoffFileReader
actual);
}
- static void read_and_verify_PE_signature(fstream& fs)
+ static void read_and_verify_pe_signature(fstream& fs)
{
- static const size_t OFFSET_TO_PE_SIGNATURE_OFFSET = 0x3c;
+ static constexpr size_t OFFSET_TO_PE_SIGNATURE_OFFSET = 0x3c;
- static const char* PE_SIGNATURE = "PE\0\0";
- static const size_t PE_SIGNATURE_SIZE = 4;
+ static constexpr StringLiteral PE_SIGNATURE = "PE\0\0";
+ static constexpr size_t PE_SIGNATURE_SIZE = 4;
fs.seekg(OFFSET_TO_PE_SIGNATURE_OFFSET, ios_base::beg);
- const int32_t offset_to_PE_signature = read_value_from_stream<int32_t>(fs);
+ const auto offset_to_pe_signature = read_value_from_stream<int32_t>(fs);
- fs.seekg(offset_to_PE_signature);
+ fs.seekg(offset_to_pe_signature);
char signature[PE_SIGNATURE_SIZE];
fs.read(signature, PE_SIGNATURE_SIZE);
- verify_equal_strings(VCPKG_LINE_INFO, PE_SIGNATURE, signature, PE_SIGNATURE_SIZE, "PE_SIGNATURE");
- fs.seekg(offset_to_PE_signature + PE_SIGNATURE_SIZE, ios_base::beg);
+ verify_equal_strings(VCPKG_LINE_INFO, PE_SIGNATURE.c_str(), signature, PE_SIGNATURE_SIZE, "PE_SIGNATURE");
+ fs.seekg(offset_to_pe_signature + PE_SIGNATURE_SIZE, ios_base::beg);
}
static fpos_t align_to_size(const uint64_t unaligned, const uint64_t alignment_size)
@@ -71,7 +72,7 @@ namespace vcpkg::CoffFileReader
struct CoffFileHeader
{
- static const size_t HEADER_SIZE = 20;
+ static constexpr size_t HEADER_SIZE = 20;
static CoffFileHeader read(fstream& fs)
{
@@ -83,11 +84,11 @@ namespace vcpkg::CoffFileReader
MachineType machine_type() const
{
- static const size_t MACHINE_TYPE_OFFSET = 0;
- static const size_t MACHINE_TYPE_SIZE = 2;
+ static constexpr size_t MACHINE_TYPE_OFFSET = 0;
+ static constexpr size_t MACHINE_TYPE_SIZE = 2;
std::string machine_field_as_string = data.substr(MACHINE_TYPE_OFFSET, MACHINE_TYPE_SIZE);
- const uint16_t machine = reinterpret_bytes<uint16_t>(machine_field_as_string.c_str());
+ const auto machine = reinterpret_bytes<uint16_t>(machine_field_as_string.c_str());
return to_machine_type(machine);
}
@@ -97,13 +98,13 @@ namespace vcpkg::CoffFileReader
struct ArchiveMemberHeader
{
- static const size_t HEADER_SIZE = 60;
+ static constexpr size_t HEADER_SIZE = 60;
static ArchiveMemberHeader read(fstream& fs)
{
- static const size_t HEADER_END_OFFSET = 58;
- static const char* HEADER_END = "`\n";
- static const size_t HEADER_END_SIZE = 2;
+ static constexpr size_t HEADER_END_OFFSET = 58;
+ static constexpr StringLiteral HEADER_END = "`\n";
+ static constexpr size_t HEADER_END_SIZE = 2;
ArchiveMemberHeader ret;
ret.data.resize(HEADER_SIZE);
@@ -113,7 +114,7 @@ namespace vcpkg::CoffFileReader
{
const std::string header_end = ret.data.substr(HEADER_END_OFFSET, HEADER_END_SIZE);
verify_equal_strings(
- VCPKG_LINE_INFO, HEADER_END, header_end.c_str(), HEADER_END_SIZE, "LIB HEADER_END");
+ VCPKG_LINE_INFO, HEADER_END.c_str(), header_end.c_str(), HEADER_END_SIZE, "LIB HEADER_END");
}
return ret;
@@ -121,17 +122,17 @@ namespace vcpkg::CoffFileReader
std::string name() const
{
- static const size_t HEADER_NAME_OFFSET = 0;
- static const size_t HEADER_NAME_SIZE = 16;
+ static constexpr size_t HEADER_NAME_OFFSET = 0;
+ static constexpr size_t HEADER_NAME_SIZE = 16;
return data.substr(HEADER_NAME_OFFSET, HEADER_NAME_SIZE);
}
uint64_t member_size() const
{
- static const size_t ALIGNMENT_SIZE = 2;
+ static constexpr size_t ALIGNMENT_SIZE = 2;
- static const size_t HEADER_SIZE_OFFSET = 48;
- static const size_t HEADER_SIZE_FIELD_SIZE = 10;
+ static constexpr size_t HEADER_SIZE_OFFSET = 48;
+ static constexpr size_t HEADER_SIZE_FIELD_SIZE = 10;
const std::string as_string = data.substr(HEADER_SIZE_OFFSET, HEADER_SIZE_FIELD_SIZE);
// This is in ASCII decimal representation
const uint64_t value = std::strtoull(as_string.c_str(), nullptr, 10);
@@ -147,18 +148,19 @@ namespace vcpkg::CoffFileReader
{
static OffsetsArray read(fstream& fs, const uint32_t offset_count)
{
- static const size_t OFFSET_WIDTH = 4;
+ static constexpr uint32_t OFFSET_WIDTH = 4;
std::string raw_offsets;
- const size_t raw_offset_size = offset_count * OFFSET_WIDTH;
+ const uint32_t raw_offset_size = offset_count * OFFSET_WIDTH;
raw_offsets.resize(raw_offset_size);
fs.read(&raw_offsets[0], raw_offset_size);
OffsetsArray ret;
for (uint32_t i = 0; i < offset_count; ++i)
{
- const std::string value_as_string = raw_offsets.substr(OFFSET_WIDTH * i, OFFSET_WIDTH * (i + 1));
- const uint32_t value = reinterpret_bytes<uint32_t>(value_as_string.c_str());
+ const std::string value_as_string = raw_offsets.substr(OFFSET_WIDTH * static_cast<size_t>(i),
+ OFFSET_WIDTH * (static_cast<size_t>(i) + 1));
+ const auto value = reinterpret_bytes<uint32_t>(value_as_string.c_str());
// Ignore offsets that point to offset 0. See vcpkg github #223 #288 #292
if (value != 0)
@@ -177,28 +179,28 @@ namespace vcpkg::CoffFileReader
struct ImportHeader
{
- static const size_t HEADER_SIZE = 20;
+ static constexpr size_t HEADER_SIZE = 20;
static ImportHeader read(fstream& fs)
{
- static const size_t SIG1_OFFSET = 0;
- static const uint16_t SIG1 = static_cast<uint16_t>(MachineType::UNKNOWN);
- static const size_t SIG1_SIZE = 2;
+ static constexpr size_t SIG1_OFFSET = 0;
+ static constexpr auto SIG1 = static_cast<uint16_t>(MachineType::UNKNOWN);
+ static constexpr size_t SIG1_SIZE = 2;
- static const size_t SIG2_OFFSET = 2;
- static const uint16_t SIG2 = 0xFFFF;
- static const size_t SIG2_SIZE = 2;
+ static constexpr size_t SIG2_OFFSET = 2;
+ static constexpr uint16_t SIG2 = 0xFFFF;
+ static constexpr size_t SIG2_SIZE = 2;
ImportHeader ret;
ret.data.resize(HEADER_SIZE);
fs.read(&ret.data[0], HEADER_SIZE);
const std::string sig1_as_string = ret.data.substr(SIG1_OFFSET, SIG1_SIZE);
- const uint16_t sig1 = reinterpret_bytes<uint16_t>(sig1_as_string.c_str());
+ const auto sig1 = reinterpret_bytes<uint16_t>(sig1_as_string.c_str());
Checks::check_exit(VCPKG_LINE_INFO, sig1 == SIG1, "Sig1 was incorrect. Expected %s but got %s", SIG1, sig1);
const std::string sig2_as_string = ret.data.substr(SIG2_OFFSET, SIG2_SIZE);
- const uint16_t sig2 = reinterpret_bytes<uint16_t>(sig2_as_string.c_str());
+ const auto sig2 = reinterpret_bytes<uint16_t>(sig2_as_string.c_str());
Checks::check_exit(VCPKG_LINE_INFO, sig2 == SIG2, "Sig2 was incorrect. Expected %s but got %s", SIG2, sig2);
return ret;
@@ -206,11 +208,11 @@ namespace vcpkg::CoffFileReader
MachineType machine_type() const
{
- static const size_t MACHINE_TYPE_OFFSET = 6;
- static const size_t MACHINE_TYPE_SIZE = 2;
+ static constexpr size_t MACHINE_TYPE_OFFSET = 6;
+ static constexpr size_t MACHINE_TYPE_SIZE = 2;
std::string machine_field_as_string = data.substr(MACHINE_TYPE_OFFSET, MACHINE_TYPE_SIZE);
- const uint16_t machine = reinterpret_bytes<uint16_t>(machine_field_as_string.c_str());
+ const auto machine = reinterpret_bytes<uint16_t>(machine_field_as_string.c_str());
return to_machine_type(machine);
}
@@ -220,14 +222,14 @@ namespace vcpkg::CoffFileReader
static void read_and_verify_archive_file_signature(fstream& fs)
{
- static const char* FILE_START = "!<arch>\n";
- static const size_t FILE_START_SIZE = 8;
+ static constexpr StringLiteral FILE_START = "!<arch>\n";
+ static constexpr size_t FILE_START_SIZE = 8;
- fs.seekg(fs.beg);
+ fs.seekg(std::fstream::beg);
char file_start[FILE_START_SIZE];
fs.read(file_start, FILE_START_SIZE);
- verify_equal_strings(VCPKG_LINE_INFO, FILE_START, file_start, FILE_START_SIZE, "LIB FILE_START");
+ verify_equal_strings(VCPKG_LINE_INFO, FILE_START.c_str(), file_start, FILE_START_SIZE, "LIB FILE_START");
}
DllInfo read_dll(const fs::path& path)
@@ -235,7 +237,7 @@ namespace vcpkg::CoffFileReader
std::fstream fs(path, std::ios::in | std::ios::binary | std::ios::ate);
Checks::check_exit(VCPKG_LINE_INFO, fs.is_open(), "Could not open file %s for reading", path.generic_string());
- read_and_verify_PE_signature(fs);
+ read_and_verify_pe_signature(fs);
CoffFileHeader header = CoffFileHeader::read(fs);
const MachineType machine = header.machine_type();
return {machine};
@@ -245,7 +247,7 @@ namespace vcpkg::CoffFileReader
{
void set_to_offset(const fpos_t position) { this->m_absolute_position = position; }
- void set_to_current_pos(fstream& fs) { this->m_absolute_position = fs.tellg().seekpos(); }
+ void set_to_current_pos(fstream& fs) { this->m_absolute_position = fs.tellg(); }
void seek_to_marker(fstream& fs) const { fs.seekg(this->m_absolute_position, ios_base::beg); }
@@ -278,13 +280,13 @@ namespace vcpkg::CoffFileReader
second_linker_member_header.name().substr(0, 2) == "/ ",
"Could not find proper second linker member");
// The first 4 bytes contains the number of archive members
- const uint32_t archive_member_count = read_value_from_stream<uint32_t>(fs);
+ const auto archive_member_count = read_value_from_stream<uint32_t>(fs);
const OffsetsArray offsets = OffsetsArray::read(fs, archive_member_count);
marker.advance_by(ArchiveMemberHeader::HEADER_SIZE + second_linker_member_header.member_size());
marker.seek_to_marker(fs);
- const bool hasLongnameMemberHeader = peek_value_from_stream<uint16_t>(fs) == 0x2F2F;
- if (hasLongnameMemberHeader)
+ const bool has_longname_member_header = peek_value_from_stream<uint16_t>(fs) == 0x2F2F;
+ if (has_longname_member_header)
{
const ArchiveMemberHeader longnames_member_header = ArchiveMemberHeader::read(fs);
marker.advance_by(ArchiveMemberHeader::HEADER_SIZE + longnames_member_header.member_size());
@@ -297,10 +299,10 @@ namespace vcpkg::CoffFileReader
{
marker.set_to_offset(offset + ArchiveMemberHeader::HEADER_SIZE); // Skip the header, no need to read it.
marker.seek_to_marker(fs);
- const uint16_t first_two_bytes = peek_value_from_stream<uint16_t>(fs);
- const bool isImportHeader = to_machine_type(first_two_bytes) == MachineType::UNKNOWN;
+ const auto first_two_bytes = peek_value_from_stream<uint16_t>(fs);
+ const bool is_import_header = to_machine_type(first_two_bytes) == MachineType::UNKNOWN;
const MachineType machine =
- isImportHeader ? ImportHeader::read(fs).machine_type() : CoffFileHeader::read(fs).machine_type();
+ is_import_header ? ImportHeader::read(fs).machine_type() : CoffFileHeader::read(fs).machine_type();
machine_types.insert(machine);
}
diff --git a/toolsrc/src/vcpkg/base/files.cpp b/toolsrc/src/vcpkg/base/files.cpp
index 4e61666b7..1723b467e 100644
--- a/toolsrc/src/vcpkg/base/files.cpp
+++ b/toolsrc/src/vcpkg/base/files.cpp
@@ -22,9 +22,9 @@ namespace vcpkg::Files
auto length = file_stream.tellg();
file_stream.seekg(0, file_stream.beg);
- if (length > SIZE_MAX)
+ if (length == std::streampos(-1))
{
- return std::make_error_code(std::errc::file_too_large);
+ return std::make_error_code(std::errc::io_error);
}
std::string output;
@@ -185,12 +185,15 @@ namespace vcpkg::Files
return;
}
- auto count = fwrite(data.data(), sizeof(data[0]), data.size(), f);
- fclose(f);
-
- if (count != data.size())
+ if (f != nullptr)
{
- ec = std::make_error_code(std::errc::no_space_on_device);
+ auto count = fwrite(data.data(), sizeof(data[0]), data.size(), f);
+ fclose(f);
+
+ if (count != data.size())
+ {
+ ec = std::make_error_code(std::errc::no_space_on_device);
+ }
}
}
};
diff --git a/toolsrc/src/vcpkg/base/strings.cpp b/toolsrc/src/vcpkg/base/strings.cpp
index 5fedf3e1f..fbc33ca42 100644
--- a/toolsrc/src/vcpkg/base/strings.cpp
+++ b/toolsrc/src/vcpkg/base/strings.cpp
@@ -7,7 +7,7 @@
namespace vcpkg::Strings::details
{
// To disambiguate between two overloads
- static bool IS_SPACE(const char c) { return std::isspace(c) != 0; };
+ static bool is_space(const char c) { return std::isspace(c) != 0; }
// Avoids C4244 warnings because of char<->int conversion that occur when using std::tolower()
static char tolower_char(const char c) { return static_cast<char>(std::tolower(c)); }
@@ -39,7 +39,7 @@ namespace vcpkg::Strings::details
_vsnprintf_s_l(&output.at(0), output.size() + 1, output.size(), fmtstr, c_locale(), args);
#else
va_start(args, fmtstr);
- auto res = vsnprintf(&output.at(0), output.size() + 1, fmtstr, args);
+ vsnprintf(&output.at(0), output.size() + 1, fmtstr, args);
#endif
va_end(args);
@@ -52,23 +52,25 @@ namespace vcpkg::Strings
std::wstring to_utf16(const CStringView& s)
{
#if defined(_WIN32)
- const int size = MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, nullptr, 0);
std::wstring output;
+ const size_t size = MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, nullptr, 0);
+ if (size == 0) return output;
output.resize(size - 1);
- MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, output.data(), size - 1);
+ MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, output.data(), static_cast<int>(size) - 1);
return output;
#else
Checks::unreachable(VCPKG_LINE_INFO);
#endif
}
- std::string to_utf8(const CWStringView& w)
+ std::string to_utf8(const wchar_t* w)
{
#if defined(_WIN32)
- const int size = WideCharToMultiByte(CP_UTF8, 0, w.c_str(), -1, nullptr, 0, nullptr, nullptr);
std::string output;
+ const size_t size = WideCharToMultiByte(CP_UTF8, 0, w, -1, nullptr, 0, nullptr, nullptr);
+ if (size == 0) return output;
output.resize(size - 1);
- WideCharToMultiByte(CP_UTF8, 0, w.c_str(), -1, output.data(), size - 1, nullptr, nullptr);
+ WideCharToMultiByte(CP_UTF8, 0, w, -1, output.data(), static_cast<int>(size) - 1, nullptr, nullptr);
return output;
#else
Checks::unreachable(VCPKG_LINE_INFO);
@@ -143,8 +145,8 @@ namespace vcpkg::Strings
std::string trim(std::string&& s)
{
- s.erase(std::find_if_not(s.rbegin(), s.rend(), details::IS_SPACE).base(), s.end());
- s.erase(s.begin(), std::find_if_not(s.begin(), s.end(), details::IS_SPACE));
+ s.erase(std::find_if_not(s.rbegin(), s.rend(), details::is_space).base(), s.end());
+ s.erase(s.begin(), std::find_if_not(s.begin(), s.end(), details::is_space));
return std::move(s);
}
diff --git a/toolsrc/src/vcpkg/base/system.cpp b/toolsrc/src/vcpkg/base/system.cpp
index 171dd2bbf..d4210fe6d 100644
--- a/toolsrc/src/vcpkg/base/system.cpp
+++ b/toolsrc/src/vcpkg/base/system.cpp
@@ -5,7 +5,7 @@
#include <vcpkg/globalstate.h>
#include <vcpkg/metrics.h>
-#include <time.h>
+#include <ctime>
#if defined(__APPLE__)
#include <mach-o/dyld.h>
@@ -23,7 +23,7 @@ namespace vcpkg::System
{
using std::chrono::system_clock;
std::time_t now_time = system_clock::to_time_t(system_clock::now());
- tm parts;
+ tm parts{};
#if defined(_WIN32)
localtime_s(&parts, &now_time);
#else
@@ -158,7 +158,7 @@ namespace vcpkg::System
#if defined(_WIN32)
static const std::string SYSTEM_ROOT = get_environment_variable("SystemRoot").value_or_exit(VCPKG_LINE_INFO);
static const std::string SYSTEM_32 = SYSTEM_ROOT + R"(\system32)";
- std::string NEW_PATH = Strings::format(
+ std::string new_path = Strings::format(
R"(Path=%s;%s;%s\Wbem;%s\WindowsPowerShell\v1.0\)", SYSTEM_32, SYSTEM_ROOT, SYSTEM_32, SYSTEM_32);
std::vector<std::wstring> env_wstrings = {
@@ -214,7 +214,7 @@ namespace vcpkg::System
for (auto&& env_wstring : env_wstrings)
{
- const Optional<std::string> value = System::get_environment_variable(Strings::to_utf8(env_wstring));
+ const Optional<std::string> value = System::get_environment_variable(Strings::to_utf8(env_wstring.c_str()));
const auto v = value.get();
if (!v || v->empty()) continue;
@@ -225,13 +225,13 @@ namespace vcpkg::System
}
if (extra_env.find("PATH") != extra_env.end())
- NEW_PATH += Strings::format(";%s", extra_env.find("PATH")->second);
- env_cstr.append(Strings::to_utf16(NEW_PATH));
+ new_path += Strings::format(";%s", extra_env.find("PATH")->second);
+ env_cstr.append(Strings::to_utf16(new_path));
env_cstr.push_back(L'\0');
env_cstr.append(L"VSLANG=1033");
env_cstr.push_back(L'\0');
- for (auto item : extra_env)
+ for (const auto& item : extra_env)
{
if (item.first == "PATH") continue;
env_cstr.append(Strings::to_utf16(item.first));
@@ -298,17 +298,6 @@ namespace vcpkg::System
return exit_code;
}
- // On Win7, output from powershell calls contain a byte order mark, so we strip it out if it is present
- static void remove_byte_order_marks(std::wstring* s)
- {
- const wchar_t* a = s->c_str();
- // This is the UTF-8 byte-order mark
- while (s->size() >= 3 && a[0] == 0xEF && a[1] == 0xBB && a[2] == 0xBF)
- {
- s->erase(0, 3);
- }
- }
-
ExitCodeAndOutput cmd_execute_and_capture_output(const CStringView cmd_line)
{
// Flush stdout before launching external process
@@ -325,7 +314,7 @@ namespace vcpkg::System
const auto pipe = _wpopen(Strings::to_utf16(actual_cmd_line).c_str(), L"r");
if (pipe == nullptr)
{
- return {1, Strings::to_utf8(output)};
+ return {1, Strings::to_utf8(output.c_str())};
}
while (fgetws(buf, 1024, pipe))
{
@@ -333,15 +322,22 @@ namespace vcpkg::System
}
if (!feof(pipe))
{
- return {1, Strings::to_utf8(output)};
+ return {1, Strings::to_utf8(output.c_str())};
}
const auto ec = _pclose(pipe);
- remove_byte_order_marks(&output);
- Debug::println("_pclose() returned %d after %8d us", ec, (int)timer.microseconds());
+ // On Win7, output from powershell calls contain a utf-8 byte order mark in the utf-16 stream, so we strip it
+ // out if it is present. 0xEF,0xBB,0xBF is the UTF-8 byte-order mark
+ const wchar_t* a = output.c_str();
+ while (output.size() >= 3 && a[0] == 0xEF && a[1] == 0xBB && a[2] == 0xBF)
+ {
+ output.erase(0, 3);
+ }
+
+ Debug::println("_pclose() returned %d after %8d us", ec, static_cast<int>(timer.microseconds()));
- return {ec, Strings::to_utf8(output)};
+ return {ec, Strings::to_utf8(output.c_str())};
#else
const auto actual_cmd_line = Strings::format(R"###(%s 2>&1)###", cmd_line);
@@ -481,7 +477,7 @@ namespace vcpkg::System
const auto sz2 = GetEnvironmentVariableW(w_varname.c_str(), ret.data(), static_cast<DWORD>(ret.size()));
Checks::check_exit(VCPKG_LINE_INFO, sz2 + 1 == sz);
ret.pop_back();
- return Strings::to_utf8(ret);
+ return Strings::to_utf8(ret.c_str());
#else
auto v = getenv(varname.c_str());
if (!v) return nullopt;
@@ -522,7 +518,7 @@ namespace vcpkg::System
return nullopt;
ret.pop_back(); // remove extra trailing null byte
- return Strings::to_utf8(ret);
+ return Strings::to_utf8(ret.c_str());
}
#else
Optional<std::string> get_registry_string(void* base_hkey, const CStringView sub_key, const CStringView valuename)
diff --git a/toolsrc/src/vcpkg/binaryparagraph.cpp b/toolsrc/src/vcpkg/binaryparagraph.cpp
index 7a8b0d577..126c7df97 100644
--- a/toolsrc/src/vcpkg/binaryparagraph.cpp
+++ b/toolsrc/src/vcpkg/binaryparagraph.cpp
@@ -24,7 +24,7 @@ namespace vcpkg
static const std::string DEFAULTFEATURES = "Default-Features";
}
- BinaryParagraph::BinaryParagraph() = default;
+ BinaryParagraph::BinaryParagraph() noexcept = default;
BinaryParagraph::BinaryParagraph(std::unordered_map<std::string, std::string> fields)
{
@@ -79,7 +79,7 @@ namespace vcpkg
}
BinaryParagraph::BinaryParagraph(const SourceParagraph& spgh, const FeatureParagraph& fpgh, const Triplet& triplet)
- : version(), feature(fpgh.name), description(fpgh.description), maintainer()
+ : version(), description(fpgh.description), maintainer(), feature(fpgh.name)
{
this->spec = PackageSpec::from_name_and_triplet(spgh.name, triplet).value_or_exit(VCPKG_LINE_INFO);
this->depends = filter_dependencies(fpgh.depends, triplet);
diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp
index 79a55bd36..7a9d35667 100644
--- a/toolsrc/src/vcpkg/build.cpp
+++ b/toolsrc/src/vcpkg/build.cpp
@@ -64,7 +64,8 @@ namespace vcpkg::Build::Command
const Build::BuildPackageOptions build_package_options{Build::UseHeadVersion::NO,
Build::AllowDownloads::YES,
Build::CleanBuildtrees::NO,
- Build::CleanPackages::NO};
+ Build::CleanPackages::NO,
+ Build::DownloadTool::BUILT_IN};
std::set<std::string> features_as_set(full_spec.features.begin(), full_spec.features.end());
features_as_set.emplace("core");
@@ -210,7 +211,7 @@ namespace vcpkg::Build
for (auto&& host : host_architectures)
{
- auto it = Util::find_if(toolset.supported_architectures, [&](const ToolsetArchOption& opt) {
+ const auto it = Util::find_if(toolset.supported_architectures, [&](const ToolsetArchOption& opt) {
return host == opt.host_arch && target_arch == opt.target_arch;
});
if (it != toolset.supported_architectures.end()) return it->name;
@@ -279,7 +280,7 @@ namespace vcpkg::Build
{
const Triplet& triplet = config.triplet;
- auto dep_strings =
+ const std::vector<std::string> dep_strings =
Util::fmap_flatten(config.feature_list, [&](std::string const& feature) -> std::vector<std::string> {
if (feature == "core")
{
@@ -302,7 +303,7 @@ namespace vcpkg::Build
if (fspec.feature().empty())
{
// reference to default features
- auto it = status_db.find_installed(fspec.spec());
+ const auto it = status_db.find_installed(fspec.spec());
if (it == status_db.end())
{
// not currently installed, so just leave the default reference so it will fail later
@@ -310,9 +311,9 @@ namespace vcpkg::Build
}
else
{
- ret.push_back(FeatureSpec{fspec.spec(), "core"});
+ ret.emplace_back(fspec.spec(), "core");
for (auto&& default_feature : it->get()->package.default_features)
- ret.push_back(FeatureSpec{fspec.spec(), default_feature});
+ ret.emplace_back(fspec.spec(), default_feature);
}
}
else
@@ -329,8 +330,7 @@ namespace vcpkg::Build
const PreBuildInfo& pre_build_info,
const PackageSpec& spec,
const std::string& abi_tag,
- const BuildPackageConfig& config,
- const StatusParagraphs& status_db)
+ const BuildPackageConfig& config)
{
auto& fs = paths.get_filesystem();
const Triplet& triplet = spec.triplet();
@@ -338,11 +338,11 @@ namespace vcpkg::Build
#if !defined(_WIN32)
// TODO: remove when vcpkg.exe is in charge for acquiring tools. Change introduced in vcpkg v0.0.107.
// bootstrap should have already downloaded ninja, but making sure it is present in case it was deleted.
- vcpkg::Util::unused(paths.get_ninja_exe());
+ vcpkg::Util::unused(paths.get_tool_exe(Tools::NINJA));
#endif
- const fs::path& cmake_exe_path = paths.get_cmake_exe();
- const fs::path& git_exe_path = paths.get_git_exe();
+ const fs::path& cmake_exe_path = paths.get_tool_exe(Tools::CMAKE);
+ const fs::path& git_exe_path = paths.get_tool_exe(Tools::GIT);
std::string all_features;
for (auto& feature : config.scf.feature_paragraphs)
@@ -361,9 +361,8 @@ namespace vcpkg::Build
{"TARGET_TRIPLET", spec.triplet().canonical_name()},
{"VCPKG_PLATFORM_TOOLSET", toolset.version.c_str()},
{"VCPKG_USE_HEAD_VERSION",
- Util::Enum::to_bool(config.build_package_options.use_head_version) ? "1" : "0"},
- {"_VCPKG_NO_DOWNLOADS",
- !Util::Enum::to_bool(config.build_package_options.allow_downloads) ? "1" : "0"},
+ Util::Enum::to_bool(config.build_package_options.use_head_version) ? "1" : "0"},
+ {"_VCPKG_NO_DOWNLOADS", !Util::Enum::to_bool(config.build_package_options.allow_downloads) ? "1" : "0"},
{"_VCPKG_DOWNLOAD_TOOL", to_string(config.build_package_options.download_tool)},
{"GIT", git_exe_path},
{"FEATURES", Strings::join(";", config.feature_list)},
@@ -419,10 +418,9 @@ namespace vcpkg::Build
const PreBuildInfo& pre_build_info,
const PackageSpec& spec,
const std::string& abi_tag,
- const BuildPackageConfig& config,
- const StatusParagraphs& status_db)
+ const BuildPackageConfig& config)
{
- auto result = do_build_package(paths, pre_build_info, spec, abi_tag, config, status_db);
+ auto result = do_build_package(paths, pre_build_info, spec, abi_tag, config);
if (config.build_package_options.clean_buildtrees == CleanBuildtrees::YES)
{
@@ -464,7 +462,7 @@ namespace vcpkg::Build
abi_tag_entries.emplace_back(AbiEntry{"triplet", pre_build_info.triplet_abi_tag});
- std::string features = Strings::join(";", config.feature_list);
+ const std::string features = Strings::join(";", config.feature_list);
abi_tag_entries.emplace_back(AbiEntry{"features", features});
if (config.build_package_options.use_head_version == UseHeadVersion::YES)
@@ -472,7 +470,7 @@ namespace vcpkg::Build
Util::sort(abi_tag_entries);
- std::string full_abi_info =
+ const std::string full_abi_info =
Strings::join("", abi_tag_entries, [](const AbiEntry& p) { return p.key + " " + p.value + "\n"; });
if (GlobalState::debugging)
@@ -492,19 +490,17 @@ namespace vcpkg::Build
{
std::error_code ec;
fs.create_directories(paths.buildtrees / name, ec);
- auto abi_file_path = paths.buildtrees / name / (triplet.canonical_name() + ".vcpkg_abi_info.txt");
+ const auto abi_file_path = paths.buildtrees / name / (triplet.canonical_name() + ".vcpkg_abi_info.txt");
fs.write_contents(abi_file_path, full_abi_info);
return AbiTagAndFile{Commands::Hash::get_file_hash(paths, abi_file_path, "SHA1"), abi_file_path};
}
- else
- {
- System::println(
- "Warning: binary caching disabled because abi keys are missing values:\n%s",
- Strings::join("", abi_tag_entries_missing, [](const AbiEntry& e) { return " " + e.key + "\n"; }));
- return nullopt;
- }
+ System::println(
+ "Warning: binary caching disabled because abi keys are missing values:\n%s",
+ Strings::join("", abi_tag_entries_missing, [](const AbiEntry& e) { return " " + e.key + "\n"; }));
+
+ return nullopt;
}
static void decompress_archive(const VcpkgPaths& paths, const PackageSpec& spec, const fs::path& archive_path)
@@ -519,10 +515,10 @@ namespace vcpkg::Build
Checks::check_exit(VCPKG_LINE_INFO, files.empty(), "unable to clear path: %s", pkg_path.u8string());
#if defined(_WIN32)
- auto&& _7za = paths.get_7za_exe();
+ auto&& seven_zip_exe = paths.get_tool_exe(Tools::SEVEN_ZIP);
System::cmd_execute_clean(Strings::format(
- R"("%s" x "%s" -o"%s" -y >nul)", _7za.u8string(), archive_path.u8string(), pkg_path.u8string()));
+ R"("%s" x "%s" -o"%s" -y >nul)", seven_zip_exe.u8string(), archive_path.u8string(), pkg_path.u8string()));
#else
System::cmd_execute_clean(Strings::format(
R"(unzip -qq "%s" "-d%s")", archive_path.u8string(), pkg_path.u8string()));
@@ -539,11 +535,11 @@ namespace vcpkg::Build
Checks::check_exit(
VCPKG_LINE_INFO, !fs.exists(tmp_archive_path), "Could not remove file: %s", tmp_archive_path.u8string());
#if defined(_WIN32)
- auto&& _7za = paths.get_7za_exe();
+ auto&& seven_zip_exe = paths.get_tool_exe(Tools::SEVEN_ZIP);
System::cmd_execute_clean(Strings::format(
R"("%s" a "%s" "%s\*" >nul)",
- _7za.u8string(),
+ seven_zip_exe.u8string(),
tmp_archive_path.u8string(),
paths.package_dir(spec).u8string()));
#else
@@ -566,7 +562,7 @@ namespace vcpkg::Build
auto dep_pspecs = Util::fmap(required_fspecs, [](FeatureSpec const& fspec) { return fspec.spec(); });
Util::sort_unique_erase(dep_pspecs);
- // Find all features that aren't installed. This destroys required_fspecs.
+ // Find all features that aren't installed. This mutates required_fspecs.
Util::unstable_keep_if(required_fspecs, [&](FeatureSpec const& fspec) {
return !status_db.is_installed(fspec) && fspec.name() != name;
});
@@ -585,7 +581,7 @@ namespace vcpkg::Build
for (auto&& pspec : dep_pspecs)
{
if (pspec == spec) continue;
- auto status_it = status_db.find_installed(pspec);
+ const auto status_it = status_db.find_installed(pspec);
Checks::check_exit(VCPKG_LINE_INFO, status_it != status_db.end());
dependency_abis.emplace_back(
AbiEntry{status_it->get()->package.spec.name(), status_it->get()->package.abi});
@@ -595,17 +591,15 @@ namespace vcpkg::Build
auto maybe_abi_tag_and_file = compute_abi_tag(paths, config, pre_build_info, dependency_abis);
- std::unique_ptr<BinaryControlFile> bcf;
-
- auto abi_tag_and_file = maybe_abi_tag_and_file.get();
+ const auto abi_tag_and_file = maybe_abi_tag_and_file.get();
if (GlobalState::g_binary_caching && abi_tag_and_file)
{
- auto archives_root_dir = paths.root / "archives";
- auto archive_name = abi_tag_and_file->tag + ".zip";
- auto archive_subpath = fs::u8path(abi_tag_and_file->tag.substr(0, 2)) / archive_name;
- auto archive_path = archives_root_dir / archive_subpath;
- auto archive_tombstone_path = archives_root_dir / "fail" / archive_subpath;
+ const fs::path archives_root_dir = paths.root / "archives";
+ const std::string archive_name = abi_tag_and_file->tag + ".zip";
+ const fs::path archive_subpath = fs::u8path(abi_tag_and_file->tag.substr(0, 2)) / archive_name;
+ const fs::path archive_path = archives_root_dir / archive_subpath;
+ const fs::path archive_tombstone_path = archives_root_dir / "fail" / archive_subpath;
if (fs.exists(archive_path))
{
@@ -614,10 +608,12 @@ namespace vcpkg::Build
decompress_archive(paths, spec, archive_path);
auto maybe_bcf = Paragraphs::try_load_cached_package(paths, spec);
- bcf = std::make_unique<BinaryControlFile>(std::move(maybe_bcf).value_or_exit(VCPKG_LINE_INFO));
+ std::unique_ptr<BinaryControlFile> bcf =
+ std::make_unique<BinaryControlFile>(std::move(maybe_bcf).value_or_exit(VCPKG_LINE_INFO));
return {BuildResult::SUCCEEDED, std::move(bcf)};
}
- else if (fs.exists(archive_tombstone_path))
+
+ if (fs.exists(archive_tombstone_path))
{
System::println("Found failure tombstone: %s", archive_tombstone_path.u8string());
return BuildResult::BUILD_FAILED;
@@ -626,7 +622,7 @@ namespace vcpkg::Build
System::println("Could not locate cached archive: %s", archive_path.u8string());
ExtendedBuildResult result = do_build_package_and_clean_buildtrees(
- paths, pre_build_info, spec, maybe_abi_tag_and_file.value_or(AbiTagAndFile{}).tag, config, status_db);
+ paths, pre_build_info, spec, maybe_abi_tag_and_file.value_or(AbiTagAndFile{}).tag, config);
std::error_code ec;
fs.create_directories(paths.package_dir(spec) / "share" / spec.name(), ec);
@@ -636,7 +632,7 @@ namespace vcpkg::Build
if (result.code == BuildResult::SUCCEEDED)
{
- auto tmp_archive_path = paths.buildtrees / spec.name() / (spec.triplet().to_string() + ".zip");
+ const auto tmp_archive_path = paths.buildtrees / spec.name() / (spec.triplet().to_string() + ".zip");
compress_archive(paths, spec, tmp_archive_path);
@@ -657,11 +653,9 @@ namespace vcpkg::Build
return result;
}
- else
- {
- return do_build_package_and_clean_buildtrees(
- paths, pre_build_info, spec, maybe_abi_tag_and_file.value_or(AbiTagAndFile{}).tag, config, status_db);
- }
+
+ return do_build_package_and_clean_buildtrees(
+ paths, pre_build_info, spec, maybe_abi_tag_and_file.value_or(AbiTagAndFile{}).tag, config);
}
const std::string& to_string(const BuildResult build_result)
@@ -771,11 +765,11 @@ namespace vcpkg::Build
{
static constexpr CStringView FLAG_GUID = "c35112b6-d1ba-415b-aa5d-81de856ef8eb";
- const fs::path& cmake_exe_path = paths.get_cmake_exe();
+ const fs::path& cmake_exe_path = paths.get_tool_exe(Tools::CMAKE);
const fs::path ports_cmake_script_path = paths.scripts / "get_triplet_environment.cmake";
const fs::path triplet_file_path = paths.triplets / (triplet.canonical_name() + ".cmake");
- auto triplet_abi_tag = [&]() {
+ const std::string triplet_abi_tag = [&]() {
static std::map<fs::path, std::string> s_hash_cache;
if (GlobalState::g_binary_caching)
diff --git a/toolsrc/src/vcpkg/commands.cache.cpp b/toolsrc/src/vcpkg/commands.cache.cpp
index 85bf5fb4d..a9d8ba03c 100644
--- a/toolsrc/src/vcpkg/commands.cache.cpp
+++ b/toolsrc/src/vcpkg/commands.cache.cpp
@@ -38,7 +38,7 @@ namespace vcpkg::Commands::Cache
void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths)
{
- args.parse_arguments(COMMAND_STRUCTURE);
+ Util::unused(args.parse_arguments(COMMAND_STRUCTURE));
const std::vector<BinaryParagraph> binary_paragraphs = read_all_binary_paragraphs(paths);
if (binary_paragraphs.empty())
diff --git a/toolsrc/src/vcpkg/commands.ci.cpp b/toolsrc/src/vcpkg/commands.ci.cpp
index 45eb1c83e..04b42ea00 100644
--- a/toolsrc/src/vcpkg/commands.ci.cpp
+++ b/toolsrc/src/vcpkg/commands.ci.cpp
@@ -77,11 +77,8 @@ namespace vcpkg::Commands::CI
{
auto triplet = p->spec.triplet();
- const Build::BuildPackageConfig build_config{p->source_control_file.value_or_exit(VCPKG_LINE_INFO),
- triplet,
- paths.port_dir(p->spec),
- install_plan_options,
- p->feature_list};
+ const Build::BuildPackageConfig build_config{
+ *scf, triplet, paths.port_dir(p->spec), install_plan_options, p->feature_list};
auto dependency_abis =
Util::fmap(p->computed_dependencies, [&](const PackageSpec& spec) -> Build::AbiEntry {
diff --git a/toolsrc/src/vcpkg/commands.contact.cpp b/toolsrc/src/vcpkg/commands.contact.cpp
index ffed07557..9f86a67dc 100644
--- a/toolsrc/src/vcpkg/commands.contact.cpp
+++ b/toolsrc/src/vcpkg/commands.contact.cpp
@@ -14,24 +14,28 @@ namespace vcpkg::Commands::Contact
return S_EMAIL;
}
- static const CommandSwitch switches[] = {{"--survey", "Launch default browser to the current vcpkg survey"}};
+ static constexpr StringLiteral OPTION_SURVEY = "--survey";
+
+ static constexpr std::array<CommandSwitch, 1> SWITCHES = {{
+ {OPTION_SURVEY, "Launch default browser to the current vcpkg survey"},
+ }};
const CommandStructure COMMAND_STRUCTURE = {
Help::create_example_string("contact"),
0,
0,
- {switches, {}},
+ {SWITCHES, {}},
nullptr,
};
void perform_and_exit(const VcpkgCmdArguments& args)
{
- auto parsed_args = args.parse_arguments(COMMAND_STRUCTURE);
+ const ParsedArguments parsed_args = args.parse_arguments(COMMAND_STRUCTURE);
- if (Util::Sets::contains(parsed_args.switches, switches[0].name))
+ if (Util::Sets::contains(parsed_args.switches, SWITCHES[0].name))
{
auto maybe_now = Chrono::CTime::get_current_date_time();
- if (auto p_now = maybe_now.get())
+ if (const auto p_now = maybe_now.get())
{
auto& fs = Files::get_real_filesystem();
auto config = UserConfig::try_read_data(fs);
diff --git a/toolsrc/src/vcpkg/commands.cpp b/toolsrc/src/vcpkg/commands.cpp
index d9c0e54cd..8b6ffb3d7 100644
--- a/toolsrc/src/vcpkg/commands.cpp
+++ b/toolsrc/src/vcpkg/commands.cpp
@@ -43,7 +43,8 @@ namespace vcpkg::Commands
{"portsdiff", &PortsDiff::perform_and_exit},
{"autocomplete", &Autocomplete::perform_and_exit},
{"hash", &Hash::perform_and_exit},
- };
+ // {"fetch", &Fetch::perform_and_exit},
+ };
return t;
}
@@ -51,7 +52,7 @@ namespace vcpkg::Commands
{
static std::vector<PackageNameAndFunction<CommandTypeC>> t = {
{"version", &Version::perform_and_exit},
- {"contact", &Contact::perform_and_exit}
+ {"contact", &Contact::perform_and_exit},
};
return t;
}
diff --git a/toolsrc/src/vcpkg/commands.create.cpp b/toolsrc/src/vcpkg/commands.create.cpp
index 25c34cf09..dfb3ab784 100644
--- a/toolsrc/src/vcpkg/commands.create.cpp
+++ b/toolsrc/src/vcpkg/commands.create.cpp
@@ -18,11 +18,11 @@ namespace vcpkg::Commands::Create
void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths)
{
- args.parse_arguments(COMMAND_STRUCTURE);
+ Util::unused(args.parse_arguments(COMMAND_STRUCTURE));
const std::string port_name = args.command_arguments.at(0);
const std::string url = args.command_arguments.at(1);
- const fs::path& cmake_exe = paths.get_cmake_exe();
+ const fs::path& cmake_exe = paths.get_tool_exe(Tools::CMAKE);
std::vector<System::CMakeVariable> cmake_args{{"CMD", "CREATE"}, {"PORT", port_name}, {"URL", url}};
diff --git a/toolsrc/src/vcpkg/commands.dependinfo.cpp b/toolsrc/src/vcpkg/commands.dependinfo.cpp
index bb300d96e..1ca658216 100644
--- a/toolsrc/src/vcpkg/commands.dependinfo.cpp
+++ b/toolsrc/src/vcpkg/commands.dependinfo.cpp
@@ -19,7 +19,7 @@ namespace vcpkg::Commands::DependInfo
void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths)
{
- args.parse_arguments(COMMAND_STRUCTURE);
+ Util::unused(args.parse_arguments(COMMAND_STRUCTURE));
std::vector<std::unique_ptr<SourceControlFile>> source_control_files =
Paragraphs::load_all_ports(paths.get_filesystem(), paths.ports);
@@ -30,7 +30,6 @@ namespace vcpkg::Commands::DependInfo
Util::erase_remove_if(source_control_files,
[&](const std::unique_ptr<SourceControlFile>& source_control_file) {
-
const SourceParagraph& source_paragraph = *source_control_file->core_paragraph;
if (Strings::case_insensitive_ascii_contains(source_paragraph.name, filter))
diff --git a/toolsrc/src/vcpkg/commands.edit.cpp b/toolsrc/src/vcpkg/commands.edit.cpp
index 6c696018e..82569dd07 100644
--- a/toolsrc/src/vcpkg/commands.edit.cpp
+++ b/toolsrc/src/vcpkg/commands.edit.cpp
@@ -9,14 +9,15 @@ namespace vcpkg::Commands::Edit
{
static std::vector<fs::path> find_from_registry()
{
+ std::vector<fs::path> output;
+
+#if defined(_WIN32)
static const std::array<const char*, 3> REGKEYS = {
R"(SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\{C26E74D1-022E-4238-8B9D-1E7564A36CC9}_is1)",
R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{1287CAD5-7C8D-410D-88B9-0D1EE4A83FF2}_is1)",
R"(SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\{F8A2A208-72B3-4D61-95FC-8A65D340689B}_is1)",
};
- std::vector<fs::path> output;
-#if defined(_WIN32)
for (auto&& keypath : REGKEYS)
{
const Optional<std::string> code_installpath =
@@ -93,7 +94,7 @@ namespace vcpkg::Commands::Edit
const std::vector<fs::path> from_registry = find_from_registry();
candidate_paths.insert(candidate_paths.end(), from_registry.cbegin(), from_registry.cend());
- auto it = Util::find_if(candidate_paths, [&](const fs::path& p) { return fs.exists(p); });
+ const auto it = Util::find_if(candidate_paths, [&](const fs::path& p) { return fs.exists(p); });
if (it == candidate_paths.cend())
{
System::println(
diff --git a/toolsrc/src/vcpkg/commands.exportifw.cpp b/toolsrc/src/vcpkg/commands.exportifw.cpp
index 58d9aa0be..ae106196a 100644
--- a/toolsrc/src/vcpkg/commands.exportifw.cpp
+++ b/toolsrc/src/vcpkg/commands.exportifw.cpp
@@ -291,7 +291,7 @@ namespace vcpkg::Export::IFW
std::error_code ec;
Files::Filesystem& fs = paths.get_filesystem();
- const fs::path& installerbase_exe = paths.get_ifw_installerbase_exe();
+ const fs::path& installerbase_exe = paths.get_tool_exe(Tools::IFW_INSTALLER_BASE);
fs::path tempmaintenancetool = ifw_packages_dir_path / "maintenance" / "data" / "tempmaintenancetool.exe";
fs.create_directories(tempmaintenancetool.parent_path(), ec);
Checks::check_exit(VCPKG_LINE_INFO,
@@ -335,7 +335,7 @@ namespace vcpkg::Export::IFW
void do_repository(const std::string& export_id, const Options& ifw_options, const VcpkgPaths& paths)
{
- const fs::path& repogen_exe = paths.get_ifw_repogen_exe();
+ const fs::path& repogen_exe = paths.get_tool_exe(Tools::IFW_REPOGEN);
const fs::path packages_dir = get_packages_dir_path(export_id, ifw_options, paths);
const fs::path repository_dir = get_repository_dir_path(export_id, ifw_options, paths);
@@ -361,7 +361,7 @@ namespace vcpkg::Export::IFW
void do_installer(const std::string& export_id, const Options& ifw_options, const VcpkgPaths& paths)
{
- const fs::path& binarycreator_exe = paths.get_ifw_binarycreator_exe();
+ const fs::path& binarycreator_exe = paths.get_tool_exe(Tools::IFW_BINARYCREATOR);
const fs::path config_file = get_config_file_path(export_id, ifw_options, paths);
const fs::path packages_dir = get_packages_dir_path(export_id, ifw_options, paths);
const fs::path repository_dir = get_repository_dir_path(export_id, ifw_options, paths);
diff --git a/toolsrc/src/vcpkg/commands.fetch.cpp b/toolsrc/src/vcpkg/commands.fetch.cpp
new file mode 100644
index 000000000..7a1e6a810
--- /dev/null
+++ b/toolsrc/src/vcpkg/commands.fetch.cpp
@@ -0,0 +1,717 @@
+#include "pch.h"
+
+#include <vcpkg/base/checks.h>
+#include <vcpkg/base/strings.h>
+#include <vcpkg/base/system.h>
+#include <vcpkg/base/util.h>
+#include <vcpkg/commands.h>
+#include <vcpkg/help.h>
+
+namespace vcpkg::Commands::Fetch
+{
+ static constexpr CStringView V_120 = "v120";
+ static constexpr CStringView V_140 = "v140";
+ static constexpr CStringView V_141 = "v141";
+
+ struct ToolData
+ {
+ std::array<int, 3> version;
+ fs::path exe_path;
+ std::string url;
+ fs::path download_path;
+ fs::path tool_dir_path;
+ std::string sha512;
+ };
+
+ static Optional<std::array<int, 3>> parse_version_string(const std::string& version_as_string)
+ {
+ static const std::regex RE(R"###((\d+)\.(\d+)\.(\d+))###");
+
+ std::match_results<std::string::const_iterator> match;
+ const auto found = std::regex_search(version_as_string, match, RE);
+ if (!found)
+ {
+ return {};
+ }
+
+ const int d1 = atoi(match[1].str().c_str());
+ const int d2 = atoi(match[2].str().c_str());
+ const int d3 = atoi(match[3].str().c_str());
+ const std::array<int, 3> result = {d1, d2, d3};
+ return result;
+ }
+
+ static ToolData parse_tool_data_from_xml(const VcpkgPaths& paths, const std::string& tool)
+ {
+#if defined(_WIN32)
+ static constexpr StringLiteral OS_STRING = "windows";
+#elif defined(__APPLE__)
+ static constexpr StringLiteral OS_STRING = "osx";
+#elif defined(__linux__)
+ static constexpr StringLiteral OS_STRING = "linux";
+#else
+ return ToolData{};
+#endif
+
+#if defined(_WIN32) || defined(__APPLE__) || defined(__linux__)
+ static const std::string XML_VERSION = "2";
+ static const fs::path XML_PATH = paths.scripts / "vcpkgTools.xml";
+
+ const auto maybe_get_string_inside_tags = [](const std::string& input,
+ const std::regex& regex) -> Optional<std::string> {
+ std::smatch match;
+ const bool has_match = std::regex_search(input.cbegin(), input.cend(), match, regex);
+ if (!has_match) return nullopt;
+ return match[1];
+ };
+
+ const auto get_string_inside_tags =
+ [](const std::string& input, const std::regex& regex, const std::string& tag_name) -> std::string {
+ std::smatch match;
+ const bool has_match = std::regex_search(input.cbegin(), input.cend(), match, regex);
+ Checks::check_exit(
+ VCPKG_LINE_INFO, has_match, "Could not find tag <%s> in %s", tag_name, XML_PATH.generic_string());
+
+ return match[1];
+ };
+
+ static const std::regex XML_VERSION_REGEX{R"###(<tools[\s]+version="([^"]+)">)###"};
+ static const std::string XML = paths.get_filesystem().read_contents(XML_PATH).value_or_exit(VCPKG_LINE_INFO);
+ static const std::regex VERSION_REGEX{R"###(<version>([\s\S]*?)</version>)###"};
+ static const std::regex EXE_RELATIVE_PATH_REGEX{
+ Strings::format(R"###(<exeRelativePath>([\s\S]*?)</exeRelativePath>)###")};
+ static const std::regex ARCHIVE_NAME_REGEX{Strings::format(R"###(<archiveName>([\s\S]*?)</archiveName>)###")};
+ static const std::regex URL_REGEX{Strings::format(R"###(<url>([\s\S]*?)</url>)###")};
+ static const std::regex SHA512_REGEX{Strings::format(R"###(<sha512>([\s\S]*?)</sha512>)###")};
+
+ std::smatch match_xml_version;
+ const bool has_xml_version = std::regex_search(XML.cbegin(), XML.cend(), match_xml_version, XML_VERSION_REGEX);
+ Checks::check_exit(VCPKG_LINE_INFO,
+ has_xml_version,
+ R"(Could not find <tools version="%s"> in %s)",
+ XML_VERSION,
+ XML_PATH.generic_string());
+ Checks::check_exit(VCPKG_LINE_INFO,
+ XML_VERSION == match_xml_version[1],
+ "Expected %s version: [%s], but was [%s]. Please re-run bootstrap-vcpkg.",
+ XML_PATH.generic_string(),
+ XML_VERSION,
+ match_xml_version[1]);
+
+ const std::regex tool_regex{
+ Strings::format(R"###(<tool[\s]+name="%s"[\s]+os="%s">([\s\S]*?)<\/tool>)###", tool, OS_STRING)};
+
+ std::smatch match_tool;
+ const bool has_match_tool = std::regex_search(XML.cbegin(), XML.cend(), match_tool, tool_regex);
+ Checks::check_exit(VCPKG_LINE_INFO,
+ has_match_tool,
+ "Could not find entry for tool [%s] in %s",
+ tool,
+ XML_PATH.generic_string());
+
+ const std::string tool_data_as_string = get_string_inside_tags(XML, tool_regex, tool);
+
+ const std::string required_version_as_string =
+ get_string_inside_tags(tool_data_as_string, VERSION_REGEX, "version");
+
+ const std::string url = get_string_inside_tags(tool_data_as_string, URL_REGEX, "url");
+
+ const std::string exe_relative_path =
+ get_string_inside_tags(tool_data_as_string, EXE_RELATIVE_PATH_REGEX, "exeRelativePath");
+
+ auto archive_name = maybe_get_string_inside_tags(tool_data_as_string, ARCHIVE_NAME_REGEX);
+
+ const Optional<std::array<int, 3>> required_version = parse_version_string(required_version_as_string);
+ Checks::check_exit(VCPKG_LINE_INFO,
+ required_version.has_value(),
+ "Could not parse version for tool %s. Version string was: %s",
+ tool,
+ required_version_as_string);
+
+ const std::string tool_dir_name = Strings::format("%s-%s-%s", tool, required_version_as_string, OS_STRING);
+ const fs::path tool_dir_path = paths.downloads / "tools" / tool_dir_name;
+ const fs::path exe_path = tool_dir_path / exe_relative_path;
+
+ const std::string sha512 = get_string_inside_tags(tool_data_as_string, SHA512_REGEX, "sha512");
+
+ return ToolData{*required_version.get(),
+ exe_path,
+ url,
+ paths.downloads / archive_name.value_or(exe_relative_path),
+ tool_dir_path,
+ sha512};
+#endif
+ }
+
+ static bool exists_and_has_equal_or_greater_version(const std::string& version_cmd,
+ const std::array<int, 3>& expected_version)
+ {
+ const auto rc = System::cmd_execute_and_capture_output(Strings::format(R"(%s)", version_cmd));
+ if (rc.exit_code != 0)
+ {
+ return false;
+ }
+
+ const Optional<std::array<int, 3>> v = parse_version_string(rc.output);
+ if (!v.has_value())
+ {
+ return false;
+ }
+
+ const std::array<int, 3> actual_version = *v.get();
+ return (actual_version[0] > expected_version[0] ||
+ (actual_version[0] == expected_version[0] && actual_version[1] > expected_version[1]) ||
+ (actual_version[0] == expected_version[0] && actual_version[1] == expected_version[1] &&
+ actual_version[2] >= expected_version[2]));
+ }
+
+ static Optional<fs::path> find_if_has_equal_or_greater_version(const std::vector<fs::path>& candidate_paths,
+ const std::string& version_check_arguments,
+ const std::array<int, 3>& expected_version)
+ {
+ auto it = Util::find_if(candidate_paths, [&](const fs::path& p) {
+ const std::string cmd = Strings::format(R"("%s" %s)", p.u8string(), version_check_arguments);
+ return exists_and_has_equal_or_greater_version(cmd, expected_version);
+ });
+
+ if (it != candidate_paths.cend())
+ {
+ return std::move(*it);
+ }
+
+ return nullopt;
+ }
+
+ static std::vector<std::string> keep_data_lines(const std::string& data_blob)
+ {
+ static const std::regex DATA_LINE_REGEX(R"(<sol>::(.+?)(?=::<eol>))");
+
+ std::vector<std::string> data_lines;
+
+ const std::sregex_iterator it(data_blob.cbegin(), data_blob.cend(), DATA_LINE_REGEX);
+ const std::sregex_iterator end;
+ for (std::sregex_iterator i = it; i != end; ++i)
+ {
+ const std::smatch match = *i;
+ data_lines.push_back(match[1].str());
+ }
+
+ return data_lines;
+ }
+
+#if !defined(_WIN32)
+ static void extract_archive(const VcpkgPaths& paths, const fs::path& archive, const fs::path& to_path)
+ {
+ Files::Filesystem& fs = paths.get_filesystem();
+ const fs::path to_path_partial = to_path.u8string() + ".partial";
+
+ std::error_code ec;
+ fs.remove_all(to_path_partial, ec);
+ fs.create_directories(to_path_partial, ec);
+
+ const auto ext = archive.extension();
+ if (ext == ".gz" && ext.extension() != ".tar")
+ {
+ const auto code = System::cmd_execute(
+ Strings::format(R"(cd '%s' && tar xzf '%s')", to_path_partial.u8string(), archive.u8string()));
+ Checks::check_exit(VCPKG_LINE_INFO, code == 0, "tar failed while extracting %s", archive.u8string());
+ }
+ else if (ext == ".zip")
+ {
+ const auto code = System::cmd_execute(
+ Strings::format(R"(cd '%s' && unzip -qqo '%s')", to_path_partial.u8string(), archive.u8string()));
+ Checks::check_exit(VCPKG_LINE_INFO, code == 0, "unzip failed while extracting %s", archive.u8string());
+ }
+ else
+ {
+ Checks::exit_with_message(VCPKG_LINE_INFO, "Unexpected archive extension: %s", ext.u8string());
+ }
+
+ fs.rename(to_path_partial, to_path);
+ }
+
+ static void verify_hash(const VcpkgPaths& paths,
+ const std::string& url,
+ const fs::path& path,
+ const std::string& sha512)
+ {
+ const std::string actual_hash = Hash::get_file_hash(paths, path, "SHA512");
+ Checks::check_exit(VCPKG_LINE_INFO,
+ sha512 == actual_hash,
+ "File does not have the expected hash:\n"
+ " url : [ %s ]\n"
+ " File path : [ %s ]\n"
+ " Expected hash : [ %s ]\n"
+ " Actual hash : [ %s ]\n",
+ url,
+ path.u8string(),
+ sha512,
+ actual_hash);
+ }
+
+ static void download_file(const VcpkgPaths& paths,
+ const std::string& url,
+ const fs::path& download_path,
+ const std::string& sha512)
+ {
+ Files::Filesystem& fs = paths.get_filesystem();
+ const std::string download_path_part = download_path.u8string() + ".part";
+ std::error_code ec;
+ fs.remove(download_path_part, ec);
+ const auto code = System::cmd_execute(Strings::format(
+ R"(curl -L '%s' --create-dirs --output '%s')", url, download_path_part));
+ Checks::check_exit(VCPKG_LINE_INFO, code == 0, "Could not download %s", url);
+
+ verify_hash(paths, url, download_path_part, sha512);
+ fs.rename(download_path_part, download_path);
+ }
+
+#endif
+ static fs::path fetch_tool(const VcpkgPaths& paths, const std::string& tool_name, const ToolData& tool_data)
+ {
+ const std::array<int, 3>& version = tool_data.version;
+
+ const std::string version_as_string = Strings::format("%d.%d.%d", version[0], version[1], version[2]);
+ System::println("A suitable version of %s was not found (required v%s). Downloading portable %s v%s...",
+ tool_name,
+ version_as_string,
+ tool_name,
+ version_as_string);
+#if defined(_WIN32)
+ const fs::path script = paths.scripts / "fetchtool.ps1";
+ const std::string title = Strings::format(
+ "Fetching %s version %s (No sufficient installed version was found)", tool_name, version_as_string);
+ const System::PowershellParameter tool_param("tool", tool_name);
+ const std::string output = System::powershell_execute_and_capture_output(title, script, {tool_param});
+
+ const std::vector<std::string> tool_path = keep_data_lines(output);
+ Checks::check_exit(VCPKG_LINE_INFO, tool_path.size() == 1, "Expected tool path, but got %s", output);
+
+ const fs::path actual_downloaded_path = Strings::trim(std::string{tool_path.at(0)});
+ const fs::path& expected_downloaded_path = tool_data.exe_path;
+ std::error_code ec;
+ const auto eq = fs::stdfs::equivalent(expected_downloaded_path, actual_downloaded_path, ec);
+ Checks::check_exit(VCPKG_LINE_INFO,
+ eq && !ec,
+ "Expected tool downloaded path to be %s, but was %s",
+ expected_downloaded_path.u8string(),
+ actual_downloaded_path.u8string());
+ return actual_downloaded_path;
+#else
+ const auto& fs = paths.get_filesystem();
+ if (!fs.exists(tool_data.download_path))
+ {
+ System::println("Downloading %s...", tool_name);
+ download_file(paths, tool_data.url, tool_data.download_path, tool_data.sha512);
+ System::println("Downloading %s... done.", tool_name);
+ }
+ else
+ {
+ verify_hash(paths, tool_data.url, tool_data.download_path, tool_data.sha512);
+ }
+
+ System::println("Extracting %s...", tool_name);
+ extract_archive(paths, tool_data.download_path, tool_data.tool_dir_path);
+ System::println("Extracting %s... done.", tool_name);
+
+ Checks::check_exit(VCPKG_LINE_INFO,
+ fs.exists(tool_data.exe_path),
+ "Expected %s to exist after extracting",
+ tool_data.exe_path);
+
+ return tool_data.exe_path;
+#endif
+ }
+
+ static fs::path get_cmake_path(const VcpkgPaths& paths)
+ {
+ std::vector<fs::path> candidate_paths;
+#if defined(_WIN32) || defined(__APPLE__) || defined(__linux__)
+ static const ToolData TOOL_DATA = parse_tool_data_from_xml(paths, "cmake");
+ candidate_paths.push_back(TOOL_DATA.exe_path);
+#else
+ static const ToolData TOOL_DATA = ToolData{{3, 5, 1}, ""};
+#endif
+ static const std::string VERSION_CHECK_ARGUMENTS = "--version";
+
+ const std::vector<fs::path> from_path = Files::find_from_PATH("cmake");
+ candidate_paths.insert(candidate_paths.end(), from_path.cbegin(), from_path.cend());
+
+ const auto& program_files = System::get_program_files_platform_bitness();
+ if (const auto pf = program_files.get()) candidate_paths.push_back(*pf / "CMake" / "bin" / "cmake.exe");
+ const auto& program_files_32_bit = System::get_program_files_32_bit();
+ if (const auto pf = program_files_32_bit.get()) candidate_paths.push_back(*pf / "CMake" / "bin" / "cmake.exe");
+
+ const Optional<fs::path> path =
+ find_if_has_equal_or_greater_version(candidate_paths, VERSION_CHECK_ARGUMENTS, TOOL_DATA.version);
+ if (const auto p = path.get())
+ {
+ return *p;
+ }
+
+ return fetch_tool(paths, "cmake", TOOL_DATA);
+ }
+
+ static fs::path get_7za_path(const VcpkgPaths& paths)
+ {
+#if defined(_WIN32)
+ static const ToolData TOOL_DATA = parse_tool_data_from_xml(paths, "7zip");
+ if (!paths.get_filesystem().exists(TOOL_DATA.exe_path))
+ {
+ return fetch_tool(paths, "7zip", TOOL_DATA);
+ }
+ return TOOL_DATA.exe_path;
+#else
+ Checks::exit_with_message(VCPKG_LINE_INFO, "Cannot download 7zip for non-Windows platforms.");
+#endif
+ }
+
+ static fs::path get_ninja_path(const VcpkgPaths& paths)
+ {
+ static const ToolData TOOL_DATA = parse_tool_data_from_xml(paths, "ninja");
+
+ std::vector<fs::path> candidate_paths;
+ candidate_paths.push_back(TOOL_DATA.exe_path);
+ const std::vector<fs::path> from_path = Files::find_from_PATH("ninja");
+ candidate_paths.insert(candidate_paths.end(), from_path.cbegin(), from_path.cend());
+
+ auto path = find_if_has_equal_or_greater_version(candidate_paths, "--version", TOOL_DATA.version);
+ if (const auto p = path.get())
+ {
+ return *p;
+ }
+
+ return fetch_tool(paths, "ninja", TOOL_DATA);
+ }
+
+ static fs::path get_nuget_path(const VcpkgPaths& paths)
+ {
+ static const ToolData TOOL_DATA = parse_tool_data_from_xml(paths, "nuget");
+
+ std::vector<fs::path> candidate_paths;
+ candidate_paths.push_back(TOOL_DATA.exe_path);
+ const std::vector<fs::path> from_path = Files::find_from_PATH("nuget");
+ candidate_paths.insert(candidate_paths.end(), from_path.cbegin(), from_path.cend());
+
+ auto path = find_if_has_equal_or_greater_version(candidate_paths, "", TOOL_DATA.version);
+ if (const auto p = path.get())
+ {
+ return *p;
+ }
+
+ return fetch_tool(paths, "nuget", TOOL_DATA);
+ }
+
+ static fs::path get_git_path(const VcpkgPaths& paths)
+ {
+#if defined(_WIN32)
+ static const ToolData TOOL_DATA = parse_tool_data_from_xml(paths, "git");
+#else
+ static const ToolData TOOL_DATA = ToolData{{2, 7, 4}, ""};
+#endif
+ static const std::string VERSION_CHECK_ARGUMENTS = "--version";
+
+ std::vector<fs::path> candidate_paths;
+#if defined(_WIN32)
+ candidate_paths.push_back(TOOL_DATA.exe_path);
+#endif
+ const std::vector<fs::path> from_path = Files::find_from_PATH("git");
+ candidate_paths.insert(candidate_paths.end(), from_path.cbegin(), from_path.cend());
+
+ const auto& program_files = System::get_program_files_platform_bitness();
+ if (const auto pf = program_files.get()) candidate_paths.push_back(*pf / "git" / "cmd" / "git.exe");
+ const auto& program_files_32_bit = System::get_program_files_32_bit();
+ if (const auto pf = program_files_32_bit.get()) candidate_paths.push_back(*pf / "git" / "cmd" / "git.exe");
+
+ const Optional<fs::path> path =
+ find_if_has_equal_or_greater_version(candidate_paths, VERSION_CHECK_ARGUMENTS, TOOL_DATA.version);
+ if (const auto p = path.get())
+ {
+ return *p;
+ }
+
+ return fetch_tool(paths, "git", TOOL_DATA);
+ }
+
+ static fs::path get_ifw_installerbase_path(const VcpkgPaths& paths)
+ {
+ static const ToolData TOOL_DATA = parse_tool_data_from_xml(paths, "installerbase");
+
+ static const std::string VERSION_CHECK_ARGUMENTS = "--framework-version";
+
+ std::vector<fs::path> candidate_paths;
+ candidate_paths.push_back(TOOL_DATA.exe_path);
+ // TODO: Uncomment later
+ // const std::vector<fs::path> from_path = Files::find_from_PATH("installerbase");
+ // candidate_paths.insert(candidate_paths.end(), from_path.cbegin(), from_path.cend());
+ // candidate_paths.push_back(fs::path(System::get_environment_variable("HOMEDRIVE").value_or("C:")) / "Qt" /
+ // "Tools" / "QtInstallerFramework" / "3.1" / "bin" / "installerbase.exe");
+ // candidate_paths.push_back(fs::path(System::get_environment_variable("HOMEDRIVE").value_or("C:")) / "Qt" /
+ // "QtIFW-3.1.0" / "bin" / "installerbase.exe");
+
+ const Optional<fs::path> path =
+ find_if_has_equal_or_greater_version(candidate_paths, VERSION_CHECK_ARGUMENTS, TOOL_DATA.version);
+ if (const auto p = path.get())
+ {
+ return *p;
+ }
+
+ return fetch_tool(paths, "installerbase", TOOL_DATA);
+ }
+
+ struct VisualStudioInstance
+ {
+ fs::path root_path;
+ std::string version;
+ std::string release_type;
+ std::string preference_weight; // Mostly unused, just for verification that order is as intended
+
+ std::string major_version() const { return version.substr(0, 2); }
+ };
+
+ static std::vector<VisualStudioInstance> get_visual_studio_instances(const VcpkgPaths& paths)
+ {
+ const fs::path script = paths.scripts / "findVisualStudioInstallationInstances.ps1";
+ const std::string output =
+ System::powershell_execute_and_capture_output("Detecting Visual Studio instances", script);
+
+ const std::vector<std::string> instances_as_strings = keep_data_lines(output);
+ Checks::check_exit(VCPKG_LINE_INFO,
+ !instances_as_strings.empty(),
+ "Could not detect any Visual Studio instances.\n"
+ "Powershell script:\n"
+ " %s\n"
+ "returned:\n"
+ "%s",
+ script.generic_string(),
+ output);
+
+ std::vector<VisualStudioInstance> instances;
+ for (const std::string& instance_as_string : instances_as_strings)
+ {
+ const std::vector<std::string> split = Strings::split(instance_as_string, "::");
+ Checks::check_exit(VCPKG_LINE_INFO,
+ split.size() == 4,
+ "Invalid Visual Studio instance format.\n"
+ "Expected: PreferenceWeight::ReleaseType::Version::PathToVisualStudio\n"
+ "Actual : %s\n",
+ instance_as_string);
+ instances.push_back({split.at(3), split.at(2), split.at(1), split.at(0)});
+ }
+
+ return instances;
+ }
+
+ std::vector<Toolset> find_toolset_instances(const VcpkgPaths& paths)
+ {
+ using CPU = System::CPUArchitecture;
+
+ const auto& fs = paths.get_filesystem();
+
+ // Note: this will contain a mix of vcvarsall.bat locations and dumpbin.exe locations.
+ std::vector<fs::path> paths_examined;
+
+ std::vector<Toolset> found_toolsets;
+ std::vector<Toolset> excluded_toolsets;
+
+ const std::vector<VisualStudioInstance> vs_instances = get_visual_studio_instances(paths);
+ const bool v140_is_available = Util::find_if(vs_instances, [&](const VisualStudioInstance& vs_instance) {
+ return vs_instance.major_version() == "14";
+ }) != vs_instances.cend();
+
+ for (const VisualStudioInstance& vs_instance : vs_instances)
+ {
+ const std::string major_version = vs_instance.major_version();
+ if (major_version == "15")
+ {
+ const fs::path vc_dir = vs_instance.root_path / "VC";
+
+ // Skip any instances that do not have vcvarsall.
+ const fs::path vcvarsall_dir = vc_dir / "Auxiliary" / "Build";
+ const fs::path vcvarsall_bat = vcvarsall_dir / "vcvarsall.bat";
+ paths_examined.push_back(vcvarsall_bat);
+ if (!fs.exists(vcvarsall_bat)) continue;
+
+ // Get all supported architectures
+ std::vector<ToolsetArchOption> supported_architectures;
+ if (fs.exists(vcvarsall_dir / "vcvars32.bat"))
+ supported_architectures.push_back({"x86", CPU::X86, CPU::X86});
+ if (fs.exists(vcvarsall_dir / "vcvars64.bat"))
+ supported_architectures.push_back({"amd64", CPU::X64, CPU::X64});
+ if (fs.exists(vcvarsall_dir / "vcvarsx86_amd64.bat"))
+ supported_architectures.push_back({"x86_amd64", CPU::X86, CPU::X64});
+ if (fs.exists(vcvarsall_dir / "vcvarsx86_arm.bat"))
+ supported_architectures.push_back({"x86_arm", CPU::X86, CPU::ARM});
+ if (fs.exists(vcvarsall_dir / "vcvarsx86_arm64.bat"))
+ supported_architectures.push_back({"x86_arm64", CPU::X86, CPU::ARM64});
+ if (fs.exists(vcvarsall_dir / "vcvarsamd64_x86.bat"))
+ supported_architectures.push_back({"amd64_x86", CPU::X64, CPU::X86});
+ if (fs.exists(vcvarsall_dir / "vcvarsamd64_arm.bat"))
+ supported_architectures.push_back({"amd64_arm", CPU::X64, CPU::ARM});
+ if (fs.exists(vcvarsall_dir / "vcvarsamd64_arm64.bat"))
+ supported_architectures.push_back({"amd64_arm64", CPU::X64, CPU::ARM64});
+
+ // Locate the "best" MSVC toolchain version
+ const fs::path msvc_path = vc_dir / "Tools" / "MSVC";
+ std::vector<fs::path> msvc_subdirectories = fs.get_files_non_recursive(msvc_path);
+ Util::unstable_keep_if(msvc_subdirectories,
+ [&fs](const fs::path& path) { return fs.is_directory(path); });
+
+ // Sort them so that latest comes first
+ std::sort(
+ msvc_subdirectories.begin(),
+ msvc_subdirectories.end(),
+ [](const fs::path& left, const fs::path& right) { return left.filename() > right.filename(); });
+
+ for (const fs::path& subdir : msvc_subdirectories)
+ {
+ const fs::path dumpbin_path = subdir / "bin" / "HostX86" / "x86" / "dumpbin.exe";
+ paths_examined.push_back(dumpbin_path);
+ if (fs.exists(dumpbin_path))
+ {
+ const Toolset v141toolset = Toolset{
+ vs_instance.root_path, dumpbin_path, vcvarsall_bat, {}, V_141, supported_architectures};
+
+ auto english_language_pack = dumpbin_path.parent_path() / "1033";
+
+ if (!fs.exists(english_language_pack))
+ {
+ excluded_toolsets.push_back(v141toolset);
+ break;
+ }
+
+ found_toolsets.push_back(v141toolset);
+
+ if (v140_is_available)
+ {
+ const Toolset v140toolset = Toolset{vs_instance.root_path,
+ dumpbin_path,
+ vcvarsall_bat,
+ {"-vcvars_ver=14.0"},
+ V_140,
+ supported_architectures};
+ found_toolsets.push_back(v140toolset);
+ }
+
+ break;
+ }
+ }
+
+ continue;
+ }
+
+ if (major_version == "14" || major_version == "12")
+ {
+ const fs::path vcvarsall_bat = vs_instance.root_path / "VC" / "vcvarsall.bat";
+
+ paths_examined.push_back(vcvarsall_bat);
+ if (fs.exists(vcvarsall_bat))
+ {
+ const fs::path vs_dumpbin_exe = vs_instance.root_path / "VC" / "bin" / "dumpbin.exe";
+ paths_examined.push_back(vs_dumpbin_exe);
+
+ const fs::path vs_bin_dir = vcvarsall_bat.parent_path() / "bin";
+ std::vector<ToolsetArchOption> supported_architectures;
+ if (fs.exists(vs_bin_dir / "vcvars32.bat"))
+ supported_architectures.push_back({"x86", CPU::X86, CPU::X86});
+ if (fs.exists(vs_bin_dir / "amd64\\vcvars64.bat"))
+ supported_architectures.push_back({"x64", CPU::X64, CPU::X64});
+ if (fs.exists(vs_bin_dir / "x86_amd64\\vcvarsx86_amd64.bat"))
+ supported_architectures.push_back({"x86_amd64", CPU::X86, CPU::X64});
+ if (fs.exists(vs_bin_dir / "x86_arm\\vcvarsx86_arm.bat"))
+ supported_architectures.push_back({"x86_arm", CPU::X86, CPU::ARM});
+ if (fs.exists(vs_bin_dir / "amd64_x86\\vcvarsamd64_x86.bat"))
+ supported_architectures.push_back({"amd64_x86", CPU::X64, CPU::X86});
+ if (fs.exists(vs_bin_dir / "amd64_arm\\vcvarsamd64_arm.bat"))
+ supported_architectures.push_back({"amd64_arm", CPU::X64, CPU::ARM});
+
+ if (fs.exists(vs_dumpbin_exe))
+ {
+ const Toolset toolset = {vs_instance.root_path,
+ vs_dumpbin_exe,
+ vcvarsall_bat,
+ {},
+ major_version == "14" ? V_140 : V_120,
+ supported_architectures};
+
+ auto english_language_pack = vs_dumpbin_exe.parent_path() / "1033";
+
+ if (!fs.exists(english_language_pack))
+ {
+ excluded_toolsets.push_back(toolset);
+ break;
+ }
+
+ found_toolsets.push_back(toolset);
+ }
+ }
+ }
+ }
+
+ if (!excluded_toolsets.empty())
+ {
+ System::println(
+ System::Color::warning,
+ "Warning: The following VS instances are excluded because the English language pack is unavailable.");
+ for (const Toolset& toolset : excluded_toolsets)
+ {
+ System::println(" %s", toolset.visual_studio_root_path.u8string());
+ }
+ System::println(System::Color::warning, "Please install the English language pack.");
+ }
+
+ if (found_toolsets.empty())
+ {
+ System::println(System::Color::error, "Could not locate a complete toolset.");
+ System::println("The following paths were examined:");
+ for (const fs::path& path : paths_examined)
+ {
+ System::println(" %s", path.u8string());
+ }
+ Checks::exit_fail(VCPKG_LINE_INFO);
+ }
+
+ return found_toolsets;
+ }
+
+ fs::path get_tool_path(const VcpkgPaths& paths, const std::string& tool)
+ {
+ // First deal with specially handled tools.
+ // For these we may look in locations like Program Files, the PATH etc as well as the auto-downloaded location.
+ if (tool == Tools::SEVEN_ZIP) return get_7za_path(paths);
+ if (tool == Tools::CMAKE) return get_cmake_path(paths);
+ if (tool == Tools::GIT) return get_git_path(paths);
+ if (tool == Tools::NINJA) return get_ninja_path(paths);
+ if (tool == Tools::NUGET) return get_nuget_path(paths);
+ if (tool == Tools::IFW_INSTALLER_BASE) return get_ifw_installerbase_path(paths);
+ if (tool == Tools::IFW_BINARYCREATOR)
+ return get_ifw_installerbase_path(paths).parent_path() / "binarycreator.exe";
+ if (tool == Tools::IFW_REPOGEN) return get_ifw_installerbase_path(paths).parent_path() / "repogen.exe";
+
+ // For other tools, we simply always auto-download them.
+ const ToolData tool_data = parse_tool_data_from_xml(paths, tool);
+ if (paths.get_filesystem().exists(tool_data.exe_path))
+ {
+ return tool_data.exe_path;
+ }
+ return fetch_tool(paths, tool, tool_data);
+ }
+
+ const CommandStructure COMMAND_STRUCTURE = {
+ Strings::format("The argument should be tool name\n%s", Help::create_example_string("fetch cmake")),
+ 1,
+ 1,
+ {},
+ nullptr,
+ };
+
+ void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths)
+ {
+ Util::unused(args.parse_arguments(COMMAND_STRUCTURE));
+
+ const std::string tool = args.command_arguments[0];
+ const fs::path tool_path = get_tool_path(paths, tool);
+ System::println(tool_path.u8string());
+ Checks::exit_success(VCPKG_LINE_INFO);
+ }
+}
diff --git a/toolsrc/src/vcpkg/commands.hash.cpp b/toolsrc/src/vcpkg/commands.hash.cpp
index 9e1b54390..1f709f87b 100644
--- a/toolsrc/src/vcpkg/commands.hash.cpp
+++ b/toolsrc/src/vcpkg/commands.hash.cpp
@@ -7,6 +7,19 @@
#include <vcpkg/commands.h>
#include <vcpkg/help.h>
+namespace vcpkg::Commands::Hash
+{
+ static void verify_has_only_allowed_chars(const std::string& s)
+ {
+ static const std::regex ALLOWED_CHARS{"^[a-zA-Z0-9-]*$"};
+ Checks::check_exit(VCPKG_LINE_INFO,
+ std::regex_match(s, ALLOWED_CHARS),
+ "Only alphanumeric chars and dashes are currently allowed. String was:\n"
+ " % s",
+ s);
+ }
+}
+
#if defined(_WIN32)
#include <bcrypt.h>
@@ -18,7 +31,7 @@ namespace vcpkg::Commands::Hash
{
namespace
{
- static std::string to_hex(const unsigned char* string, const size_t bytes)
+ std::string to_hex(const unsigned char* string, const size_t bytes)
{
static constexpr char HEX_MAP[] = "0123456789abcdef";
@@ -39,99 +52,172 @@ namespace vcpkg::Commands::Hash
return output;
}
- struct BCryptAlgorithmHandle : Util::ResourceBase
+ class BCryptHasher
{
- BCRYPT_ALG_HANDLE handle = nullptr;
+ struct BCryptAlgorithmHandle : Util::ResourceBase
+ {
+ BCRYPT_ALG_HANDLE handle = nullptr;
+
+ ~BCryptAlgorithmHandle()
+ {
+ if (handle) BCryptCloseAlgorithmProvider(handle, 0);
+ }
+ };
+
+ struct BCryptHashHandle : Util::ResourceBase
+ {
+ BCRYPT_HASH_HANDLE handle = nullptr;
+
+ ~BCryptHashHandle()
+ {
+ if (handle) BCryptDestroyHash(handle);
+ }
+ };
- ~BCryptAlgorithmHandle()
+ static void initialize_hash_handle(BCryptHashHandle& hash_handle,
+ const BCryptAlgorithmHandle& algorithm_handle)
{
- if (handle) BCryptCloseAlgorithmProvider(handle, 0);
+ const NTSTATUS error_code =
+ BCryptCreateHash(algorithm_handle.handle, &hash_handle.handle, nullptr, 0, nullptr, 0, 0);
+ Checks::check_exit(VCPKG_LINE_INFO, NT_SUCCESS(error_code), "Failed to initialize the hasher");
}
- };
- struct BCryptHashHandle : Util::ResourceBase
- {
- BCRYPT_HASH_HANDLE handle = nullptr;
+ static void hash_data(BCryptHashHandle& hash_handle, const unsigned char* buffer, const size_t& data_size)
+ {
+ const NTSTATUS error_code = BCryptHashData(
+ hash_handle.handle, const_cast<unsigned char*>(buffer), static_cast<ULONG>(data_size), 0);
+ Checks::check_exit(VCPKG_LINE_INFO, NT_SUCCESS(error_code), "Failed to hash data");
+ }
- ~BCryptHashHandle()
+ static std::string finalize_hash_handle(const BCryptHashHandle& hash_handle, const ULONG length_in_bytes)
{
- if (handle) BCryptDestroyHash(handle);
+ std::unique_ptr<unsigned char[]> hash_buffer = std::make_unique<UCHAR[]>(length_in_bytes);
+ const NTSTATUS error_code = BCryptFinishHash(hash_handle.handle, hash_buffer.get(), length_in_bytes, 0);
+ Checks::check_exit(VCPKG_LINE_INFO, NT_SUCCESS(error_code), "Failed to finalize the hash");
+ return to_hex(hash_buffer.get(), length_in_bytes);
}
- };
- }
- std::string get_file_hash(const VcpkgPaths&, const fs::path& path, const std::string& hash_type)
- {
- BCryptAlgorithmHandle algorithm_handle;
-
- NTSTATUS error_code = BCryptOpenAlgorithmProvider(
- &algorithm_handle.handle, Strings::to_utf16(Strings::ascii_to_uppercase(hash_type)).c_str(), nullptr, 0);
- Checks::check_exit(VCPKG_LINE_INFO, NT_SUCCESS(error_code), "Failed to open the algorithm provider");
-
- DWORD hash_buffer_bytes;
- DWORD cb_data;
- error_code = BCryptGetProperty(algorithm_handle.handle,
- BCRYPT_HASH_LENGTH,
- reinterpret_cast<PUCHAR>(&hash_buffer_bytes),
- sizeof(DWORD),
- &cb_data,
- 0);
- Checks::check_exit(VCPKG_LINE_INFO, NT_SUCCESS(error_code), "Failed to get hash length");
- const ULONG length_in_bytes = hash_buffer_bytes;
-
- BCryptHashHandle hash_handle;
-
- error_code = BCryptCreateHash(algorithm_handle.handle, &hash_handle.handle, nullptr, 0, nullptr, 0, 0);
- Checks::check_exit(VCPKG_LINE_INFO, NT_SUCCESS(error_code), "Failed to initialize the hasher");
-
- FILE* file = nullptr;
- const auto ec = _wfopen_s(&file, path.c_str(), L"rb");
- Checks::check_exit(VCPKG_LINE_INFO, ec == 0, "Failed to open file: %s", path.u8string());
- unsigned char buffer[4096];
- while (const auto actual_size = fread(buffer, 1, sizeof(buffer), file))
- {
- error_code = BCryptHashData(hash_handle.handle, buffer, static_cast<ULONG>(actual_size), 0);
- Checks::check_exit(VCPKG_LINE_INFO, NT_SUCCESS(error_code), "Failed to hash data");
- }
+ public:
+ explicit BCryptHasher(const std::string& hash_type)
+ {
+ NTSTATUS error_code =
+ BCryptOpenAlgorithmProvider(&this->algorithm_handle.handle,
+ Strings::to_utf16(Strings::ascii_to_uppercase(hash_type)).c_str(),
+ nullptr,
+ 0);
+ Checks::check_exit(VCPKG_LINE_INFO, NT_SUCCESS(error_code), "Failed to open the algorithm provider");
+
+ DWORD hash_buffer_bytes;
+ DWORD cb_data;
+ error_code = BCryptGetProperty(this->algorithm_handle.handle,
+ BCRYPT_HASH_LENGTH,
+ reinterpret_cast<PUCHAR>(&hash_buffer_bytes),
+ sizeof(DWORD),
+ &cb_data,
+ 0);
+ Checks::check_exit(VCPKG_LINE_INFO, NT_SUCCESS(error_code), "Failed to get hash length");
+ this->length_in_bytes = hash_buffer_bytes;
+ }
- fclose(file);
+ std::string hash_file(const fs::path& path) const
+ {
+ BCryptHashHandle hash_handle;
+ initialize_hash_handle(hash_handle, this->algorithm_handle);
+
+ FILE* file = nullptr;
+ const auto ec = _wfopen_s(&file, path.c_str(), L"rb");
+ Checks::check_exit(VCPKG_LINE_INFO, ec == 0, "Failed to open file: %s", path.u8string());
+ if (file != nullptr)
+ {
+ unsigned char buffer[4096];
+ while (const auto actual_size = fread(buffer, 1, sizeof(buffer), file))
+ {
+ hash_data(hash_handle, buffer, actual_size);
+ }
+ fclose(file);
+ }
+
+ return finalize_hash_handle(hash_handle, length_in_bytes);
+ }
- std::unique_ptr<unsigned char[]> hash_buffer = std::make_unique<UCHAR[]>(length_in_bytes);
+ std::string hash_string(const std::string& s) const
+ {
+ BCryptHashHandle hash_handle;
+ initialize_hash_handle(hash_handle, this->algorithm_handle);
+ hash_data(hash_handle, reinterpret_cast<const unsigned char*>(s.c_str()), s.size());
+ return finalize_hash_handle(hash_handle, length_in_bytes);
+ }
+
+ private:
+ BCryptAlgorithmHandle algorithm_handle;
+ ULONG length_in_bytes;
+ };
+ }
- error_code = BCryptFinishHash(hash_handle.handle, hash_buffer.get(), length_in_bytes, 0);
- Checks::check_exit(VCPKG_LINE_INFO, NT_SUCCESS(error_code), "Failed to finalize the hash");
+ std::string get_file_hash(const VcpkgPaths& paths, const fs::path& path, const std::string& hash_type)
+ {
+ Checks::check_exit(
+ VCPKG_LINE_INFO, paths.get_filesystem().exists(path), "File %s does not exist", path.u8string());
+ return BCryptHasher{hash_type}.hash_file(path);
+ }
- return to_hex(hash_buffer.get(), length_in_bytes);
+ std::string get_string_hash(const std::string& s, const std::string& hash_type)
+ {
+ verify_has_only_allowed_chars(s);
+ return BCryptHasher{hash_type}.hash_string(s);
}
}
#else
namespace vcpkg::Commands::Hash
{
- std::string get_file_hash(const VcpkgPaths& paths, const fs::path& path, const std::string& hash_type)
+ static std::string get_digest_size(const std::string& hash_type)
{
- const std::string cmd_line = Strings::format(
- R"("%s" -E %ssum "%s")",
- paths.get_cmake_exe().u8string(),
- Strings::ascii_to_lowercase(hash_type),
- path.u8string());
+ if (!Strings::case_insensitive_ascii_starts_with(hash_type, "SHA"))
+ {
+ Checks::exit_with_message(
+ VCPKG_LINE_INFO, "shasum only supports SHA hashes, but %s was provided", hash_type);
+ }
- const auto ec_data = System::cmd_execute_and_capture_output(cmd_line);
- Checks::check_exit(VCPKG_LINE_INFO, ec_data.exit_code == 0, "Running command:\n %s\n failed", cmd_line);
+ return hash_type.substr(3, hash_type.length() - 3);
+ }
- std::string const& output = ec_data.output;
+ static std::string run_shasum_and_post_process(const std::string& cmd_line)
+ {
+ const auto ec_data = System::cmd_execute_and_capture_output(cmd_line);
+ Checks::check_exit(VCPKG_LINE_INFO,
+ ec_data.exit_code == 0,
+ "Failed to run:\n"
+ " %s",
+ cmd_line);
+
+ std::vector<std::string> split = Strings::split(ec_data.output, " ");
+ Checks::check_exit(VCPKG_LINE_INFO,
+ split.size() == 3,
+ "Expected output of the form [hash filename\n] (3 tokens), but got\n"
+ "[%s] (%s tokens)",
+ ec_data.output,
+ std::to_string(split.size()));
+
+ return split[0];
+ }
- const auto start = output.find_first_of(' ');
+ std::string get_file_hash(const VcpkgPaths& paths, const fs::path& path, const std::string& hash_type)
+ {
+ const std::string digest_size = get_digest_size(hash_type);
Checks::check_exit(
- VCPKG_LINE_INFO, start != std::string::npos, "Unexpected output format from command: %s", cmd_line);
+ VCPKG_LINE_INFO, paths.get_filesystem().exists(path), "File %s does not exist", path.u8string());
+ const std::string cmd_line = Strings::format(R"(shasum -a %s "%s")", digest_size, path.u8string());
+ return run_shasum_and_post_process(cmd_line);
+ }
- const auto end = output.find_first_of("\r\n", start + 1);
- Checks::check_exit(
- VCPKG_LINE_INFO, end != std::string::npos, "Unexpected output format from command: %s", cmd_line);
+ std::string get_string_hash(const std::string& s, const std::string& hash_type)
+ {
+ const std::string digest_size = get_digest_size(hash_type);
+ verify_has_only_allowed_chars(s);
- auto hash = output.substr(0, start);
- Util::erase_remove_if(hash, isspace);
- return hash;
+ const std::string cmd_line = Strings::format(R"(echo -n "%s" | shasum -a %s)", s, digest_size);
+ return run_shasum_and_post_process(cmd_line);
}
}
#endif
diff --git a/toolsrc/src/vcpkg/commands.import.cpp b/toolsrc/src/vcpkg/commands.import.cpp
index 24394207b..4b595697a 100644
--- a/toolsrc/src/vcpkg/commands.import.cpp
+++ b/toolsrc/src/vcpkg/commands.import.cpp
@@ -103,7 +103,7 @@ namespace vcpkg::Commands::Import
void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths)
{
- args.parse_arguments(COMMAND_STRUCTURE);
+ Util::unused(args.parse_arguments(COMMAND_STRUCTURE));
const fs::path control_file_path(args.command_arguments[0]);
const fs::path include_directory(args.command_arguments[1]);
diff --git a/toolsrc/src/vcpkg/commands.integrate.cpp b/toolsrc/src/vcpkg/commands.integrate.cpp
index 36e4e56e7..7061a3984 100644
--- a/toolsrc/src/vcpkg/commands.integrate.cpp
+++ b/toolsrc/src/vcpkg/commands.integrate.cpp
@@ -8,6 +8,7 @@
namespace vcpkg::Commands::Integrate
{
+#if defined(_WIN32)
static std::string create_appdata_targets_shortcut(const std::string& target_path) noexcept
{
return Strings::format(R"###(
@@ -18,7 +19,9 @@ namespace vcpkg::Commands::Integrate
target_path,
target_path);
}
+#endif
+#if defined(_WIN32)
static std::string create_system_targets_shortcut() noexcept
{
return R"###(
@@ -31,7 +34,9 @@ namespace vcpkg::Commands::Integrate
</Project>
)###";
}
+#endif
+#if defined(_WIN32)
static std::string create_nuget_targets_file_contents(const fs::path& msbuild_vcpkg_targets_file) noexcept
{
const std::string as_string = msbuild_vcpkg_targets_file.string();
@@ -47,7 +52,9 @@ namespace vcpkg::Commands::Integrate
as_string,
as_string);
}
+#endif
+#if defined(_WIN32)
static std::string create_nuget_props_file_contents() noexcept
{
return R"###(
@@ -58,7 +65,9 @@ namespace vcpkg::Commands::Integrate
</Project>
)###";
}
+#endif
+#if defined(_WIN32)
static std::string get_nuget_id(const fs::path& vcpkg_root_dir)
{
std::string dir_id = vcpkg_root_dir.generic_string();
@@ -71,7 +80,9 @@ namespace vcpkg::Commands::Integrate
const std::string nuget_id = "vcpkg." + dir_id;
return nuget_id;
}
+#endif
+#if defined(_WIN32)
static std::string create_nuspec_file_contents(const fs::path& vcpkg_root_dir,
const std::string& nuget_id,
const std::string& nupkg_version)
@@ -98,17 +109,18 @@ namespace vcpkg::Commands::Integrate
content = Strings::replace_all(std::move(content), "@VERSION@", nupkg_version);
return content;
}
+#endif
+#if defined(_WIN32)
enum class ElevationPromptChoice
{
YES,
NO
};
-#if defined(_WIN32)
static ElevationPromptChoice elevated_cmd_execute(const std::string& param)
{
- SHELLEXECUTEINFOW sh_ex_info = {0};
+ SHELLEXECUTEINFOW sh_ex_info{};
sh_ex_info.cbSize = sizeof(sh_ex_info);
sh_ex_info.fMask = SEE_MASK_NOCLOSEPROCESS;
sh_ex_info.hwnd = nullptr;
@@ -272,11 +284,12 @@ CMake projects should use: "-DCMAKE_TOOLCHAIN_FILE=%s")",
}
#endif
+#if defined(WIN32)
static void integrate_project(const VcpkgPaths& paths)
{
auto& fs = paths.get_filesystem();
- const fs::path& nuget_exe = paths.get_nuget_exe();
+ const fs::path& nuget_exe = paths.get_tool_exe(Tools::NUGET);
const fs::path& buildsystems_dir = paths.buildsystems;
const fs::path tmp_dir = buildsystems_dir / "tmp";
@@ -319,13 +332,19 @@ With a project open, go to Tools->NuGet Package Manager->Package Manager Console
Checks::exit_success(VCPKG_LINE_INFO);
}
+#endif
+#if defined(_WIN32)
const char* const INTEGRATE_COMMAND_HELPSTRING =
" vcpkg integrate install Make installed packages available user-wide. Requires admin privileges on "
"first use\n"
" vcpkg integrate remove Remove user-wide integration\n"
" vcpkg integrate project Generate a referencing nuget package for individual VS project use\n"
" vcpkg integrate powershell Enable PowerShell Tab-Completion\n";
+#else
+ const char* const INTEGRATE_COMMAND_HELPSTRING =
+ "No user-wide integration methods are available on this platform\n";
+#endif
namespace Subcommand
{
@@ -352,7 +371,7 @@ With a project open, go to Tools->NuGet Package Manager->Package Manager Console
void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths)
{
- args.parse_arguments(COMMAND_STRUCTURE);
+ Util::unused(args.parse_arguments(COMMAND_STRUCTURE));
#if defined(_WIN32)
if (args.command_arguments[0] == Subcommand::INSTALL)
diff --git a/toolsrc/src/vcpkg/commands.list.cpp b/toolsrc/src/vcpkg/commands.list.cpp
index a5efd5442..1bfbc4247 100644
--- a/toolsrc/src/vcpkg/commands.list.cpp
+++ b/toolsrc/src/vcpkg/commands.list.cpp
@@ -10,7 +10,7 @@ namespace vcpkg::Commands::List
static constexpr StringLiteral OPTION_FULLDESC =
"--x-full-desc"; // TODO: This should find a better home, eventually
- static void do_print(const StatusParagraph& pgh, bool full_desc)
+ static void do_print(const StatusParagraph& pgh, const bool full_desc)
{
if (full_desc)
{
@@ -44,14 +44,19 @@ namespace vcpkg::Commands::List
const ParsedArguments options = args.parse_arguments(COMMAND_STRUCTURE);
const StatusParagraphs status_paragraphs = database_load_check(paths);
- std::vector<StatusParagraph*> installed_packages = get_installed_ports(status_paragraphs);
+ auto installed_ipv = get_installed_ports(status_paragraphs);
- if (installed_packages.empty())
+ if (installed_ipv.empty())
{
System::println("No packages are installed. Did you mean `search`?");
Checks::exit_success(VCPKG_LINE_INFO);
}
+ auto installed_packages = Util::fmap(installed_ipv, [](const InstalledPackageView& ipv) { return ipv.core; });
+ auto installed_features =
+ Util::fmap_flatten(installed_ipv, [](const InstalledPackageView& ipv) { return ipv.features; });
+ installed_packages.insert(installed_packages.end(), installed_features.begin(), installed_features.end());
+
std::sort(installed_packages.begin(),
installed_packages.end(),
[](const StatusParagraph* lhs, const StatusParagraph* rhs) -> bool {
diff --git a/toolsrc/src/vcpkg/commands.owns.cpp b/toolsrc/src/vcpkg/commands.owns.cpp
index 52249187b..ee9584651 100644
--- a/toolsrc/src/vcpkg/commands.owns.cpp
+++ b/toolsrc/src/vcpkg/commands.owns.cpp
@@ -34,7 +34,7 @@ namespace vcpkg::Commands::Owns
void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths)
{
- args.parse_arguments(COMMAND_STRUCTURE);
+ Util::unused(args.parse_arguments(COMMAND_STRUCTURE));
const StatusParagraphs status_db = database_load_check(paths);
search_file(paths, args.command_arguments[0], status_db);
diff --git a/toolsrc/src/vcpkg/commands.portsdiff.cpp b/toolsrc/src/vcpkg/commands.portsdiff.cpp
index dba04ce5b..2d2b4bd5f 100644
--- a/toolsrc/src/vcpkg/commands.portsdiff.cpp
+++ b/toolsrc/src/vcpkg/commands.portsdiff.cpp
@@ -3,6 +3,7 @@
#include <vcpkg/commands.h>
#include <vcpkg/help.h>
#include <vcpkg/paragraphs.h>
+#include <vcpkg/versiont.h>
#include <vcpkg/base/sortedvector.h>
#include <vcpkg/base/system.h>
@@ -79,7 +80,7 @@ namespace vcpkg::Commands::PortsDiff
{
std::error_code ec;
auto& fs = paths.get_filesystem();
- const fs::path& git_exe = paths.get_git_exe();
+ const fs::path& git_exe = paths.get_tool_exe(Tools::GIT);
const fs::path dot_git_dir = paths.root / ".git";
const std::string ports_dir_name_as_string = paths.ports.filename().u8string();
const fs::path temp_checkout_path =
@@ -128,9 +129,9 @@ namespace vcpkg::Commands::PortsDiff
void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths)
{
- args.parse_arguments(COMMAND_STRUCTURE);
+ Util::unused(args.parse_arguments(COMMAND_STRUCTURE));
- const fs::path& git_exe = paths.get_git_exe();
+ const fs::path& git_exe = paths.get_tool_exe(Tools::GIT);
const std::string git_commit_id_for_previous_snapshot = args.command_arguments.at(0);
const std::string git_commit_id_for_current_snapshot =
diff --git a/toolsrc/src/vcpkg/commands.upgrade.cpp b/toolsrc/src/vcpkg/commands.upgrade.cpp
index c5b48f2a2..a902ddeaf 100644
--- a/toolsrc/src/vcpkg/commands.upgrade.cpp
+++ b/toolsrc/src/vcpkg/commands.upgrade.cpp
@@ -144,7 +144,8 @@ namespace vcpkg::Commands::Upgrade
const Build::BuildPackageOptions install_plan_options = {Build::UseHeadVersion::NO,
Build::AllowDownloads::YES,
Build::CleanBuildtrees::NO,
- Build::CleanPackages::NO};
+ Build::CleanPackages::NO,
+ Build::DownloadTool::BUILT_IN};
// Set build settings for all install actions
for (auto&& action : plan)
diff --git a/toolsrc/src/vcpkg/commands.version.cpp b/toolsrc/src/vcpkg/commands.version.cpp
index ffc5d2c8f..2ad91b57d 100644
--- a/toolsrc/src/vcpkg/commands.version.cpp
+++ b/toolsrc/src/vcpkg/commands.version.cpp
@@ -83,7 +83,7 @@ namespace vcpkg::Commands::Version
void perform_and_exit(const VcpkgCmdArguments& args)
{
- args.parse_arguments(COMMAND_STRUCTURE);
+ Util::unused(args.parse_arguments(COMMAND_STRUCTURE));
System::println("Vcpkg package management program version %s\n"
"\n"
diff --git a/toolsrc/src/vcpkg/dependencies.cpp b/toolsrc/src/vcpkg/dependencies.cpp
index f6d81c973..8fb35b0da 100644
--- a/toolsrc/src/vcpkg/dependencies.cpp
+++ b/toolsrc/src/vcpkg/dependencies.cpp
@@ -13,11 +13,17 @@
namespace vcpkg::Dependencies
{
- struct FeatureNodeEdges
+ struct ClusterInstalled
{
- std::vector<FeatureSpec> remove_edges;
- std::vector<FeatureSpec> build_edges;
- bool plus = false;
+ InstalledPackageView ipv;
+ std::set<PackageSpec> remove_edges;
+ std::set<std::string> original_features;
+ };
+
+ struct ClusterSource
+ {
+ const SourceControlFile* scf = nullptr;
+ std::unordered_map<std::string, std::vector<FeatureSpec>> build_edges;
};
/// <summary>
@@ -25,14 +31,15 @@ namespace vcpkg::Dependencies
/// </summary>
struct Cluster : Util::MoveOnlyBase
{
- InstalledPackageView installed_package;
-
- Optional<const SourceControlFile*> source_control_file;
PackageSpec spec;
- std::unordered_map<std::string, FeatureNodeEdges> edges_by_feature;
+
+ Optional<ClusterInstalled> installed;
+ Optional<ClusterSource> source;
+
+ // Note: this map can contain "special" strings such as "" and "*"
+ std::unordered_map<std::string, bool> plus;
std::set<std::string> to_install_features;
- std::set<std::string> original_features;
- bool will_remove = false;
+ bool minus = false;
bool transient_uninstalled = true;
RequestType request_type = RequestType::AUTO_SELECTED;
};
@@ -88,27 +95,26 @@ namespace vcpkg::Dependencies
auto maybe_scf = m_provider.get_control_file(spec.name());
auto& clust = m_graph[spec];
clust.spec = spec;
- if (auto p_scf = maybe_scf.get()) cluster_from_scf(*p_scf, clust);
+ if (auto p_scf = maybe_scf.get())
+ {
+ clust.source = cluster_from_scf(*p_scf, clust.spec.triplet());
+ }
return clust;
}
return it->second;
}
private:
- void cluster_from_scf(const SourceControlFile& scf, Cluster& out_cluster) const
+ static ClusterSource cluster_from_scf(const SourceControlFile& scf, Triplet t)
{
- FeatureNodeEdges core_dependencies;
- core_dependencies.build_edges =
- filter_dependencies_to_specs(scf.core_paragraph->depends, out_cluster.spec.triplet());
- out_cluster.edges_by_feature.emplace("core", std::move(core_dependencies));
+ ClusterSource ret;
+ ret.build_edges.emplace("core", filter_dependencies_to_specs(scf.core_paragraph->depends, t));
for (const auto& feature : scf.feature_paragraphs)
- {
- FeatureNodeEdges added_edges;
- added_edges.build_edges = filter_dependencies_to_specs(feature->depends, out_cluster.spec.triplet());
- out_cluster.edges_by_feature.emplace(feature->name, std::move(added_edges));
- }
- out_cluster.source_control_file = &scf;
+ ret.build_edges.emplace(feature->name, filter_dependencies_to_specs(feature->depends, t));
+
+ ret.scf = &scf;
+ return ret;
}
std::unordered_map<PackageSpec, Cluster> m_graph;
@@ -139,7 +145,10 @@ namespace vcpkg::Dependencies
}
}
- InstallPlanAction::InstallPlanAction() : plan_type(InstallPlanType::UNKNOWN), request_type(RequestType::UNKNOWN) {}
+ InstallPlanAction::InstallPlanAction() noexcept
+ : plan_type(InstallPlanType::UNKNOWN), request_type(RequestType::UNKNOWN), build_options{}
+ {
+ }
InstallPlanAction::InstallPlanAction(const PackageSpec& spec,
const SourceControlFile& scf,
@@ -150,19 +159,20 @@ namespace vcpkg::Dependencies
, source_control_file(scf)
, plan_type(InstallPlanType::BUILD_AND_INSTALL)
, request_type(request_type)
+ , build_options{}
, feature_list(features)
, computed_dependencies(std::move(dependencies))
{
}
- InstallPlanAction::InstallPlanAction(const PackageSpec& spec,
- InstalledPackageView&& ipv,
+ InstallPlanAction::InstallPlanAction(InstalledPackageView&& ipv,
const std::set<std::string>& features,
const RequestType& request_type)
- : spec(spec)
+ : spec(ipv.spec())
, installed_package(std::move(ipv))
, plan_type(InstallPlanType::ALREADY_INSTALLED)
, request_type(request_type)
+ , build_options{}
, feature_list(features)
, computed_dependencies(installed_package.get()->dependencies())
{
@@ -184,7 +194,10 @@ namespace vcpkg::Dependencies
return left->spec.name() < right->spec.name();
}
- RemovePlanAction::RemovePlanAction() : plan_type(RemovePlanType::UNKNOWN), request_type(RequestType::UNKNOWN) {}
+ RemovePlanAction::RemovePlanAction() noexcept
+ : plan_type(RemovePlanType::UNKNOWN), request_type(RequestType::UNKNOWN)
+ {
+ }
RemovePlanAction::RemovePlanAction(const PackageSpec& spec,
const RemovePlanType& plan_type,
@@ -213,7 +226,10 @@ namespace vcpkg::Dependencies
return left->spec.name() < right->spec.name();
}
- ExportPlanAction::ExportPlanAction() : plan_type(ExportPlanType::UNKNOWN), request_type(RequestType::UNKNOWN) {}
+ ExportPlanAction::ExportPlanAction() noexcept
+ : plan_type(ExportPlanType::UNKNOWN), request_type(RequestType::UNKNOWN)
+ {
+ }
ExportPlanAction::ExportPlanAction(const PackageSpec& spec,
InstalledPackageView&& installed_package,
@@ -289,11 +305,11 @@ namespace vcpkg::Dependencies
struct RemoveAdjacencyProvider final : Graphs::AdjacencyProvider<PackageSpec, RemovePlanAction>
{
const StatusParagraphs& status_db;
- const std::vector<StatusParagraph*>& installed_ports;
+ const std::vector<InstalledPackageView>& installed_ports;
const std::unordered_set<PackageSpec>& specs_as_set;
RemoveAdjacencyProvider(const StatusParagraphs& status_db,
- const std::vector<StatusParagraph*>& installed_ports,
+ const std::vector<InstalledPackageView>& installed_ports,
const std::unordered_set<PackageSpec>& specs_as_set)
: status_db(status_db), installed_ports(installed_ports), specs_as_set(specs_as_set)
{
@@ -308,24 +324,13 @@ namespace vcpkg::Dependencies
const PackageSpec& spec = plan.spec;
std::vector<PackageSpec> dependents;
- for (const StatusParagraph* an_installed_package : installed_ports)
+ for (auto&& ipv : installed_ports)
{
- if (an_installed_package->package.spec.triplet() != spec.triplet()) continue;
+ auto deps = ipv.dependencies();
- std::vector<std::string> deps = an_installed_package->package.depends;
- // <hack>
- // This is a hack to work around existing installations that put featurespecs into binary packages
- // (example: curl[core]) Eventually, this can be returned to a simple string search.
- for (auto&& dep : deps)
- {
- dep.erase(std::find(dep.begin(), dep.end(), '['), dep.end());
- }
- Util::unstable_keep_if(deps,
- [&](auto&& e) { return e != an_installed_package->package.spec.name(); });
- // </hack>
- if (std::find(deps.begin(), deps.end(), spec.name()) == deps.end()) continue;
+ if (std::find(deps.begin(), deps.end(), spec) == deps.end()) continue;
- dependents.push_back(an_installed_package->package.spec);
+ dependents.push_back(ipv.spec());
}
return dependents;
@@ -347,7 +352,7 @@ namespace vcpkg::Dependencies
std::string to_string(const PackageSpec& spec) const override { return spec.to_string(); }
};
- const std::vector<StatusParagraph*>& installed_ports = get_installed_ports(status_db);
+ auto installed_ports = get_installed_ports(status_db);
const std::unordered_set<PackageSpec> specs_as_set(specs.cbegin(), specs.cend());
return Graphs::topological_sort(specs, RemoveAdjacencyProvider{status_db, installed_ports, specs_as_set});
}
@@ -405,161 +410,201 @@ namespace vcpkg::Dependencies
Cluster& cluster,
ClusterGraph& graph,
GraphPlan& graph_plan,
- const std::unordered_set<std::string>& prevent_default_features = {});
+ const std::unordered_set<std::string>& prevent_default_features);
- static void mark_minus(Cluster& cluster, ClusterGraph& graph, GraphPlan& graph_plan);
+ static void mark_minus(Cluster& cluster,
+ ClusterGraph& graph,
+ GraphPlan& graph_plan,
+ const std::unordered_set<std::string>& prevent_default_features);
- MarkPlusResult mark_plus(const std::string& feature,
- Cluster& cluster,
- ClusterGraph& graph,
- GraphPlan& graph_plan,
- const std::unordered_set<std::string>& prevent_default_features)
+ static MarkPlusResult follow_plus_dependencies(const std::string& feature,
+ Cluster& cluster,
+ ClusterGraph& graph,
+ GraphPlan& graph_plan,
+ const std::unordered_set<std::string>& prevent_default_features)
{
- if (feature.empty())
+ if (auto p_source = cluster.source.get())
{
- if (prevent_default_features.find(cluster.spec.name()) == prevent_default_features.end())
+ auto it_build_edges = p_source->build_edges.find(feature);
+ if (it_build_edges != p_source->build_edges.end())
{
- // Indicates that core was not specified in the reference
+ // mark this package for rebuilding if needed
+ mark_minus(cluster, graph, graph_plan, prevent_default_features);
- // Add default features for this package, if this is the "core" feature and we
- // are not supposed to prevent default features for this package
- if (auto scf = cluster.source_control_file.value_or(nullptr))
+ graph_plan.install_graph.add_vertex({&cluster});
+ cluster.to_install_features.insert(feature);
+
+ if (feature != "core")
{
- for (auto&& default_feature : scf->core_paragraph.get()->default_features)
- {
- auto res = mark_plus(default_feature, cluster, graph, graph_plan, prevent_default_features);
- if (res != MarkPlusResult::SUCCESS)
- {
- return res;
- }
- }
+ // All features implicitly depend on core
+ auto res = mark_plus("core", cluster, graph, graph_plan, prevent_default_features);
+
+ // Should be impossible for "core" to not exist
+ Checks::check_exit(VCPKG_LINE_INFO, res == MarkPlusResult::SUCCESS);
}
- // "core" is always an implicit default feature. In case we did not add it as
- // a dependency above (e.g. no default features), add it here.
- auto res = mark_plus("core", cluster, graph, graph_plan, prevent_default_features);
- if (res != MarkPlusResult::SUCCESS)
+ if (!cluster.installed.get() && !Util::Sets::contains(prevent_default_features, cluster.spec.name()))
{
- return res;
+ // Add the default features of this package if it was not previously installed and it isn't being
+ // suppressed.
+ auto res = mark_plus("", cluster, graph, graph_plan, prevent_default_features);
+
+ Checks::check_exit(VCPKG_LINE_INFO,
+ res == MarkPlusResult::SUCCESS,
+ "Error: Unable to satisfy default dependencies of %s",
+ cluster.spec);
+ }
+
+ for (auto&& depend : it_build_edges->second)
+ {
+ auto& depend_cluster = graph.get(depend.spec());
+ auto res = mark_plus(depend.feature(), depend_cluster, graph, graph_plan, prevent_default_features);
+
+ Checks::check_exit(VCPKG_LINE_INFO,
+ res == MarkPlusResult::SUCCESS,
+ "Error: Unable to satisfy dependency %s of %s",
+ depend,
+ FeatureSpec(cluster.spec, feature));
+
+ if (&depend_cluster == &cluster) continue;
+ graph_plan.install_graph.add_edge({&cluster}, {&depend_cluster});
}
- return MarkPlusResult::SUCCESS;
- }
- else
- {
- // Skip adding the default features, as explicitly told not to.
return MarkPlusResult::SUCCESS;
}
}
- auto it = cluster.edges_by_feature.find(feature);
- if (it == cluster.edges_by_feature.end()) return MarkPlusResult::FEATURE_NOT_FOUND;
+ // The feature was not available in the installed package nor the source paragraph.
+ return MarkPlusResult::FEATURE_NOT_FOUND;
+ }
- if (cluster.edges_by_feature[feature].plus) return MarkPlusResult::SUCCESS;
+ MarkPlusResult mark_plus(const std::string& feature,
+ Cluster& cluster,
+ ClusterGraph& graph,
+ GraphPlan& graph_plan,
+ const std::unordered_set<std::string>& prevent_default_features)
+ {
+ auto& plus = cluster.plus[feature];
+ if (plus) return MarkPlusResult::SUCCESS;
+ plus = true;
- if (cluster.original_features.find(feature) == cluster.original_features.end())
+ if (feature.empty())
{
- cluster.transient_uninstalled = true;
- }
+ // Add default features for this package. This is an exact reference, so ignore prevent_default_features.
+ if (auto p_source = cluster.source.get())
+ {
+ for (auto&& default_feature : p_source->scf->core_paragraph.get()->default_features)
+ {
+ auto res = mark_plus(default_feature, cluster, graph, graph_plan, prevent_default_features);
+ if (res != MarkPlusResult::SUCCESS)
+ {
+ return res;
+ }
+ }
+ }
+ else
+ {
+ Checks::exit_with_message(VCPKG_LINE_INFO,
+ "Error: Unable to install default features because can't find CONTROL for %s",
+ cluster.spec);
+ }
- if (!cluster.transient_uninstalled)
- {
- return MarkPlusResult::SUCCESS;
+ // "core" is always required.
+ return mark_plus("core", cluster, graph, graph_plan, prevent_default_features);
}
- cluster.edges_by_feature[feature].plus = true;
- if (!cluster.original_features.empty())
+ if (feature == "*")
{
- mark_minus(cluster, graph, graph_plan);
- }
+ if (auto p_source = cluster.source.get())
+ {
+ for (auto&& fpgh : p_source->scf->feature_paragraphs)
+ {
+ auto res = mark_plus(fpgh->name, cluster, graph, graph_plan, prevent_default_features);
- graph_plan.install_graph.add_vertex({&cluster});
- auto& tracked = cluster.to_install_features;
- tracked.insert(feature);
+ Checks::check_exit(VCPKG_LINE_INFO,
+ res == MarkPlusResult::SUCCESS,
+ "Error: Unable to locate feature %s in %s",
+ fpgh->name,
+ cluster.spec);
+ }
- if (feature != "core")
- {
- // All features implicitly depend on core
- auto res = mark_plus("core", cluster, graph, graph_plan, prevent_default_features);
+ auto res = mark_plus("core", cluster, graph, graph_plan, prevent_default_features);
- // Should be impossible for "core" to not exist
- Checks::check_exit(VCPKG_LINE_INFO, res == MarkPlusResult::SUCCESS);
- }
- else
- {
- // Add the default features of this package.
- auto res = mark_plus("", cluster, graph, graph_plan, prevent_default_features);
+ Checks::check_exit(VCPKG_LINE_INFO, res == MarkPlusResult::SUCCESS);
+ }
+ else
+ {
+ Checks::exit_with_message(
+ VCPKG_LINE_INFO, "Error: Unable to handle '*' because can't find CONTROL for %s", cluster.spec);
+ }
+ return MarkPlusResult::SUCCESS;
}
- for (auto&& depend : cluster.edges_by_feature[feature].build_edges)
+ if (auto p_installed = cluster.installed.get())
{
- auto& depend_cluster = graph.get(depend.spec());
- auto res = mark_plus(depend.feature(), depend_cluster, graph, graph_plan, prevent_default_features);
-
- Checks::check_exit(VCPKG_LINE_INFO,
- res == MarkPlusResult::SUCCESS,
- "Error: Unable to satisfy dependency %s of %s",
- depend,
- FeatureSpec(cluster.spec, feature));
-
- if (&depend_cluster == &cluster) continue;
- graph_plan.install_graph.add_edge({&cluster}, {&depend_cluster});
+ if (p_installed->original_features.find(feature) != p_installed->original_features.end())
+ {
+ return MarkPlusResult::SUCCESS;
+ }
}
- return MarkPlusResult::SUCCESS;
+ // This feature was or will be uninstalled, therefore we need to rebuild
+ mark_minus(cluster, graph, graph_plan, prevent_default_features);
+
+ return follow_plus_dependencies(feature, cluster, graph, graph_plan, prevent_default_features);
}
- void mark_minus(Cluster& cluster, ClusterGraph& graph, GraphPlan& graph_plan)
+ void mark_minus(Cluster& cluster,
+ ClusterGraph& graph,
+ GraphPlan& graph_plan,
+ const std::unordered_set<std::string>& prevent_default_features)
{
- if (cluster.will_remove) return;
- cluster.will_remove = true;
-
- std::unordered_set<std::string> prevent_default_features;
+ if (cluster.minus) return;
+ cluster.minus = true;
+ cluster.transient_uninstalled = true;
- if (cluster.request_type == RequestType::USER_REQUESTED)
- {
- // Do not install default features for packages which the user
- // installed explicitly. New default features for dependent
- // clusters should still be upgraded.
- prevent_default_features.insert(cluster.spec.name());
+ auto p_installed = cluster.installed.get();
+ auto p_source = cluster.source.get();
- // For dependent packages this is handles through the recursion
- }
+ Checks::check_exit(
+ VCPKG_LINE_INFO,
+ p_source,
+ "Error: cannot locate new portfile for %s. Please explicitly remove this package with `vcpkg remove %s`.",
+ cluster.spec,
+ cluster.spec);
- graph_plan.remove_graph.add_vertex({&cluster});
- for (auto&& pair : cluster.edges_by_feature)
+ if (p_installed)
{
- auto& remove_edges_edges = pair.second.remove_edges;
- for (auto&& depend : remove_edges_edges)
+ graph_plan.remove_graph.add_vertex({&cluster});
+ for (auto&& edge : p_installed->remove_edges)
{
- auto& depend_cluster = graph.get(depend.spec());
- if (&depend_cluster != &cluster) graph_plan.remove_graph.add_edge({&cluster}, {&depend_cluster});
- mark_minus(depend_cluster, graph, graph_plan);
+ auto& depend_cluster = graph.get(edge);
+ Checks::check_exit(VCPKG_LINE_INFO, &cluster != &depend_cluster);
+ graph_plan.remove_graph.add_edge({&cluster}, {&depend_cluster});
+ mark_minus(depend_cluster, graph, graph_plan, prevent_default_features);
}
- }
- cluster.transient_uninstalled = true;
- for (auto&& original_feature : cluster.original_features)
- {
- auto res = mark_plus(original_feature, cluster, graph, graph_plan, prevent_default_features);
- if (res != MarkPlusResult::SUCCESS)
+ // Reinstall all original features. Don't use mark_plus because it will ignore them since they are
+ // "already installed".
+ for (auto&& f : p_installed->original_features)
{
- System::println(System::Color::warning,
- "Warning: could not reinstall feature %s",
- FeatureSpec{cluster.spec, original_feature});
+ auto res = follow_plus_dependencies(f, cluster, graph, graph_plan, prevent_default_features);
+ if (res != MarkPlusResult::SUCCESS)
+ {
+ System::println(System::Color::warning,
+ "Warning: could not reinstall feature %s",
+ FeatureSpec{cluster.spec, f});
+ }
}
- }
- // Check if any default features have been added
- if (auto scf = cluster.source_control_file.value_or(nullptr))
- {
- auto& previous_df = cluster.installed_package.core->package.default_features;
- for (auto&& default_feature : scf->core_paragraph->default_features)
+ // Check if any default features have been added
+ auto& previous_df = p_installed->ipv.core->package.default_features;
+ for (auto&& default_feature : p_source->scf->core_paragraph->default_features)
{
if (std::find(previous_df.begin(), previous_df.end(), default_feature) == previous_df.end())
{
- // this is a new default feature, mark it for installation
- auto res = mark_plus(default_feature, cluster, graph, graph_plan);
+ // This is a new default feature, mark it for installation
+ auto res = mark_plus(default_feature, cluster, graph, graph_plan, prevent_default_features);
if (res != MarkPlusResult::SUCCESS)
{
System::println(System::Color::warning,
@@ -588,7 +633,11 @@ namespace vcpkg::Dependencies
PackageGraph pgraph(provider, status_db);
for (auto&& spec : specs)
+ {
+ // If preventing default features, ignore the automatically generated "" references
+ if (spec.feature().empty() && Util::Sets::contains(prevent_default_features, spec.name())) continue;
pgraph.install(spec, prevent_default_features);
+ }
return pgraph.serialize();
}
@@ -614,37 +663,10 @@ namespace vcpkg::Dependencies
{
Cluster& spec_cluster = m_graph->get(spec.spec());
spec_cluster.request_type = RequestType::USER_REQUESTED;
- if (spec.feature() == "*")
- {
- if (auto p_scf = spec_cluster.source_control_file.value_or(nullptr))
- {
- for (auto&& feature : p_scf->feature_paragraphs)
- {
- auto res =
- mark_plus(feature->name, spec_cluster, *m_graph, *m_graph_plan, prevent_default_features);
- Checks::check_exit(
- VCPKG_LINE_INFO, res == MarkPlusResult::SUCCESS, "Error: Unable to locate feature %s", spec);
- }
+ auto res = mark_plus(spec.feature(), spec_cluster, *m_graph, *m_graph_plan, prevent_default_features);
- auto res = mark_plus("core", spec_cluster, *m_graph, *m_graph_plan, prevent_default_features);
-
- Checks::check_exit(
- VCPKG_LINE_INFO, res == MarkPlusResult::SUCCESS, "Error: Unable to locate feature %s", spec);
- }
- else
- {
- Checks::exit_with_message(
- VCPKG_LINE_INFO, "Error: Unable to handle '*' because can't find CONTROL for %s", spec.spec());
- }
- }
- else
- {
- auto res = mark_plus(spec.feature(), spec_cluster, *m_graph, *m_graph_plan, prevent_default_features);
-
- Checks::check_exit(
- VCPKG_LINE_INFO, res == MarkPlusResult::SUCCESS, "Error: Unable to locate feature %s", spec);
- }
+ Checks::check_exit(VCPKG_LINE_INFO, res == MarkPlusResult::SUCCESS, "Error: Unable to locate feature %s", spec);
m_graph_plan->install_graph.add_vertex(ClusterPtr{&spec_cluster});
}
@@ -654,7 +676,7 @@ namespace vcpkg::Dependencies
Cluster& spec_cluster = m_graph->get(spec);
spec_cluster.request_type = RequestType::USER_REQUESTED;
- mark_minus(spec_cluster, *m_graph, *m_graph_plan);
+ mark_minus(spec_cluster, *m_graph, *m_graph_plan, {});
}
std::vector<AnyAction> PackageGraph::serialize() const
@@ -669,11 +691,8 @@ namespace vcpkg::Dependencies
for (auto&& p_cluster : remove_toposort)
{
- auto scf = *p_cluster->source_control_file.get();
- auto spec = PackageSpec::from_name_and_triplet(scf->core_paragraph->name, p_cluster->spec.triplet())
- .value_or_exit(VCPKG_LINE_INFO);
plan.emplace_back(RemovePlanAction{
- std::move(spec),
+ std::move(p_cluster->spec),
RemovePlanType::REMOVE,
p_cluster->request_type,
});
@@ -684,8 +703,7 @@ namespace vcpkg::Dependencies
if (p_cluster->transient_uninstalled)
{
// If it will be transiently uninstalled, we need to issue a full installation command
- auto pscf = p_cluster->source_control_file.value_or_exit(VCPKG_LINE_INFO);
- Checks::check_exit(VCPKG_LINE_INFO, pscf != nullptr);
+ auto pscf = p_cluster->source.value_or_exit(VCPKG_LINE_INFO).scf;
auto dep_specs = Util::fmap(m_graph_plan->install_graph.adjacency_list(p_cluster),
[](ClusterPtr const& p) { return p->spec; });
@@ -703,10 +721,10 @@ namespace vcpkg::Dependencies
{
// If the package isn't transitively installed, still include it if the user explicitly requested it
if (p_cluster->request_type != RequestType::USER_REQUESTED) continue;
+ auto&& installed = p_cluster->installed.value_or_exit(VCPKG_LINE_INFO);
plan.emplace_back(InstallPlanAction{
- p_cluster->spec,
- InstalledPackageView{p_cluster->installed_package},
- p_cluster->original_features,
+ InstalledPackageView{installed.ipv},
+ installed.original_features,
p_cluster->request_type,
});
}
@@ -722,44 +740,36 @@ namespace vcpkg::Dependencies
auto installed_ports = get_installed_ports(status_db);
- for (auto&& status_paragraph : installed_ports)
+ for (auto&& ipv : installed_ports)
{
- Cluster& cluster = graph->get(status_paragraph->package.spec);
+ Cluster& cluster = graph->get(ipv.spec());
cluster.transient_uninstalled = false;
- auto& status_paragraph_feature = status_paragraph->package.feature;
-
- // In this case, empty string indicates the "core" paragraph for a package.
- if (status_paragraph_feature.empty())
- {
- cluster.original_features.insert("core");
- cluster.installed_package.core = status_paragraph;
- }
- else
- {
- cluster.original_features.insert(status_paragraph_feature);
- cluster.installed_package.features.emplace_back(status_paragraph);
- }
+ cluster.installed = [](const InstalledPackageView& ipv) -> ClusterInstalled {
+ ClusterInstalled ret;
+ ret.ipv = ipv;
+ ret.original_features.emplace("core");
+ for (auto&& feature : ipv.features)
+ ret.original_features.emplace(feature->package.feature);
+ return ret;
+ }(ipv);
}
// Populate the graph with "remove edges", which are the reverse of the Build-Depends edges.
- for (auto&& status_paragraph : installed_ports)
+ for (auto&& ipv : installed_ports)
{
- auto& spec = status_paragraph->package.spec;
- auto& status_paragraph_feature = status_paragraph->package.feature;
- auto reverse_edges = FeatureSpec::from_strings_and_triplet(status_paragraph->package.depends,
- status_paragraph->package.spec.triplet());
+ auto deps = ipv.dependencies();
- for (auto&& dependency : reverse_edges)
+ for (auto&& dep : deps)
{
- auto& dep_cluster = graph->get(dependency.spec());
-
- auto depends_name = dependency.feature();
- if (depends_name.empty()) depends_name = "core";
-
- auto& target_node = dep_cluster.edges_by_feature[depends_name];
- target_node.remove_edges.emplace_back(FeatureSpec{spec, status_paragraph_feature});
+ auto p_installed = graph->get(dep).installed.get();
+ Checks::check_exit(VCPKG_LINE_INFO,
+ p_installed,
+ "Error: database corrupted. Package %s is installed but dependency %s is not.",
+ ipv.spec(),
+ dep);
+ p_installed->remove_edges.emplace(ipv.spec());
}
}
return graph;
diff --git a/toolsrc/src/vcpkg/export.cpp b/toolsrc/src/vcpkg/export.cpp
index 16c84f99d..152252018 100644
--- a/toolsrc/src/vcpkg/export.cpp
+++ b/toolsrc/src/vcpkg/export.cpp
@@ -13,8 +13,6 @@
#include <vcpkg/paragraphs.h>
#include <vcpkg/vcpkglib.h>
-#include <regex>
-
namespace vcpkg::Export
{
using Dependencies::ExportPlanAction;
@@ -70,8 +68,11 @@ namespace vcpkg::Export
{
static constexpr std::array<ExportPlanType, 2> ORDER = {ExportPlanType::ALREADY_BUILT,
ExportPlanType::NOT_BUILT};
- static constexpr Build::BuildPackageOptions build_options = {Build::UseHeadVersion::NO,
- Build::AllowDownloads::YES};
+ static constexpr Build::BuildPackageOptions BUILD_OPTIONS = {Build::UseHeadVersion::NO,
+ Build::AllowDownloads::YES,
+ Build::CleanBuildtrees::NO,
+ Build::CleanPackages::NO,
+ Build::DownloadTool::BUILT_IN};
for (const ExportPlanType plan_type : ORDER)
{
@@ -84,7 +85,7 @@ namespace vcpkg::Export
std::vector<const ExportPlanAction*> cont = it->second;
std::sort(cont.begin(), cont.end(), &ExportPlanAction::compare_by_name);
const std::string as_string = Strings::join("\n", cont, [](const ExportPlanAction* p) {
- return Dependencies::to_output_string(p->request_type, p->spec.to_string(), build_options);
+ return Dependencies::to_output_string(p->request_type, p->spec.to_string(), BUILD_OPTIONS);
});
switch (plan_type)
@@ -123,7 +124,7 @@ namespace vcpkg::Export
const fs::path& output_dir)
{
Files::Filesystem& fs = paths.get_filesystem();
- const fs::path& nuget_exe = paths.get_nuget_exe();
+ const fs::path& nuget_exe = paths.get_tool_exe(Tools::NUGET);
// This file will be placed in "build\native" in the nuget package. Therefore, go up two dirs.
const std::string targets_redirect_content =
@@ -189,7 +190,7 @@ namespace vcpkg::Export
const fs::path& output_dir,
const ArchiveFormat& format)
{
- const fs::path& cmake_exe = paths.get_cmake_exe();
+ const fs::path& cmake_exe = paths.get_tool_exe(Tools::CMAKE);
const std::string exported_dir_filename = raw_exported_dir.filename().u8string();
const std::string exported_archive_filename =
@@ -246,12 +247,12 @@ namespace vcpkg::Export
struct ExportArguments
{
- bool dry_run;
- bool raw;
- bool nuget;
- bool ifw;
- bool zip;
- bool seven_zip;
+ bool dry_run = false;
+ bool raw = false;
+ bool nuget = false;
+ bool ifw = false;
+ bool zip = false;
+ bool seven_zip = false;
Optional<std::string> maybe_output;
diff --git a/toolsrc/src/vcpkg/metrics.cpp b/toolsrc/src/vcpkg/metrics.cpp
index 9e17b237d..8890c067f 100644
--- a/toolsrc/src/vcpkg/metrics.cpp
+++ b/toolsrc/src/vcpkg/metrics.cpp
@@ -245,12 +245,6 @@ namespace vcpkg::Metrics
bool get_compiled_metrics_enabled() { return DISABLE_METRICS == 0; }
- static fs::path get_vcpkg_root()
- {
- return Files::get_real_filesystem().find_file_recursively_up(
- fs::stdfs::absolute(System::get_exe_path_of_current_process()), ".vcpkg-root");
- }
-
std::string get_MAC_user()
{
#if defined(_WIN32)
@@ -264,17 +258,10 @@ namespace vcpkg::Metrics
while (next != last)
{
- auto match = *next;
+ const auto match = *next;
if (match[0] != "00-00-00-00-00-00")
{
- const std::string matchstr = match[0];
- const System::PowershellParameter value("Value", matchstr);
- auto hash_result = System::powershell_execute_and_capture_output(
- "SHA256Hash", get_vcpkg_root() / "scripts" / "SHA256Hash.ps1", {value});
- Util::erase_remove_if(hash_result,
- [](char ch) { return !(ch >= 'A' && ch <= 'F') && !(ch >= '0' && ch <= '9'); });
- hash_result = Strings::ascii_to_lowercase(hash_result);
- return hash_result;
+ return vcpkg::Commands::Hash::get_string_hash(match[0], "SHA256");
}
++next;
}
diff --git a/toolsrc/src/vcpkg/parse.cpp b/toolsrc/src/vcpkg/parse.cpp
index c2670f561..d50296cf8 100644
--- a/toolsrc/src/vcpkg/parse.cpp
+++ b/toolsrc/src/vcpkg/parse.cpp
@@ -2,7 +2,6 @@
#include <vcpkg/parse.h>
-#include <vcpkg/base/checks.h>
#include <vcpkg/base/util.h>
namespace vcpkg::Parse
diff --git a/toolsrc/src/vcpkg/postbuildlint.cpp b/toolsrc/src/vcpkg/postbuildlint.cpp
index a31518ad7..6fe11951f 100644
--- a/toolsrc/src/vcpkg/postbuildlint.cpp
+++ b/toolsrc/src/vcpkg/postbuildlint.cpp
@@ -361,6 +361,7 @@ namespace vcpkg::PostBuildLint
std::string actual_arch;
};
+#if defined(_WIN32)
static std::string get_actual_architecture(const MachineType& machine_type)
{
switch (machine_type)
@@ -374,7 +375,9 @@ namespace vcpkg::PostBuildLint
default: return "Machine Type Code = " + std::to_string(static_cast<uint16_t>(machine_type));
}
}
+#endif
+#if defined(_WIN32)
static void print_invalid_architecture_files(const std::string& expected_architecture,
std::vector<FileAndArch> binaries_with_invalid_architecture)
{
@@ -391,7 +394,6 @@ namespace vcpkg::PostBuildLint
static LintStatus check_dll_architecture(const std::string& expected_architecture,
const std::vector<fs::path>& files)
{
-#if defined(_WIN32)
std::vector<FileAndArch> binaries_with_invalid_architecture;
for (const fs::path& file : files)
@@ -414,10 +416,10 @@ namespace vcpkg::PostBuildLint
print_invalid_architecture_files(expected_architecture, binaries_with_invalid_architecture);
return LintStatus::ERROR_DETECTED;
}
-#endif
return LintStatus::SUCCESS;
}
+#endif
static LintStatus check_lib_architecture(const std::string& expected_architecture,
const std::vector<fs::path>& files)
@@ -802,7 +804,9 @@ namespace vcpkg::PostBuildLint
check_outdated_crt_linkage_of_dlls(dlls, toolset.dumpbin, build_info, pre_build_info);
}
+#if defined(_WIN32)
error_count += check_dll_architecture(pre_build_info.target_architecture, dlls);
+#endif
break;
}
case Build::LinkageType::STATIC:
diff --git a/toolsrc/src/vcpkg/remove.cpp b/toolsrc/src/vcpkg/remove.cpp
index 32433b234..13cc9325e 100644
--- a/toolsrc/src/vcpkg/remove.cpp
+++ b/toolsrc/src/vcpkg/remove.cpp
@@ -201,9 +201,9 @@ namespace vcpkg::Remove
static std::vector<std::string> valid_arguments(const VcpkgPaths& paths)
{
const StatusParagraphs status_db = database_load_check(paths);
- const std::vector<StatusParagraph*> installed_packages = get_installed_ports(status_db);
+ auto installed_packages = get_installed_ports(status_db);
- return Util::fmap(installed_packages, [](auto&& pgh) -> std::string { return pgh->package.spec.to_string(); });
+ return Util::fmap(installed_packages, [](auto&& pgh) -> std::string { return pgh.spec().to_string(); });
}
const CommandStructure COMMAND_STRUCTURE = {
diff --git a/toolsrc/src/vcpkg/statusparagraph.cpp b/toolsrc/src/vcpkg/statusparagraph.cpp
index 62d1d4b42..462d8d8ed 100644
--- a/toolsrc/src/vcpkg/statusparagraph.cpp
+++ b/toolsrc/src/vcpkg/statusparagraph.cpp
@@ -12,7 +12,7 @@ namespace vcpkg
static const std::string STATUS = "Status";
}
- StatusParagraph::StatusParagraph() : want(Want::ERROR_STATE), state(InstallState::ERROR_STATE) {}
+ StatusParagraph::StatusParagraph() noexcept : want(Want::ERROR_STATE), state(InstallState::ERROR_STATE) {}
void serialize(const StatusParagraph& pgh, std::string& out_str)
{
@@ -25,6 +25,7 @@ namespace vcpkg
}
StatusParagraph::StatusParagraph(std::unordered_map<std::string, std::string>&& fields)
+ : want(Want::ERROR_STATE), state(InstallState::ERROR_STATE)
{
auto status_it = fields.find(BinaryParagraphRequiredField::STATUS);
Checks::check_exit(VCPKG_LINE_INFO, status_it != fields.end(), "Expected 'Status' field in status paragraph");
@@ -95,7 +96,7 @@ namespace vcpkg
// Add the core paragraph dependencies to the list
deps.insert(deps.end(), core->package.depends.begin(), core->package.depends.end());
- auto&& spec = core->package.spec;
+ auto&& l_spec = spec();
// <hack>
// This is a hack to work around existing installations that put featurespecs into binary packages
@@ -104,12 +105,12 @@ namespace vcpkg
{
dep.erase(std::find(dep.begin(), dep.end(), '['), dep.end());
}
- Util::unstable_keep_if(deps, [&](auto&& e) { return e != spec.name(); });
+ Util::unstable_keep_if(deps, [&](auto&& e) { return e != l_spec.name(); });
// </hack>
Util::sort_unique_erase(deps);
return Util::fmap(deps, [&](const std::string& dep) -> PackageSpec {
- auto maybe_dependency_spec = PackageSpec::from_name_and_triplet(dep, spec.triplet());
+ auto maybe_dependency_spec = PackageSpec::from_name_and_triplet(dep, l_spec.triplet());
if (auto dependency_spec = maybe_dependency_spec.get())
{
return std::move(*dependency_spec);
@@ -120,7 +121,7 @@ namespace vcpkg
"Invalid dependency [%s] in package [%s]\n"
"%s",
dep,
- spec.name(),
+ l_spec.name(),
vcpkg::to_string(error_type));
});
}
diff --git a/toolsrc/src/vcpkg/triplet.cpp b/toolsrc/src/vcpkg/triplet.cpp
index ef0fab183..c4ad3f690 100644
--- a/toolsrc/src/vcpkg/triplet.cpp
+++ b/toolsrc/src/vcpkg/triplet.cpp
@@ -1,6 +1,5 @@
#include "pch.h"
-#include <vcpkg/base/checks.h>
#include <vcpkg/base/strings.h>
#include <vcpkg/triplet.h>
@@ -38,7 +37,7 @@ namespace vcpkg
const Triplet Triplet::ARM_UWP = from_canonical_name("arm-uwp");
const Triplet Triplet::ARM64_UWP = from_canonical_name("arm64-uwp");
const Triplet Triplet::ARM_WINDOWS = from_canonical_name("arm-windows");
- const Triplet Triplet::ARM64_WINDOWS = from_canonical_name("arm64-windows");
+ const Triplet Triplet::ARM64_WINDOWS = from_canonical_name("arm64-windows");
bool Triplet::operator==(const Triplet& other) const { return this->m_instance == other.m_instance; }
diff --git a/toolsrc/src/vcpkg/update.cpp b/toolsrc/src/vcpkg/update.cpp
index d6c5614ed..57259f952 100644
--- a/toolsrc/src/vcpkg/update.cpp
+++ b/toolsrc/src/vcpkg/update.cpp
@@ -17,17 +17,12 @@ namespace vcpkg::Update
std::vector<OutdatedPackage> find_outdated_packages(const Dependencies::PortFileProvider& provider,
const StatusParagraphs& status_db)
{
- const std::vector<StatusParagraph*> installed_packages = get_installed_ports(status_db);
+ auto installed_packages = get_installed_ports(status_db);
std::vector<OutdatedPackage> output;
- for (const StatusParagraph* pgh : installed_packages)
+ for (auto&& ipv : installed_packages)
{
- if (!pgh->package.feature.empty())
- {
- // Skip feature paragraphs; only consider master paragraphs for needing updates.
- continue;
- }
-
+ const auto& pgh = ipv.core;
auto maybe_scf = provider.get_control_file(pgh->package.spec.name());
if (auto p_scf = maybe_scf.get())
{
diff --git a/toolsrc/src/vcpkg/vcpkglib.cpp b/toolsrc/src/vcpkg/vcpkglib.cpp
index 7979fd9a5..c8e95dab1 100644
--- a/toolsrc/src/vcpkg/vcpkglib.cpp
+++ b/toolsrc/src/vcpkg/vcpkglib.cpp
@@ -169,16 +169,32 @@ namespace vcpkg
fs.rename(updated_listfile_path, listfile_path);
}
- std::vector<StatusParagraph*> get_installed_ports(const StatusParagraphs& status_db)
+ std::vector<InstalledPackageView> get_installed_ports(const StatusParagraphs& status_db)
{
- std::vector<StatusParagraph*> installed_packages;
+ std::map<PackageSpec, InstalledPackageView> ipv_map;
+
+ std::vector<InstalledPackageView> installed_packages;
for (auto&& pgh : status_db)
{
if (!pgh->is_installed()) continue;
- installed_packages.push_back(pgh.get());
+ auto& ipv = ipv_map[pgh->package.spec];
+ if (pgh->package.feature.empty())
+ {
+ ipv.core = pgh.get();
+ }
+ else
+ {
+ ipv.features.emplace_back(pgh.get());
+ }
}
- return installed_packages;
+ for (auto&& ipv : ipv_map)
+ Checks::check_exit(VCPKG_LINE_INFO,
+ ipv.second.core != nullptr,
+ "Database is corrupted: package %s has features but no core paragraph.",
+ ipv.first);
+
+ return Util::fmap(ipv_map, [](auto&& p) -> InstalledPackageView { return std::move(p.second); });
}
std::vector<StatusParagraphAndAssociatedFiles> get_installed_files(const VcpkgPaths& paths,
diff --git a/toolsrc/src/vcpkg/vcpkgpaths.cpp b/toolsrc/src/vcpkg/vcpkgpaths.cpp
index bda2c4174..0903c2d76 100644
--- a/toolsrc/src/vcpkg/vcpkgpaths.cpp
+++ b/toolsrc/src/vcpkg/vcpkgpaths.cpp
@@ -5,407 +5,13 @@
#include <vcpkg/base/system.h>
#include <vcpkg/base/util.h>
#include <vcpkg/build.h>
+#include <vcpkg/commands.h>
#include <vcpkg/metrics.h>
#include <vcpkg/packagespec.h>
#include <vcpkg/vcpkgpaths.h>
namespace vcpkg
{
- static constexpr CStringView V_120 = "v120";
- static constexpr CStringView V_140 = "v140";
- static constexpr CStringView V_141 = "v141";
-
- struct ToolData
- {
- std::array<int, 3> required_version;
- fs::path exe_path;
- std::string url;
- fs::path downloaded_path;
- fs::path tool_dir_path;
- };
-
- static Optional<std::array<int, 3>> parse_version_string(const std::string& version_as_string)
- {
- static const std::regex RE(R"###((\d+)\.(\d+)\.(\d+))###");
-
- std::match_results<std::string::const_iterator> match;
- const auto found = std::regex_search(version_as_string, match, RE);
- if (!found)
- {
- return {};
- }
-
- const int d1 = atoi(match[1].str().c_str());
- const int d2 = atoi(match[2].str().c_str());
- const int d3 = atoi(match[3].str().c_str());
- const std::array<int, 3> result = {d1, d2, d3};
- return result;
- }
-
- static ToolData parse_tool_data_from_xml(const VcpkgPaths& paths, const std::string& tool)
- {
-#if defined(_WIN32)
- static constexpr StringLiteral OS_STRING = "windows";
-#elif defined(__APPLE__)
- static constexpr StringLiteral OS_STRING = "osx";
-#else // assume linux
- static constexpr StringLiteral OS_STRING = "linux";
-#endif
-
- static const fs::path XML_PATH = paths.scripts / "vcpkgTools.xml";
-
- const auto maybe_get_string_inside_tags = [](const std::string& input,
- const std::regex& regex) -> Optional<std::string> {
- std::smatch match;
- const bool has_match = std::regex_search(input.cbegin(), input.cend(), match, regex);
- if (!has_match) return nullopt;
- return match[1];
- };
-
- const auto get_string_inside_tags =
- [](const std::string& input, const std::regex& regex, const std::string& tag_name) -> std::string {
- std::smatch match;
- const bool has_match = std::regex_search(input.cbegin(), input.cend(), match, regex);
- Checks::check_exit(
- VCPKG_LINE_INFO, has_match, "Could not find tag <%s> in %s", tag_name, XML_PATH.generic_string());
-
- return match[1];
- };
-
- static const std::string XML = paths.get_filesystem().read_contents(XML_PATH).value_or_exit(VCPKG_LINE_INFO);
- static const std::regex VERSION_REGEX{R"###(<requiredVersion>([\s\S]*?)</requiredVersion>)###"};
- static const std::regex EXE_RELATIVE_PATH_REGEX{
- Strings::format(R"###(<exeRelativePath>([\s\S]*?)</exeRelativePath>)###")};
- static const std::regex ARCHIVE_RELATIVE_PATH_REGEX{
- Strings::format(R"###(<archiveRelativePath>([\s\S]*?)</archiveRelativePath>)###")};
- static const std::regex URL_REGEX{Strings::format(R"###(<url>([\s\S]*?)</url>)###")};
-
- std::regex tool_regex{
- Strings::format(R"###(<tool[\s]+name="%s"[\s]+os="%s">([\s\S]*?)<\/tool>)###", tool, OS_STRING)};
-
- std::smatch match_tool;
- bool has_match_tool = std::regex_search(XML.cbegin(), XML.cend(), match_tool, tool_regex);
- if (!has_match_tool && OS_STRING == "windows") // Legacy support. Change introduced in vcpkg v0.0.107.
- {
- tool_regex = Strings::format(R"###(<tool[\s]+name="%s">([\s\S]*?)<\/tool>)###", tool);
- has_match_tool = std::regex_search(XML.cbegin(), XML.cend(), match_tool, tool_regex);
- }
- Checks::check_exit(VCPKG_LINE_INFO,
- has_match_tool,
- "Could not find entry for tool [%s] in %s",
- tool,
- XML_PATH.generic_string());
-
- const std::string tool_data_as_string = get_string_inside_tags(XML, tool_regex, tool);
-
- const std::string required_version_as_string =
- get_string_inside_tags(tool_data_as_string, VERSION_REGEX, "requiredVersion");
-
- const std::string url = get_string_inside_tags(tool_data_as_string, URL_REGEX, "url");
-
- const std::string exe_relative_path =
- get_string_inside_tags(tool_data_as_string, EXE_RELATIVE_PATH_REGEX, "exeRelativePath");
-
- auto archive_relative_path = maybe_get_string_inside_tags(tool_data_as_string, ARCHIVE_RELATIVE_PATH_REGEX);
-
- const Optional<std::array<int, 3>> required_version = parse_version_string(required_version_as_string);
- Checks::check_exit(VCPKG_LINE_INFO,
- required_version.has_value(),
- "Could not parse version for tool %s. Version string was: %s",
- tool,
- required_version_as_string);
-
-// Legacy support. Change introduced in vcpkg v0.0.107.
-#if !defined(_WIN32)
- const std::string tool_dir_name = Strings::format("%s-%s", tool, required_version_as_string);
- const fs::path tool_dir_path = paths.downloads / "tools" / tool_dir_name;
- const fs::path exe_path = tool_dir_path / exe_relative_path;
-#else
- const fs::path tool_dir_path;
- const fs::path exe_path = paths.downloads / exe_relative_path;
-#endif
- return ToolData{*required_version.get(),
- exe_path,
- url,
- paths.downloads / archive_relative_path.value_or(exe_relative_path),
- tool_dir_path};
- }
-
- static bool exists_and_has_equal_or_greater_version(const std::string& version_cmd,
- const std::array<int, 3>& expected_version)
- {
- const auto rc = System::cmd_execute_and_capture_output(Strings::format(R"(%s)", version_cmd));
- if (rc.exit_code != 0)
- {
- return false;
- }
-
- const Optional<std::array<int, 3>> v = parse_version_string(rc.output);
- if (!v.has_value())
- {
- return false;
- }
-
- const std::array<int, 3> actual_version = *v.get();
- return (actual_version[0] > expected_version[0] ||
- (actual_version[0] == expected_version[0] && actual_version[1] > expected_version[1]) ||
- (actual_version[0] == expected_version[0] && actual_version[1] == expected_version[1] &&
- actual_version[2] >= expected_version[2]));
- }
-
- static Optional<fs::path> find_if_has_equal_or_greater_version(const std::vector<fs::path>& candidate_paths,
- const std::string& version_check_arguments,
- const std::array<int, 3>& expected_version)
- {
- auto it = Util::find_if(candidate_paths, [&](const fs::path& p) {
- const std::string cmd = Strings::format(R"("%s" %s)", p.u8string(), version_check_arguments);
- return exists_and_has_equal_or_greater_version(cmd, expected_version);
- });
-
- if (it != candidate_paths.cend())
- {
- return std::move(*it);
- }
-
- return nullopt;
- }
-
- static std::vector<std::string> keep_data_lines(const std::string& data_blob)
- {
- static const std::regex DATA_LINE_REGEX(R"(<sol>::(.+?)(?=::<eol>))");
-
- std::vector<std::string> data_lines;
-
- const std::sregex_iterator it(data_blob.cbegin(), data_blob.cend(), DATA_LINE_REGEX);
- const std::sregex_iterator end;
- for (std::sregex_iterator i = it; i != end; ++i)
- {
- const std::smatch match = *i;
- data_lines.push_back(match[1].str());
- }
-
- return data_lines;
- }
-
- static void extract_archive(const VcpkgPaths& paths, const fs::path& archive, const fs::path& to_path)
- {
- Files::Filesystem& fs = paths.get_filesystem();
- const fs::path to_path_partial = to_path.u8string() + ".partial";
-
- std::error_code ec;
- fs.remove_all(to_path_partial, ec);
- fs.create_directories(to_path_partial, ec);
-
- const auto ext = archive.extension();
- if (ext == ".gz" && ext.extension() != ".tar")
- {
- const auto code = System::cmd_execute(
- Strings::format(R"(cd '%s' && tar xzf '%s')", to_path_partial.u8string(), archive.u8string()));
- Checks::check_exit(VCPKG_LINE_INFO, code == 0, "tar failed while extracting %s", archive.u8string());
- }
- else if (ext == ".zip")
- {
- const auto code = System::cmd_execute(
- Strings::format(R"(cd '%s' && unzip -qqo '%s')", to_path_partial.u8string(), archive.u8string()));
- Checks::check_exit(VCPKG_LINE_INFO, code == 0, "unzip failed while extracting %s", archive.u8string());
- }
- else
- {
- Checks::exit_with_message(VCPKG_LINE_INFO, "Unexpected archive extension: %s", ext.u8string());
- }
-
- fs.rename(to_path_partial, to_path);
- }
-
- static fs::path fetch_tool(const VcpkgPaths& paths, const std::string& tool_name, const ToolData& tool_data)
- {
- const auto& fs = paths.get_filesystem();
- const fs::path& scripts_folder = paths.scripts;
- const std::array<int, 3>& version = tool_data.required_version;
-
- const std::string version_as_string = Strings::format("%d.%d.%d", version[0], version[1], version[2]);
- System::println("A suitable version of %s was not found (required v%s). Downloading portable %s v%s...",
- tool_name,
- version_as_string,
- tool_name,
- version_as_string);
-#if defined(_WIN32)
- const fs::path script = scripts_folder / "fetchtool.ps1";
- const std::string title = Strings::format(
- "Fetching %s version %s (No sufficient installed version was found)", tool_name, version_as_string);
- const System::PowershellParameter tool_param("tool", tool_name);
- const std::string output = System::powershell_execute_and_capture_output(title, script, {tool_param});
-
- const std::vector<std::string> tool_path = keep_data_lines(output);
- Checks::check_exit(VCPKG_LINE_INFO, tool_path.size() == 1, "Expected tool path, but got %s", output);
-
- const fs::path actual_downloaded_path = Strings::trim(std::string{tool_path.at(0)});
- const fs::path& expected_downloaded_path = tool_data.exe_path;
- std::error_code ec;
- const auto eq = fs::stdfs::equivalent(expected_downloaded_path, actual_downloaded_path, ec);
- Checks::check_exit(VCPKG_LINE_INFO,
- eq && !ec,
- "Expected tool downloaded path to be %s, but was %s",
- expected_downloaded_path.u8string(),
- actual_downloaded_path.u8string());
- return actual_downloaded_path;
-#else
- if (!fs.exists(tool_data.downloaded_path))
- {
- auto code = System::cmd_execute(Strings::format(
- R"(curl -L '%s' --create-dirs --output '%s')", tool_data.url, tool_data.downloaded_path));
- Checks::check_exit(VCPKG_LINE_INFO, code == 0, "curl failed while downloading %s", tool_data.url);
- }
-
- System::println("Extracting %s...", tool_name);
- extract_archive(paths, tool_data.downloaded_path, tool_data.tool_dir_path);
- System::println("Extracting %s... done.", tool_name);
-
- Checks::check_exit(VCPKG_LINE_INFO,
- fs.exists(tool_data.exe_path),
- "Expected %s to exist after extracting",
- tool_data.exe_path);
-
- return tool_data.exe_path;
-#endif
- }
-
- static fs::path get_cmake_path(const VcpkgPaths& paths)
- {
- std::vector<fs::path> candidate_paths;
-#if defined(_WIN32) || defined(__APPLE__) || defined(__linux__)
- static const ToolData TOOL_DATA = parse_tool_data_from_xml(paths, "cmake");
- candidate_paths.push_back(TOOL_DATA.exe_path);
-#else
- static const ToolData TOOL_DATA = ToolData{{3, 5, 1}, ""};
-#endif
- static const std::string VERSION_CHECK_ARGUMENTS = "--version";
-
- const std::vector<fs::path> from_path = Files::find_from_PATH("cmake");
- candidate_paths.insert(candidate_paths.end(), from_path.cbegin(), from_path.cend());
-
- const auto& program_files = System::get_program_files_platform_bitness();
- if (const auto pf = program_files.get()) candidate_paths.push_back(*pf / "CMake" / "bin" / "cmake.exe");
- const auto& program_files_32_bit = System::get_program_files_32_bit();
- if (const auto pf = program_files_32_bit.get()) candidate_paths.push_back(*pf / "CMake" / "bin" / "cmake.exe");
-
- const Optional<fs::path> path =
- find_if_has_equal_or_greater_version(candidate_paths, VERSION_CHECK_ARGUMENTS, TOOL_DATA.required_version);
- if (const auto p = path.get())
- {
- return *p;
- }
-
- return fetch_tool(paths, "cmake", TOOL_DATA);
- }
-
- static fs::path get_7za_path(const VcpkgPaths& paths)
- {
-#if defined(_WIN32)
- static const ToolData TOOL_DATA = parse_tool_data_from_xml(paths, "7zip");
- if (!paths.get_filesystem().exists(TOOL_DATA.exe_path))
- {
- return fetch_tool(paths, "7zip", TOOL_DATA);
- }
- return TOOL_DATA.exe_path;
-#else
- Checks::exit_with_message(VCPKG_LINE_INFO, "Cannot download 7zip for non-Windows platforms.");
-#endif
- }
-
- static fs::path get_ninja_path(const VcpkgPaths& paths)
- {
- static const ToolData TOOL_DATA = parse_tool_data_from_xml(paths, "ninja");
-
- std::vector<fs::path> candidate_paths;
- candidate_paths.push_back(TOOL_DATA.exe_path);
- const std::vector<fs::path> from_path = Files::find_from_PATH("ninja");
- candidate_paths.insert(candidate_paths.end(), from_path.cbegin(), from_path.cend());
-
- auto path = find_if_has_equal_or_greater_version(candidate_paths, "--version", TOOL_DATA.required_version);
- if (const auto p = path.get())
- {
- return *p;
- }
-
- return fetch_tool(paths, "ninja", TOOL_DATA);
- }
-
- static fs::path get_nuget_path(const VcpkgPaths& paths)
- {
- static const ToolData TOOL_DATA = parse_tool_data_from_xml(paths, "nuget");
-
- std::vector<fs::path> candidate_paths;
- candidate_paths.push_back(TOOL_DATA.exe_path);
- const std::vector<fs::path> from_path = Files::find_from_PATH("nuget");
- candidate_paths.insert(candidate_paths.end(), from_path.cbegin(), from_path.cend());
-
- auto path = find_if_has_equal_or_greater_version(candidate_paths, "", TOOL_DATA.required_version);
- if (const auto p = path.get())
- {
- return *p;
- }
-
- return fetch_tool(paths, "nuget", TOOL_DATA);
- }
-
- static fs::path get_git_path(const VcpkgPaths& paths)
- {
-#if defined(_WIN32)
- static const ToolData TOOL_DATA = parse_tool_data_from_xml(paths, "git");
-#else
- static const ToolData TOOL_DATA = ToolData{{2, 7, 4}, ""};
-#endif
- static const std::string VERSION_CHECK_ARGUMENTS = "--version";
-
- std::vector<fs::path> candidate_paths;
-#if defined(_WIN32)
- candidate_paths.push_back(TOOL_DATA.exe_path);
-#endif
- const std::vector<fs::path> from_path = Files::find_from_PATH("git");
- candidate_paths.insert(candidate_paths.end(), from_path.cbegin(), from_path.cend());
-
- const auto& program_files = System::get_program_files_platform_bitness();
- if (const auto pf = program_files.get()) candidate_paths.push_back(*pf / "git" / "cmd" / "git.exe");
- const auto& program_files_32_bit = System::get_program_files_32_bit();
- if (const auto pf = program_files_32_bit.get()) candidate_paths.push_back(*pf / "git" / "cmd" / "git.exe");
-
- const Optional<fs::path> path =
- find_if_has_equal_or_greater_version(candidate_paths, VERSION_CHECK_ARGUMENTS, TOOL_DATA.required_version);
- if (const auto p = path.get())
- {
- return *p;
- }
-
- return fetch_tool(paths, "git", TOOL_DATA);
- }
-
- static fs::path get_ifw_installerbase_path(const VcpkgPaths& paths)
- {
- static const ToolData TOOL_DATA = parse_tool_data_from_xml(paths, "installerbase");
-
- static const std::string VERSION_CHECK_ARGUMENTS = "--framework-version";
-
- std::vector<fs::path> candidate_paths;
- candidate_paths.push_back(TOOL_DATA.exe_path);
- // TODO: Uncomment later
- // const std::vector<fs::path> from_path = Files::find_from_PATH("installerbase");
- // candidate_paths.insert(candidate_paths.end(), from_path.cbegin(), from_path.cend());
- // candidate_paths.push_back(fs::path(System::get_environment_variable("HOMEDRIVE").value_or("C:")) / "Qt" /
- // "Tools" / "QtInstallerFramework" / "3.1" / "bin" / "installerbase.exe");
- // candidate_paths.push_back(fs::path(System::get_environment_variable("HOMEDRIVE").value_or("C:")) / "Qt" /
- // "QtIFW-3.1.0" / "bin" / "installerbase.exe");
-
- const Optional<fs::path> path =
- find_if_has_equal_or_greater_version(candidate_paths, VERSION_CHECK_ARGUMENTS, TOOL_DATA.required_version);
- if (const auto p = path.get())
- {
- return *p;
- }
-
- return fetch_tool(paths, "installerbase", TOOL_DATA);
- }
-
Expected<VcpkgPaths> VcpkgPaths::create(const fs::path& vcpkg_root_dir, const std::string& default_vs_path)
{
std::error_code ec;
@@ -477,266 +83,15 @@ namespace vcpkg
bool VcpkgPaths::is_valid_triplet(const Triplet& t) const
{
- auto it = Util::find_if(this->get_available_triplets(),
- [&](auto&& available_triplet) { return t.canonical_name() == available_triplet; });
+ const auto it = Util::find_if(this->get_available_triplets(), [&](auto&& available_triplet) {
+ return t.canonical_name() == available_triplet;
+ });
return it != this->get_available_triplets().cend();
}
- const fs::path& VcpkgPaths::get_7za_exe() const
- {
- return this->_7za_exe.get_lazy([this]() { return get_7za_path(*this); });
- }
-
- const fs::path& VcpkgPaths::get_cmake_exe() const
- {
- return this->cmake_exe.get_lazy([this]() { return get_cmake_path(*this); });
- }
-
- const fs::path& VcpkgPaths::get_git_exe() const
- {
- return this->git_exe.get_lazy([this]() { return get_git_path(*this); });
- }
-
- const fs::path& VcpkgPaths::get_ninja_exe() const
- {
- return this->ninja_exe.get_lazy([this]() { return get_ninja_path(*this); });
- }
-
- const fs::path& VcpkgPaths::get_nuget_exe() const
- {
- return this->nuget_exe.get_lazy([this]() { return get_nuget_path(*this); });
- }
-
- const fs::path& VcpkgPaths::get_ifw_installerbase_exe() const
- {
- return this->ifw_installerbase_exe.get_lazy([this]() { return get_ifw_installerbase_path(*this); });
- }
-
- const fs::path& VcpkgPaths::get_ifw_binarycreator_exe() const
- {
- return this->ifw_binarycreator_exe.get_lazy(
- [this]() { return get_ifw_installerbase_exe().parent_path() / "binarycreator.exe"; });
- }
-
- const fs::path& VcpkgPaths::get_ifw_repogen_exe() const
- {
- return this->ifw_repogen_exe.get_lazy(
- [this]() { return get_ifw_installerbase_exe().parent_path() / "repogen.exe"; });
- }
-
- struct VisualStudioInstance
- {
- fs::path root_path;
- std::string version;
- std::string release_type;
- std::string preference_weight; // Mostly unused, just for verification that order is as intended
-
- std::string major_version() const { return version.substr(0, 2); }
- };
-
- static std::vector<VisualStudioInstance> get_visual_studio_instances(const VcpkgPaths& paths)
- {
- const fs::path script = paths.scripts / "findVisualStudioInstallationInstances.ps1";
- const std::string output =
- System::powershell_execute_and_capture_output("Detecting Visual Studio instances", script);
-
- const std::vector<std::string> instances_as_strings = keep_data_lines(output);
- Checks::check_exit(VCPKG_LINE_INFO,
- !instances_as_strings.empty(),
- "Could not detect any Visual Studio instances.\n"
- "Powershell script:\n"
- " %s\n"
- "returned:\n"
- "%s",
- script.generic_string(),
- output);
-
- std::vector<VisualStudioInstance> instances;
- for (const std::string& instance_as_string : instances_as_strings)
- {
- const std::vector<std::string> split = Strings::split(instance_as_string, "::");
- Checks::check_exit(VCPKG_LINE_INFO,
- split.size() == 4,
- "Invalid Visual Studio instance format.\n"
- "Expected: PreferenceWeight::ReleaseType::Version::PathToVisualStudio\n"
- "Actual : %s\n",
- instance_as_string);
- instances.push_back({split.at(3), split.at(2), split.at(1), split.at(0)});
- }
-
- return instances;
- }
-
- static std::vector<Toolset> find_toolset_instances(const VcpkgPaths& paths)
+ const fs::path& VcpkgPaths::get_tool_exe(const std::string& tool) const
{
- using CPU = System::CPUArchitecture;
-
- const auto& fs = paths.get_filesystem();
-
- // Note: this will contain a mix of vcvarsall.bat locations and dumpbin.exe locations.
- std::vector<fs::path> paths_examined;
-
- std::vector<Toolset> found_toolsets;
- std::vector<Toolset> excluded_toolsets;
-
- const std::vector<VisualStudioInstance> vs_instances = get_visual_studio_instances(paths);
- const bool v140_is_available = Util::find_if(vs_instances, [&](const VisualStudioInstance& vs_instance) {
- return vs_instance.major_version() == "14";
- }) != vs_instances.cend();
-
- for (const VisualStudioInstance& vs_instance : vs_instances)
- {
- const std::string major_version = vs_instance.major_version();
- if (major_version == "15")
- {
- const fs::path vc_dir = vs_instance.root_path / "VC";
-
- // Skip any instances that do not have vcvarsall.
- const fs::path vcvarsall_dir = vc_dir / "Auxiliary" / "Build";
- const fs::path vcvarsall_bat = vcvarsall_dir / "vcvarsall.bat";
- paths_examined.push_back(vcvarsall_bat);
- if (!fs.exists(vcvarsall_bat)) continue;
-
- // Get all supported architectures
- std::vector<ToolsetArchOption> supported_architectures;
- if (fs.exists(vcvarsall_dir / "vcvars32.bat"))
- supported_architectures.push_back({"x86", CPU::X86, CPU::X86});
- if (fs.exists(vcvarsall_dir / "vcvars64.bat"))
- supported_architectures.push_back({"amd64", CPU::X64, CPU::X64});
- if (fs.exists(vcvarsall_dir / "vcvarsx86_amd64.bat"))
- supported_architectures.push_back({"x86_amd64", CPU::X86, CPU::X64});
- if (fs.exists(vcvarsall_dir / "vcvarsx86_arm.bat"))
- supported_architectures.push_back({"x86_arm", CPU::X86, CPU::ARM});
- if (fs.exists(vcvarsall_dir / "vcvarsx86_arm64.bat"))
- supported_architectures.push_back({"x86_arm64", CPU::X86, CPU::ARM64});
- if (fs.exists(vcvarsall_dir / "vcvarsamd64_x86.bat"))
- supported_architectures.push_back({"amd64_x86", CPU::X64, CPU::X86});
- if (fs.exists(vcvarsall_dir / "vcvarsamd64_arm.bat"))
- supported_architectures.push_back({"amd64_arm", CPU::X64, CPU::ARM});
- if (fs.exists(vcvarsall_dir / "vcvarsamd64_arm64.bat"))
- supported_architectures.push_back({"amd64_arm64", CPU::X64, CPU::ARM64});
-
- // Locate the "best" MSVC toolchain version
- const fs::path msvc_path = vc_dir / "Tools" / "MSVC";
- std::vector<fs::path> msvc_subdirectories = fs.get_files_non_recursive(msvc_path);
- Util::unstable_keep_if(msvc_subdirectories,
- [&fs](const fs::path& path) { return fs.is_directory(path); });
-
- // Sort them so that latest comes first
- std::sort(
- msvc_subdirectories.begin(),
- msvc_subdirectories.end(),
- [](const fs::path& left, const fs::path& right) { return left.filename() > right.filename(); });
-
- for (const fs::path& subdir : msvc_subdirectories)
- {
- const fs::path dumpbin_path = subdir / "bin" / "HostX86" / "x86" / "dumpbin.exe";
- paths_examined.push_back(dumpbin_path);
- if (fs.exists(dumpbin_path))
- {
- const Toolset v141toolset = Toolset{
- vs_instance.root_path, dumpbin_path, vcvarsall_bat, {}, V_141, supported_architectures};
-
- auto english_language_pack = dumpbin_path.parent_path() / "1033";
-
- if (!fs.exists(english_language_pack))
- {
- excluded_toolsets.push_back(v141toolset);
- break;
- }
-
- found_toolsets.push_back(v141toolset);
-
- if (v140_is_available)
- {
- const Toolset v140toolset = Toolset{vs_instance.root_path,
- dumpbin_path,
- vcvarsall_bat,
- {"-vcvars_ver=14.0"},
- V_140,
- supported_architectures};
- found_toolsets.push_back(v140toolset);
- }
-
- break;
- }
- }
-
- continue;
- }
-
- if (major_version == "14" || major_version == "12")
- {
- const fs::path vcvarsall_bat = vs_instance.root_path / "VC" / "vcvarsall.bat";
-
- paths_examined.push_back(vcvarsall_bat);
- if (fs.exists(vcvarsall_bat))
- {
- const fs::path vs_dumpbin_exe = vs_instance.root_path / "VC" / "bin" / "dumpbin.exe";
- paths_examined.push_back(vs_dumpbin_exe);
-
- const fs::path vs_bin_dir = vcvarsall_bat.parent_path() / "bin";
- std::vector<ToolsetArchOption> supported_architectures;
- if (fs.exists(vs_bin_dir / "vcvars32.bat"))
- supported_architectures.push_back({"x86", CPU::X86, CPU::X86});
- if (fs.exists(vs_bin_dir / "amd64\\vcvars64.bat"))
- supported_architectures.push_back({"x64", CPU::X64, CPU::X64});
- if (fs.exists(vs_bin_dir / "x86_amd64\\vcvarsx86_amd64.bat"))
- supported_architectures.push_back({"x86_amd64", CPU::X86, CPU::X64});
- if (fs.exists(vs_bin_dir / "x86_arm\\vcvarsx86_arm.bat"))
- supported_architectures.push_back({"x86_arm", CPU::X86, CPU::ARM});
- if (fs.exists(vs_bin_dir / "amd64_x86\\vcvarsamd64_x86.bat"))
- supported_architectures.push_back({"amd64_x86", CPU::X64, CPU::X86});
- if (fs.exists(vs_bin_dir / "amd64_arm\\vcvarsamd64_arm.bat"))
- supported_architectures.push_back({"amd64_arm", CPU::X64, CPU::ARM});
-
- if (fs.exists(vs_dumpbin_exe))
- {
- const Toolset toolset = {vs_instance.root_path,
- vs_dumpbin_exe,
- vcvarsall_bat,
- {},
- major_version == "14" ? V_140 : V_120,
- supported_architectures};
-
- auto english_language_pack = vs_dumpbin_exe.parent_path() / "1033";
-
- if (!fs.exists(english_language_pack))
- {
- excluded_toolsets.push_back(toolset);
- break;
- }
-
- found_toolsets.push_back(toolset);
- }
- }
- }
- }
-
- if (!excluded_toolsets.empty())
- {
- System::println(
- System::Color::warning,
- "Warning: The following VS instances are excluded because the English language pack is unavailable.");
- for (const Toolset& toolset : excluded_toolsets)
- {
- System::println(" %s", toolset.visual_studio_root_path.u8string());
- }
- System::println(System::Color::warning, "Please install the English language pack.");
- }
-
- if (found_toolsets.empty())
- {
- System::println(System::Color::error, "Could not locate a complete toolset.");
- System::println("The following paths were examined:");
- for (const fs::path& path : paths_examined)
- {
- System::println(" %s", path.u8string());
- }
- Checks::exit_fail(VCPKG_LINE_INFO);
- }
-
- return found_toolsets;
+ return this->tool_paths.get_lazy(tool, [&]() { return Commands::Fetch::get_tool_path(*this, tool); });
}
const Toolset& VcpkgPaths::get_toolset(const Build::PreBuildInfo& prebuildinfo) const
@@ -760,7 +115,7 @@ namespace vcpkg
// Invariant: toolsets are non-empty and sorted with newest at back()
const std::vector<Toolset>& vs_toolsets =
- this->toolsets.get_lazy([this]() { return find_toolset_instances(*this); });
+ this->toolsets.get_lazy([this]() { return Commands::Fetch::find_toolset_instances(*this); });
std::vector<const Toolset*> candidates = Util::element_pointers(vs_toolsets);
const auto tsv = prebuildinfo.platform_toolset.get();
diff --git a/toolsrc/src/vcpkg/versiont.cpp b/toolsrc/src/vcpkg/versiont.cpp
index 0d4a39255..d20e6b577 100644
--- a/toolsrc/src/vcpkg/versiont.cpp
+++ b/toolsrc/src/vcpkg/versiont.cpp
@@ -5,7 +5,7 @@
namespace vcpkg
{
- VersionT::VersionT() : value("0.0.0") {}
+ VersionT::VersionT() noexcept : value("0.0.0") {}
VersionT::VersionT(std::string&& value) : value(std::move(value)) {}
VersionT::VersionT(const std::string& value) : value(value) {}
const std::string& VersionT::to_string() const { return value; }
@@ -13,7 +13,7 @@ namespace vcpkg
bool operator!=(const VersionT& left, const VersionT& right) { return left.to_string() != right.to_string(); }
std::string to_printf_arg(const VersionT& version) { return version.to_string(); }
- VersionDiff::VersionDiff() : left(), right() {}
+ VersionDiff::VersionDiff() noexcept : left(), right() {}
VersionDiff::VersionDiff(const VersionT& left, const VersionT& right) : left(left), right(right) {}
std::string VersionDiff::to_string() const