aboutsummaryrefslogtreecommitdiff
path: root/toolsrc/src
diff options
context:
space:
mode:
authoryurybura <yurybura@gmail.com>2018-05-11 13:34:43 +0300
committeryurybura <yurybura@gmail.com>2018-05-11 13:34:43 +0300
commit7d261fbbc39a1d36027299190920e0a7e222ebd7 (patch)
treed9b6745f2e6c670836cbbf61dbd2c4eb9ef857fe /toolsrc/src
parent50e5ee1e40380cf543ae804775462181984a86dc (diff)
parent9535a5631ac212b1c657a02be3ed9398df30c96c (diff)
downloadvcpkg-7d261fbbc39a1d36027299190920e0a7e222ebd7.tar.gz
vcpkg-7d261fbbc39a1d36027299190920e0a7e222ebd7.zip
Merge branch 'master' of https://github.com/yurybura/vcpkg
Diffstat (limited to 'toolsrc/src')
-rw-r--r--toolsrc/src/tests.paragraph.cpp9
-rw-r--r--toolsrc/src/tests.plan.cpp230
-rw-r--r--toolsrc/src/tests.utils.cpp30
-rw-r--r--toolsrc/src/vcpkg.cpp14
-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.cpp28
-rw-r--r--toolsrc/src/vcpkg/base/strings.cpp46
-rw-r--r--toolsrc/src/vcpkg/base/system.cpp117
-rw-r--r--toolsrc/src/vcpkg/binaryparagraph.cpp2
-rw-r--r--toolsrc/src/vcpkg/build.cpp513
-rw-r--r--toolsrc/src/vcpkg/commands.cache.cpp2
-rw-r--r--toolsrc/src/vcpkg/commands.ci.cpp158
-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.cpp96
-rw-r--r--toolsrc/src/vcpkg/commands.env.cpp54
-rw-r--r--toolsrc/src/vcpkg/commands.exportifw.cpp6
-rw-r--r--toolsrc/src/vcpkg/commands.fetch.cpp716
-rw-r--r--toolsrc/src/vcpkg/commands.hash.cpp240
-rw-r--r--toolsrc/src/vcpkg/commands.import.cpp2
-rw-r--r--toolsrc/src/vcpkg/commands.integrate.cpp114
-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.cpp463
-rw-r--r--toolsrc/src/vcpkg/export.cpp27
-rw-r--r--toolsrc/src/vcpkg/help.cpp6
-rw-r--r--toolsrc/src/vcpkg/install.cpp83
-rw-r--r--toolsrc/src/vcpkg/metrics.cpp19
-rw-r--r--toolsrc/src/vcpkg/paragraphs.cpp10
-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/sourceparagraph.cpp10
-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/userconfig.cpp11
-rw-r--r--toolsrc/src/vcpkg/vcpkglib.cpp25
-rw-r--r--toolsrc/src/vcpkg/vcpkgpaths.cpp542
-rw-r--r--toolsrc/src/vcpkg/versiont.cpp4
46 files changed, 2358 insertions, 1420 deletions
diff --git a/toolsrc/src/tests.paragraph.cpp b/toolsrc/src/tests.paragraph.cpp
index dca89bc59..9a56ad9ee 100644
--- a/toolsrc/src/tests.paragraph.cpp
+++ b/toolsrc/src/tests.paragraph.cpp
@@ -5,15 +5,6 @@
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
-namespace Microsoft::VisualStudio::CppUnitTestFramework
-{
- template<>
- inline std::wstring ToString<vcpkg::PackageSpecParseResult>(const vcpkg::PackageSpecParseResult& t)
- {
- return ToString(static_cast<uint32_t>(t));
- }
-}
-
namespace Strings = vcpkg::Strings;
namespace UnitTest1
diff --git a/toolsrc/src/tests.plan.cpp b/toolsrc/src/tests.plan.cpp
index 95056810c..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"}};
@@ -593,17 +593,116 @@ namespace UnitTest1
features_check(&install_plan[0], "a", {"core"}, Triplet::X64_WINDOWS);
}
+ TEST_METHOD(install_plan_action_dependencies)
+ {
+ std::vector<std::unique_ptr<StatusParagraph>> status_paragraphs;
+
+ // Add a port "a" which depends on the core of "b", which was already
+ // installed explicitly
+ PackageSpecMap spec_map(Triplet::X64_WINDOWS);
+ auto spec_c = spec_map.emplace("c");
+ auto spec_b = spec_map.emplace("b", "c");
+ spec_map.emplace("a", "b");
+
+ // Install "a" (without explicit feature specification)
+ auto install_specs = FullPackageSpec::from_string("a", Triplet::X64_WINDOWS);
+ auto install_plan = Dependencies::create_feature_install_plan(
+ spec_map.map,
+ FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}),
+ StatusParagraphs(std::move(status_paragraphs)));
+
+ Assert::IsTrue(install_plan.size() == 3);
+ features_check(&install_plan[0], "c", {"core"}, Triplet::X64_WINDOWS);
+
+ features_check(&install_plan[1], "b", {"core"}, Triplet::X64_WINDOWS);
+ Assert::IsTrue(install_plan[1].install_action.get()->computed_dependencies ==
+ std::vector<PackageSpec>{spec_c});
+
+ features_check(&install_plan[2], "a", {"core"}, Triplet::X64_WINDOWS);
+ Assert::IsTrue(install_plan[2].install_action.get()->computed_dependencies ==
+ std::vector<PackageSpec>{spec_b});
+ }
+
+ TEST_METHOD(install_plan_action_dependencies_2)
+ {
+ std::vector<std::unique_ptr<StatusParagraph>> status_paragraphs;
+
+ // Add a port "a" which depends on the core of "b", which was already
+ // installed explicitly
+ PackageSpecMap spec_map(Triplet::X64_WINDOWS);
+ auto spec_c = spec_map.emplace("c");
+ auto spec_b = spec_map.emplace("b", "c");
+ spec_map.emplace("a", "c, b");
+
+ // Install "a" (without explicit feature specification)
+ auto install_specs = FullPackageSpec::from_string("a", Triplet::X64_WINDOWS);
+ auto install_plan = Dependencies::create_feature_install_plan(
+ spec_map.map,
+ FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}),
+ StatusParagraphs(std::move(status_paragraphs)));
+
+ Assert::IsTrue(install_plan.size() == 3);
+ features_check(&install_plan[0], "c", {"core"}, Triplet::X64_WINDOWS);
+
+ features_check(&install_plan[1], "b", {"core"}, Triplet::X64_WINDOWS);
+ Assert::IsTrue(install_plan[1].install_action.get()->computed_dependencies ==
+ std::vector<PackageSpec>{spec_c});
+
+ features_check(&install_plan[2], "a", {"core"}, Triplet::X64_WINDOWS);
+ Assert::IsTrue(install_plan[2].install_action.get()->computed_dependencies ==
+ std::vector<PackageSpec>{spec_b, spec_c});
+ }
+
+ TEST_METHOD(install_plan_action_dependencies_3)
+ {
+ std::vector<std::unique_ptr<StatusParagraph>> status_paragraphs;
+
+ // Add a port "a" which depends on the core of "b", which was already
+ // installed explicitly
+ PackageSpecMap spec_map(Triplet::X64_WINDOWS);
+ spec_map.emplace("a", "", {{"0", ""}, {"1", "a[0]"}}, {"1"});
+
+ // Install "a" (without explicit feature specification)
+ auto install_specs = FullPackageSpec::from_string("a", Triplet::X64_WINDOWS);
+ auto install_plan = Dependencies::create_feature_install_plan(
+ spec_map.map,
+ FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}),
+ StatusParagraphs(std::move(status_paragraphs)));
+
+ Assert::IsTrue(install_plan.size() == 1);
+ features_check(&install_plan[0], "a", {"1", "0", "core"}, Triplet::X64_WINDOWS);
+ 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);
@@ -616,24 +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());
- Assert::IsTrue(plan[1].install_action.has_value());
- 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"});
@@ -644,19 +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());
- Assert::IsTrue(plan[1].install_action.has_value());
- 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());
- Assert::IsTrue(plan[2].install_action.has_value());
- 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)
@@ -846,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);
@@ -870,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");
@@ -902,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");
@@ -926,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");
@@ -953,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);
@@ -979,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);
@@ -1005,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);
@@ -1034,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);
@@ -1051,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");
@@ -1072,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");
@@ -1087,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);
@@ -1105,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/tests.utils.cpp b/toolsrc/src/tests.utils.cpp
index a3d8ffc7d..ac391f559 100644
--- a/toolsrc/src/tests.utils.cpp
+++ b/toolsrc/src/tests.utils.cpp
@@ -5,36 +5,6 @@
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace vcpkg;
-namespace Microsoft::VisualStudio::CppUnitTestFramework
-{
- std::wstring ToString(const vcpkg::Dependencies::InstallPlanType& t)
- {
- switch (t)
- {
- case Dependencies::InstallPlanType::ALREADY_INSTALLED: return L"ALREADY_INSTALLED";
- case Dependencies::InstallPlanType::BUILD_AND_INSTALL: return L"BUILD_AND_INSTALL";
- case Dependencies::InstallPlanType::EXCLUDED: return L"EXCLUDED";
- case Dependencies::InstallPlanType::UNKNOWN: return L"UNKNOWN";
- default: return ToString(static_cast<int>(t));
- }
- }
-
- std::wstring ToString(const vcpkg::Dependencies::RequestType& t)
- {
- switch (t)
- {
- case Dependencies::RequestType::AUTO_SELECTED: return L"AUTO_SELECTED";
- case Dependencies::RequestType::USER_REQUESTED: return L"USER_REQUESTED";
- case Dependencies::RequestType::UNKNOWN: return L"UNKNOWN";
- default: return ToString(static_cast<int>(t));
- }
- }
-
- std::wstring ToString(const vcpkg::PackageSpecParseResult& t) { return ToString(static_cast<uint32_t>(t)); }
-
- std::wstring ToString(const vcpkg::PackageSpec& t) { return ToString(t.to_string()); }
-}
-
std::unique_ptr<StatusParagraph> make_status_pgh(const char* name,
const char* depends,
const char* default_features,
diff --git a/toolsrc/src/vcpkg.cpp b/toolsrc/src/vcpkg.cpp
index d9b915367..ac2eec876 100644
--- a/toolsrc/src/vcpkg.cpp
+++ b/toolsrc/src/vcpkg.cpp
@@ -70,7 +70,7 @@ static void inner(const VcpkgCmdArguments& args)
fs::path vcpkg_root_dir;
if (args.vcpkg_root_dir != nullptr)
{
- vcpkg_root_dir = fs::stdfs::absolute(Strings::to_utf16(*args.vcpkg_root_dir));
+ vcpkg_root_dir = fs::stdfs::absolute(fs::u8path(*args.vcpkg_root_dir));
}
else
{
@@ -94,6 +94,8 @@ static void inner(const VcpkgCmdArguments& args)
Checks::check_exit(VCPKG_LINE_INFO, !vcpkg_root_dir.empty(), "Error: Could not detect vcpkg-root.");
+ Debug::println("Using vcpkg-root: %s", vcpkg_root_dir.u8string());
+
auto default_vs_path = System::get_environment_variable("VCPKG_DEFAULT_VS_PATH").value_or("");
const Expected<VcpkgPaths> expected_paths = VcpkgPaths::create(vcpkg_root_dir, default_vs_path);
@@ -157,7 +159,15 @@ static void inner(const VcpkgCmdArguments& args)
}
else
{
+#if defined(_WIN32)
default_triplet = Triplet::X86_WINDOWS;
+#elif defined(__APPLE__)
+ default_triplet = Triplet::from_canonical_name("x64-osx");
+#elif defined(__FreeBSD__)
+ default_triplet = Triplet::from_canonical_name("x64-freebsd");
+#else
+ default_triplet = Triplet::from_canonical_name("x64-linux");
+#endif
}
}
@@ -215,6 +225,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(
@@ -235,6 +246,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 b59104a59..3d96e834b 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;
@@ -55,17 +55,18 @@ namespace vcpkg::Files
virtual fs::path find_file_recursively_up(const fs::path& starting_dir,
const std::string& filename) const override
{
+ static const fs::path UNIX_ROOT = "/";
fs::path current_dir = starting_dir;
- for (; !current_dir.empty(); current_dir = current_dir.parent_path())
+ for (; !current_dir.empty() && current_dir != UNIX_ROOT; current_dir = current_dir.parent_path())
{
const fs::path candidate = current_dir / filename;
if (exists(candidate))
{
- break;
+ return current_dir;
}
}
- return current_dir;
+ return fs::path();
}
virtual std::vector<fs::path> get_files_recursive(const fs::path& dir) const override
@@ -108,6 +109,10 @@ namespace vcpkg::Files
output.close();
}
+ virtual void rename(const fs::path& oldpath, const fs::path& newpath, std::error_code& ec) override
+ {
+ fs::stdfs::rename(oldpath, newpath, ec);
+ }
virtual void rename(const fs::path& oldpath, const fs::path& newpath) override
{
fs::stdfs::rename(oldpath, newpath);
@@ -181,12 +186,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 d912734e3..48dc5ed09 100644
--- a/toolsrc/src/vcpkg/base/strings.cpp
+++ b/toolsrc/src/vcpkg/base/strings.cpp
@@ -7,10 +7,11 @@
namespace vcpkg::Strings::details
{
// To disambiguate between two overloads
- static const auto isspace = [](const char c) { return std::isspace(c); };
+ 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)); }
+ static char toupper_char(const char c) { return static_cast<char>(std::toupper(c)); }
#if defined(_WIN32)
static _locale_t& c_locale()
@@ -38,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);
@@ -48,31 +49,29 @@ namespace vcpkg::Strings::details
namespace vcpkg::Strings
{
+#if defined(_WIN32)
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
}
+#endif
- std::string to_utf8(const CWStringView& w)
- {
#if defined(_WIN32)
- const int size = WideCharToMultiByte(CP_UTF8, 0, w.c_str(), -1, nullptr, 0, nullptr, nullptr);
+ std::string to_utf8(const wchar_t* w)
+ {
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);
-#endif
}
+#endif
std::string escape_string(const CStringView& s, char char_to_escape, char escape_char)
{
@@ -108,11 +107,16 @@ namespace vcpkg::Strings
#endif
}
- std::string ascii_to_lowercase(const std::string& input)
+ std::string ascii_to_lowercase(std::string s)
{
- std::string output(input);
- std::transform(output.begin(), output.end(), output.begin(), &details::tolower_char);
- return output;
+ std::transform(s.begin(), s.end(), s.begin(), &details::tolower_char);
+ return s;
+ }
+
+ std::string ascii_to_uppercase(std::string s)
+ {
+ std::transform(s.begin(), s.end(), s.begin(), &details::toupper_char);
+ return s;
}
bool case_insensitive_ascii_starts_with(const std::string& s, const std::string& pattern)
@@ -137,8 +141,8 @@ namespace vcpkg::Strings
std::string trim(std::string&& s)
{
- s.erase(std::find_if_not(s.rbegin(), s.rend(), details::isspace).base(), s.end());
- s.erase(s.begin(), std::find_if_not(s.begin(), s.end(), details::isspace));
+ 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 e55db9461..95c9511f9 100644
--- a/toolsrc/src/vcpkg/base/system.cpp
+++ b/toolsrc/src/vcpkg/base/system.cpp
@@ -5,10 +5,14 @@
#include <vcpkg/globalstate.h>
#include <vcpkg/metrics.h>
-#include <time.h>
+#include <ctime>
#if defined(__APPLE__)
-# include <mach-o/dyld.h>
+#include <mach-o/dyld.h>
+#endif
+
+#if defined(__FreeBSD__)
+#include <sys/sysctl.h>
#endif
#pragma comment(lib, "Advapi32")
@@ -19,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
@@ -35,14 +39,22 @@ namespace vcpkg::System
const int bytes = GetModuleFileNameW(nullptr, buf, _MAX_PATH);
if (bytes == 0) std::abort();
return fs::path(buf, buf + bytes);
-#elif __APPLE__
+#elif defined(__APPLE__)
uint32_t size = 1024 * 32;
char buf[size] = {};
bool result = _NSGetExecutablePath(buf, &size);
Checks::check_exit(VCPKG_LINE_INFO, result != -1, "Could not determine current executable path.");
- std::unique_ptr<char> canonicalPath (realpath(buf, NULL));
+ std::unique_ptr<char> canonicalPath(realpath(buf, NULL));
Checks::check_exit(VCPKG_LINE_INFO, result != -1, "Could not determine current executable path.");
return fs::path(std::string(canonicalPath.get()));
+#elif defined(__FreeBSD__)
+ int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
+ char exePath[2048];
+ size_t len = sizeof(exePath);
+ auto rcode = sysctl(mib, 4, exePath, &len, NULL, 0);
+ Checks::check_exit(VCPKG_LINE_INFO, rcode == 0, "Could not determine current executable path.");
+ Checks::check_exit(VCPKG_LINE_INFO, len > 0, "Could not determine current executable path.");
+ return fs::path(exePath, exePath + len - 1);
#else /* LINUX */
std::array<char, 1024 * 4> buf;
auto written = readlink("/proc/self/exe", buf.data(), buf.size());
@@ -141,12 +153,12 @@ namespace vcpkg::System
R"(powershell -NoProfile -ExecutionPolicy Bypass -Command "& {& '%s' %s}")", script_path.u8string(), args);
}
- int cmd_execute_clean(const CStringView cmd_line)
+ int cmd_execute_clean(const CStringView cmd_line, const std::unordered_map<std::string, std::string>& extra_env)
{
#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)";
- static const 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 = {
@@ -202,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;
@@ -212,11 +224,22 @@ namespace vcpkg::System
env_cstr.push_back(L'\0');
}
- env_cstr.append(Strings::to_utf16(NEW_PATH));
+ 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));
env_cstr.push_back(L'\0');
env_cstr.append(L"VSLANG=1033");
env_cstr.push_back(L'\0');
+ for (const auto& item : extra_env)
+ {
+ if (item.first == "PATH") continue;
+ env_cstr.append(Strings::to_utf16(item.first));
+ env_cstr.push_back(L'=');
+ env_cstr.append(Strings::to_utf16(item.second));
+ env_cstr.push_back(L'\0');
+ }
+
STARTUPINFOW startup_info;
memset(&startup_info, 0, sizeof(STARTUPINFOW));
startup_info.cb = sizeof(STARTUPINFOW);
@@ -251,8 +274,11 @@ namespace vcpkg::System
Debug::println("CreateProcessW() returned %lu", exit_code);
return static_cast<int>(exit_code);
#else
+ Debug::println("system(%s)", cmd_line.c_str());
fflush(nullptr);
- return system(cmd_line.c_str());
+ int rc = system(cmd_line.c_str());
+ Debug::println("system() returned %d", rc);
+ return rc;
#endif
}
@@ -262,35 +288,26 @@ namespace vcpkg::System
fflush(nullptr);
// Basically we are wrapping it in quotes
- const std::string& actual_cmd_line = Strings::format(R"###("%s")###", cmd_line);
#if defined(_WIN32)
+ const std::string& actual_cmd_line = Strings::format(R"###("%s")###", cmd_line);
Debug::println("_wsystem(%s)", actual_cmd_line);
const int exit_code = _wsystem(Strings::to_utf16(actual_cmd_line).c_str());
Debug::println("_wsystem() returned %d", exit_code);
#else
- Debug::println("_system(%s)", actual_cmd_line);
- const int exit_code = system(actual_cmd_line.c_str());
+ Debug::println("_system(%s)", cmd_line);
+ const int exit_code = system(cmd_line.c_str());
Debug::println("_system() returned %d", exit_code);
#endif
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
fflush(stdout);
+ auto timer = Chrono::ElapsedTimer::create_started();
+
#if defined(_WIN32)
const auto actual_cmd_line = Strings::format(R"###("%s 2>&1")###", cmd_line);
@@ -300,7 +317,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))
{
@@ -308,13 +325,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);
- Debug::println("_pclose() returned %d", ec);
- remove_byte_order_marks(&output);
- return {ec, Strings::to_utf8(output)};
+
+ // 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.c_str())};
#else
const auto actual_cmd_line = Strings::format(R"###(%s 2>&1)###", cmd_line);
@@ -336,7 +362,9 @@ namespace vcpkg::System
}
const auto ec = pclose(pipe);
- Debug::println("pclose() returned %d", ec);
+
+ Debug::println("_pclose() returned %d after %8d us", ec, (int)timer.microseconds());
+
return {ec, output};
#endif
}
@@ -452,7 +480,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;
@@ -493,7 +521,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)
@@ -502,32 +530,41 @@ namespace vcpkg::System
}
#endif
- static const fs::path& get_program_files()
+ static const Optional<fs::path>& get_program_files()
{
- static const fs::path PATH = System::get_environment_variable("PROGRAMFILES").value_or_exit(VCPKG_LINE_INFO);
+ static const auto PATH = []() -> Optional<fs::path> {
+ auto value = System::get_environment_variable("PROGRAMFILES");
+ if (auto v = value.get())
+ {
+ return *v;
+ }
+
+ return nullopt;
+ }();
+
return PATH;
}
- const fs::path& get_program_files_32_bit()
+ const Optional<fs::path>& get_program_files_32_bit()
{
- static const fs::path PATH = []() -> fs::path {
+ static const auto PATH = []() -> Optional<fs::path> {
auto value = System::get_environment_variable("ProgramFiles(x86)");
if (auto v = value.get())
{
- return std::move(*v);
+ return *v;
}
return get_program_files();
}();
return PATH;
}
- const fs::path& get_program_files_platform_bitness()
+ const Optional<fs::path>& get_program_files_platform_bitness()
{
- static const fs::path PATH = []() -> fs::path {
+ static const auto PATH = []() -> Optional<fs::path> {
auto value = System::get_environment_variable("ProgramW6432");
if (auto v = value.get())
{
- return std::move(*v);
+ return *v;
}
return get_program_files();
}();
diff --git a/toolsrc/src/vcpkg/binaryparagraph.cpp b/toolsrc/src/vcpkg/binaryparagraph.cpp
index 7a8b0d577..73ca23df1 100644
--- a/toolsrc/src/vcpkg/binaryparagraph.cpp
+++ b/toolsrc/src/vcpkg/binaryparagraph.cpp
@@ -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 408dde798..1ed5e744a 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");
@@ -165,6 +166,19 @@ namespace vcpkg::Build
}
}
+ static const std::string NAME_BUILD_IN_DOWNLOAD = "BUILT_IN";
+ static const std::string NAME_ARIA2_DOWNLOAD = "ARIA2";
+
+ const std::string& to_string(DownloadTool tool)
+ {
+ switch (tool)
+ {
+ case DownloadTool::BUILT_IN: return NAME_BUILD_IN_DOWNLOAD;
+ case DownloadTool::ARIA2: return NAME_ARIA2_DOWNLOAD;
+ default: Checks::unreachable(VCPKG_LINE_INFO);
+ }
+ }
+
Optional<LinkageType> to_linkage_type(const std::string& str)
{
if (str == "dynamic") return LinkageType::DYNAMIC;
@@ -197,13 +211,18 @@ 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;
}
- Checks::exit_with_message(VCPKG_LINE_INFO, "Unsupported toolchain combination %s", target_architecture);
+ Checks::exit_with_message(VCPKG_LINE_INFO,
+ "Unsupported toolchain combination. Target was: %s but supported ones were:\n%s",
+ target_architecture,
+ Strings::join(",", toolset.supported_architectures, [](const ToolsetArchOption& t) {
+ return t.name.c_str();
+ }));
}
std::string make_build_env_cmd(const PreBuildInfo& pre_build_info, const Toolset& toolset)
@@ -266,19 +285,17 @@ 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")
{
return filter_dependencies(config.scf.core_paragraph->depends, triplet);
}
- auto it =
- Util::find_if(config.scf.feature_paragraphs,
- [&](std::unique_ptr<FeatureParagraph> const& fpgh) { return fpgh->name == feature; });
- Checks::check_exit(VCPKG_LINE_INFO, it != config.scf.feature_paragraphs.end());
+ auto maybe_feature = config.scf.find_feature(feature);
+ Checks::check_exit(VCPKG_LINE_INFO, maybe_feature.has_value());
- return filter_dependencies(it->get()->depends, triplet);
+ return filter_dependencies(maybe_feature.get()->depends, triplet);
});
auto dep_fspecs = FeatureSpec::from_strings_and_triplet(dep_strings, triplet);
@@ -291,7 +308,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
@@ -299,9 +316,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
@@ -315,280 +332,334 @@ namespace vcpkg::Build
}
static ExtendedBuildResult do_build_package(const VcpkgPaths& paths,
- const BuildPackageConfig& config,
- const StatusParagraphs& status_db)
+ const PreBuildInfo& pre_build_info,
+ const PackageSpec& spec,
+ const std::string& abi_tag,
+ const BuildPackageConfig& config)
{
auto& fs = paths.get_filesystem();
- const Triplet& triplet = config.triplet;
+ const Triplet& triplet = spec.triplet();
- struct AbiEntry
- {
- std::string key;
- std::string value;
- };
+#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_tool_exe(Tools::NINJA));
+#endif
- std::vector<AbiEntry> abi_tag_entries;
+ const fs::path& cmake_exe_path = paths.get_tool_exe(Tools::CMAKE);
+ const fs::path& git_exe_path = paths.get_tool_exe(Tools::GIT);
- const PackageSpec spec =
- PackageSpec::from_name_and_triplet(config.scf.core_paragraph->name, triplet).value_or_exit(VCPKG_LINE_INFO);
+ std::string all_features;
+ for (auto& feature : config.scf.feature_paragraphs)
+ {
+ all_features.append(feature->name + ";");
+ }
- std::vector<FeatureSpec> required_fspecs = compute_required_feature_specs(config, status_db);
+ const Toolset& toolset = paths.get_toolset(pre_build_info);
+ const std::string cmd_launch_cmake = System::make_cmake_cmd(
+ cmake_exe_path,
+ paths.ports_cmake,
+ {
+ {"CMD", "BUILD"},
+ {"PORT", config.scf.core_paragraph->name},
+ {"CURRENT_PORT_DIR", config.port_dir},
+ {"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"},
+ {"_VCPKG_DOWNLOAD_TOOL", to_string(config.build_package_options.download_tool)},
+ {"GIT", git_exe_path},
+ {"FEATURES", Strings::join(";", config.feature_list)},
+ {"ALL_FEATURES", all_features},
+ });
- // extract out the actual package ids
- auto dep_pspecs = Util::fmap(required_fspecs, [](FeatureSpec const& fspec) { return fspec.spec(); });
- Util::sort_unique_erase(dep_pspecs);
+ auto command = make_build_env_cmd(pre_build_info, toolset);
+ if (!command.empty()) command.append(" && ");
+ command.append(cmd_launch_cmake);
- // Find all features that aren't installed. This destroys required_fspecs.
- Util::unstable_keep_if(required_fspecs, [&](FeatureSpec const& fspec) {
- return !status_db.is_installed(fspec) && fspec.name() != spec.name();
- });
+ const auto timer = Chrono::ElapsedTimer::create_started();
+
+ const int return_code = System::cmd_execute_clean(command);
+ const auto buildtimeus = timer.microseconds();
+ const auto spec_string = spec.to_string();
- if (!required_fspecs.empty())
{
- return {BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES, std::move(required_fspecs)};
+ auto locked_metrics = Metrics::g_metrics.lock();
+ locked_metrics->track_buildtime(spec.to_string() + ":[" + Strings::join(",", config.feature_list) + "]",
+ buildtimeus);
+ if (return_code != 0)
+ {
+ locked_metrics->track_property("error", "build failed");
+ locked_metrics->track_property("build_error", spec_string);
+ return BuildResult::BUILD_FAILED;
+ }
}
- // dep_pspecs was not destroyed
- for (auto&& pspec : dep_pspecs)
+ const BuildInfo build_info = read_build_info(fs, paths.build_info_file_path(spec));
+ const size_t error_count = PostBuildLint::perform_all_checks(spec, paths, pre_build_info, build_info);
+
+ auto bcf = create_binary_control_file(*config.scf.core_paragraph, triplet, build_info, abi_tag);
+
+ if (error_count != 0)
{
- if (pspec == spec) continue;
- auto status_it = status_db.find_installed(pspec);
- Checks::check_exit(VCPKG_LINE_INFO, status_it != status_db.end());
- abi_tag_entries.emplace_back(
- AbiEntry{status_it->get()->package.spec.name(), status_it->get()->package.abi});
+ return BuildResult::POST_BUILD_CHECKS_FAILED;
+ }
+ for (auto&& feature : config.feature_list)
+ {
+ for (auto&& f_pgh : config.scf.feature_paragraphs)
+ {
+ if (f_pgh->name == feature)
+ bcf->features.push_back(
+ create_binary_feature_control_file(*config.scf.core_paragraph, *f_pgh, triplet));
+ }
}
- const fs::path& cmake_exe_path = paths.get_cmake_exe();
- const fs::path& git_exe_path = paths.get_git_exe();
+ write_binary_control_file(paths, *bcf);
+ return {BuildResult::SUCCEEDED, std::move(bcf)};
+ }
- const fs::path ports_cmake_script_path = paths.ports_cmake;
+ static ExtendedBuildResult do_build_package_and_clean_buildtrees(const VcpkgPaths& paths,
+ const PreBuildInfo& pre_build_info,
+ const PackageSpec& spec,
+ const std::string& abi_tag,
+ const BuildPackageConfig& config)
+ {
+ auto result = do_build_package(paths, pre_build_info, spec, abi_tag, config);
- if (GlobalState::g_binary_caching)
+ if (config.build_package_options.clean_buildtrees == CleanBuildtrees::YES)
{
- abi_tag_entries.emplace_back(AbiEntry{
- "portfile", Commands::Hash::get_file_hash(cmake_exe_path, config.port_dir / "portfile.cmake", "SHA1")});
- abi_tag_entries.emplace_back(AbiEntry{
- "control", Commands::Hash::get_file_hash(cmake_exe_path, config.port_dir / "CONTROL", "SHA1")});
+ auto& fs = paths.get_filesystem();
+ const fs::path buildtrees_dir = paths.buildtrees / config.scf.core_paragraph->name;
+ auto buildtree_files = fs.get_files_non_recursive(buildtrees_dir);
+ for (auto&& file : buildtree_files)
+ {
+ if (fs.is_directory(file) && file.filename() != "src")
+ {
+ std::error_code ec;
+ fs.remove_all(file, ec);
+ }
+ }
}
- const auto pre_build_info = PreBuildInfo::from_triplet_file(paths, triplet);
+ return result;
+ }
+
+ Optional<AbiTagAndFile> compute_abi_tag(const VcpkgPaths& paths,
+ const BuildPackageConfig& config,
+ const PreBuildInfo& pre_build_info,
+ Span<const AbiEntry> dependency_abis)
+ {
+ if (!GlobalState::g_binary_caching) return nullopt;
+
+ auto& fs = paths.get_filesystem();
+ const Triplet& triplet = config.triplet;
+ const std::string& name = config.scf.core_paragraph->name;
+
+ std::vector<AbiEntry> abi_tag_entries;
+
+ abi_tag_entries.insert(abi_tag_entries.end(), dependency_abis.begin(), dependency_abis.end());
+
+ abi_tag_entries.emplace_back(
+ AbiEntry{"portfile", Commands::Hash::get_file_hash(paths, config.port_dir / "portfile.cmake", "SHA1")});
+ abi_tag_entries.emplace_back(
+ AbiEntry{"control", Commands::Hash::get_file_hash(paths, config.port_dir / "CONTROL", "SHA1")});
+
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)
abi_tag_entries.emplace_back(AbiEntry{"head", ""});
- std::string full_abi_info =
- Strings::join("", abi_tag_entries, [](const AbiEntry& p) { return p.key + " " + p.value + "\n"; });
+ Util::sort(abi_tag_entries);
- std::string abi_tag;
+ const std::string full_abi_info =
+ Strings::join("", abi_tag_entries, [](const AbiEntry& p) { return p.key + " " + p.value + "\n"; });
- if (GlobalState::g_binary_caching)
+ if (GlobalState::debugging)
{
- if (GlobalState::debugging)
+ System::println("[DEBUG] <abientries>");
+ for (auto&& entry : abi_tag_entries)
{
- System::println("[DEBUG] <abientries>");
- for (auto&& entry : abi_tag_entries)
- {
- System::println("[DEBUG] %s|%s", entry.key, entry.value);
- }
- System::println("[DEBUG] </abientries>");
+ System::println("[DEBUG] %s|%s", entry.key, entry.value);
}
+ System::println("[DEBUG] </abientries>");
+ }
- auto abi_tag_entries_missing = abi_tag_entries;
- Util::stable_keep_if(abi_tag_entries_missing, [](const AbiEntry& p) { return p.value.empty(); });
+ auto abi_tag_entries_missing = abi_tag_entries;
+ Util::stable_keep_if(abi_tag_entries_missing, [](const AbiEntry& p) { return p.value.empty(); });
- if (abi_tag_entries_missing.empty())
- {
- std::error_code ec;
- fs.create_directories(paths.buildtrees / spec.name(), ec);
- auto abi_file_path = paths.buildtrees / spec.name() / "vcpkg_abi_info";
- fs.write_contents(abi_file_path, full_abi_info);
+ if (abi_tag_entries_missing.empty())
+ {
+ std::error_code ec;
+ fs.create_directories(paths.buildtrees / name, ec);
+ const auto abi_file_path = paths.buildtrees / name / (triplet.canonical_name() + ".vcpkg_abi_info.txt");
+ fs.write_contents(abi_file_path, full_abi_info);
- abi_tag = Commands::Hash::get_file_hash(paths.get_cmake_exe(), abi_file_path, "SHA1");
- }
- 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 AbiTagAndFile{Commands::Hash::get_file_hash(paths, abi_file_path, "SHA1"), abi_file_path};
}
- std::unique_ptr<BinaryControlFile> bcf;
+ 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"; }));
- auto archives_dir = paths.root / "archives";
- if (!abi_tag.empty())
- {
- archives_dir /= abi_tag.substr(0, 2);
- }
- auto archive_path = archives_dir / (abi_tag + ".zip");
+ return nullopt;
+ }
- if (GlobalState::g_binary_caching && !abi_tag.empty() && fs.exists(archive_path))
- {
- System::println("Using cached binary package: %s", archive_path.u8string());
+ static void decompress_archive(const VcpkgPaths& paths, const PackageSpec& spec, const fs::path& archive_path)
+ {
+ auto& fs = paths.get_filesystem();
- auto pkg_path = paths.package_dir(spec);
- std::error_code ec;
- fs.remove_all(pkg_path, ec);
- fs.create_directories(pkg_path, ec);
- auto files = fs.get_files_non_recursive(pkg_path);
- Checks::check_exit(VCPKG_LINE_INFO, files.empty(), "unable to clear path: %s", pkg_path.u8string());
+ auto pkg_path = paths.package_dir(spec);
+ std::error_code ec;
+ fs.remove_all(pkg_path, ec);
+ fs.create_directories(pkg_path, ec);
+ auto files = fs.get_files_non_recursive(pkg_path);
+ 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()));
+ System::cmd_execute_clean(Strings::format(
+ 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()));
+ System::cmd_execute_clean(
+ Strings::format(R"(unzip -qq "%s" "-d%s")", archive_path.u8string(), pkg_path.u8string()));
#endif
+ }
- auto maybe_bcf = Paragraphs::try_load_cached_control_package(paths, spec);
- bcf = std::make_unique<BinaryControlFile>(std::move(maybe_bcf).value_or_exit(VCPKG_LINE_INFO));
- }
- else
+ static void compress_archive(const VcpkgPaths& paths, const PackageSpec& spec, const fs::path& tmp_archive_path)
+ {
+ auto& fs = paths.get_filesystem();
+
+ std::error_code ec;
+
+ fs.remove(tmp_archive_path, ec);
+ Checks::check_exit(
+ VCPKG_LINE_INFO, !fs.exists(tmp_archive_path), "Could not remove file: %s", tmp_archive_path.u8string());
+#if defined(_WIN32)
+ auto&& seven_zip_exe = paths.get_tool_exe(Tools::SEVEN_ZIP);
+
+ System::cmd_execute_clean(Strings::format(R"("%s" a "%s" "%s\*" >nul)",
+ seven_zip_exe.u8string(),
+ tmp_archive_path.u8string(),
+ paths.package_dir(spec).u8string()));
+#else
+ System::cmd_execute_clean(Strings::format(
+ R"(cd '%s' && zip --quiet -r '%s' *)", paths.package_dir(spec).u8string(), tmp_archive_path.u8string()));
+#endif
+ }
+
+ ExtendedBuildResult build_package(const VcpkgPaths& paths,
+ const BuildPackageConfig& config,
+ const StatusParagraphs& status_db)
+ {
+ auto& fs = paths.get_filesystem();
+ const Triplet& triplet = config.triplet;
+ const std::string& name = config.scf.core_paragraph->name;
+
+ std::vector<FeatureSpec> required_fspecs = compute_required_feature_specs(config, status_db);
+
+ // extract out the actual package ids
+ 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 mutates required_fspecs.
+ Util::unstable_keep_if(required_fspecs, [&](FeatureSpec const& fspec) {
+ return !status_db.is_installed(fspec) && fspec.name() != name;
+ });
+
+ if (!required_fspecs.empty())
{
- if (GlobalState::g_binary_caching && !abi_tag.empty())
- {
- System::println("Could not locate cached archive: %s", archive_path.u8string());
- }
+ return {BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES, std::move(required_fspecs)};
+ }
- std::string all_features;
- for (auto& feature : config.scf.feature_paragraphs)
- {
- all_features.append(feature->name + ";");
- }
+ const PackageSpec spec =
+ PackageSpec::from_name_and_triplet(config.scf.core_paragraph->name, triplet).value_or_exit(VCPKG_LINE_INFO);
- const Toolset& toolset = paths.get_toolset(pre_build_info);
- const std::string cmd_launch_cmake = System::make_cmake_cmd(
- cmake_exe_path,
- ports_cmake_script_path,
- {
- {"CMD", "BUILD"},
- {"PORT", config.scf.core_paragraph->name},
- {"CURRENT_PORT_DIR", config.port_dir / "/."},
- {"TARGET_TRIPLET", 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"},
- {"GIT", git_exe_path},
- {"FEATURES", features},
- {"ALL_FEATURES", all_features},
- });
-
- auto command = make_build_env_cmd(pre_build_info, toolset);
- if (!command.empty()) command.append(" && ");
- command.append(cmd_launch_cmake);
-
- const auto timer = Chrono::ElapsedTimer::create_started();
-
- const int return_code = System::cmd_execute_clean(command);
- const auto buildtimeus = timer.microseconds();
- const auto spec_string = spec.to_string();
+ std::vector<AbiEntry> dependency_abis;
- {
- auto locked_metrics = Metrics::g_metrics.lock();
- locked_metrics->track_buildtime(spec.to_string() + ":[" + Strings::join(",", config.feature_list) + "]",
- buildtimeus);
- if (return_code != 0)
- {
- locked_metrics->track_property("error", "build failed");
- locked_metrics->track_property("build_error", spec_string);
- return BuildResult::BUILD_FAILED;
- }
- }
+ // dep_pspecs was not destroyed
+ for (auto&& pspec : dep_pspecs)
+ {
+ if (pspec == spec) continue;
+ 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});
+ }
- const BuildInfo build_info = read_build_info(fs, paths.build_info_file_path(spec));
- const size_t error_count = PostBuildLint::perform_all_checks(spec, paths, pre_build_info, build_info);
+ const auto pre_build_info = PreBuildInfo::from_triplet_file(paths, triplet);
- bcf = create_binary_control_file(*config.scf.core_paragraph, triplet, build_info, abi_tag);
+ auto maybe_abi_tag_and_file = compute_abi_tag(paths, config, pre_build_info, dependency_abis);
- if (error_count != 0)
- {
- return BuildResult::POST_BUILD_CHECKS_FAILED;
- }
- for (auto&& feature : config.feature_list)
+ const auto abi_tag_and_file = maybe_abi_tag_and_file.get();
+
+ if (GlobalState::g_binary_caching && abi_tag_and_file)
+ {
+ 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))
{
- for (auto&& f_pgh : config.scf.feature_paragraphs)
- {
- if (f_pgh->name == feature)
- bcf->features.push_back(
- create_binary_feature_control_file(*config.scf.core_paragraph, *f_pgh, triplet));
- }
+ System::println("Using cached binary package: %s", archive_path.u8string());
+
+ decompress_archive(paths, spec, archive_path);
+
+ auto maybe_bcf = Paragraphs::try_load_cached_package(paths, spec);
+ 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)};
}
- if (GlobalState::g_binary_caching && !abi_tag.empty())
+ if (fs.exists(archive_tombstone_path))
{
- std::error_code ec;
- fs.write_contents(
- paths.package_dir(spec) / "share" / spec.name() / "vcpkg_abi_info.txt", full_abi_info, ec);
+ System::println("Found failure tombstone: %s", archive_tombstone_path.u8string());
+ return BuildResult::BUILD_FAILED;
}
- write_binary_control_file(paths, *bcf);
+ System::println("Could not locate cached archive: %s", archive_path.u8string());
- if (GlobalState::g_binary_caching && !abi_tag.empty())
- {
- auto tmp_archive_path = paths.buildtrees / spec.name() / (spec.triplet().to_string() + ".zip");
-
- std::error_code ec;
- fs.remove(tmp_archive_path, ec);
- 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();
+ ExtendedBuildResult result = do_build_package_and_clean_buildtrees(
+ paths, pre_build_info, spec, maybe_abi_tag_and_file.value_or(AbiTagAndFile{}).tag, config);
- System::cmd_execute_clean(Strings::format(
- R"("%s" a "%s" "%s\*" >nul)",
- _7za.u8string(),
- tmp_archive_path.u8string(),
- paths.package_dir(spec).u8string()));
-#else
- System::cmd_execute_clean(Strings::format(
- R"(cd '%s' && zip --quiet -r '%s' *)",
- paths.package_dir(spec).u8string(),
- tmp_archive_path.u8string()));
-#endif
- fs.create_directories(archives_dir, ec);
-
- fs.rename(tmp_archive_path, archive_path);
+ std::error_code ec;
+ fs.create_directories(paths.package_dir(spec) / "share" / spec.name(), ec);
+ auto abi_file_in_package = paths.package_dir(spec) / "share" / spec.name() / "vcpkg_abi_info.txt";
+ fs.copy_file(abi_tag_and_file->tag_file, abi_file_in_package, fs::stdfs::copy_options::none, ec);
+ Checks::check_exit(VCPKG_LINE_INFO, !ec, "Could not copy into file: %s", abi_file_in_package.u8string());
- System::println("Stored binary cache: %s", archive_path.u8string());
- }
- }
- return {BuildResult::SUCCEEDED, std::move(bcf)};
- }
+ if (result.code == BuildResult::SUCCEEDED)
+ {
+ const auto tmp_archive_path = paths.buildtrees / spec.name() / (spec.triplet().to_string() + ".zip");
- ExtendedBuildResult build_package(const VcpkgPaths& paths,
- const BuildPackageConfig& config,
- const StatusParagraphs& status_db)
- {
- ExtendedBuildResult result = do_build_package(paths, config, status_db);
+ compress_archive(paths, spec, tmp_archive_path);
- if (config.build_package_options.clean_buildtrees == CleanBuildtrees::YES)
- {
- auto& fs = paths.get_filesystem();
- const fs::path buildtrees_dir = paths.buildtrees / config.scf.core_paragraph->name;
- auto buildtree_files = fs.get_files_non_recursive(buildtrees_dir);
- for (auto&& file : buildtree_files)
+ fs.create_directories(archive_path.parent_path(), ec);
+ fs.rename(tmp_archive_path, archive_path, ec);
+ if (ec)
+ System::println(
+ System::Color::warning, "Failed to store binary cache: %s", archive_path.u8string());
+ else
+ System::println("Stored binary cache: %s", archive_path.u8string());
+ }
+ else if (result.code == BuildResult::BUILD_FAILED || result.code == BuildResult::POST_BUILD_CHECKS_FAILED)
{
- if (fs.is_directory(file) && file.filename() != "src")
- {
- std::error_code ec;
- fs.remove_all(file, ec);
- }
+ // Build failed, so store tombstone archive
+ fs.create_directories(archive_tombstone_path.parent_path(), ec);
+ fs.write_contents(archive_tombstone_path, "", ec);
}
+
+ return result;
}
- return result;
+ 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)
@@ -698,11 +769,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)
@@ -712,7 +783,7 @@ namespace vcpkg::Build
{
return it_hash->second;
}
- auto hash = Commands::Hash::get_file_hash(paths.get_cmake_exe(), triplet_file_path, "SHA1");
+ auto hash = Commands::Hash::get_file_hash(paths, triplet_file_path, "SHA1");
s_hash_cache.emplace(triplet_file_path, hash);
return hash;
}
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 c43f25b40..e2b93dc7e 100644
--- a/toolsrc/src/vcpkg/commands.ci.cpp
+++ b/toolsrc/src/vcpkg/commands.ci.cpp
@@ -1,5 +1,6 @@
#include "pch.h"
+#include <vcpkg/base/cache.h>
#include <vcpkg/base/files.h>
#include <vcpkg/base/stringliteral.h>
#include <vcpkg/base/system.h>
@@ -7,6 +8,7 @@
#include <vcpkg/build.h>
#include <vcpkg/commands.h>
#include <vcpkg/dependencies.h>
+#include <vcpkg/globalstate.h>
#include <vcpkg/help.h>
#include <vcpkg/input.h>
#include <vcpkg/install.h>
@@ -24,6 +26,7 @@ namespace vcpkg::Commands::CI
Install::InstallSummary summary;
};
+ static constexpr StringLiteral OPTION_DRY_RUN = "--dry-run";
static constexpr StringLiteral OPTION_EXCLUDE = "--exclude";
static constexpr StringLiteral OPTION_XUNIT = "--x-xunit";
@@ -32,16 +35,130 @@ namespace vcpkg::Commands::CI
{OPTION_XUNIT, "File to output results in XUnit format (internal)"},
}};
+ static constexpr std::array<CommandSwitch, 1> CI_SWITCHES = {
+ {{OPTION_DRY_RUN, "Print out plan without execution"}}};
+
const CommandStructure COMMAND_STRUCTURE = {
Help::create_example_string("ci x64-windows"),
- 0,
+ 1,
SIZE_MAX,
- {{}, CI_SETTINGS},
+ {CI_SWITCHES, CI_SETTINGS},
nullptr,
};
+ UnknownCIPortsResults find_unknown_ports_for_ci(const VcpkgPaths& paths,
+ const std::set<std::string>& exclusions,
+ const Dependencies::PortFileProvider& provider,
+ const std::vector<FeatureSpec>& fspecs)
+ {
+ UnknownCIPortsResults ret;
+
+ auto& fs = paths.get_filesystem();
+
+ std::map<PackageSpec, std::string> abi_tag_map;
+ std::set<PackageSpec> will_fail;
+
+ const Build::BuildPackageOptions install_plan_options = {Build::UseHeadVersion::NO,
+ Build::AllowDownloads::YES,
+ Build::CleanBuildtrees::YES,
+ Build::CleanPackages::YES};
+
+ vcpkg::Cache<Triplet, Build::PreBuildInfo> pre_build_info_cache;
+
+ auto action_plan = Dependencies::create_feature_install_plan(provider, fspecs, StatusParagraphs{});
+
+ for (auto&& action : action_plan)
+ {
+ if (auto p = action.install_action.get())
+ {
+ // determine abi tag
+ std::string abi;
+ if (auto scf = p->source_control_file.get())
+ {
+ auto triplet = p->spec.triplet();
+
+ 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 {
+ auto it = abi_tag_map.find(spec);
+
+ if (it == abi_tag_map.end())
+ return {spec.name(), ""};
+ else
+ return {spec.name(), it->second};
+ });
+ const auto& pre_build_info = pre_build_info_cache.get_lazy(
+ triplet, [&]() { return Build::PreBuildInfo::from_triplet_file(paths, triplet); });
+
+ auto maybe_tag_and_file =
+ Build::compute_abi_tag(paths, build_config, pre_build_info, dependency_abis);
+ if (auto tag_and_file = maybe_tag_and_file.get())
+ {
+ abi = tag_and_file->tag;
+ abi_tag_map.emplace(p->spec, abi);
+ }
+ }
+ else if (auto ipv = p->installed_package.get())
+ {
+ abi = ipv->core->package.abi;
+ if (!abi.empty()) abi_tag_map.emplace(p->spec, abi);
+ }
+
+ std::string state;
+
+ auto archives_root_dir = paths.root / "archives";
+ auto archive_name = abi + ".zip";
+ auto archive_subpath = fs::u8path(abi.substr(0, 2)) / archive_name;
+ auto archive_path = archives_root_dir / archive_subpath;
+ auto archive_tombstone_path = archives_root_dir / "fail" / archive_subpath;
+
+ bool b_will_build = false;
+
+ if (Util::Sets::contains(exclusions, p->spec.name()))
+ {
+ ret.known.emplace(p->spec, BuildResult::EXCLUDED);
+ will_fail.emplace(p->spec);
+ }
+ else if (std::any_of(p->computed_dependencies.begin(),
+ p->computed_dependencies.end(),
+ [&](const PackageSpec& spec) { return Util::Sets::contains(will_fail, spec); }))
+ {
+ ret.known.emplace(p->spec, BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES);
+ will_fail.emplace(p->spec);
+ }
+ else if (fs.exists(archive_path))
+ {
+ state += "pass";
+ ret.known.emplace(p->spec, BuildResult::SUCCEEDED);
+ }
+ else if (fs.exists(archive_tombstone_path))
+ {
+ state += "fail";
+ ret.known.emplace(p->spec, BuildResult::BUILD_FAILED);
+ will_fail.emplace(p->spec);
+ }
+ else
+ {
+ ret.unknown.push_back(p->spec);
+ b_will_build = true;
+ }
+
+ System::println("%40s: %1s %8s: %s", p->spec, (b_will_build ? "*" : " "), state, abi);
+ }
+ }
+
+ return ret;
+ }
+
void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, const Triplet& default_triplet)
{
+ if (!GlobalState::g_binary_caching)
+ {
+ System::println(System::Color::warning, "Warning: Running ci without binary caching!");
+ }
+
const ParsedArguments options = args.parse_arguments(COMMAND_STRUCTURE);
std::set<std::string> exclusions_set;
@@ -52,6 +169,8 @@ namespace vcpkg::Commands::CI
exclusions_set.insert(exclusions.begin(), exclusions.end());
}
+ auto is_dry_run = Util::Sets::contains(options.switches, OPTION_DRY_RUN);
+
std::vector<Triplet> triplets;
for (const std::string& triplet : args.command_arguments)
{
@@ -71,16 +190,21 @@ namespace vcpkg::Commands::CI
Build::CleanBuildtrees::YES,
Build::CleanPackages::YES};
- std::vector<std::string> ports = Install::get_all_port_names(paths);
+ std::vector<std::map<PackageSpec, BuildResult>> all_known_results;
+
+ std::vector<std::string> all_ports = Install::get_all_port_names(paths);
std::vector<TripletAndSummary> results;
for (const Triplet& triplet : triplets)
{
Input::check_triplet(triplet, paths);
- std::vector<PackageSpec> specs = PackageSpec::to_package_specs(ports, triplet);
+
+ std::vector<PackageSpec> specs = PackageSpec::to_package_specs(all_ports, triplet);
// Install the default features for every package
- const auto featurespecs = Util::fmap(specs, [](auto& spec) { return FeatureSpec(spec, ""); });
+ auto all_fspecs = Util::fmap(specs, [](auto& spec) { return FeatureSpec(spec, ""); });
+ auto split_specs = find_unknown_ports_for_ci(paths, exclusions_set, paths_port_file, all_fspecs);
+ auto fspecs = Util::fmap(split_specs.unknown, [](auto& spec) { return FeatureSpec(spec, ""); });
- auto action_plan = Dependencies::create_feature_install_plan(paths_port_file, featurespecs, status_db);
+ auto action_plan = Dependencies::create_feature_install_plan(paths_port_file, fspecs, status_db);
for (auto&& action : action_plan)
{
@@ -94,8 +218,18 @@ namespace vcpkg::Commands::CI
}
}
- auto summary = Install::perform(action_plan, Install::KeepGoing::YES, paths, status_db);
- results.push_back({triplet, std::move(summary)});
+ if (is_dry_run)
+ {
+ Dependencies::print_plan(action_plan);
+ }
+ else
+ {
+ auto summary = Install::perform(action_plan, Install::KeepGoing::YES, paths, status_db);
+ for (auto&& result : summary.results)
+ split_specs.known.erase(result.spec);
+ results.push_back({triplet, std::move(summary)});
+ all_known_results.emplace_back(std::move(split_specs.known));
+ }
}
for (auto&& result : results)
@@ -112,6 +246,14 @@ namespace vcpkg::Commands::CI
for (auto&& result : results)
xunit_doc += result.summary.xunit_results();
+ for (auto&& known_result : all_known_results)
+ {
+ for (auto&& result : known_result)
+ {
+ xunit_doc +=
+ Install::InstallSummary::xunit_result(result.first, Chrono::ElapsedTime{}, result.second);
+ }
+ }
xunit_doc += "</collection></assembly></assemblies>\n";
paths.get_filesystem().write_contents(fs::u8path(it_xunit->second), xunit_doc);
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 41f261a53..b6324565c 100644
--- a/toolsrc/src/vcpkg/commands.edit.cpp
+++ b/toolsrc/src/vcpkg/commands.edit.cpp
@@ -1,5 +1,6 @@
#include "pch.h"
+#include <vcpkg/base/strings.h>
#include <vcpkg/base/system.h>
#include <vcpkg/commands.h>
#include <vcpkg/help.h>
@@ -9,14 +10,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 =
@@ -34,6 +36,8 @@ namespace vcpkg::Commands::Edit
static constexpr StringLiteral OPTION_BUILDTREES = "--buildtrees";
+ static constexpr StringLiteral OPTION_ALL = "--all";
+
static std::vector<std::string> valid_arguments(const VcpkgPaths& paths)
{
auto sources_and_errors = Paragraphs::try_load_all_ports(paths.get_filesystem(), paths.ports);
@@ -42,18 +46,49 @@ namespace vcpkg::Commands::Edit
[](auto&& pgh) -> std::string { return pgh->core_paragraph->name; });
}
- static constexpr std::array<CommandSwitch, 1> EDIT_SWITCHES = {{
- {OPTION_BUILDTREES, "Open editor into the port-specific buildtree subfolder"},
- }};
+ static constexpr std::array<CommandSwitch, 2> EDIT_SWITCHES = {
+ {{OPTION_BUILDTREES, "Open editor into the port-specific buildtree subfolder"},
+ {OPTION_ALL, "Open editor into the port as well as the port-specific buildtree subfolder"}}};
const CommandStructure COMMAND_STRUCTURE = {
Help::create_example_string("edit zlib"),
1,
- 1,
+ 10,
{EDIT_SWITCHES, {}},
&valid_arguments,
};
+ static std::vector<std::string> create_editor_arguments(const VcpkgPaths& paths,
+ const ParsedArguments& options,
+ const std::vector<std::string>& ports)
+ {
+ if (Util::Sets::contains(options.switches, OPTION_ALL))
+ {
+ return Util::fmap(ports, [&](const std::string& port_name) -> std::string {
+ const auto portpath = paths.ports / port_name;
+ const auto portfile = portpath / "portfile.cmake";
+ const auto buildtrees_current_dir = paths.buildtrees / port_name;
+ return Strings::format(R"###("%s" "%s" "%s")###",
+ portpath.u8string(),
+ portfile.u8string(),
+ buildtrees_current_dir.u8string());
+ });
+ }
+
+ if (Util::Sets::contains(options.switches, OPTION_BUILDTREES))
+ {
+ return Util::fmap(ports, [&](const std::string& port_name) -> std::string {
+ return (paths.buildtrees / port_name).u8string();
+ });
+ }
+
+ return Util::fmap(ports, [&](const std::string& port_name) -> std::string {
+ const auto portpath = paths.ports / port_name;
+ const auto portfile = portpath / "portfile.cmake";
+ return Strings::format(R"###("%s" "%s")###", portpath.u8string(), portfile.u8string());
+ });
+ }
+
void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths)
{
static const fs::path VS_CODE_INSIDERS = fs::path{"Microsoft VS Code Insiders"} / "Code - Insiders.exe";
@@ -62,26 +97,40 @@ namespace vcpkg::Commands::Edit
auto& fs = paths.get_filesystem();
const ParsedArguments options = args.parse_arguments(COMMAND_STRUCTURE);
- const std::string port_name = args.command_arguments.at(0);
- const fs::path portpath = paths.ports / port_name;
- Checks::check_exit(VCPKG_LINE_INFO, fs.is_directory(portpath), R"(Could not find port named "%s")", port_name);
+ const std::vector<std::string>& ports = args.command_arguments;
+ for (auto&& port_name : ports)
+ {
+ const fs::path portpath = paths.ports / port_name;
+ Checks::check_exit(
+ VCPKG_LINE_INFO, fs.is_directory(portpath), R"(Could not find port named "%s")", port_name);
+ }
std::vector<fs::path> candidate_paths;
auto maybe_editor_path = System::get_environment_variable("EDITOR");
- if (auto editor_path = maybe_editor_path.get())
+ if (const std::string* editor_path = maybe_editor_path.get())
{
candidate_paths.emplace_back(*editor_path);
}
- candidate_paths.push_back(System::get_program_files_platform_bitness() / VS_CODE_INSIDERS);
- candidate_paths.push_back(System::get_program_files_32_bit() / VS_CODE_INSIDERS);
- candidate_paths.push_back(System::get_program_files_platform_bitness() / VS_CODE);
- candidate_paths.push_back(System::get_program_files_32_bit() / VS_CODE);
+
+ const auto& program_files = System::get_program_files_platform_bitness();
+ if (const fs::path* pf = program_files.get())
+ {
+ candidate_paths.push_back(*pf / VS_CODE_INSIDERS);
+ candidate_paths.push_back(*pf / VS_CODE);
+ }
+
+ const auto& program_files_32_bit = System::get_program_files_32_bit();
+ if (const fs::path* pf = program_files_32_bit.get())
+ {
+ candidate_paths.push_back(*pf / VS_CODE_INSIDERS);
+ candidate_paths.push_back(*pf / VS_CODE);
+ }
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(
@@ -94,20 +143,9 @@ namespace vcpkg::Commands::Edit
}
const fs::path env_editor = *it;
- if (Util::Sets::contains(options.switches, OPTION_BUILDTREES))
- {
- const auto buildtrees_current_dir = paths.buildtrees / port_name;
-
- const auto cmd_line =
- Strings::format(R"("%s" "%s" -n)", env_editor.u8string(), buildtrees_current_dir.u8string());
- Checks::exit_with_code(VCPKG_LINE_INFO, System::cmd_execute(cmd_line));
- }
-
- const auto cmd_line = Strings::format(
- R"("%s" "%s" "%s" -n)",
- env_editor.u8string(),
- portpath.u8string(),
- (portpath / "portfile.cmake").u8string());
+ const std::vector<std::string> arguments = create_editor_arguments(paths, options, ports);
+ const auto args_as_string = Strings::join(" ", arguments);
+ const auto cmd_line = Strings::format(R"("%s" %s -n)", env_editor.u8string(), args_as_string);
Checks::exit_with_code(VCPKG_LINE_INFO, System::cmd_execute(cmd_line));
}
}
diff --git a/toolsrc/src/vcpkg/commands.env.cpp b/toolsrc/src/vcpkg/commands.env.cpp
index f3beef6cd..d078baedb 100644
--- a/toolsrc/src/vcpkg/commands.env.cpp
+++ b/toolsrc/src/vcpkg/commands.env.cpp
@@ -1,5 +1,6 @@
#include "pch.h"
+#include <vcpkg/base/strings.h>
#include <vcpkg/base/system.h>
#include <vcpkg/build.h>
#include <vcpkg/commands.h>
@@ -7,25 +8,66 @@
namespace vcpkg::Commands::Env
{
+ static constexpr StringLiteral OPTION_BIN = "--bin";
+ static constexpr StringLiteral OPTION_INCLUDE = "--include";
+ static constexpr StringLiteral OPTION_DEBUG_BIN = "--debug-bin";
+ static constexpr StringLiteral OPTION_TOOLS = "--tools";
+ static constexpr StringLiteral OPTION_PYTHON = "--python";
+
+ static constexpr std::array<CommandSwitch, 5> SWITCHES = {{
+ {OPTION_BIN, "Add installed bin/ to PATH"},
+ {OPTION_INCLUDE, "Add installed include/ to INCLUDE"},
+ {OPTION_DEBUG_BIN, "Add installed debug/bin/ to PATH"},
+ {OPTION_TOOLS, "Add installed tools/*/ to PATH"},
+ {OPTION_PYTHON, "Add installed python/ to PYTHONPATH"},
+ }};
+
const CommandStructure COMMAND_STRUCTURE = {
Help::create_example_string("env --triplet x64-windows"),
0,
0,
- {},
+ {SWITCHES, {}},
nullptr,
};
- void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, const Triplet& default_triplet)
+ void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, const Triplet& triplet)
{
- args.parse_arguments(COMMAND_STRUCTURE);
+ const auto& fs = paths.get_filesystem();
+
+ const ParsedArguments options = args.parse_arguments(COMMAND_STRUCTURE);
- const auto pre_build_info = Build::PreBuildInfo::from_triplet_file(paths, default_triplet);
+ const auto pre_build_info = Build::PreBuildInfo::from_triplet_file(paths, triplet);
const Toolset& toolset = paths.get_toolset(pre_build_info);
auto env_cmd = Build::make_build_env_cmd(pre_build_info, toolset);
+
+ std::unordered_map<std::string, std::string> extra_env = {};
+ const bool add_bin = Util::Sets::contains(options.switches, OPTION_BIN);
+ const bool add_include = Util::Sets::contains(options.switches, OPTION_INCLUDE);
+ const bool add_debug_bin = Util::Sets::contains(options.switches, OPTION_DEBUG_BIN);
+ const bool add_tools = Util::Sets::contains(options.switches, OPTION_TOOLS);
+ const bool add_python = Util::Sets::contains(options.switches, OPTION_PYTHON);
+
+ std::vector<std::string> path_vars;
+ if (add_bin) path_vars.push_back((paths.installed / triplet.to_string() / "bin").u8string());
+ if (add_debug_bin) path_vars.push_back((paths.installed / triplet.to_string() / "debug" / "bin").u8string());
+ if (add_include) extra_env.emplace("INCLUDE", (paths.installed / triplet.to_string() / "include").u8string());
+ if (add_tools)
+ {
+ auto tools_dir = paths.installed / triplet.to_string() / "tools";
+ auto tool_files = fs.get_files_non_recursive(tools_dir);
+ path_vars.push_back(tools_dir.u8string());
+ for (auto&& tool_dir : tool_files)
+ {
+ if (fs.is_directory(tool_dir)) path_vars.push_back(tool_dir.u8string());
+ }
+ }
+ if (add_python) extra_env.emplace("PYTHONPATH", (paths.installed / triplet.to_string() / "python").u8string());
+ if (path_vars.size() > 0) extra_env.emplace("PATH", Strings::join(";", path_vars));
+
if (env_cmd.empty())
- System::cmd_execute_clean("cmd");
+ System::cmd_execute_clean("cmd", extra_env);
else
- System::cmd_execute_clean(env_cmd + " && cmd");
+ System::cmd_execute_clean(env_cmd + " && cmd", extra_env);
Checks::exit_success(VCPKG_LINE_INFO);
}
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..a6cfec3f0
--- /dev/null
+++ b/toolsrc/src/vcpkg/commands.fetch.cpp
@@ -0,0 +1,716 @@
+#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 Optional<std::string> extract_string_between_delimiters(const std::string& input,
+ const std::string& left_delim,
+ const std::string& right_delim,
+ const size_t& starting_offset = 0)
+ {
+ const size_t from = input.find(left_delim, starting_offset);
+ if (from == std::string::npos) return nullopt;
+
+ const size_t substring_start = from + left_delim.length();
+
+ const size_t to = input.find(right_delim, substring_start);
+ if (from == std::string::npos) return nullopt;
+
+ return input.substr(substring_start, to - substring_start);
+ }
+
+ 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 get_string_inside_tags =
+ [](const std::string& input, const std::string& left_delim, const std::string& right_delim) -> std::string {
+ Optional<std::string> result = extract_string_between_delimiters(input, left_delim, right_delim);
+ Checks::check_exit(VCPKG_LINE_INFO,
+ result.has_value(),
+ "Could not find tag <%s>.*<%s> in %s",
+ left_delim,
+ right_delim,
+ XML_PATH.generic_string());
+
+ auto r = *result.get();
+ return Strings::trim(std::move(r));
+ };
+
+ 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);
+ 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">)###", tool, OS_STRING)};
+ std::smatch match_tool_entry;
+ const bool has_tool_entry = std::regex_search(XML.cbegin(), XML.cend(), match_tool_entry, tool_regex);
+ Checks::check_exit(VCPKG_LINE_INFO,
+ has_tool_entry,
+ "Could not find entry for tool [%s] in %s",
+ tool,
+ XML_PATH.generic_string());
+
+ const std::string tool_data = get_string_inside_tags(XML, match_tool_entry[0], R"(</tool>)");
+
+ const std::string version_as_string = get_string_inside_tags(tool_data, "<version>", R"(</version>)");
+ const std::string exe_relative_path =
+ get_string_inside_tags(tool_data, "<exeRelativePath>", R"(</exeRelativePath>)");
+ const std::string url = get_string_inside_tags(tool_data, "<url>", R"(</url>)");
+ const std::string sha512 = get_string_inside_tags(tool_data, "<sha512>", R"(</sha512>)");
+ auto archive_name = extract_string_between_delimiters(tool_data, "<archiveName>", R"(</archiveName>)");
+
+ const Optional<std::array<int, 3>> version = parse_version_string(version_as_string);
+ Checks::check_exit(VCPKG_LINE_INFO,
+ version.has_value(),
+ "Could not parse version for tool %s. Version string was: %s",
+ tool,
+ version_as_string);
+
+ const std::string tool_dir_name = Strings::format("%s-%s-%s", tool, 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;
+
+ return ToolData{*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]);
+ Checks::check_exit(VCPKG_LINE_INFO,
+ !tool_data.url.empty(),
+ "A suitable version of %s was not found (required v%s) and unable to automatically "
+ "download a portable one. Please install a newer version of git.",
+ tool_name,
+ version_as_string);
+ 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)
+ {
+ static const ToolData TOOL_DATA = parse_tool_data_from_xml(paths, "git");
+ 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 bbbbed036..1f709f87b 100644
--- a/toolsrc/src/vcpkg/commands.hash.cpp
+++ b/toolsrc/src/vcpkg/commands.hash.cpp
@@ -1,5 +1,7 @@
#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>
@@ -7,32 +9,221 @@
namespace vcpkg::Commands::Hash
{
- std::string get_file_hash(fs::path const& cmake_exe_path, fs::path const& path, std::string const& hash_type)
+ static void verify_has_only_allowed_chars(const std::string& s)
{
- const std::string cmd_line = Strings::format(
- R"("%s" -E %ssum "%s")",
- cmake_exe_path.u8string(),
- Strings::ascii_to_lowercase(hash_type),
- path.u8string());
+ 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);
+ }
+}
- 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);
+#if defined(_WIN32)
+#include <bcrypt.h>
+
+#ifndef NT_SUCCESS
+#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
+#endif
+
+namespace vcpkg::Commands::Hash
+{
+ namespace
+ {
+ std::string to_hex(const unsigned char* string, const size_t bytes)
+ {
+ static constexpr char HEX_MAP[] = "0123456789abcdef";
+
+ std::string output;
+ output.resize(2 * bytes);
+
+ size_t current_char = 0;
+ for (size_t i = 0; i < bytes; i++)
+ {
+ // high
+ output[current_char] = HEX_MAP[(string[i] & 0xF0) >> 4];
+ ++current_char;
+ // low
+ output[current_char] = HEX_MAP[(string[i] & 0x0F)];
+ ++current_char;
+ }
+
+ return output;
+ }
+
+ class BCryptHasher
+ {
+ struct BCryptAlgorithmHandle : Util::ResourceBase
+ {
+ BCRYPT_ALG_HANDLE handle = nullptr;
- std::string const& output = ec_data.output;
+ ~BCryptAlgorithmHandle()
+ {
+ if (handle) BCryptCloseAlgorithmProvider(handle, 0);
+ }
+ };
- const auto start = output.find_first_of(' ');
+ struct BCryptHashHandle : Util::ResourceBase
+ {
+ BCRYPT_HASH_HANDLE handle = nullptr;
+
+ ~BCryptHashHandle()
+ {
+ if (handle) BCryptDestroyHash(handle);
+ }
+ };
+
+ static void initialize_hash_handle(BCryptHashHandle& hash_handle,
+ const BCryptAlgorithmHandle& algorithm_handle)
+ {
+ 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");
+ }
+
+ 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");
+ }
+
+ static std::string finalize_hash_handle(const BCryptHashHandle& hash_handle, const ULONG length_in_bytes)
+ {
+ 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);
+ }
+
+ 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;
+ }
+
+ 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::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;
+ };
+ }
+
+ std::string get_file_hash(const VcpkgPaths& paths, const fs::path& path, const std::string& 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());
+ return BCryptHasher{hash_type}.hash_file(path);
+ }
- const auto end = output.find_first_of("\r\n", start + 1);
+ 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
+{
+ static std::string get_digest_size(const std::string& hash_type)
+ {
+ 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);
+ }
+
+ return hash_type.substr(3, hash_type.length() - 3);
+ }
+
+ 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];
+ }
+
+ 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, end != 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);
+ }
+
+ 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
+namespace vcpkg::Commands::Hash
+{
const CommandStructure COMMAND_STRUCTURE = {
Strings::format("The argument should be a file path\n%s",
Help::create_example_string("hash boost_1_62_0.tar.bz2")),
@@ -44,19 +235,12 @@ namespace vcpkg::Commands::Hash
void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths)
{
- args.parse_arguments(COMMAND_STRUCTURE);
-
- if (args.command_arguments.size() == 1)
- {
- auto hash = get_file_hash(paths.get_cmake_exe(), args.command_arguments[0], "SHA512");
- System::println(hash);
- }
- if (args.command_arguments.size() == 2)
- {
- auto hash = get_file_hash(paths.get_cmake_exe(), args.command_arguments[0], args.command_arguments[1]);
- System::println(hash);
- }
+ Util::unused(args.parse_arguments(COMMAND_STRUCTURE));
+ const fs::path file_to_hash = args.command_arguments[0];
+ const std::string algorithm = args.command_arguments.size() == 2 ? args.command_arguments[1] : "SHA512";
+ const std::string hash = get_file_hash(paths, file_to_hash, algorithm);
+ System::println(hash);
Checks::exit_success(VCPKG_LINE_INFO);
}
}
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 460e99b88..8897ea138 100644
--- a/toolsrc/src/vcpkg/commands.integrate.cpp
+++ b/toolsrc/src/vcpkg/commands.integrate.cpp
@@ -5,9 +5,11 @@
#include <vcpkg/base/system.h>
#include <vcpkg/base/util.h>
#include <vcpkg/commands.h>
+#include <vcpkg/userconfig.h>
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 +20,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 +35,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 +53,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 +66,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 +81,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 +110,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;
@@ -144,20 +157,20 @@ namespace vcpkg::Commands::Integrate
}
#endif
+ static fs::path get_path_txt_path() { return get_user_dir() / "vcpkg.path.txt"; }
+
#if defined(_WIN32)
- static void integrate_install(const VcpkgPaths& paths)
+ static void integrate_install_msbuild14(Files::Filesystem& fs, const fs::path& tmp_dir)
{
static const std::array<fs::path, 2> OLD_SYSTEM_TARGET_FILES = {
- System::get_program_files_32_bit() /
+ System::get_program_files_32_bit().value_or_exit(VCPKG_LINE_INFO) /
"MSBuild/14.0/Microsoft.Common.Targets/ImportBefore/vcpkg.nuget.targets",
- System::get_program_files_32_bit() /
+ System::get_program_files_32_bit().value_or_exit(VCPKG_LINE_INFO) /
"MSBuild/14.0/Microsoft.Common.Targets/ImportBefore/vcpkg.system.targets"};
static const fs::path SYSTEM_WIDE_TARGETS_FILE =
- System::get_program_files_32_bit() /
+ System::get_program_files_32_bit().value_or_exit(VCPKG_LINE_INFO) /
"MSBuild/Microsoft.Cpp/v4.0/V140/ImportBefore/Default/vcpkg.system.props";
- auto& fs = paths.get_filesystem();
-
// TODO: This block of code should eventually be removed
for (auto&& old_system_wide_targets_file : OLD_SYSTEM_TARGET_FILES)
{
@@ -176,12 +189,6 @@ namespace vcpkg::Commands::Integrate
}
}
}
-
- std::error_code ec;
- const fs::path tmp_dir = paths.buildsystems / "tmp";
- fs.create_directory(paths.buildsystems, ec);
- fs.create_directory(tmp_dir, ec);
-
bool should_install_system = true;
const Expected<std::string> system_wide_file_contents = fs.read_contents(SYSTEM_WIDE_TARGETS_FILE);
static const std::regex RE(R"###(<!-- version (\d+) -->)###");
@@ -220,24 +227,52 @@ namespace vcpkg::Commands::Integrate
"Error: failed to copy targets file to %s",
SYSTEM_WIDE_TARGETS_FILE.string());
}
+ }
+#endif
+
+ static void integrate_install(const VcpkgPaths& paths)
+ {
+ auto& fs = paths.get_filesystem();
+
+#if defined(_WIN32)
+ {
+ std::error_code ec;
+ const fs::path tmp_dir = paths.buildsystems / "tmp";
+ fs.create_directory(paths.buildsystems, ec);
+ fs.create_directory(tmp_dir, ec);
+
+ integrate_install_msbuild14(fs, tmp_dir);
+
+ const fs::path appdata_src_path = tmp_dir / "vcpkg.user.targets";
+ fs.write_contents(appdata_src_path,
+ create_appdata_targets_shortcut(paths.buildsystems_msbuild_targets.string()));
+ auto appdata_dst_path = get_appdata_targets_path();
- const fs::path appdata_src_path = tmp_dir / "vcpkg.user.targets";
- fs.write_contents(appdata_src_path,
- create_appdata_targets_shortcut(paths.buildsystems_msbuild_targets.string()));
- auto appdata_dst_path = get_appdata_targets_path();
+ const auto rc = fs.copy_file(appdata_src_path, appdata_dst_path, fs::copy_options::overwrite_existing, ec);
- const auto rc = fs.copy_file(appdata_src_path, appdata_dst_path, fs::copy_options::overwrite_existing, ec);
+ if (!rc || ec)
+ {
+ System::println(System::Color::error,
+ "Error: Failed to copy file: %s -> %s",
+ appdata_src_path.string(),
+ appdata_dst_path.string());
+ Checks::exit_fail(VCPKG_LINE_INFO);
+ }
+ }
+#endif
- if (!rc || ec)
+ const auto pathtxt = get_path_txt_path();
+ std::error_code ec;
+ fs.write_contents(pathtxt, paths.root.generic_u8string(), ec);
+ if (ec)
{
- System::println(System::Color::error,
- "Error: Failed to copy file: %s -> %s",
- appdata_src_path.string(),
- appdata_dst_path.string());
+ System::println(System::Color::error, "Error: Failed to write file: %s", pathtxt.string());
Checks::exit_fail(VCPKG_LINE_INFO);
}
+
System::println(System::Color::success, "Applied user-wide integration for this vcpkg root.");
const fs::path cmake_toolchain = paths.buildsystems / "vcpkg.cmake";
+#if defined(_WIN32)
System::println(
R"(
All MSBuild C++ projects can now #include any installed libraries.
@@ -246,17 +281,29 @@ Installing new libraries will make them instantly available.
CMake projects should use: "-DCMAKE_TOOLCHAIN_FILE=%s")",
cmake_toolchain.generic_string());
+#else
+ System::println(
+ R"(
+CMake projects should use: "-DCMAKE_TOOLCHAIN_FILE=%s")",
+ cmake_toolchain.generic_string());
+#endif
Checks::exit_success(VCPKG_LINE_INFO);
}
static void integrate_remove(Files::Filesystem& fs)
{
+ std::error_code ec;
+ bool was_deleted = false;
+
+#if defined(_WIN32)
const fs::path path = get_appdata_targets_path();
- std::error_code ec;
- const bool was_deleted = fs.remove(path, ec);
+ was_deleted |= fs.remove(path, ec);
+ Checks::check_exit(VCPKG_LINE_INFO, !ec, "Error: Unable to remove user-wide integration: %s", ec.message());
+#endif
+ was_deleted |= fs.remove(get_path_txt_path(), ec);
Checks::check_exit(VCPKG_LINE_INFO, !ec, "Error: Unable to remove user-wide integration: %s", ec.message());
if (was_deleted)
@@ -270,13 +317,13 @@ CMake projects should use: "-DCMAKE_TOOLCHAIN_FILE=%s")",
Checks::exit_success(VCPKG_LINE_INFO);
}
-#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 +366,20 @@ 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 =
+ " vcpkg integrate install Make installed packages available user-wide.\n"
+ " vcpkg integrate remove Remove user-wide integration\n";
+#endif
namespace Subcommand
{
@@ -352,9 +406,8 @@ 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)
{
return integrate_install(paths);
@@ -363,6 +416,7 @@ With a project open, go to Tools->NuGet Package Manager->Package Manager Console
{
return integrate_remove(paths.get_filesystem());
}
+#if defined(_WIN32)
if (args.command_arguments[0] == Subcommand::PROJECT)
{
return integrate_project(paths);
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 1d017a8d3..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,29 +145,36 @@ 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,
const std::set<std::string>& features,
- const RequestType& request_type)
+ const RequestType& request_type,
+ std::vector<PackageSpec>&& dependencies)
: spec(spec)
, 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())
{
}
@@ -181,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,
@@ -210,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,
@@ -286,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)
{
@@ -305,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;
@@ -344,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});
}
@@ -402,9 +410,73 @@ 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);
+
+ 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 (auto p_source = cluster.source.get())
+ {
+ auto it_build_edges = p_source->build_edges.find(feature);
+ if (it_build_edges != p_source->build_edges.end())
+ {
+ // mark this package for rebuilding if needed
+ mark_minus(cluster, graph, graph_plan, prevent_default_features);
+
+ graph_plan.install_graph.add_vertex({&cluster});
+ cluster.to_install_features.insert(feature);
+
+ if (feature != "core")
+ {
+ // 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);
+ }
+
+ if (!cluster.installed.get() && !Util::Sets::contains(prevent_default_features, cluster.spec.name()))
+ {
+ // 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;
+ }
+ }
+
+ // The feature was not available in the installed package nor the source paragraph.
+ return MarkPlusResult::FEATURE_NOT_FOUND;
+ }
MarkPlusResult mark_plus(const std::string& feature,
Cluster& cluster,
@@ -412,151 +484,127 @@ namespace vcpkg::Dependencies
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 (feature.empty())
{
- if (prevent_default_features.find(cluster.spec.name()) == prevent_default_features.end())
+ // Add default features for this package. This is an exact reference, so ignore prevent_default_features.
+ if (auto p_source = cluster.source.get())
{
- // Indicates that core was not specified in the reference
-
- // 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))
+ for (auto&& default_feature : p_source->scf->core_paragraph.get()->default_features)
{
- 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)
{
- auto res = mark_plus(default_feature, cluster, graph, graph_plan, prevent_default_features);
- if (res != MarkPlusResult::SUCCESS)
- {
- return res;
- }
+ return res;
}
}
-
- // "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)
- {
- return res;
- }
-
- return MarkPlusResult::SUCCESS;
}
else
{
- // Skip adding the default features, as explicitly told not to.
- return MarkPlusResult::SUCCESS;
+ Checks::exit_with_message(VCPKG_LINE_INFO,
+ "Error: Unable to install default features because can't find CONTROL for %s",
+ cluster.spec);
}
- }
-
- auto it = cluster.edges_by_feature.find(feature);
- if (it == cluster.edges_by_feature.end()) return MarkPlusResult::FEATURE_NOT_FOUND;
- if (cluster.edges_by_feature[feature].plus) return MarkPlusResult::SUCCESS;
-
- if (cluster.original_features.find(feature) == cluster.original_features.end())
- {
- cluster.transient_uninstalled = true;
+ // "core" is always required.
+ return mark_plus("core", cluster, graph, graph_plan, prevent_default_features);
}
- if (!cluster.transient_uninstalled)
+ if (feature == "*")
{
- return MarkPlusResult::SUCCESS;
- }
- cluster.edges_by_feature[feature].plus = true;
-
- if (!cluster.original_features.empty())
- {
- 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,
@@ -585,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();
}
@@ -611,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("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);
+ 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});
}
@@ -651,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
@@ -666,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,
});
@@ -681,23 +703,28 @@ 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; });
+ Util::sort_unique_erase(dep_specs);
+
plan.emplace_back(InstallPlanAction{
p_cluster->spec,
*pscf,
p_cluster->to_install_features,
p_cluster->request_type,
+ std::move(dep_specs),
});
}
else
{
// 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,
});
}
@@ -713,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/help.cpp b/toolsrc/src/vcpkg/help.cpp
index b7d355742..743619937 100644
--- a/toolsrc/src/vcpkg/help.cpp
+++ b/toolsrc/src/vcpkg/help.cpp
@@ -98,14 +98,10 @@ namespace vcpkg::Help
" vcpkg create <pkg> <url>\n"
" [archivename] Create a new package\n"
" vcpkg owns <pat> Search for files in installed packages\n"
- " vcpkg cache List cached compiled packages\n"
+ " vcpkg env Creates a clean shell environment for development or compiling.\n"
" vcpkg version Display version information\n"
" vcpkg contact Display contact information to send feedback\n"
"\n"
- //"internal commands:\n"
- //" --check-build-deps <controlfile>\n"
- //" --create-binary-control <controlfile>\n"
- //"\n"
"Options:\n"
" --triplet <t> Specify the target architecture triplet.\n"
" (default: %%VCPKG_DEFAULT_TRIPLET%%, see 'vcpkg help triplet')\n"
diff --git a/toolsrc/src/vcpkg/install.cpp b/toolsrc/src/vcpkg/install.cpp
index 46c7c53b8..fc336d6c7 100644
--- a/toolsrc/src/vcpkg/install.cpp
+++ b/toolsrc/src/vcpkg/install.cpp
@@ -70,8 +70,8 @@ namespace vcpkg::Install
}
const std::string filename = file.filename().u8string();
- if (fs::is_regular_file(status) && (Strings::case_insensitive_ascii_equals(filename.c_str(), "CONTROL") ||
- Strings::case_insensitive_ascii_equals(filename.c_str(), "BUILD_INFO")))
+ if (fs::is_regular_file(status) && (Strings::case_insensitive_ascii_equals(filename, "CONTROL") ||
+ Strings::case_insensitive_ascii_equals(filename, "BUILD_INFO")))
{
// Do not copy the control file
continue;
@@ -306,7 +306,7 @@ namespace vcpkg::Install
System::println("Building package %s... done", display_name_with_features);
auto bcf = std::make_unique<BinaryControlFile>(
- Paragraphs::try_load_cached_control_package(paths, action.spec).value_or_exit(VCPKG_LINE_INFO));
+ Paragraphs::try_load_cached_package(paths, action.spec).value_or_exit(VCPKG_LINE_INFO));
auto code = aux_install(display_name_with_features, *bcf);
if (action.build_options.clean_packages == Build::CleanPackages::YES)
@@ -412,13 +412,15 @@ namespace vcpkg::Install
static constexpr StringLiteral OPTION_RECURSE = "--recurse";
static constexpr StringLiteral OPTION_KEEP_GOING = "--keep-going";
static constexpr StringLiteral OPTION_XUNIT = "--x-xunit";
+ static constexpr StringLiteral OPTION_USE_ARIA2 = "--x-use-aria2";
- static constexpr std::array<CommandSwitch, 5> INSTALL_SWITCHES = {{
+ static constexpr std::array<CommandSwitch, 6> INSTALL_SWITCHES = {{
{OPTION_DRY_RUN, "Do not actually build or install"},
{OPTION_USE_HEAD_VERSION, "Install the libraries on the command line using the latest upstream sources"},
{OPTION_NO_DOWNLOADS, "Do not download new sources"},
{OPTION_RECURSE, "Allow removal of packages as part of installation"},
{OPTION_KEEP_GOING, "Continue installing packages on failure"},
+ {OPTION_USE_ARIA2, "Use aria2 to perform download tasks"},
}};
static constexpr std::array<CommandSetting, 1> INSTALL_SETTINGS = {{
{OPTION_XUNIT, "File to output results in XUnit format (Internal use)"},
@@ -547,19 +549,21 @@ namespace vcpkg::Install
const bool use_head_version = Util::Sets::contains(options.switches, (OPTION_USE_HEAD_VERSION));
const bool no_downloads = Util::Sets::contains(options.switches, (OPTION_NO_DOWNLOADS));
const bool is_recursive = Util::Sets::contains(options.switches, (OPTION_RECURSE));
+ const bool use_aria2 = Util::Sets::contains(options.switches, (OPTION_USE_ARIA2));
const KeepGoing keep_going = to_keep_going(Util::Sets::contains(options.switches, OPTION_KEEP_GOING));
// create the plan
StatusParagraphs status_db = database_load_check(paths);
+ Build::DownloadTool download_tool = Build::DownloadTool::BUILT_IN;
+ if (use_aria2) download_tool = Build::DownloadTool::ARIA2;
+
const Build::BuildPackageOptions install_plan_options = {
Util::Enum::to_enum<Build::UseHeadVersion>(use_head_version),
Util::Enum::to_enum<Build::AllowDownloads>(!no_downloads),
Build::CleanBuildtrees::NO,
- Build::CleanPackages::NO};
-
- // Note: action_plan will hold raw pointers to SourceControlFiles from this map
- std::vector<AnyAction> action_plan;
+ Build::CleanPackages::NO,
+ download_tool};
auto all_ports = Paragraphs::load_all_ports(paths.get_filesystem(), paths.ports);
std::unordered_map<std::string, SourceControlFile> scf_map;
@@ -567,7 +571,9 @@ namespace vcpkg::Install
scf_map[port->core_paragraph->name] = std::move(*port);
MapPortFileProvider provider(scf_map);
- action_plan = create_feature_install_plan(provider, FullPackageSpec::to_feature_specs(specs), status_db);
+ // Note: action_plan will hold raw pointers to SourceControlFiles from this map
+ std::vector<AnyAction> action_plan =
+ create_feature_install_plan(provider, FullPackageSpec::to_feature_specs(specs), status_db);
if (!GlobalState::feature_packages)
{
@@ -668,39 +674,42 @@ namespace vcpkg::Install
return nullptr;
}
+ std::string InstallSummary::xunit_result(const PackageSpec& spec, Chrono::ElapsedTime time, BuildResult code)
+ {
+ std::string inner_block;
+ const char* result_string = "";
+ switch (code)
+ {
+ case BuildResult::POST_BUILD_CHECKS_FAILED:
+ case BuildResult::FILE_CONFLICTS:
+ case BuildResult::BUILD_FAILED:
+ result_string = "Fail";
+ inner_block = Strings::format("<failure><message><![CDATA[%s]]></message></failure>", to_string(code));
+ break;
+ case BuildResult::EXCLUDED:
+ case BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES:
+ result_string = "Skip";
+ inner_block = Strings::format("<reason><![CDATA[%s]]></reason>", to_string(code));
+ break;
+ case BuildResult::SUCCEEDED: result_string = "Pass"; break;
+ default: Checks::exit_fail(VCPKG_LINE_INFO);
+ }
+
+ return Strings::format(R"(<test name="%s" method="%s" time="%lld" result="%s">%s</test>)"
+ "\n",
+ spec,
+ spec,
+ time.as<std::chrono::seconds>().count(),
+ result_string,
+ inner_block);
+ }
+
std::string InstallSummary::xunit_results() const
{
std::string xunit_doc;
for (auto&& result : results)
{
- std::string inner_block;
- const char* result_string = "";
- switch (result.build_result.code)
- {
- case BuildResult::POST_BUILD_CHECKS_FAILED:
- case BuildResult::FILE_CONFLICTS:
- case BuildResult::BUILD_FAILED:
- result_string = "Fail";
- inner_block = Strings::format("<failure><message><![CDATA[%s]]></message></failure>",
- to_string(result.build_result.code));
- break;
- case BuildResult::EXCLUDED:
- case BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES:
- result_string = "Skip";
- inner_block =
- Strings::format("<reason><![CDATA[%s]]></reason>", to_string(result.build_result.code));
- break;
- case BuildResult::SUCCEEDED: result_string = "Pass"; break;
- default: Checks::exit_fail(VCPKG_LINE_INFO);
- }
-
- xunit_doc += Strings::format(R"(<test name="%s" method="%s" time="%lld" result="%s">%s</test>)"
- "\n",
- result.spec,
- result.spec,
- result.timing.as<std::chrono::seconds>().count(),
- result_string,
- inner_block);
+ xunit_doc += xunit_result(result.spec, result.timing, result.build_result.code);
}
return xunit_doc;
}
diff --git a/toolsrc/src/vcpkg/metrics.cpp b/toolsrc/src/vcpkg/metrics.cpp
index d49cadbe2..8890c067f 100644
--- a/toolsrc/src/vcpkg/metrics.cpp
+++ b/toolsrc/src/vcpkg/metrics.cpp
@@ -92,7 +92,7 @@ namespace vcpkg::Metrics
{
encoded.append("\\\"");
}
- else if (ch < 0x20 || ch >= 0x80)
+ else if (ch < 0x20 || static_cast<unsigned char>(ch) >= 0x80)
{
// Note: this treats incoming Strings as Latin-1
static constexpr const char HEX[16] = {
@@ -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/paragraphs.cpp b/toolsrc/src/vcpkg/paragraphs.cpp
index b66d53994..77c028937 100644
--- a/toolsrc/src/vcpkg/paragraphs.cpp
+++ b/toolsrc/src/vcpkg/paragraphs.cpp
@@ -228,7 +228,7 @@ namespace vcpkg::Paragraphs
return error_info;
}
- Expected<BinaryControlFile> try_load_cached_control_package(const VcpkgPaths& paths, const PackageSpec& spec)
+ Expected<BinaryControlFile> try_load_cached_package(const VcpkgPaths& paths, const PackageSpec& spec)
{
Expected<std::vector<std::unordered_map<std::string, std::string>>> pghs =
get_paragraphs(paths.get_filesystem(), paths.package_dir(spec) / "CONTROL");
@@ -251,7 +251,13 @@ namespace vcpkg::Paragraphs
LoadResults try_load_all_ports(const Files::Filesystem& fs, const fs::path& ports_dir)
{
LoadResults ret;
- for (auto&& path : fs.get_files_non_recursive(ports_dir))
+ auto port_dirs = fs.get_files_non_recursive(ports_dir);
+ Util::sort(port_dirs);
+ Util::erase_remove_if(port_dirs, [&](auto&& port_dir_entry) {
+ return fs.is_regular_file(port_dir_entry) && port_dir_entry.filename() == ".DS_Store";
+ });
+
+ for (auto&& path : port_dirs)
{
auto maybe_spgh = try_load_port(fs, path);
if (const auto spgh = maybe_spgh.get())
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/sourceparagraph.cpp b/toolsrc/src/vcpkg/sourceparagraph.cpp
index 0b4baf189..ed61cb42a 100644
--- a/toolsrc/src/vcpkg/sourceparagraph.cpp
+++ b/toolsrc/src/vcpkg/sourceparagraph.cpp
@@ -158,6 +158,16 @@ namespace vcpkg
return std::move(control_file);
}
+ Optional<const FeatureParagraph&> SourceControlFile::find_feature(const std::string& featurename) const
+ {
+ auto it = Util::find_if(feature_paragraphs,
+ [&](const std::unique_ptr<FeatureParagraph>& p) { return p->name == featurename; });
+ if (it != feature_paragraphs.end())
+ return **it;
+ else
+ return nullopt;
+ }
+
Dependency Dependency::parse_dependency(std::string name, std::string qualifier)
{
Dependency dep;
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/userconfig.cpp b/toolsrc/src/vcpkg/userconfig.cpp
index 9db2e5d47..4945fdaaa 100644
--- a/toolsrc/src/vcpkg/userconfig.cpp
+++ b/toolsrc/src/vcpkg/userconfig.cpp
@@ -29,16 +29,21 @@ namespace
namespace vcpkg
{
- static fs::path get_config_path()
+ fs::path get_user_dir()
{
#if defined(_WIN32)
- return get_localappdata() / "vcpkg" / "config";
+ return get_localappdata() / "vcpkg";
#else
auto maybe_home = System::get_environment_variable("HOME");
- return fs::path(maybe_home.value_or("/var")) / "vcpkg" / "config";
+ return fs::path(maybe_home.value_or("/var")) / ".vcpkg";
#endif
}
+ static fs::path get_config_path()
+ {
+ return get_user_dir() / "config";
+ }
+
UserConfig UserConfig::try_read_data(const Files::Filesystem& fs)
{
UserConfig ret;
diff --git a/toolsrc/src/vcpkg/vcpkglib.cpp b/toolsrc/src/vcpkg/vcpkglib.cpp
index 220c29720..c8e95dab1 100644
--- a/toolsrc/src/vcpkg/vcpkglib.cpp
+++ b/toolsrc/src/vcpkg/vcpkglib.cpp
@@ -54,6 +54,7 @@ namespace vcpkg
StatusParagraphs current_status_db = load_current_database(fs, status_file, status_file_old);
auto update_files = fs.get_files_non_recursive(updates_dir);
+ Util::sort(update_files);
if (update_files.empty())
{
// updates directory is empty, control file is up-to-date.
@@ -168,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 46e80c4a9..0903c2d76 100644
--- a/toolsrc/src/vcpkg/vcpkgpaths.cpp
+++ b/toolsrc/src/vcpkg/vcpkgpaths.cpp
@@ -5,294 +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 downloaded_exe_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)
- {
- static const fs::path XML_PATH = paths.scripts / "vcpkgTools.xml";
-
- 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{
- Strings::format(R"###(<requiredVersion>([\s\S]*?)</requiredVersion>)###", tool)};
- static const std::regex EXE_RELATIVE_PATH_REGEX{
- Strings::format(R"###(<exeRelativePath>([\s\S]*?)</exeRelativePath>)###", tool)};
-
- const std::regex tool_regex{Strings::format(R"###(<tool[\s]+name="%s">([\s\S]*?)</tool>)###", tool)};
-
- 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, "requiredVersion");
-
- const std::string exe_relative_path =
- get_string_inside_tags(tool_data_as_string, EXE_RELATIVE_PATH_REGEX, "exeRelativePath");
-
- 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 fs::path exe_path = paths.downloads / exe_relative_path;
- return ToolData{*required_version.get(), exe_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 fs::path fetch_tool(const fs::path& scripts_folder, const std::string& tool_name, const ToolData& tool_data)
- {
- 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);
- 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.downloaded_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;
- }
-
- static fs::path get_cmake_path(const VcpkgPaths& paths)
- {
-#if defined(_WIN32)
- static const ToolData TOOL_DATA = parse_tool_data_from_xml(paths, "cmake");
-#else
- static const ToolData TOOL_DATA = ToolData{{3, 5, 1}, ""};
-#endif
- static const std::string VERSION_CHECK_ARGUMENTS = "--version";
-
- std::vector<fs::path> candidate_paths;
-#if defined(_WIN32)
- candidate_paths.push_back(TOOL_DATA.downloaded_exe_path);
-#endif
- const std::vector<fs::path> from_path = Files::find_from_PATH("cmake");
- candidate_paths.insert(candidate_paths.end(), from_path.cbegin(), from_path.cend());
-#if defined(_WIN32)
- candidate_paths.push_back(System::get_program_files_platform_bitness() / "CMake" / "bin" / "cmake.exe");
- candidate_paths.push_back(System::get_program_files_32_bit() / "CMake" / "bin");
-#endif
-
- 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.scripts, "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.downloaded_exe_path))
- {
- return fetch_tool(paths.scripts, "7zip", TOOL_DATA);
- }
- return TOOL_DATA.downloaded_exe_path;
-#else
- Checks::exit_with_message(VCPKG_LINE_INFO, "Cannot download 7zip for non-Windows platforms.");
-#endif
- }
-
- 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.downloaded_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.scripts, "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.downloaded_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());
-#if defined(_WIN32)
- candidate_paths.push_back(System::get_program_files_platform_bitness() / "git" / "cmd" / "git.exe");
- candidate_paths.push_back(System::get_program_files_32_bit() / "git" / "cmd" / "git.exe");
-#endif
-
- 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.scripts, "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.downloaded_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.scripts, "installerbase", TOOL_DATA);
- }
-
Expected<VcpkgPaths> VcpkgPaths::create(const fs::path& vcpkg_root_dir, const std::string& default_vs_path)
{
std::error_code ec;
@@ -356,6 +75,7 @@ namespace vcpkg
{
output.push_back(path.stem().filename().string());
}
+ Util::sort(output);
return output;
});
@@ -363,261 +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_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
@@ -641,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