aboutsummaryrefslogtreecommitdiff
path: root/toolsrc/src
diff options
context:
space:
mode:
authornicole mazzuca <mazzucan@outlook.com>2020-07-14 08:50:19 -0700
committerGitHub <noreply@github.com>2020-07-14 08:50:19 -0700
commitd2620cf02bf01bb3cd6873aa2ba7687644019ed0 (patch)
treefda361dda33da62d10553519d4bb1acc2f49caf7 /toolsrc/src
parente55460813578f6a8633bbf76ef96e10c1fa22382 (diff)
downloadvcpkg-d2620cf02bf01bb3cd6873aa2ba7687644019ed0.tar.gz
vcpkg-d2620cf02bf01bb3cd6873aa2ba7687644019ed0.zip
[vcpkg formatting] Turn off DeriveLineEnding (#12368)
* [vcpkg formatting] Turn off DeriveLineEnding * format * Add newlines to the end of files Since we're reformatting anyways
Diffstat (limited to 'toolsrc/src')
-rw-r--r--toolsrc/src/vcpkg-test/mockcmakevarsprovider.cpp56
-rw-r--r--toolsrc/src/vcpkg/binarycaching.cpp2112
-rw-r--r--toolsrc/src/vcpkg/build.cpp2526
-rw-r--r--toolsrc/src/vcpkg/buildenvironment.cpp40
-rw-r--r--toolsrc/src/vcpkg/commands.ciclean.cpp84
-rw-r--r--toolsrc/src/vcpkg/commands.dependinfo.cpp662
-rw-r--r--toolsrc/src/vcpkg/commands.xvsinstances.cpp72
-rw-r--r--toolsrc/src/vcpkg/export.chocolatey.cpp316
8 files changed, 2934 insertions, 2934 deletions
diff --git a/toolsrc/src/vcpkg-test/mockcmakevarsprovider.cpp b/toolsrc/src/vcpkg-test/mockcmakevarsprovider.cpp
index 655bc33b4..77a796fad 100644
--- a/toolsrc/src/vcpkg-test/mockcmakevarsprovider.cpp
+++ b/toolsrc/src/vcpkg-test/mockcmakevarsprovider.cpp
@@ -1,28 +1,28 @@
-#include <vcpkg-test/mockcmakevarprovider.h>
-
-namespace vcpkg::Test
-{
- Optional<const std::unordered_map<std::string, std::string>&> MockCMakeVarProvider::get_generic_triplet_vars(
- Triplet triplet) const
- {
- auto it = generic_triplet_vars.find(triplet);
- if (it == generic_triplet_vars.end()) return nullopt;
- return it->second;
- }
-
- Optional<const std::unordered_map<std::string, std::string>&> MockCMakeVarProvider::get_dep_info_vars(
- const PackageSpec& spec) const
- {
- auto it = dep_info_vars.find(spec);
- if (it == dep_info_vars.end()) return nullopt;
- return it->second;
- }
-
- Optional<const std::unordered_map<std::string, std::string>&> MockCMakeVarProvider::get_tag_vars(
- const PackageSpec& spec) const
- {
- auto it = tag_vars.find(spec);
- if (it == tag_vars.end()) return nullopt;
- return it->second;
- }
-} \ No newline at end of file
+#include <vcpkg-test/mockcmakevarprovider.h>
+
+namespace vcpkg::Test
+{
+ Optional<const std::unordered_map<std::string, std::string>&> MockCMakeVarProvider::get_generic_triplet_vars(
+ Triplet triplet) const
+ {
+ auto it = generic_triplet_vars.find(triplet);
+ if (it == generic_triplet_vars.end()) return nullopt;
+ return it->second;
+ }
+
+ Optional<const std::unordered_map<std::string, std::string>&> MockCMakeVarProvider::get_dep_info_vars(
+ const PackageSpec& spec) const
+ {
+ auto it = dep_info_vars.find(spec);
+ if (it == dep_info_vars.end()) return nullopt;
+ return it->second;
+ }
+
+ Optional<const std::unordered_map<std::string, std::string>&> MockCMakeVarProvider::get_tag_vars(
+ const PackageSpec& spec) const
+ {
+ auto it = tag_vars.find(spec);
+ if (it == tag_vars.end()) return nullopt;
+ return it->second;
+ }
+}
diff --git a/toolsrc/src/vcpkg/binarycaching.cpp b/toolsrc/src/vcpkg/binarycaching.cpp
index 0a0b100dc..d63d6b3d4 100644
--- a/toolsrc/src/vcpkg/binarycaching.cpp
+++ b/toolsrc/src/vcpkg/binarycaching.cpp
@@ -1,1056 +1,1056 @@
-#include "pch.h"
-
-#include <vcpkg/base/checks.h>
-#include <vcpkg/base/files.h>
-#include <vcpkg/base/parse.h>
-#include <vcpkg/base/system.debug.h>
-#include <vcpkg/base/system.print.h>
-#include <vcpkg/base/system.process.h>
-
-#include <vcpkg/binarycaching.h>
-#include <vcpkg/binarycaching.private.h>
-#include <vcpkg/build.h>
-#include <vcpkg/dependencies.h>
-
-using namespace vcpkg;
-
-namespace
-{
- static System::ExitCodeAndOutput 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);
- fs.remove_all(pkg_path, VCPKG_LINE_INFO);
- std::error_code 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&& seven_zip_exe = paths.get_tool_exe(Tools::SEVEN_ZIP);
- auto cmd = Strings::format(
- R"("%s" x "%s" -o"%s" -y)", seven_zip_exe.u8string(), archive_path.u8string(), pkg_path.u8string());
-#else
- auto cmd = Strings::format(R"(unzip -qq "%s" "-d%s")", archive_path.u8string(), pkg_path.u8string());
-#endif
- return System::cmd_execute_and_capture_output(cmd, System::get_clean_environment());
- }
-
- // Compress the source directory into the destination file.
- static void compress_directory(const VcpkgPaths& paths, const fs::path& source, const fs::path& destination)
- {
- auto& fs = paths.get_filesystem();
-
- std::error_code ec;
-
- fs.remove(destination, ec);
- Checks::check_exit(
- VCPKG_LINE_INFO, !fs.exists(destination), "Could not remove file: %s", destination.u8string());
-#if defined(_WIN32)
- auto&& seven_zip_exe = paths.get_tool_exe(Tools::SEVEN_ZIP);
-
- System::cmd_execute_and_capture_output(
- Strings::format(
- R"("%s" a "%s" "%s\*")", seven_zip_exe.u8string(), destination.u8string(), source.u8string()),
- System::get_clean_environment());
-#else
- System::cmd_execute_clean(
- Strings::format(R"(cd '%s' && zip --quiet -r '%s' *)", source.u8string(), destination.u8string()));
-#endif
- }
-
- struct ArchivesBinaryProvider : IBinaryProvider
- {
- ArchivesBinaryProvider(std::vector<fs::path>&& read_dirs, std::vector<fs::path>&& write_dirs)
- : m_read_dirs(std::move(read_dirs)), m_write_dirs(std::move(write_dirs))
- {
- }
- ~ArchivesBinaryProvider() = default;
- void prefetch(const VcpkgPaths&, const Dependencies::ActionPlan&) override { }
- RestoreResult try_restore(const VcpkgPaths& paths, const Dependencies::InstallPlanAction& action) override
- {
- const auto& abi_tag = action.abi_info.value_or_exit(VCPKG_LINE_INFO).package_abi;
- auto& spec = action.spec;
- auto& fs = paths.get_filesystem();
- std::error_code ec;
- for (auto&& archives_root_dir : m_read_dirs)
- {
- const std::string archive_name = abi_tag + ".zip";
- const fs::path archive_subpath = fs::u8path(abi_tag.substr(0, 2)) / archive_name;
- const fs::path archive_path = archives_root_dir / archive_subpath;
- if (fs.exists(archive_path))
- {
- System::print2("Using cached binary package: ", archive_path.u8string(), "\n");
-
- int archive_result = decompress_archive(paths, spec, archive_path).exit_code;
-
- if (archive_result == 0)
- {
- return RestoreResult::success;
- }
- else
- {
- System::print2("Failed to decompress archive package\n");
- if (action.build_options.purge_decompress_failure == Build::PurgeDecompressFailure::NO)
- {
- return RestoreResult::build_failed;
- }
- else
- {
- System::print2("Purging bad archive\n");
- fs.remove(archive_path, ec);
- }
- }
- }
-
- System::printf("Could not locate cached archive: %s\n", archive_path.u8string());
- }
-
- return RestoreResult::missing;
- }
- void push_success(const VcpkgPaths& paths, const Dependencies::InstallPlanAction& action) override
- {
- if (m_write_dirs.empty()) return;
- const auto& abi_tag = action.abi_info.value_or_exit(VCPKG_LINE_INFO).package_abi;
- auto& spec = action.spec;
- auto& fs = paths.get_filesystem();
- const auto tmp_archive_path = paths.buildtrees / spec.name() / (spec.triplet().to_string() + ".zip");
- compress_directory(paths, paths.package_dir(spec), tmp_archive_path);
-
- for (auto&& m_directory : m_write_dirs)
- {
- const fs::path& archives_root_dir = m_directory;
- const std::string archive_name = abi_tag + ".zip";
- const fs::path archive_subpath = fs::u8path(abi_tag.substr(0, 2)) / archive_name;
- const fs::path archive_path = archives_root_dir / archive_subpath;
-
- fs.create_directories(archive_path.parent_path(), ignore_errors);
- std::error_code ec;
- if (m_write_dirs.size() > 1)
- fs.copy_file(tmp_archive_path, archive_path, fs::copy_options::overwrite_existing, ec);
- else
- fs.rename_or_copy(tmp_archive_path, archive_path, ".tmp", ec);
- if (ec)
- {
- System::printf(System::Color::warning,
- "Failed to store binary cache %s: %s\n",
- archive_path.u8string(),
- ec.message());
- }
- else
- System::printf("Stored binary cache: %s\n", archive_path.u8string());
- }
- if (m_write_dirs.size() > 1) fs.remove(tmp_archive_path, ignore_errors);
- }
- RestoreResult precheck(const VcpkgPaths& paths, const Dependencies::InstallPlanAction& action) override
- {
- const auto& abi_tag = action.abi_info.value_or_exit(VCPKG_LINE_INFO).package_abi;
- auto& fs = paths.get_filesystem();
- std::error_code ec;
- for (auto&& archives_root_dir : m_read_dirs)
- {
- const std::string archive_name = abi_tag + ".zip";
- const fs::path archive_subpath = fs::u8path(abi_tag.substr(0, 2)) / archive_name;
- const fs::path archive_path = archives_root_dir / archive_subpath;
-
- if (fs.exists(archive_path))
- {
- return RestoreResult::success;
- }
- }
- return RestoreResult::missing;
- }
-
- private:
- std::vector<fs::path> m_read_dirs, m_write_dirs;
- };
-
- static std::string trim_leading_zeroes(std::string v)
- {
- auto n = v.find_first_not_of('0');
- if (n == std::string::npos)
- {
- v = "0";
- }
- else if (n > 0)
- {
- v.erase(0, n);
- }
- return v;
- }
-
- struct NugetBinaryProvider : IBinaryProvider
- {
- NugetBinaryProvider(std::vector<std::string>&& read_sources,
- std::vector<std::string>&& write_sources,
- std::vector<fs::path>&& read_configs,
- std::vector<fs::path>&& write_configs,
- bool interactive)
- : m_read_sources(std::move(read_sources))
- , m_write_sources(std::move(write_sources))
- , m_read_configs(std::move(read_configs))
- , m_write_configs(std::move(write_configs))
- , m_interactive(interactive)
- {
- }
- void prefetch(const VcpkgPaths& paths, const Dependencies::ActionPlan& plan) override
- {
- if (m_read_sources.empty() && m_read_configs.empty()) return;
-
- auto& fs = paths.get_filesystem();
-
- std::vector<std::pair<PackageSpec, NugetReference>> nuget_refs;
-
- for (auto&& action : plan.install_actions)
- {
- if (action.build_options.editable == Build::Editable::YES) continue;
-
- auto& spec = action.spec;
- fs.remove_all(paths.package_dir(spec), VCPKG_LINE_INFO);
-
- nuget_refs.emplace_back(spec, NugetReference(action));
- }
-
- if (nuget_refs.empty()) return;
-
- System::print2("Attempting to fetch ", nuget_refs.size(), " packages from nuget.\n");
-
- auto packages_config = paths.buildtrees / fs::u8path("packages.config");
-
- auto generate_packages_config = [&] {
- XmlSerializer xml;
- xml.emit_declaration().line_break();
- xml.open_tag("packages").line_break();
-
- for (auto&& nuget_ref : nuget_refs)
- xml.start_complex_open_tag("package")
- .text_attr("id", nuget_ref.second.id)
- .text_attr("version", nuget_ref.second.version)
- .finish_self_closing_complex_tag()
- .line_break();
-
- xml.close_tag("packages").line_break();
- paths.get_filesystem().write_contents(packages_config, xml.buf, VCPKG_LINE_INFO);
- };
-
- const auto& nuget_exe = paths.get_tool_exe("nuget");
- std::vector<std::string> cmdlines;
-
- if (!m_read_sources.empty())
- {
- // First check using all sources
- System::CmdLineBuilder cmdline;
-#ifndef _WIN32
- cmdline.path_arg(paths.get_tool_exe(Tools::MONO));
-#endif
- cmdline.path_arg(nuget_exe)
- .string_arg("install")
- .path_arg(packages_config)
- .string_arg("-OutputDirectory")
- .path_arg(paths.packages)
- .string_arg("-Source")
- .string_arg(Strings::join(";", m_read_sources))
- .string_arg("-ExcludeVersion")
- .string_arg("-NoCache")
- .string_arg("-PreRelease")
- .string_arg("-DirectDownload")
- .string_arg("-PackageSaveMode")
- .string_arg("nupkg")
- .string_arg("-Verbosity")
- .string_arg("detailed")
- .string_arg("-ForceEnglishOutput");
- if (!m_interactive) cmdline.string_arg("-NonInteractive");
- cmdlines.push_back(cmdline.extract());
- }
- for (auto&& cfg : m_read_configs)
- {
- // Then check using each config
- System::CmdLineBuilder cmdline;
-#ifndef _WIN32
- cmdline.path_arg(paths.get_tool_exe(Tools::MONO));
-#endif
- cmdline.path_arg(nuget_exe)
- .string_arg("install")
- .path_arg(packages_config)
- .string_arg("-OutputDirectory")
- .path_arg(paths.packages)
- .string_arg("-ConfigFile")
- .path_arg(cfg)
- .string_arg("-ExcludeVersion")
- .string_arg("-NoCache")
- .string_arg("-PreRelease")
- .string_arg("-DirectDownload")
- .string_arg("-PackageSaveMode")
- .string_arg("nupkg")
- .string_arg("-Verbosity")
- .string_arg("detailed")
- .string_arg("-ForceEnglishOutput");
- if (!m_interactive) cmdline.string_arg("-NonInteractive");
- cmdlines.push_back(cmdline.extract());
- }
-
- size_t num_restored = 0;
-
- for (const auto& cmdline : cmdlines)
- {
- if (nuget_refs.empty()) break;
-
- [&] {
- generate_packages_config();
- if (Debug::g_debugging)
- System::cmd_execute(cmdline);
- else
- {
- auto res = System::cmd_execute_and_capture_output(cmdline);
- if (res.output.find("Authentication may require manual action.") != std::string::npos)
- {
- System::print2(
- System::Color::warning,
- "One or more NuGet credential providers requested manual action. Add the binary "
- "source 'interactive' to allow interactivity.\n");
- }
- }
- }();
-
- Util::erase_remove_if(nuget_refs, [&](const std::pair<PackageSpec, NugetReference>& nuget_ref) -> bool {
- auto nupkg_path = paths.package_dir(nuget_ref.first) / fs::u8path(nuget_ref.second.id + ".nupkg");
- if (fs.exists(nupkg_path, ignore_errors))
- {
- fs.remove(nupkg_path, VCPKG_LINE_INFO);
- Checks::check_exit(VCPKG_LINE_INFO,
- !fs.exists(nupkg_path, ignore_errors),
- "Unable to remove nupkg after restoring: %s",
- nupkg_path.u8string());
- m_restored.emplace(nuget_ref.first);
- ++num_restored;
- return true;
- }
- else
- {
- return false;
- }
- });
- }
-
- System::print2("Restored ", num_restored, " packages. Use --debug for more information.\n");
- }
- RestoreResult try_restore(const VcpkgPaths&, const Dependencies::InstallPlanAction& action) override
- {
- if (Util::Sets::contains(m_restored, action.spec))
- return RestoreResult::success;
- else
- return RestoreResult::missing;
- }
- void push_success(const VcpkgPaths& paths, const Dependencies::InstallPlanAction& action) override
- {
- if (m_write_sources.empty() && m_write_configs.empty()) return;
- auto& spec = action.spec;
-
- NugetReference nuget_ref(action);
- auto nuspec_path = paths.buildtrees / spec.name() / (spec.triplet().to_string() + ".nuspec");
- paths.get_filesystem().write_contents(
- nuspec_path, generate_nuspec(paths, action, nuget_ref), VCPKG_LINE_INFO);
-
- const auto& nuget_exe = paths.get_tool_exe("nuget");
- System::CmdLineBuilder cmdline;
-#ifndef _WIN32
- cmdline.path_arg(paths.get_tool_exe(Tools::MONO));
-#endif
- cmdline.path_arg(nuget_exe)
- .string_arg("pack")
- .path_arg(nuspec_path)
- .string_arg("-OutputDirectory")
- .path_arg(paths.buildtrees)
- .string_arg("-NoDefaultExcludes")
- .string_arg("-ForceEnglishOutput");
- if (!m_interactive) cmdline.string_arg("-NonInteractive");
-
- auto pack_rc = [&] {
- if (Debug::g_debugging)
- return System::cmd_execute(cmdline);
- else
- return System::cmd_execute_and_capture_output(cmdline).exit_code;
- }();
-
- if (pack_rc != 0)
- {
- System::print2(System::Color::error, "Packing NuGet failed. Use --debug for more information.\n");
- }
- else
- {
- auto nupkg_path = paths.buildtrees / nuget_ref.nupkg_filename();
- for (auto&& write_src : m_write_sources)
- {
- System::CmdLineBuilder cmd;
-#ifndef _WIN32
- cmd.path_arg(paths.get_tool_exe(Tools::MONO));
-#endif
- cmd.path_arg(nuget_exe)
- .string_arg("push")
- .path_arg(nupkg_path)
- .string_arg("-ApiKey")
- .string_arg("AzureDevOps")
- .string_arg("-ForceEnglishOutput")
- .string_arg("-Source")
- .string_arg(write_src);
- if (!m_interactive) cmd.string_arg("-NonInteractive");
-
- System::print2("Uploading binaries for ", spec, " to NuGet source ", write_src, ".\n");
-
- auto rc = [&] {
- if (Debug::g_debugging)
- return System::cmd_execute(cmd);
- else
- return System::cmd_execute_and_capture_output(cmd).exit_code;
- }();
-
- if (rc != 0)
- {
- System::print2(System::Color::error,
- "Pushing NuGet to ",
- write_src,
- " failed. Use --debug for more information.\n");
- }
- }
- for (auto&& write_cfg : m_write_configs)
- {
- System::CmdLineBuilder cmd;
-#ifndef _WIN32
- cmd.path_arg(paths.get_tool_exe(Tools::MONO));
-#endif
- cmd.path_arg(nuget_exe)
- .string_arg("push")
- .path_arg(nupkg_path)
- .string_arg("-ApiKey")
- .string_arg("AzureDevOps")
- .string_arg("-ForceEnglishOutput")
- .string_arg("-ConfigFile")
- .path_arg(write_cfg);
- if (!m_interactive) cmd.string_arg("-NonInteractive");
-
- System::print2(
- "Uploading binaries for ", spec, " using NuGet config ", write_cfg.u8string(), ".\n");
-
- auto rc = [&] {
- if (Debug::g_debugging)
- return System::cmd_execute(cmd);
- else
- return System::cmd_execute_and_capture_output(cmd).exit_code;
- }();
-
- if (rc != 0)
- {
- System::print2(System::Color::error,
- "Pushing NuGet with ",
- write_cfg.u8string(),
- " failed. Use --debug for more information.\n");
- }
- }
- paths.get_filesystem().remove(nupkg_path, ignore_errors);
- }
- }
- RestoreResult precheck(const VcpkgPaths&, const Dependencies::InstallPlanAction&) override
- {
- return RestoreResult::missing;
- }
-
- private:
- std::vector<std::string> m_read_sources;
- std::vector<std::string> m_write_sources;
-
- std::vector<fs::path> m_read_configs;
- std::vector<fs::path> m_write_configs;
-
- std::set<PackageSpec> m_restored;
- bool m_interactive;
- };
-
- struct MergeBinaryProviders : IBinaryProvider
- {
- explicit MergeBinaryProviders(std::vector<std::unique_ptr<IBinaryProvider>>&& providers)
- : m_providers(std::move(providers))
- {
- }
-
- void prefetch(const VcpkgPaths& paths, const Dependencies::ActionPlan& plan) override
- {
- for (auto&& provider : m_providers)
- {
- provider->prefetch(paths, plan);
- }
- }
- RestoreResult try_restore(const VcpkgPaths& paths, const Dependencies::InstallPlanAction& action) override
- {
- for (auto&& provider : m_providers)
- {
- auto result = provider->try_restore(paths, action);
- switch (result)
- {
- case RestoreResult::build_failed:
- case RestoreResult::success: return result;
- case RestoreResult::missing: continue;
- default: Checks::unreachable(VCPKG_LINE_INFO);
- }
- }
- return RestoreResult::missing;
- }
- void push_success(const VcpkgPaths& paths, const Dependencies::InstallPlanAction& action) override
- {
- for (auto&& provider : m_providers)
- {
- provider->push_success(paths, action);
- }
- }
- RestoreResult precheck(const VcpkgPaths& paths, const Dependencies::InstallPlanAction& action) override
- {
- for (auto&& provider : m_providers)
- {
- auto result = provider->precheck(paths, action);
- switch (result)
- {
- case RestoreResult::build_failed:
- case RestoreResult::success: return result;
- case RestoreResult::missing: continue;
- default: Checks::unreachable(VCPKG_LINE_INFO);
- }
- }
- return RestoreResult::missing;
- }
-
- private:
- std::vector<std::unique_ptr<IBinaryProvider>> m_providers;
- };
-
- struct NullBinaryProvider : IBinaryProvider
- {
- void prefetch(const VcpkgPaths&, const Dependencies::ActionPlan&) override { }
- RestoreResult try_restore(const VcpkgPaths&, const Dependencies::InstallPlanAction&) override
- {
- return RestoreResult::missing;
- }
- void push_success(const VcpkgPaths&, const Dependencies::InstallPlanAction&) override { }
- RestoreResult precheck(const VcpkgPaths&, const Dependencies::InstallPlanAction&) override
- {
- return RestoreResult::missing;
- }
- };
-}
-
-XmlSerializer& XmlSerializer::emit_declaration()
-{
- buf.append(R"(<?xml version="1.0" encoding="utf-8"?>)");
- return *this;
-}
-XmlSerializer& XmlSerializer::open_tag(StringLiteral sl)
-{
- emit_pending_indent();
- Strings::append(buf, '<', sl, '>');
- m_indent += 2;
- return *this;
-}
-XmlSerializer& XmlSerializer::start_complex_open_tag(StringLiteral sl)
-{
- emit_pending_indent();
- Strings::append(buf, '<', sl);
- m_indent += 2;
- return *this;
-}
-XmlSerializer& XmlSerializer::text_attr(StringLiteral name, StringView content)
-{
- if (m_pending_indent)
- {
- m_pending_indent = false;
- buf.append(m_indent, ' ');
- }
- else
- {
- buf.push_back(' ');
- }
- Strings::append(buf, name, "=\"");
- text(content);
- Strings::append(buf, '"');
- return *this;
-}
-XmlSerializer& XmlSerializer::finish_complex_open_tag()
-{
- emit_pending_indent();
- Strings::append(buf, '>');
- return *this;
-}
-XmlSerializer& XmlSerializer::finish_self_closing_complex_tag()
-{
- emit_pending_indent();
- Strings::append(buf, "/>");
- m_indent -= 2;
- return *this;
-}
-XmlSerializer& XmlSerializer::close_tag(StringLiteral sl)
-{
- m_indent -= 2;
- emit_pending_indent();
- Strings::append(buf, "</", sl, '>');
- return *this;
-}
-XmlSerializer& XmlSerializer::text(StringView sv)
-{
- emit_pending_indent();
- for (auto ch : sv)
- {
- if (ch == '&')
- {
- buf.append("&amp;");
- }
- else if (ch == '<')
- {
- buf.append("&lt;");
- }
- else if (ch == '>')
- {
- buf.append("&gt;");
- }
- else if (ch == '"')
- {
- buf.append("&quot;");
- }
- else if (ch == '\'')
- {
- buf.append("&apos;");
- }
- else
- {
- buf.push_back(ch);
- }
- }
- return *this;
-}
-XmlSerializer& XmlSerializer::simple_tag(StringLiteral tag, StringView content)
-{
- return emit_pending_indent().open_tag(tag).text(content).close_tag(tag);
-}
-XmlSerializer& XmlSerializer::line_break()
-{
- buf.push_back('\n');
- m_pending_indent = true;
- return *this;
-}
-XmlSerializer& XmlSerializer::emit_pending_indent()
-{
- if (m_pending_indent)
- {
- m_pending_indent = false;
- buf.append(m_indent, ' ');
- }
- return *this;
-}
-
-IBinaryProvider& vcpkg::null_binary_provider()
-{
- static NullBinaryProvider p;
- return p;
-}
-
-ExpectedS<std::unique_ptr<IBinaryProvider>> vcpkg::create_binary_provider_from_configs(View<std::string> args)
-{
- std::string env_string = System::get_environment_variable("VCPKG_BINARY_SOURCES").value_or("");
-
- return create_binary_provider_from_configs_pure(env_string, args);
-}
-namespace
-{
- const ExpectedS<fs::path>& default_cache_path()
- {
- static auto cachepath = System::get_platform_cache_home().then([](fs::path p) -> ExpectedS<fs::path> {
- p /= fs::u8path("vcpkg/archives");
- if (p.is_absolute())
- {
- return {std::move(p), expected_left_tag};
- }
- else
- {
- return {"default path was not absolute: " + p.u8string(), expected_right_tag};
- }
- });
- return cachepath;
- }
-
- struct State
- {
- bool m_cleared = false;
- bool interactive = false;
-
- std::vector<fs::path> archives_to_read;
- std::vector<fs::path> archives_to_write;
-
- std::vector<std::string> sources_to_read;
- std::vector<std::string> sources_to_write;
-
- std::vector<fs::path> configs_to_read;
- std::vector<fs::path> configs_to_write;
-
- void clear()
- {
- m_cleared = true;
- interactive = false;
- archives_to_read.clear();
- archives_to_write.clear();
- sources_to_read.clear();
- sources_to_write.clear();
- configs_to_read.clear();
- configs_to_write.clear();
- }
- };
-
- struct BinaryConfigParser : Parse::ParserBase
- {
- BinaryConfigParser(StringView text, StringView origin, State* state)
- : Parse::ParserBase(text, origin), state(state)
- {
- }
-
- State* state;
-
- void parse()
- {
- while (!at_eof())
- {
- std::vector<std::pair<SourceLoc, std::string>> segments;
-
- for (;;)
- {
- SourceLoc loc = cur_loc();
- std::string segment;
- for (;;)
- {
- auto n = match_until([](char32_t ch) { return ch == ',' || ch == '`' || ch == ';'; });
- Strings::append(segment, n);
- auto ch = cur();
- if (ch == Unicode::end_of_file || ch == ',' || ch == ';')
- break;
- else if (ch == '`')
- {
- ch = next();
- if (ch == Unicode::end_of_file)
- add_error("unexpected eof: trailing unescaped backticks (`) are not allowed");
- else
- Unicode::utf8_append_code_point(segment, ch);
- next();
- }
- else
- Checks::unreachable(VCPKG_LINE_INFO);
- }
- segments.emplace_back(std::move(loc), std::move(segment));
-
- auto ch = cur();
- if (ch == Unicode::end_of_file || ch == ';')
- break;
- else if (ch == ',')
- {
- next();
- continue;
- }
- else
- Checks::unreachable(VCPKG_LINE_INFO);
- }
-
- if (segments.size() != 1 || !segments[0].second.empty()) handle_segments(std::move(segments));
- segments.clear();
- if (get_error()) return;
- if (cur() == ';') next();
- }
- }
-
- template<class T>
- void handle_readwrite(std::vector<T>& read,
- std::vector<T>& write,
- T&& t,
- const std::vector<std::pair<SourceLoc, std::string>>& segments,
- size_t segment_idx)
- {
- if (segment_idx >= segments.size())
- {
- read.push_back(std::move(t));
- return;
- }
-
- auto& mode = segments[segment_idx].second;
-
- if (mode == "read")
- {
- read.push_back(std::move(t));
- }
- else if (mode == "write")
- {
- write.push_back(std::move(t));
- }
- else if (mode == "readwrite")
- {
- read.push_back(t);
- write.push_back(std::move(t));
- }
- else
- {
- return add_error("unexpected argument: expected 'read', readwrite', or 'write'",
- segments[segment_idx].first);
- }
- }
-
- void handle_segments(std::vector<std::pair<SourceLoc, std::string>>&& segments)
- {
- if (segments.empty()) return;
- if (segments[0].second == "clear")
- {
- if (segments.size() != 1)
- return add_error("unexpected arguments: binary config 'clear' does not take arguments",
- segments[1].first);
- state->clear();
- }
- else if (segments[0].second == "files")
- {
- if (segments.size() < 2)
- {
- return add_error("expected arguments: binary config 'files' requires at least a path argument",
- segments[0].first);
- }
-
- auto p = fs::u8path(segments[1].second);
- if (!p.is_absolute())
- {
- return add_error("expected arguments: path arguments for binary config strings must be absolute",
- segments[1].first);
- }
- handle_readwrite(state->archives_to_read, state->archives_to_write, std::move(p), segments, 2);
- if (segments.size() > 3)
- return add_error("unexpected arguments: binary config 'files' requires 1 or 2 arguments",
- segments[3].first);
- }
- else if (segments[0].second == "interactive")
- {
- if (segments.size() > 1)
- return add_error("unexpected arguments: binary config 'interactive' does not accept any arguments",
- segments[1].first);
- state->interactive = true;
- }
- else if (segments[0].second == "nugetconfig")
- {
- if (segments.size() < 2)
- return add_error(
- "expected arguments: binary config 'nugetconfig' requires at least a source argument",
- segments[0].first);
-
- auto p = fs::u8path(segments[1].second);
- if (!p.is_absolute())
- return add_error("expected arguments: path arguments for binary config strings must be absolute",
- segments[1].first);
- handle_readwrite(state->configs_to_read, state->configs_to_write, std::move(p), segments, 2);
- if (segments.size() > 3)
- return add_error("unexpected arguments: binary config 'nugetconfig' requires 1 or 2 arguments",
- segments[3].first);
- }
- else if (segments[0].second == "nuget")
- {
- if (segments.size() < 2)
- return add_error("expected arguments: binary config 'nuget' requires at least a source argument",
- segments[0].first);
-
- auto&& p = segments[1].second;
- if (p.empty())
- return add_error("unexpected arguments: binary config 'nuget' requires non-empty source");
-
- handle_readwrite(state->sources_to_read, state->sources_to_write, std::move(p), segments, 2);
- if (segments.size() > 3)
- return add_error("unexpected arguments: binary config 'nuget' requires 1 or 2 arguments",
- segments[3].first);
- }
- else if (segments[0].second == "default")
- {
- if (segments.size() > 2)
- {
- return add_error("unexpected arguments: binary config 'default' does not take more than 1 argument",
- segments[0].first);
- }
-
- const auto& maybe_home = default_cache_path();
- if (!maybe_home.has_value()) return add_error(maybe_home.error(), segments[0].first);
-
- handle_readwrite(
- state->archives_to_read, state->archives_to_write, fs::path(*maybe_home.get()), segments, 1);
- }
- else
- {
- return add_error(
- "unknown binary provider type: valid providers are 'clear', 'default', 'nuget', 'nugetconfig', "
- "'interactive', and 'files'",
- segments[0].first);
- }
- }
- };
-}
-
-ExpectedS<std::unique_ptr<IBinaryProvider>> vcpkg::create_binary_provider_from_configs_pure(
- const std::string& env_string, View<std::string> args)
-{
- State s;
-
- BinaryConfigParser default_parser("default,readwrite", "<defaults>", &s);
- default_parser.parse();
-
- BinaryConfigParser env_parser(env_string, "VCPKG_BINARY_SOURCES", &s);
- env_parser.parse();
- if (auto err = env_parser.get_error()) return err->format();
- for (auto&& arg : args)
- {
- BinaryConfigParser arg_parser(arg, "<command>", &s);
- arg_parser.parse();
- if (auto err = arg_parser.get_error()) return err->format();
- }
-
- std::vector<std::unique_ptr<IBinaryProvider>> providers;
- if (!s.archives_to_read.empty() || !s.archives_to_write.empty())
- providers.push_back(
- std::make_unique<ArchivesBinaryProvider>(std::move(s.archives_to_read), std::move(s.archives_to_write)));
- if (!s.sources_to_read.empty() || !s.sources_to_write.empty() || !s.configs_to_read.empty() ||
- !s.configs_to_write.empty())
- providers.push_back(std::make_unique<NugetBinaryProvider>(std::move(s.sources_to_read),
- std::move(s.sources_to_write),
- std::move(s.configs_to_read),
- std::move(s.configs_to_write),
- s.interactive));
-
- return {std::make_unique<MergeBinaryProviders>(std::move(providers))};
-}
-
-std::string vcpkg::reformat_version(const std::string& version, const std::string& abi_tag)
-{
- static const std::regex semver_matcher(R"(v?(\d+)(\.\d+|$)(\.\d+)?.*)");
-
- std::smatch sm;
- if (std::regex_match(version.cbegin(), version.cend(), sm, semver_matcher))
- {
- auto major = trim_leading_zeroes(sm.str(1));
- auto minor = sm.size() > 2 && !sm.str(2).empty() ? trim_leading_zeroes(sm.str(2).substr(1)) : "0";
- auto patch = sm.size() > 3 && !sm.str(3).empty() ? trim_leading_zeroes(sm.str(3).substr(1)) : "0";
- return Strings::concat(major, '.', minor, '.', patch, "-", abi_tag);
- }
-
- static const std::regex date_matcher(R"((\d\d\d\d)-(\d\d)-(\d\d).*)");
- if (std::regex_match(version.cbegin(), version.cend(), sm, date_matcher))
- {
- return Strings::concat(trim_leading_zeroes(sm.str(1)),
- '.',
- trim_leading_zeroes(sm.str(2)),
- '.',
- trim_leading_zeroes(sm.str(3)),
- "-",
- abi_tag);
- }
-
- return Strings::concat("0.0.0-", abi_tag);
-}
-
-std::string vcpkg::generate_nuspec(const VcpkgPaths& paths,
- const Dependencies::InstallPlanAction& action,
- const vcpkg::NugetReference& ref)
-{
- auto& spec = action.spec;
- auto& scf = *action.source_control_file_location.value_or_exit(VCPKG_LINE_INFO).source_control_file;
- auto& version = scf.core_paragraph->version;
- std::string description =
- Strings::concat("NOT FOR DIRECT USE. Automatically generated cache package.\n\n",
- Strings::join("\n ", scf.core_paragraph->description),
- "\n\nVersion: ",
- version,
- "\nTriplet/Compiler hash: ",
- action.abi_info.value_or_exit(VCPKG_LINE_INFO).triplet_abi.value_or_exit(VCPKG_LINE_INFO),
- "\nFeatures:",
- Strings::join(",", action.feature_list, [](const std::string& s) { return " " + s; }),
- "\nDependencies:\n");
-
- for (auto&& dep : action.package_dependencies)
- {
- Strings::append(description, " ", dep.name(), '\n');
- }
- XmlSerializer xml;
- xml.open_tag("package").line_break();
- xml.open_tag("metadata").line_break();
- xml.simple_tag("id", ref.id).line_break();
- xml.simple_tag("version", ref.version).line_break();
- if (!scf.core_paragraph->homepage.empty()) xml.simple_tag("projectUrl", scf.core_paragraph->homepage);
- xml.simple_tag("authors", "vcpkg").line_break();
- xml.simple_tag("description", description).line_break();
- xml.open_tag("packageTypes");
- xml.start_complex_open_tag("packageType").text_attr("name", "vcpkg").finish_self_closing_complex_tag();
- xml.close_tag("packageTypes").line_break();
- xml.close_tag("metadata").line_break();
- xml.open_tag("files");
- xml.start_complex_open_tag("file")
- .text_attr("src", (paths.package_dir(spec) / fs::u8path("**")).u8string())
- .text_attr("target", "")
- .finish_self_closing_complex_tag();
- xml.close_tag("files").line_break();
- xml.close_tag("package").line_break();
- return std::move(xml.buf);
-}
-
-void vcpkg::help_topic_binary_caching(const VcpkgPaths&)
-{
- HelpTableFormatter tbl;
- tbl.text("Vcpkg can cache compiled packages to accelerate restoration on a single machine or across the network."
- " This functionality is currently enabled by default and can be disabled by either passing "
- "`--no-binarycaching` to every vcpkg command line or setting the environment variable "
- "`VCPKG_FEATURE_FLAGS` to `-binarycaching`.");
- tbl.blank();
- tbl.blank();
- tbl.text(
- "Once caching is enabled, it can be further configured by either passing `--binarysource=<source>` options "
- "to every command line or setting the `VCPKG_BINARY_SOURCES` environment variable to a set of sources (Ex: "
- "\"<source>;<source>;...\"). Command line sources are interpreted after environment sources.");
- tbl.blank();
- tbl.blank();
- tbl.header("Valid source strings");
- tbl.format("clear", "Removes all previous sources");
- tbl.format("default[,<rw>]", "Adds the default file-based location.");
- tbl.format("files,<path>[,<rw>]", "Adds a custom file-based location.");
- tbl.format("nuget,<uri>[,<rw>]",
- "Adds a NuGet-based source; equivalent to the `-Source` parameter of the NuGet CLI.");
- tbl.format("nugetconfig,<path>[,<rw>]",
- "Adds a NuGet-config-file-based source; equivalent to the `-Config` parameter of the NuGet CLI. This "
- "config should specify `defaultPushSource` for uploads.");
- tbl.format("interactive", "Enables interactive credential management for some source types");
- tbl.blank();
- tbl.text("The `<rw>` optional parameter for certain strings controls whether they will be consulted for "
- "downloading binaries and whether on-demand builds will be uploaded to that remote. It can be specified "
- "as 'read', 'write', or 'readwrite'.");
- tbl.blank();
- System::print2(tbl.m_str);
- const auto& maybe_cachepath = default_cache_path();
- if (auto p = maybe_cachepath.get())
- {
- auto p_preferred = *p;
- System::print2(
- "\nBased on your system settings, the default path to store binaries is\n ",
- p_preferred.make_preferred().u8string(),
- "\n\nThis consults %LOCALAPPDATA%/%APPDATA% on Windows and $XDG_CACHE_HOME or $HOME on other platforms.");
- }
-}
-
-std::string vcpkg::generate_nuget_packages_config(const Dependencies::ActionPlan& action)
-{
- auto refs = Util::fmap(action.install_actions,
- [&](const Dependencies::InstallPlanAction& ipa) { return NugetReference(ipa); });
- XmlSerializer xml;
- xml.emit_declaration().line_break();
- xml.open_tag("packages").line_break();
- for (auto&& ref : refs)
- {
- xml.start_complex_open_tag("package")
- .text_attr("id", ref.id)
- .text_attr("version", ref.version)
- .finish_self_closing_complex_tag()
- .line_break();
- }
- xml.close_tag("packages").line_break();
- return std::move(xml.buf);
-}
+#include "pch.h"
+
+#include <vcpkg/base/checks.h>
+#include <vcpkg/base/files.h>
+#include <vcpkg/base/parse.h>
+#include <vcpkg/base/system.debug.h>
+#include <vcpkg/base/system.print.h>
+#include <vcpkg/base/system.process.h>
+
+#include <vcpkg/binarycaching.h>
+#include <vcpkg/binarycaching.private.h>
+#include <vcpkg/build.h>
+#include <vcpkg/dependencies.h>
+
+using namespace vcpkg;
+
+namespace
+{
+ static System::ExitCodeAndOutput 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);
+ fs.remove_all(pkg_path, VCPKG_LINE_INFO);
+ std::error_code 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&& seven_zip_exe = paths.get_tool_exe(Tools::SEVEN_ZIP);
+ auto cmd = Strings::format(
+ R"("%s" x "%s" -o"%s" -y)", seven_zip_exe.u8string(), archive_path.u8string(), pkg_path.u8string());
+#else
+ auto cmd = Strings::format(R"(unzip -qq "%s" "-d%s")", archive_path.u8string(), pkg_path.u8string());
+#endif
+ return System::cmd_execute_and_capture_output(cmd, System::get_clean_environment());
+ }
+
+ // Compress the source directory into the destination file.
+ static void compress_directory(const VcpkgPaths& paths, const fs::path& source, const fs::path& destination)
+ {
+ auto& fs = paths.get_filesystem();
+
+ std::error_code ec;
+
+ fs.remove(destination, ec);
+ Checks::check_exit(
+ VCPKG_LINE_INFO, !fs.exists(destination), "Could not remove file: %s", destination.u8string());
+#if defined(_WIN32)
+ auto&& seven_zip_exe = paths.get_tool_exe(Tools::SEVEN_ZIP);
+
+ System::cmd_execute_and_capture_output(
+ Strings::format(
+ R"("%s" a "%s" "%s\*")", seven_zip_exe.u8string(), destination.u8string(), source.u8string()),
+ System::get_clean_environment());
+#else
+ System::cmd_execute_clean(
+ Strings::format(R"(cd '%s' && zip --quiet -r '%s' *)", source.u8string(), destination.u8string()));
+#endif
+ }
+
+ struct ArchivesBinaryProvider : IBinaryProvider
+ {
+ ArchivesBinaryProvider(std::vector<fs::path>&& read_dirs, std::vector<fs::path>&& write_dirs)
+ : m_read_dirs(std::move(read_dirs)), m_write_dirs(std::move(write_dirs))
+ {
+ }
+ ~ArchivesBinaryProvider() = default;
+ void prefetch(const VcpkgPaths&, const Dependencies::ActionPlan&) override { }
+ RestoreResult try_restore(const VcpkgPaths& paths, const Dependencies::InstallPlanAction& action) override
+ {
+ const auto& abi_tag = action.abi_info.value_or_exit(VCPKG_LINE_INFO).package_abi;
+ auto& spec = action.spec;
+ auto& fs = paths.get_filesystem();
+ std::error_code ec;
+ for (auto&& archives_root_dir : m_read_dirs)
+ {
+ const std::string archive_name = abi_tag + ".zip";
+ const fs::path archive_subpath = fs::u8path(abi_tag.substr(0, 2)) / archive_name;
+ const fs::path archive_path = archives_root_dir / archive_subpath;
+ if (fs.exists(archive_path))
+ {
+ System::print2("Using cached binary package: ", archive_path.u8string(), "\n");
+
+ int archive_result = decompress_archive(paths, spec, archive_path).exit_code;
+
+ if (archive_result == 0)
+ {
+ return RestoreResult::success;
+ }
+ else
+ {
+ System::print2("Failed to decompress archive package\n");
+ if (action.build_options.purge_decompress_failure == Build::PurgeDecompressFailure::NO)
+ {
+ return RestoreResult::build_failed;
+ }
+ else
+ {
+ System::print2("Purging bad archive\n");
+ fs.remove(archive_path, ec);
+ }
+ }
+ }
+
+ System::printf("Could not locate cached archive: %s\n", archive_path.u8string());
+ }
+
+ return RestoreResult::missing;
+ }
+ void push_success(const VcpkgPaths& paths, const Dependencies::InstallPlanAction& action) override
+ {
+ if (m_write_dirs.empty()) return;
+ const auto& abi_tag = action.abi_info.value_or_exit(VCPKG_LINE_INFO).package_abi;
+ auto& spec = action.spec;
+ auto& fs = paths.get_filesystem();
+ const auto tmp_archive_path = paths.buildtrees / spec.name() / (spec.triplet().to_string() + ".zip");
+ compress_directory(paths, paths.package_dir(spec), tmp_archive_path);
+
+ for (auto&& m_directory : m_write_dirs)
+ {
+ const fs::path& archives_root_dir = m_directory;
+ const std::string archive_name = abi_tag + ".zip";
+ const fs::path archive_subpath = fs::u8path(abi_tag.substr(0, 2)) / archive_name;
+ const fs::path archive_path = archives_root_dir / archive_subpath;
+
+ fs.create_directories(archive_path.parent_path(), ignore_errors);
+ std::error_code ec;
+ if (m_write_dirs.size() > 1)
+ fs.copy_file(tmp_archive_path, archive_path, fs::copy_options::overwrite_existing, ec);
+ else
+ fs.rename_or_copy(tmp_archive_path, archive_path, ".tmp", ec);
+ if (ec)
+ {
+ System::printf(System::Color::warning,
+ "Failed to store binary cache %s: %s\n",
+ archive_path.u8string(),
+ ec.message());
+ }
+ else
+ System::printf("Stored binary cache: %s\n", archive_path.u8string());
+ }
+ if (m_write_dirs.size() > 1) fs.remove(tmp_archive_path, ignore_errors);
+ }
+ RestoreResult precheck(const VcpkgPaths& paths, const Dependencies::InstallPlanAction& action) override
+ {
+ const auto& abi_tag = action.abi_info.value_or_exit(VCPKG_LINE_INFO).package_abi;
+ auto& fs = paths.get_filesystem();
+ std::error_code ec;
+ for (auto&& archives_root_dir : m_read_dirs)
+ {
+ const std::string archive_name = abi_tag + ".zip";
+ const fs::path archive_subpath = fs::u8path(abi_tag.substr(0, 2)) / archive_name;
+ const fs::path archive_path = archives_root_dir / archive_subpath;
+
+ if (fs.exists(archive_path))
+ {
+ return RestoreResult::success;
+ }
+ }
+ return RestoreResult::missing;
+ }
+
+ private:
+ std::vector<fs::path> m_read_dirs, m_write_dirs;
+ };
+
+ static std::string trim_leading_zeroes(std::string v)
+ {
+ auto n = v.find_first_not_of('0');
+ if (n == std::string::npos)
+ {
+ v = "0";
+ }
+ else if (n > 0)
+ {
+ v.erase(0, n);
+ }
+ return v;
+ }
+
+ struct NugetBinaryProvider : IBinaryProvider
+ {
+ NugetBinaryProvider(std::vector<std::string>&& read_sources,
+ std::vector<std::string>&& write_sources,
+ std::vector<fs::path>&& read_configs,
+ std::vector<fs::path>&& write_configs,
+ bool interactive)
+ : m_read_sources(std::move(read_sources))
+ , m_write_sources(std::move(write_sources))
+ , m_read_configs(std::move(read_configs))
+ , m_write_configs(std::move(write_configs))
+ , m_interactive(interactive)
+ {
+ }
+ void prefetch(const VcpkgPaths& paths, const Dependencies::ActionPlan& plan) override
+ {
+ if (m_read_sources.empty() && m_read_configs.empty()) return;
+
+ auto& fs = paths.get_filesystem();
+
+ std::vector<std::pair<PackageSpec, NugetReference>> nuget_refs;
+
+ for (auto&& action : plan.install_actions)
+ {
+ if (action.build_options.editable == Build::Editable::YES) continue;
+
+ auto& spec = action.spec;
+ fs.remove_all(paths.package_dir(spec), VCPKG_LINE_INFO);
+
+ nuget_refs.emplace_back(spec, NugetReference(action));
+ }
+
+ if (nuget_refs.empty()) return;
+
+ System::print2("Attempting to fetch ", nuget_refs.size(), " packages from nuget.\n");
+
+ auto packages_config = paths.buildtrees / fs::u8path("packages.config");
+
+ auto generate_packages_config = [&] {
+ XmlSerializer xml;
+ xml.emit_declaration().line_break();
+ xml.open_tag("packages").line_break();
+
+ for (auto&& nuget_ref : nuget_refs)
+ xml.start_complex_open_tag("package")
+ .text_attr("id", nuget_ref.second.id)
+ .text_attr("version", nuget_ref.second.version)
+ .finish_self_closing_complex_tag()
+ .line_break();
+
+ xml.close_tag("packages").line_break();
+ paths.get_filesystem().write_contents(packages_config, xml.buf, VCPKG_LINE_INFO);
+ };
+
+ const auto& nuget_exe = paths.get_tool_exe("nuget");
+ std::vector<std::string> cmdlines;
+
+ if (!m_read_sources.empty())
+ {
+ // First check using all sources
+ System::CmdLineBuilder cmdline;
+#ifndef _WIN32
+ cmdline.path_arg(paths.get_tool_exe(Tools::MONO));
+#endif
+ cmdline.path_arg(nuget_exe)
+ .string_arg("install")
+ .path_arg(packages_config)
+ .string_arg("-OutputDirectory")
+ .path_arg(paths.packages)
+ .string_arg("-Source")
+ .string_arg(Strings::join(";", m_read_sources))
+ .string_arg("-ExcludeVersion")
+ .string_arg("-NoCache")
+ .string_arg("-PreRelease")
+ .string_arg("-DirectDownload")
+ .string_arg("-PackageSaveMode")
+ .string_arg("nupkg")
+ .string_arg("-Verbosity")
+ .string_arg("detailed")
+ .string_arg("-ForceEnglishOutput");
+ if (!m_interactive) cmdline.string_arg("-NonInteractive");
+ cmdlines.push_back(cmdline.extract());
+ }
+ for (auto&& cfg : m_read_configs)
+ {
+ // Then check using each config
+ System::CmdLineBuilder cmdline;
+#ifndef _WIN32
+ cmdline.path_arg(paths.get_tool_exe(Tools::MONO));
+#endif
+ cmdline.path_arg(nuget_exe)
+ .string_arg("install")
+ .path_arg(packages_config)
+ .string_arg("-OutputDirectory")
+ .path_arg(paths.packages)
+ .string_arg("-ConfigFile")
+ .path_arg(cfg)
+ .string_arg("-ExcludeVersion")
+ .string_arg("-NoCache")
+ .string_arg("-PreRelease")
+ .string_arg("-DirectDownload")
+ .string_arg("-PackageSaveMode")
+ .string_arg("nupkg")
+ .string_arg("-Verbosity")
+ .string_arg("detailed")
+ .string_arg("-ForceEnglishOutput");
+ if (!m_interactive) cmdline.string_arg("-NonInteractive");
+ cmdlines.push_back(cmdline.extract());
+ }
+
+ size_t num_restored = 0;
+
+ for (const auto& cmdline : cmdlines)
+ {
+ if (nuget_refs.empty()) break;
+
+ [&] {
+ generate_packages_config();
+ if (Debug::g_debugging)
+ System::cmd_execute(cmdline);
+ else
+ {
+ auto res = System::cmd_execute_and_capture_output(cmdline);
+ if (res.output.find("Authentication may require manual action.") != std::string::npos)
+ {
+ System::print2(
+ System::Color::warning,
+ "One or more NuGet credential providers requested manual action. Add the binary "
+ "source 'interactive' to allow interactivity.\n");
+ }
+ }
+ }();
+
+ Util::erase_remove_if(nuget_refs, [&](const std::pair<PackageSpec, NugetReference>& nuget_ref) -> bool {
+ auto nupkg_path = paths.package_dir(nuget_ref.first) / fs::u8path(nuget_ref.second.id + ".nupkg");
+ if (fs.exists(nupkg_path, ignore_errors))
+ {
+ fs.remove(nupkg_path, VCPKG_LINE_INFO);
+ Checks::check_exit(VCPKG_LINE_INFO,
+ !fs.exists(nupkg_path, ignore_errors),
+ "Unable to remove nupkg after restoring: %s",
+ nupkg_path.u8string());
+ m_restored.emplace(nuget_ref.first);
+ ++num_restored;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ });
+ }
+
+ System::print2("Restored ", num_restored, " packages. Use --debug for more information.\n");
+ }
+ RestoreResult try_restore(const VcpkgPaths&, const Dependencies::InstallPlanAction& action) override
+ {
+ if (Util::Sets::contains(m_restored, action.spec))
+ return RestoreResult::success;
+ else
+ return RestoreResult::missing;
+ }
+ void push_success(const VcpkgPaths& paths, const Dependencies::InstallPlanAction& action) override
+ {
+ if (m_write_sources.empty() && m_write_configs.empty()) return;
+ auto& spec = action.spec;
+
+ NugetReference nuget_ref(action);
+ auto nuspec_path = paths.buildtrees / spec.name() / (spec.triplet().to_string() + ".nuspec");
+ paths.get_filesystem().write_contents(
+ nuspec_path, generate_nuspec(paths, action, nuget_ref), VCPKG_LINE_INFO);
+
+ const auto& nuget_exe = paths.get_tool_exe("nuget");
+ System::CmdLineBuilder cmdline;
+#ifndef _WIN32
+ cmdline.path_arg(paths.get_tool_exe(Tools::MONO));
+#endif
+ cmdline.path_arg(nuget_exe)
+ .string_arg("pack")
+ .path_arg(nuspec_path)
+ .string_arg("-OutputDirectory")
+ .path_arg(paths.buildtrees)
+ .string_arg("-NoDefaultExcludes")
+ .string_arg("-ForceEnglishOutput");
+ if (!m_interactive) cmdline.string_arg("-NonInteractive");
+
+ auto pack_rc = [&] {
+ if (Debug::g_debugging)
+ return System::cmd_execute(cmdline);
+ else
+ return System::cmd_execute_and_capture_output(cmdline).exit_code;
+ }();
+
+ if (pack_rc != 0)
+ {
+ System::print2(System::Color::error, "Packing NuGet failed. Use --debug for more information.\n");
+ }
+ else
+ {
+ auto nupkg_path = paths.buildtrees / nuget_ref.nupkg_filename();
+ for (auto&& write_src : m_write_sources)
+ {
+ System::CmdLineBuilder cmd;
+#ifndef _WIN32
+ cmd.path_arg(paths.get_tool_exe(Tools::MONO));
+#endif
+ cmd.path_arg(nuget_exe)
+ .string_arg("push")
+ .path_arg(nupkg_path)
+ .string_arg("-ApiKey")
+ .string_arg("AzureDevOps")
+ .string_arg("-ForceEnglishOutput")
+ .string_arg("-Source")
+ .string_arg(write_src);
+ if (!m_interactive) cmd.string_arg("-NonInteractive");
+
+ System::print2("Uploading binaries for ", spec, " to NuGet source ", write_src, ".\n");
+
+ auto rc = [&] {
+ if (Debug::g_debugging)
+ return System::cmd_execute(cmd);
+ else
+ return System::cmd_execute_and_capture_output(cmd).exit_code;
+ }();
+
+ if (rc != 0)
+ {
+ System::print2(System::Color::error,
+ "Pushing NuGet to ",
+ write_src,
+ " failed. Use --debug for more information.\n");
+ }
+ }
+ for (auto&& write_cfg : m_write_configs)
+ {
+ System::CmdLineBuilder cmd;
+#ifndef _WIN32
+ cmd.path_arg(paths.get_tool_exe(Tools::MONO));
+#endif
+ cmd.path_arg(nuget_exe)
+ .string_arg("push")
+ .path_arg(nupkg_path)
+ .string_arg("-ApiKey")
+ .string_arg("AzureDevOps")
+ .string_arg("-ForceEnglishOutput")
+ .string_arg("-ConfigFile")
+ .path_arg(write_cfg);
+ if (!m_interactive) cmd.string_arg("-NonInteractive");
+
+ System::print2(
+ "Uploading binaries for ", spec, " using NuGet config ", write_cfg.u8string(), ".\n");
+
+ auto rc = [&] {
+ if (Debug::g_debugging)
+ return System::cmd_execute(cmd);
+ else
+ return System::cmd_execute_and_capture_output(cmd).exit_code;
+ }();
+
+ if (rc != 0)
+ {
+ System::print2(System::Color::error,
+ "Pushing NuGet with ",
+ write_cfg.u8string(),
+ " failed. Use --debug for more information.\n");
+ }
+ }
+ paths.get_filesystem().remove(nupkg_path, ignore_errors);
+ }
+ }
+ RestoreResult precheck(const VcpkgPaths&, const Dependencies::InstallPlanAction&) override
+ {
+ return RestoreResult::missing;
+ }
+
+ private:
+ std::vector<std::string> m_read_sources;
+ std::vector<std::string> m_write_sources;
+
+ std::vector<fs::path> m_read_configs;
+ std::vector<fs::path> m_write_configs;
+
+ std::set<PackageSpec> m_restored;
+ bool m_interactive;
+ };
+
+ struct MergeBinaryProviders : IBinaryProvider
+ {
+ explicit MergeBinaryProviders(std::vector<std::unique_ptr<IBinaryProvider>>&& providers)
+ : m_providers(std::move(providers))
+ {
+ }
+
+ void prefetch(const VcpkgPaths& paths, const Dependencies::ActionPlan& plan) override
+ {
+ for (auto&& provider : m_providers)
+ {
+ provider->prefetch(paths, plan);
+ }
+ }
+ RestoreResult try_restore(const VcpkgPaths& paths, const Dependencies::InstallPlanAction& action) override
+ {
+ for (auto&& provider : m_providers)
+ {
+ auto result = provider->try_restore(paths, action);
+ switch (result)
+ {
+ case RestoreResult::build_failed:
+ case RestoreResult::success: return result;
+ case RestoreResult::missing: continue;
+ default: Checks::unreachable(VCPKG_LINE_INFO);
+ }
+ }
+ return RestoreResult::missing;
+ }
+ void push_success(const VcpkgPaths& paths, const Dependencies::InstallPlanAction& action) override
+ {
+ for (auto&& provider : m_providers)
+ {
+ provider->push_success(paths, action);
+ }
+ }
+ RestoreResult precheck(const VcpkgPaths& paths, const Dependencies::InstallPlanAction& action) override
+ {
+ for (auto&& provider : m_providers)
+ {
+ auto result = provider->precheck(paths, action);
+ switch (result)
+ {
+ case RestoreResult::build_failed:
+ case RestoreResult::success: return result;
+ case RestoreResult::missing: continue;
+ default: Checks::unreachable(VCPKG_LINE_INFO);
+ }
+ }
+ return RestoreResult::missing;
+ }
+
+ private:
+ std::vector<std::unique_ptr<IBinaryProvider>> m_providers;
+ };
+
+ struct NullBinaryProvider : IBinaryProvider
+ {
+ void prefetch(const VcpkgPaths&, const Dependencies::ActionPlan&) override { }
+ RestoreResult try_restore(const VcpkgPaths&, const Dependencies::InstallPlanAction&) override
+ {
+ return RestoreResult::missing;
+ }
+ void push_success(const VcpkgPaths&, const Dependencies::InstallPlanAction&) override { }
+ RestoreResult precheck(const VcpkgPaths&, const Dependencies::InstallPlanAction&) override
+ {
+ return RestoreResult::missing;
+ }
+ };
+}
+
+XmlSerializer& XmlSerializer::emit_declaration()
+{
+ buf.append(R"(<?xml version="1.0" encoding="utf-8"?>)");
+ return *this;
+}
+XmlSerializer& XmlSerializer::open_tag(StringLiteral sl)
+{
+ emit_pending_indent();
+ Strings::append(buf, '<', sl, '>');
+ m_indent += 2;
+ return *this;
+}
+XmlSerializer& XmlSerializer::start_complex_open_tag(StringLiteral sl)
+{
+ emit_pending_indent();
+ Strings::append(buf, '<', sl);
+ m_indent += 2;
+ return *this;
+}
+XmlSerializer& XmlSerializer::text_attr(StringLiteral name, StringView content)
+{
+ if (m_pending_indent)
+ {
+ m_pending_indent = false;
+ buf.append(m_indent, ' ');
+ }
+ else
+ {
+ buf.push_back(' ');
+ }
+ Strings::append(buf, name, "=\"");
+ text(content);
+ Strings::append(buf, '"');
+ return *this;
+}
+XmlSerializer& XmlSerializer::finish_complex_open_tag()
+{
+ emit_pending_indent();
+ Strings::append(buf, '>');
+ return *this;
+}
+XmlSerializer& XmlSerializer::finish_self_closing_complex_tag()
+{
+ emit_pending_indent();
+ Strings::append(buf, "/>");
+ m_indent -= 2;
+ return *this;
+}
+XmlSerializer& XmlSerializer::close_tag(StringLiteral sl)
+{
+ m_indent -= 2;
+ emit_pending_indent();
+ Strings::append(buf, "</", sl, '>');
+ return *this;
+}
+XmlSerializer& XmlSerializer::text(StringView sv)
+{
+ emit_pending_indent();
+ for (auto ch : sv)
+ {
+ if (ch == '&')
+ {
+ buf.append("&amp;");
+ }
+ else if (ch == '<')
+ {
+ buf.append("&lt;");
+ }
+ else if (ch == '>')
+ {
+ buf.append("&gt;");
+ }
+ else if (ch == '"')
+ {
+ buf.append("&quot;");
+ }
+ else if (ch == '\'')
+ {
+ buf.append("&apos;");
+ }
+ else
+ {
+ buf.push_back(ch);
+ }
+ }
+ return *this;
+}
+XmlSerializer& XmlSerializer::simple_tag(StringLiteral tag, StringView content)
+{
+ return emit_pending_indent().open_tag(tag).text(content).close_tag(tag);
+}
+XmlSerializer& XmlSerializer::line_break()
+{
+ buf.push_back('\n');
+ m_pending_indent = true;
+ return *this;
+}
+XmlSerializer& XmlSerializer::emit_pending_indent()
+{
+ if (m_pending_indent)
+ {
+ m_pending_indent = false;
+ buf.append(m_indent, ' ');
+ }
+ return *this;
+}
+
+IBinaryProvider& vcpkg::null_binary_provider()
+{
+ static NullBinaryProvider p;
+ return p;
+}
+
+ExpectedS<std::unique_ptr<IBinaryProvider>> vcpkg::create_binary_provider_from_configs(View<std::string> args)
+{
+ std::string env_string = System::get_environment_variable("VCPKG_BINARY_SOURCES").value_or("");
+
+ return create_binary_provider_from_configs_pure(env_string, args);
+}
+namespace
+{
+ const ExpectedS<fs::path>& default_cache_path()
+ {
+ static auto cachepath = System::get_platform_cache_home().then([](fs::path p) -> ExpectedS<fs::path> {
+ p /= fs::u8path("vcpkg/archives");
+ if (p.is_absolute())
+ {
+ return {std::move(p), expected_left_tag};
+ }
+ else
+ {
+ return {"default path was not absolute: " + p.u8string(), expected_right_tag};
+ }
+ });
+ return cachepath;
+ }
+
+ struct State
+ {
+ bool m_cleared = false;
+ bool interactive = false;
+
+ std::vector<fs::path> archives_to_read;
+ std::vector<fs::path> archives_to_write;
+
+ std::vector<std::string> sources_to_read;
+ std::vector<std::string> sources_to_write;
+
+ std::vector<fs::path> configs_to_read;
+ std::vector<fs::path> configs_to_write;
+
+ void clear()
+ {
+ m_cleared = true;
+ interactive = false;
+ archives_to_read.clear();
+ archives_to_write.clear();
+ sources_to_read.clear();
+ sources_to_write.clear();
+ configs_to_read.clear();
+ configs_to_write.clear();
+ }
+ };
+
+ struct BinaryConfigParser : Parse::ParserBase
+ {
+ BinaryConfigParser(StringView text, StringView origin, State* state)
+ : Parse::ParserBase(text, origin), state(state)
+ {
+ }
+
+ State* state;
+
+ void parse()
+ {
+ while (!at_eof())
+ {
+ std::vector<std::pair<SourceLoc, std::string>> segments;
+
+ for (;;)
+ {
+ SourceLoc loc = cur_loc();
+ std::string segment;
+ for (;;)
+ {
+ auto n = match_until([](char32_t ch) { return ch == ',' || ch == '`' || ch == ';'; });
+ Strings::append(segment, n);
+ auto ch = cur();
+ if (ch == Unicode::end_of_file || ch == ',' || ch == ';')
+ break;
+ else if (ch == '`')
+ {
+ ch = next();
+ if (ch == Unicode::end_of_file)
+ add_error("unexpected eof: trailing unescaped backticks (`) are not allowed");
+ else
+ Unicode::utf8_append_code_point(segment, ch);
+ next();
+ }
+ else
+ Checks::unreachable(VCPKG_LINE_INFO);
+ }
+ segments.emplace_back(std::move(loc), std::move(segment));
+
+ auto ch = cur();
+ if (ch == Unicode::end_of_file || ch == ';')
+ break;
+ else if (ch == ',')
+ {
+ next();
+ continue;
+ }
+ else
+ Checks::unreachable(VCPKG_LINE_INFO);
+ }
+
+ if (segments.size() != 1 || !segments[0].second.empty()) handle_segments(std::move(segments));
+ segments.clear();
+ if (get_error()) return;
+ if (cur() == ';') next();
+ }
+ }
+
+ template<class T>
+ void handle_readwrite(std::vector<T>& read,
+ std::vector<T>& write,
+ T&& t,
+ const std::vector<std::pair<SourceLoc, std::string>>& segments,
+ size_t segment_idx)
+ {
+ if (segment_idx >= segments.size())
+ {
+ read.push_back(std::move(t));
+ return;
+ }
+
+ auto& mode = segments[segment_idx].second;
+
+ if (mode == "read")
+ {
+ read.push_back(std::move(t));
+ }
+ else if (mode == "write")
+ {
+ write.push_back(std::move(t));
+ }
+ else if (mode == "readwrite")
+ {
+ read.push_back(t);
+ write.push_back(std::move(t));
+ }
+ else
+ {
+ return add_error("unexpected argument: expected 'read', readwrite', or 'write'",
+ segments[segment_idx].first);
+ }
+ }
+
+ void handle_segments(std::vector<std::pair<SourceLoc, std::string>>&& segments)
+ {
+ if (segments.empty()) return;
+ if (segments[0].second == "clear")
+ {
+ if (segments.size() != 1)
+ return add_error("unexpected arguments: binary config 'clear' does not take arguments",
+ segments[1].first);
+ state->clear();
+ }
+ else if (segments[0].second == "files")
+ {
+ if (segments.size() < 2)
+ {
+ return add_error("expected arguments: binary config 'files' requires at least a path argument",
+ segments[0].first);
+ }
+
+ auto p = fs::u8path(segments[1].second);
+ if (!p.is_absolute())
+ {
+ return add_error("expected arguments: path arguments for binary config strings must be absolute",
+ segments[1].first);
+ }
+ handle_readwrite(state->archives_to_read, state->archives_to_write, std::move(p), segments, 2);
+ if (segments.size() > 3)
+ return add_error("unexpected arguments: binary config 'files' requires 1 or 2 arguments",
+ segments[3].first);
+ }
+ else if (segments[0].second == "interactive")
+ {
+ if (segments.size() > 1)
+ return add_error("unexpected arguments: binary config 'interactive' does not accept any arguments",
+ segments[1].first);
+ state->interactive = true;
+ }
+ else if (segments[0].second == "nugetconfig")
+ {
+ if (segments.size() < 2)
+ return add_error(
+ "expected arguments: binary config 'nugetconfig' requires at least a source argument",
+ segments[0].first);
+
+ auto p = fs::u8path(segments[1].second);
+ if (!p.is_absolute())
+ return add_error("expected arguments: path arguments for binary config strings must be absolute",
+ segments[1].first);
+ handle_readwrite(state->configs_to_read, state->configs_to_write, std::move(p), segments, 2);
+ if (segments.size() > 3)
+ return add_error("unexpected arguments: binary config 'nugetconfig' requires 1 or 2 arguments",
+ segments[3].first);
+ }
+ else if (segments[0].second == "nuget")
+ {
+ if (segments.size() < 2)
+ return add_error("expected arguments: binary config 'nuget' requires at least a source argument",
+ segments[0].first);
+
+ auto&& p = segments[1].second;
+ if (p.empty())
+ return add_error("unexpected arguments: binary config 'nuget' requires non-empty source");
+
+ handle_readwrite(state->sources_to_read, state->sources_to_write, std::move(p), segments, 2);
+ if (segments.size() > 3)
+ return add_error("unexpected arguments: binary config 'nuget' requires 1 or 2 arguments",
+ segments[3].first);
+ }
+ else if (segments[0].second == "default")
+ {
+ if (segments.size() > 2)
+ {
+ return add_error("unexpected arguments: binary config 'default' does not take more than 1 argument",
+ segments[0].first);
+ }
+
+ const auto& maybe_home = default_cache_path();
+ if (!maybe_home.has_value()) return add_error(maybe_home.error(), segments[0].first);
+
+ handle_readwrite(
+ state->archives_to_read, state->archives_to_write, fs::path(*maybe_home.get()), segments, 1);
+ }
+ else
+ {
+ return add_error(
+ "unknown binary provider type: valid providers are 'clear', 'default', 'nuget', 'nugetconfig', "
+ "'interactive', and 'files'",
+ segments[0].first);
+ }
+ }
+ };
+}
+
+ExpectedS<std::unique_ptr<IBinaryProvider>> vcpkg::create_binary_provider_from_configs_pure(
+ const std::string& env_string, View<std::string> args)
+{
+ State s;
+
+ BinaryConfigParser default_parser("default,readwrite", "<defaults>", &s);
+ default_parser.parse();
+
+ BinaryConfigParser env_parser(env_string, "VCPKG_BINARY_SOURCES", &s);
+ env_parser.parse();
+ if (auto err = env_parser.get_error()) return err->format();
+ for (auto&& arg : args)
+ {
+ BinaryConfigParser arg_parser(arg, "<command>", &s);
+ arg_parser.parse();
+ if (auto err = arg_parser.get_error()) return err->format();
+ }
+
+ std::vector<std::unique_ptr<IBinaryProvider>> providers;
+ if (!s.archives_to_read.empty() || !s.archives_to_write.empty())
+ providers.push_back(
+ std::make_unique<ArchivesBinaryProvider>(std::move(s.archives_to_read), std::move(s.archives_to_write)));
+ if (!s.sources_to_read.empty() || !s.sources_to_write.empty() || !s.configs_to_read.empty() ||
+ !s.configs_to_write.empty())
+ providers.push_back(std::make_unique<NugetBinaryProvider>(std::move(s.sources_to_read),
+ std::move(s.sources_to_write),
+ std::move(s.configs_to_read),
+ std::move(s.configs_to_write),
+ s.interactive));
+
+ return {std::make_unique<MergeBinaryProviders>(std::move(providers))};
+}
+
+std::string vcpkg::reformat_version(const std::string& version, const std::string& abi_tag)
+{
+ static const std::regex semver_matcher(R"(v?(\d+)(\.\d+|$)(\.\d+)?.*)");
+
+ std::smatch sm;
+ if (std::regex_match(version.cbegin(), version.cend(), sm, semver_matcher))
+ {
+ auto major = trim_leading_zeroes(sm.str(1));
+ auto minor = sm.size() > 2 && !sm.str(2).empty() ? trim_leading_zeroes(sm.str(2).substr(1)) : "0";
+ auto patch = sm.size() > 3 && !sm.str(3).empty() ? trim_leading_zeroes(sm.str(3).substr(1)) : "0";
+ return Strings::concat(major, '.', minor, '.', patch, "-", abi_tag);
+ }
+
+ static const std::regex date_matcher(R"((\d\d\d\d)-(\d\d)-(\d\d).*)");
+ if (std::regex_match(version.cbegin(), version.cend(), sm, date_matcher))
+ {
+ return Strings::concat(trim_leading_zeroes(sm.str(1)),
+ '.',
+ trim_leading_zeroes(sm.str(2)),
+ '.',
+ trim_leading_zeroes(sm.str(3)),
+ "-",
+ abi_tag);
+ }
+
+ return Strings::concat("0.0.0-", abi_tag);
+}
+
+std::string vcpkg::generate_nuspec(const VcpkgPaths& paths,
+ const Dependencies::InstallPlanAction& action,
+ const vcpkg::NugetReference& ref)
+{
+ auto& spec = action.spec;
+ auto& scf = *action.source_control_file_location.value_or_exit(VCPKG_LINE_INFO).source_control_file;
+ auto& version = scf.core_paragraph->version;
+ std::string description =
+ Strings::concat("NOT FOR DIRECT USE. Automatically generated cache package.\n\n",
+ Strings::join("\n ", scf.core_paragraph->description),
+ "\n\nVersion: ",
+ version,
+ "\nTriplet/Compiler hash: ",
+ action.abi_info.value_or_exit(VCPKG_LINE_INFO).triplet_abi.value_or_exit(VCPKG_LINE_INFO),
+ "\nFeatures:",
+ Strings::join(",", action.feature_list, [](const std::string& s) { return " " + s; }),
+ "\nDependencies:\n");
+
+ for (auto&& dep : action.package_dependencies)
+ {
+ Strings::append(description, " ", dep.name(), '\n');
+ }
+ XmlSerializer xml;
+ xml.open_tag("package").line_break();
+ xml.open_tag("metadata").line_break();
+ xml.simple_tag("id", ref.id).line_break();
+ xml.simple_tag("version", ref.version).line_break();
+ if (!scf.core_paragraph->homepage.empty()) xml.simple_tag("projectUrl", scf.core_paragraph->homepage);
+ xml.simple_tag("authors", "vcpkg").line_break();
+ xml.simple_tag("description", description).line_break();
+ xml.open_tag("packageTypes");
+ xml.start_complex_open_tag("packageType").text_attr("name", "vcpkg").finish_self_closing_complex_tag();
+ xml.close_tag("packageTypes").line_break();
+ xml.close_tag("metadata").line_break();
+ xml.open_tag("files");
+ xml.start_complex_open_tag("file")
+ .text_attr("src", (paths.package_dir(spec) / fs::u8path("**")).u8string())
+ .text_attr("target", "")
+ .finish_self_closing_complex_tag();
+ xml.close_tag("files").line_break();
+ xml.close_tag("package").line_break();
+ return std::move(xml.buf);
+}
+
+void vcpkg::help_topic_binary_caching(const VcpkgPaths&)
+{
+ HelpTableFormatter tbl;
+ tbl.text("Vcpkg can cache compiled packages to accelerate restoration on a single machine or across the network."
+ " This functionality is currently enabled by default and can be disabled by either passing "
+ "`--no-binarycaching` to every vcpkg command line or setting the environment variable "
+ "`VCPKG_FEATURE_FLAGS` to `-binarycaching`.");
+ tbl.blank();
+ tbl.blank();
+ tbl.text(
+ "Once caching is enabled, it can be further configured by either passing `--binarysource=<source>` options "
+ "to every command line or setting the `VCPKG_BINARY_SOURCES` environment variable to a set of sources (Ex: "
+ "\"<source>;<source>;...\"). Command line sources are interpreted after environment sources.");
+ tbl.blank();
+ tbl.blank();
+ tbl.header("Valid source strings");
+ tbl.format("clear", "Removes all previous sources");
+ tbl.format("default[,<rw>]", "Adds the default file-based location.");
+ tbl.format("files,<path>[,<rw>]", "Adds a custom file-based location.");
+ tbl.format("nuget,<uri>[,<rw>]",
+ "Adds a NuGet-based source; equivalent to the `-Source` parameter of the NuGet CLI.");
+ tbl.format("nugetconfig,<path>[,<rw>]",
+ "Adds a NuGet-config-file-based source; equivalent to the `-Config` parameter of the NuGet CLI. This "
+ "config should specify `defaultPushSource` for uploads.");
+ tbl.format("interactive", "Enables interactive credential management for some source types");
+ tbl.blank();
+ tbl.text("The `<rw>` optional parameter for certain strings controls whether they will be consulted for "
+ "downloading binaries and whether on-demand builds will be uploaded to that remote. It can be specified "
+ "as 'read', 'write', or 'readwrite'.");
+ tbl.blank();
+ System::print2(tbl.m_str);
+ const auto& maybe_cachepath = default_cache_path();
+ if (auto p = maybe_cachepath.get())
+ {
+ auto p_preferred = *p;
+ System::print2(
+ "\nBased on your system settings, the default path to store binaries is\n ",
+ p_preferred.make_preferred().u8string(),
+ "\n\nThis consults %LOCALAPPDATA%/%APPDATA% on Windows and $XDG_CACHE_HOME or $HOME on other platforms.");
+ }
+}
+
+std::string vcpkg::generate_nuget_packages_config(const Dependencies::ActionPlan& action)
+{
+ auto refs = Util::fmap(action.install_actions,
+ [&](const Dependencies::InstallPlanAction& ipa) { return NugetReference(ipa); });
+ XmlSerializer xml;
+ xml.emit_declaration().line_break();
+ xml.open_tag("packages").line_break();
+ for (auto&& ref : refs)
+ {
+ xml.start_complex_open_tag("package")
+ .text_attr("id", ref.id)
+ .text_attr("version", ref.version)
+ .finish_self_closing_complex_tag()
+ .line_break();
+ }
+ xml.close_tag("packages").line_break();
+ return std::move(xml.buf);
+}
diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp
index 70d097873..147ad46b2 100644
--- a/toolsrc/src/vcpkg/build.cpp
+++ b/toolsrc/src/vcpkg/build.cpp
@@ -1,1263 +1,1263 @@
-#include "pch.h"
-
-#include <vcpkg/base/cache.h>
-#include <vcpkg/base/checks.h>
-#include <vcpkg/base/chrono.h>
-#include <vcpkg/base/enums.h>
-#include <vcpkg/base/hash.h>
-#include <vcpkg/base/optional.h>
-#include <vcpkg/base/stringliteral.h>
-#include <vcpkg/base/system.debug.h>
-#include <vcpkg/base/system.print.h>
-#include <vcpkg/base/system.process.h>
-#include <vcpkg/base/util.h>
-
-#include <vcpkg/binarycaching.h>
-#include <vcpkg/build.h>
-#include <vcpkg/buildenvironment.h>
-#include <vcpkg/commands.h>
-#include <vcpkg/dependencies.h>
-#include <vcpkg/globalstate.h>
-#include <vcpkg/help.h>
-#include <vcpkg/input.h>
-#include <vcpkg/metrics.h>
-#include <vcpkg/paragraphs.h>
-#include <vcpkg/postbuildlint.h>
-#include <vcpkg/statusparagraphs.h>
-#include <vcpkg/vcpkglib.h>
-
-using namespace vcpkg;
-using vcpkg::Build::BuildResult;
-using vcpkg::Parse::ParseControlErrorInfo;
-using vcpkg::Parse::ParseExpected;
-using vcpkg::PortFileProvider::PathsPortFileProvider;
-
-namespace
-{
- using vcpkg::PackageSpec;
- using vcpkg::VcpkgPaths;
- using vcpkg::Build::IBuildLogsRecorder;
- struct NullBuildLogsRecorder final : IBuildLogsRecorder
- {
- void record_build_result(const VcpkgPaths& paths, const PackageSpec& spec, BuildResult result) const override
- {
- (void)paths;
- (void)spec;
- (void)result;
- }
- };
-
- static const NullBuildLogsRecorder null_build_logs_recorder_instance;
-}
-
-namespace vcpkg::Build
-{
- using Dependencies::InstallPlanAction;
- using Dependencies::InstallPlanType;
-
- void Command::perform_and_exit_ex(const FullPackageSpec& full_spec,
- const SourceControlFileLocation& scfl,
- const PathsPortFileProvider& provider,
- IBinaryProvider& binaryprovider,
- const IBuildLogsRecorder& build_logs_recorder,
- const VcpkgPaths& paths)
- {
- Checks::exit_with_code(VCPKG_LINE_INFO,
- perform_ex(full_spec, scfl, provider, binaryprovider, build_logs_recorder, paths));
- }
-
- const CommandStructure COMMAND_STRUCTURE = {
- create_example_string("build zlib:x64-windows"),
- 1,
- 1,
- {{}, {}},
- nullptr,
- };
-
- void Command::perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, Triplet default_triplet)
- {
- Checks::exit_with_code(VCPKG_LINE_INFO, perform(args, paths, default_triplet));
- }
-
- int Command::perform_ex(const FullPackageSpec& full_spec,
- const SourceControlFileLocation& scfl,
- const PathsPortFileProvider& provider,
- IBinaryProvider& binaryprovider,
- const IBuildLogsRecorder& build_logs_recorder,
- const VcpkgPaths& paths)
- {
- auto var_provider_storage = CMakeVars::make_triplet_cmake_var_provider(paths);
- auto& var_provider = *var_provider_storage;
- var_provider.load_dep_info_vars(std::array<PackageSpec, 1>{full_spec.package_spec});
-
- StatusParagraphs status_db = database_load_check(paths);
-
- auto action_plan = Dependencies::create_feature_install_plan(
- provider, var_provider, std::vector<FullPackageSpec>{full_spec}, status_db);
-
- var_provider.load_tag_vars(action_plan, provider);
-
- const PackageSpec& spec = full_spec.package_spec;
- const SourceControlFile& scf = *scfl.source_control_file;
-
- Checks::check_exit(VCPKG_LINE_INFO,
- spec.name() == scf.core_paragraph->name,
- "The Source field inside the CONTROL file does not match the port directory: '%s' != '%s'",
- scf.core_paragraph->name,
- spec.name());
-
- compute_all_abis(paths, action_plan, var_provider, status_db);
-
- InstallPlanAction* action = nullptr;
- for (auto& install_action : action_plan.already_installed)
- {
- if (install_action.spec == full_spec.package_spec)
- {
- action = &install_action;
- }
- }
- for (auto& install_action : action_plan.install_actions)
- {
- if (install_action.spec == full_spec.package_spec)
- {
- action = &install_action;
- }
- }
-
- Checks::check_exit(VCPKG_LINE_INFO, action != nullptr);
- ASSUME(action != nullptr);
- action->build_options = default_build_package_options;
- action->build_options.editable = Editable::YES;
- action->build_options.clean_buildtrees = CleanBuildtrees::NO;
- action->build_options.clean_packages = CleanPackages::NO;
-
- const auto build_timer = Chrono::ElapsedTimer::create_started();
- const auto result = Build::build_package(paths, *action, binaryprovider, build_logs_recorder, status_db);
- System::print2("Elapsed time for package ", spec, ": ", build_timer, '\n');
-
- if (result.code == BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES)
- {
- System::print2(System::Color::error,
- "The build command requires all dependencies to be already installed.\n");
- System::print2("The following dependencies are missing:\n\n");
- for (const auto& p : result.unmet_dependencies)
- {
- System::print2(" ", p, '\n');
- }
- System::print2('\n');
- Checks::exit_fail(VCPKG_LINE_INFO);
- }
-
- Checks::check_exit(VCPKG_LINE_INFO, result.code != BuildResult::EXCLUDED);
-
- if (result.code != BuildResult::SUCCEEDED)
- {
- System::print2(System::Color::error, Build::create_error_message(result.code, spec), '\n');
- System::print2(Build::create_user_troubleshooting_message(spec), '\n');
- return 1;
- }
-
- return 0;
- }
-
- int Command::perform(const VcpkgCmdArguments& args, const VcpkgPaths& paths, Triplet default_triplet)
- {
- // Build only takes a single package and all dependencies must already be installed
- const ParsedArguments options = args.parse_arguments(COMMAND_STRUCTURE);
- std::string first_arg = args.command_arguments.at(0);
-
- auto binaryprovider = create_binary_provider_from_configs(args.binary_sources).value_or_exit(VCPKG_LINE_INFO);
-
- const FullPackageSpec spec = Input::check_and_get_full_package_spec(
- std::move(first_arg), default_triplet, COMMAND_STRUCTURE.example_text);
-
- Input::check_triplet(spec.package_spec.triplet(), paths);
-
- PathsPortFileProvider provider(paths, args.overlay_ports);
- const auto port_name = spec.package_spec.name();
- const auto* scfl = provider.get_control_file(port_name).get();
-
- Checks::check_exit(VCPKG_LINE_INFO, scfl != nullptr, "Error: Couldn't find port '%s'", port_name);
- ASSUME(scfl != nullptr);
-
- return perform_ex(spec,
- *scfl,
- provider,
- args.binary_caching_enabled() ? *binaryprovider : null_binary_provider(),
- Build::null_build_logs_recorder(),
- paths);
- }
-}
-
-namespace vcpkg::Build
-{
- static const std::string NAME_EMPTY_PACKAGE = "PolicyEmptyPackage";
- static const std::string NAME_DLLS_WITHOUT_LIBS = "PolicyDLLsWithoutLIBs";
- static const std::string NAME_DLLS_WITHOUT_EXPORTS = "PolicyDLLsWithoutExports";
- static const std::string NAME_ONLY_RELEASE_CRT = "PolicyOnlyReleaseCRT";
- static const std::string NAME_EMPTY_INCLUDE_FOLDER = "PolicyEmptyIncludeFolder";
- static const std::string NAME_ALLOW_OBSOLETE_MSVCRT = "PolicyAllowObsoleteMsvcrt";
- static const std::string NAME_ALLOW_RESTRICTED_HEADERS = "PolicyAllowRestrictedHeaders";
- static const std::string NAME_SKIP_DUMPBIN_CHECKS = "PolicySkipDumpbinChecks";
- static const std::string NAME_SKIP_ARCHITECTURE_CHECK = "PolicySkipArchitectureCheck";
-
- const std::string& to_string(BuildPolicy policy)
- {
- switch (policy)
- {
- case BuildPolicy::EMPTY_PACKAGE: return NAME_EMPTY_PACKAGE;
- case BuildPolicy::DLLS_WITHOUT_LIBS: return NAME_DLLS_WITHOUT_LIBS;
- case BuildPolicy::DLLS_WITHOUT_EXPORTS: return NAME_DLLS_WITHOUT_EXPORTS;
- case BuildPolicy::ONLY_RELEASE_CRT: return NAME_ONLY_RELEASE_CRT;
- case BuildPolicy::EMPTY_INCLUDE_FOLDER: return NAME_EMPTY_INCLUDE_FOLDER;
- case BuildPolicy::ALLOW_OBSOLETE_MSVCRT: return NAME_ALLOW_OBSOLETE_MSVCRT;
- case BuildPolicy::ALLOW_RESTRICTED_HEADERS: return NAME_ALLOW_RESTRICTED_HEADERS;
- case BuildPolicy::SKIP_DUMPBIN_CHECKS: return NAME_SKIP_DUMPBIN_CHECKS;
- case BuildPolicy::SKIP_ARCHITECTURE_CHECK: return NAME_SKIP_ARCHITECTURE_CHECK;
- default: Checks::unreachable(VCPKG_LINE_INFO);
- }
- }
-
- CStringView to_cmake_variable(BuildPolicy policy)
- {
- switch (policy)
- {
- case BuildPolicy::EMPTY_PACKAGE: return "VCPKG_POLICY_EMPTY_PACKAGE";
- case BuildPolicy::DLLS_WITHOUT_LIBS: return "VCPKG_POLICY_DLLS_WITHOUT_LIBS";
- case BuildPolicy::DLLS_WITHOUT_EXPORTS: return "VCPKG_POLICY_DLLS_WITHOUT_EXPORTS";
- case BuildPolicy::ONLY_RELEASE_CRT: return "VCPKG_POLICY_ONLY_RELEASE_CRT";
- case BuildPolicy::EMPTY_INCLUDE_FOLDER: return "VCPKG_POLICY_EMPTY_INCLUDE_FOLDER";
- case BuildPolicy::ALLOW_OBSOLETE_MSVCRT: return "VCPKG_POLICY_ALLOW_OBSOLETE_MSVCRT";
- case BuildPolicy::ALLOW_RESTRICTED_HEADERS: return "VCPKG_POLICY_ALLOW_RESTRICTED_HEADERS";
- case BuildPolicy::SKIP_DUMPBIN_CHECKS: return "VCPKG_POLICY_SKIP_DUMPBIN_CHECKS";
- case BuildPolicy::SKIP_ARCHITECTURE_CHECK: return "VCPKG_POLICY_SKIP_ARCHITECTURE_CHECK";
- default: Checks::unreachable(VCPKG_LINE_INFO);
- }
- }
-
- 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;
- if (str == "static") return LinkageType::STATIC;
- return nullopt;
- }
-
- namespace BuildInfoRequiredField
- {
- static const std::string CRT_LINKAGE = "CRTLinkage";
- static const std::string LIBRARY_LINKAGE = "LibraryLinkage";
- }
-
- static CStringView to_vcvarsall_target(const std::string& cmake_system_name)
- {
- if (cmake_system_name.empty()) return "";
- if (cmake_system_name == "Windows") return "";
- if (cmake_system_name == "WindowsStore") return "store";
-
- Checks::exit_with_message(VCPKG_LINE_INFO, "Unsupported vcvarsall target %s", cmake_system_name);
- }
-
- static CStringView to_vcvarsall_toolchain(const std::string& target_architecture, const Toolset& toolset)
- {
- auto maybe_target_arch = System::to_cpu_architecture(target_architecture);
- Checks::check_exit(
- VCPKG_LINE_INFO, maybe_target_arch.has_value(), "Invalid architecture string: %s", target_architecture);
- auto target_arch = maybe_target_arch.value_or_exit(VCPKG_LINE_INFO);
- auto host_architectures = System::get_supported_host_architectures();
-
- for (auto&& host : host_architectures)
- {
- 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. Target was: %s but supported ones were:\n%s",
- target_architecture,
- Strings::join(",", toolset.supported_architectures, [](const ToolsetArchOption& t) {
- return t.name.c_str();
- }));
- }
-
- const System::Environment& EnvCache::get_action_env(const VcpkgPaths& paths, const AbiInfo& abi_info)
- {
-#if defined(_WIN32)
- std::string build_env_cmd =
- make_build_env_cmd(*abi_info.pre_build_info, abi_info.toolset.value_or_exit(VCPKG_LINE_INFO));
-
- const auto& base_env = envs.get_lazy(abi_info.pre_build_info->passthrough_env_vars, [&]() -> EnvMapEntry {
- std::unordered_map<std::string, std::string> env;
-
- for (auto&& env_var : abi_info.pre_build_info->passthrough_env_vars)
- {
- auto env_val = System::get_environment_variable(env_var);
-
- if (env_val)
- {
- env[env_var] = env_val.value_or_exit(VCPKG_LINE_INFO);
- }
- }
-
- return {env};
- });
-
- return base_env.cmd_cache.get_lazy(build_env_cmd, [&]() {
- const fs::path& powershell_exe_path = paths.get_tool_exe("powershell-core");
- auto& fs = paths.get_filesystem();
- if (!fs.exists(powershell_exe_path.parent_path() / "powershell.exe"))
- {
- fs.copy(
- powershell_exe_path, powershell_exe_path.parent_path() / "powershell.exe", fs::copy_options::none);
- }
-
- auto clean_env = System::get_modified_clean_environment(base_env.env_map,
- powershell_exe_path.parent_path().u8string() + ";");
- if (build_env_cmd.empty())
- return clean_env;
- else
- return System::cmd_execute_modify_env(build_env_cmd, clean_env);
- });
-#else
- return System::get_clean_environment();
-#endif
- }
-
- static std::string load_compiler_hash(const VcpkgPaths& paths, const AbiInfo& abi_info);
-
- const std::string& EnvCache::get_triplet_info(const VcpkgPaths& paths, const AbiInfo& abi_info)
- {
- const auto& fs = paths.get_filesystem();
- Checks::check_exit(VCPKG_LINE_INFO, abi_info.pre_build_info != nullptr);
- const fs::path triplet_file_path = paths.get_triplet_file_path(abi_info.pre_build_info->triplet);
-
- auto tcfile = abi_info.pre_build_info->toolchain_file();
- auto&& toolchain_hash = m_toolchain_cache.get_lazy(
- tcfile, [&]() { return Hash::get_file_hash(VCPKG_LINE_INFO, fs, tcfile, Hash::Algorithm::Sha1); });
-
- auto&& triplet_entry = m_triplet_cache.get_lazy(triplet_file_path, [&]() -> TripletMapEntry {
- return TripletMapEntry{Hash::get_file_hash(VCPKG_LINE_INFO, fs, triplet_file_path, Hash::Algorithm::Sha1)};
- });
-
- return triplet_entry.compiler_hashes.get_lazy(toolchain_hash, [&]() -> std::string {
- if (m_compiler_tracking)
- {
- auto compiler_hash = load_compiler_hash(paths, abi_info);
- return Strings::concat(triplet_entry.hash, '-', toolchain_hash, '-', compiler_hash);
- }
- else
- {
- return triplet_entry.hash + "-" + toolchain_hash;
- }
- });
- }
-
- std::string make_build_env_cmd(const PreBuildInfo& pre_build_info, const Toolset& toolset)
- {
- if (!pre_build_info.using_vcvars()) return "";
-
- const char* tonull = " >nul";
- if (Debug::g_debugging)
- {
- tonull = "";
- }
-
- const auto arch = to_vcvarsall_toolchain(pre_build_info.target_architecture, toolset);
- const auto target = to_vcvarsall_target(pre_build_info.cmake_system_name);
-
- return Strings::format(R"(cmd /c ""%s" %s %s %s %s 2>&1 <NUL")",
- toolset.vcvarsall.u8string(),
- Strings::join(" ", toolset.vcvarsall_options),
- arch,
- target,
- tonull);
- }
-
- static std::unique_ptr<BinaryControlFile> create_binary_control_file(
- const SourceParagraph& source_paragraph,
- Triplet triplet,
- const BuildInfo& build_info,
- const std::string& abi_tag,
- const std::vector<FeatureSpec>& core_dependencies)
- {
- auto bcf = std::make_unique<BinaryControlFile>();
- BinaryParagraph bpgh(source_paragraph, triplet, abi_tag, core_dependencies);
- if (const auto p_ver = build_info.version.get())
- {
- bpgh.version = *p_ver;
- }
-
- bcf->core_paragraph = std::move(bpgh);
- return bcf;
- }
-
- static void write_binary_control_file(const VcpkgPaths& paths, const BinaryControlFile& bcf)
- {
- std::string start = Strings::serialize(bcf.core_paragraph);
- for (auto&& feature : bcf.features)
- {
- start += "\n" + Strings::serialize(feature);
- }
- const fs::path binary_control_file = paths.packages / bcf.core_paragraph.dir() / fs::u8path("CONTROL");
- paths.get_filesystem().write_contents(binary_control_file, start, VCPKG_LINE_INFO);
- }
-
- static int get_concurrency()
- {
- static int concurrency = [] {
- auto user_defined_concurrency = System::get_environment_variable("VCPKG_MAX_CONCURRENCY");
- if (user_defined_concurrency)
- {
- return std::stoi(user_defined_concurrency.value_or_exit(VCPKG_LINE_INFO));
- }
- else
- {
- return System::get_num_logical_cores() + 1;
- }
- }();
-
- return concurrency;
- }
-
- static void get_generic_cmake_build_args(const VcpkgPaths& paths,
- Triplet triplet,
- const Toolset& toolset,
- std::vector<System::CMakeVariable>& out_vars)
- {
- Util::Vectors::append(&out_vars,
- std::initializer_list<System::CMakeVariable>{
- {"CMD", "BUILD"},
- {"TARGET_TRIPLET", triplet.canonical_name()},
- {"TARGET_TRIPLET_FILE", paths.get_triplet_file_path(triplet).u8string()},
- {"VCPKG_PLATFORM_TOOLSET", toolset.version.c_str()},
- {"DOWNLOADS", paths.downloads},
- {"VCPKG_CONCURRENCY", std::to_string(get_concurrency())},
- });
- if (!System::get_environment_variable("VCPKG_FORCE_SYSTEM_BINARIES").has_value())
- {
- const fs::path& git_exe_path = paths.get_tool_exe(Tools::GIT);
- out_vars.push_back({"GIT", git_exe_path});
- }
- }
-
- static std::string load_compiler_hash(const VcpkgPaths& paths, const AbiInfo& abi_info)
- {
- auto triplet = abi_info.pre_build_info->triplet;
- System::print2("Detecting compiler hash for triplet ", triplet, "...\n");
- auto buildpath = paths.buildtrees / "detect_compiler";
-
-#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<System::CMakeVariable> cmake_args{
- {"CURRENT_PORT_DIR", paths.scripts / "detect_compiler"},
- {"CURRENT_BUILDTREES_DIR", buildpath},
- {"CURRENT_PACKAGES_DIR", paths.packages / ("detect_compiler_" + triplet.canonical_name())},
- };
- get_generic_cmake_build_args(paths, triplet, abi_info.toolset.value_or_exit(VCPKG_LINE_INFO), cmake_args);
-
- auto command = vcpkg::make_cmake_cmd(paths, paths.ports_cmake, std::move(cmake_args));
-
- const auto& env = paths.get_action_env(abi_info);
- auto& fs = paths.get_filesystem();
- if (!fs.exists(buildpath))
- {
- std::error_code err;
- fs.create_directory(buildpath, err);
- Checks::check_exit(VCPKG_LINE_INFO,
- !err.value(),
- "Failed to create directory '%s', code: %d",
- buildpath.u8string(),
- err.value());
- }
- auto stdoutlog = buildpath / ("stdout-" + triplet.canonical_name() + ".log");
- std::ofstream out_file(stdoutlog.native().c_str(), std::ios::out | std::ios::binary | std::ios::trunc);
- Checks::check_exit(VCPKG_LINE_INFO, out_file, "Failed to open '%s' for writing", stdoutlog.u8string());
- std::string compiler_hash;
- const int return_code = System::cmd_execute_and_stream_lines(
- command,
- [&](const std::string& s) {
- static const StringLiteral s_marker = "#COMPILER_HASH#";
- if (Strings::starts_with(s, s_marker))
- {
- compiler_hash = s.data() + s_marker.size();
- }
- Debug::print(s, '\n');
- out_file.write(s.data(), s.size()).put('\n');
- Checks::check_exit(
- VCPKG_LINE_INFO, out_file, "Error occurred while writing '%s'", stdoutlog.u8string());
- },
- env);
- out_file.close();
-
- if (compiler_hash.empty())
- {
- Debug::print("Compiler information tracking can be disabled by passing --",
- VcpkgCmdArguments::FEATURE_FLAGS_ARG,
- "=-",
- VcpkgCmdArguments::COMPILER_TRACKING_FEATURE,
- "\n");
- }
- Checks::check_exit(VCPKG_LINE_INFO,
- !compiler_hash.empty(),
- "Error occured while detecting compiler information. Pass `--debug` for more information.");
-
- Debug::print("Detecting compiler hash for triplet ", triplet, ": ", compiler_hash, "\n");
- return compiler_hash;
- }
-
- static std::vector<System::CMakeVariable> get_cmake_build_args(const VcpkgPaths& paths,
- const Dependencies::InstallPlanAction& action,
- Triplet triplet)
- {
-#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
- auto& scfl = action.source_control_file_location.value_or_exit(VCPKG_LINE_INFO);
- auto& scf = *scfl.source_control_file;
-
- std::string all_features;
- for (auto& feature : scf.feature_paragraphs)
- {
- all_features.append(feature->name + ";");
- }
-
- std::vector<System::CMakeVariable> variables{
- {"PORT", scf.core_paragraph->name},
- {"CURRENT_PORT_DIR", scfl.source_location},
- {"VCPKG_USE_HEAD_VERSION", Util::Enum::to_bool(action.build_options.use_head_version) ? "1" : "0"},
- {"_VCPKG_NO_DOWNLOADS", !Util::Enum::to_bool(action.build_options.allow_downloads) ? "1" : "0"},
- {"_VCPKG_DOWNLOAD_TOOL", to_string(action.build_options.download_tool)},
- {"_VCPKG_EDITABLE", Util::Enum::to_bool(action.build_options.editable) ? "1" : "0"},
- {"FEATURES", Strings::join(";", action.feature_list)},
- {"ALL_FEATURES", all_features},
- };
- get_generic_cmake_build_args(
- paths,
- triplet,
- action.abi_info.value_or_exit(VCPKG_LINE_INFO).toolset.value_or_exit(VCPKG_LINE_INFO),
- variables);
-
- if (Util::Enum::to_bool(action.build_options.only_downloads))
- {
- variables.push_back({"VCPKG_DOWNLOAD_MODE", "true"});
- }
-
- const Files::Filesystem& fs = paths.get_filesystem();
-
- std::vector<std::string> port_configs;
- for (const PackageSpec& dependency : action.package_dependencies)
- {
- const fs::path port_config_path = paths.installed / fs::u8path(dependency.triplet().canonical_name()) /
- fs::u8path("share") / fs::u8path(dependency.name()) /
- fs::u8path("vcpkg-port-config.cmake");
-
- if (fs.is_regular_file(port_config_path))
- {
- port_configs.emplace_back(port_config_path.u8string());
- }
- }
-
- if (!port_configs.empty())
- {
- variables.emplace_back("VCPKG_PORT_CONFIGS", Strings::join(";", port_configs));
- }
-
- return variables;
- }
-
- bool PreBuildInfo::using_vcvars() const
- {
- return (!external_toolchain_file.has_value() || load_vcvars_env) &&
- (cmake_system_name.empty() || cmake_system_name == "WindowsStore");
- }
-
- fs::path PreBuildInfo::toolchain_file() const
- {
- if (auto p = external_toolchain_file.get())
- {
- return fs::u8path(*p);
- }
- else if (cmake_system_name == "Linux")
- {
- return m_paths.scripts / fs::u8path("toolchains/linux.cmake");
- }
- else if (cmake_system_name == "Darwin")
- {
- return m_paths.scripts / fs::u8path("toolchains/osx.cmake");
- }
- else if (cmake_system_name == "FreeBSD")
- {
- return m_paths.scripts / fs::u8path("toolchains/freebsd.cmake");
- }
- else if (cmake_system_name == "Android")
- {
- return m_paths.scripts / fs::u8path("toolchains/android.cmake");
- }
- else if (cmake_system_name == "iOS")
- {
- return m_paths.scripts / fs::u8path("toolchains/ios.cmake");
- }
- else if (cmake_system_name.empty() || cmake_system_name == "Windows" || cmake_system_name == "WindowsStore")
- {
- return m_paths.scripts / fs::u8path("toolchains/windows.cmake");
- }
- else
- {
- Checks::exit_with_message(VCPKG_LINE_INFO,
- "Unable to determine toolchain to use for triplet %s with CMAKE_SYSTEM_NAME %s",
- triplet,
- cmake_system_name);
- }
- }
-
- static ExtendedBuildResult do_build_package(const VcpkgPaths& paths, const Dependencies::InstallPlanAction& action)
- {
- const auto& pre_build_info = action.pre_build_info(VCPKG_LINE_INFO);
-
- auto& fs = paths.get_filesystem();
- auto&& scfl = action.source_control_file_location.value_or_exit(VCPKG_LINE_INFO);
-
- Triplet triplet = action.spec.triplet();
- const auto& triplet_file_path = paths.get_triplet_file_path(triplet).u8string();
-
- if (Strings::case_insensitive_ascii_starts_with(triplet_file_path, paths.community_triplets.u8string()))
- {
- System::printf(vcpkg::System::Color::warning,
- "-- Using community triplet %s. This triplet configuration is not guaranteed to succeed.\n",
- triplet.canonical_name());
- System::printf("-- [COMMUNITY] Loading triplet configuration from: %s\n", triplet_file_path);
- }
- else if (!Strings::case_insensitive_ascii_starts_with(triplet_file_path, paths.triplets.u8string()))
- {
- System::printf("-- [OVERLAY] Loading triplet configuration from: %s\n", triplet_file_path);
- }
-
- auto u8portdir = scfl.source_location.u8string();
- if (!Strings::case_insensitive_ascii_starts_with(u8portdir, paths.ports.u8string()))
- {
- System::printf("-- Installing port from location: %s\n", u8portdir);
- }
-
- const auto timer = Chrono::ElapsedTimer::create_started();
-
- auto command = vcpkg::make_cmake_cmd(paths, paths.ports_cmake, get_cmake_build_args(paths, action, triplet));
-
- const auto& env = paths.get_action_env(action.abi_info.value_or_exit(VCPKG_LINE_INFO));
-
- auto buildpath = paths.buildtrees / action.spec.name();
- if (!fs.exists(buildpath))
- {
- std::error_code err;
- fs.create_directory(buildpath, err);
- Checks::check_exit(VCPKG_LINE_INFO,
- !err.value(),
- "Failed to create directory '%s', code: %d",
- buildpath.u8string(),
- err.value());
- }
- auto stdoutlog = buildpath / ("stdout-" + action.spec.triplet().canonical_name() + ".log");
- std::ofstream out_file(stdoutlog.native().c_str(), std::ios::out | std::ios::binary | std::ios::trunc);
- Checks::check_exit(VCPKG_LINE_INFO, out_file, "Failed to open '%s' for writing", stdoutlog.u8string());
- const int return_code = System::cmd_execute_and_stream_data(
- command,
- [&](StringView sv) {
- System::print2(sv);
- out_file.write(sv.data(), sv.size());
- Checks::check_exit(
- VCPKG_LINE_INFO, out_file, "Error occurred while writing '%s'", stdoutlog.u8string());
- },
- env);
- out_file.close();
-
- // With the exception of empty packages, builds in "Download Mode" always result in failure.
- if (action.build_options.only_downloads == Build::OnlyDownloads::YES)
- {
- // TODO: Capture executed command output and evaluate whether the failure was intended.
- // If an unintended error occurs then return a BuildResult::DOWNLOAD_FAILURE status.
- return BuildResult::DOWNLOADED;
- }
-
- const auto buildtimeus = timer.microseconds();
- const auto spec_string = action.spec.to_string();
-
- {
- auto locked_metrics = Metrics::g_metrics.lock();
-
- locked_metrics->track_buildtime(Hash::get_string_hash(spec_string, Hash::Algorithm::Sha256) + ":[" +
- Strings::join(",",
- action.feature_list,
- [](const std::string& feature) {
- return Hash::get_string_hash(feature,
- Hash::Algorithm::Sha256);
- }) +
- "]",
- buildtimeus);
- if (return_code != 0)
- {
- locked_metrics->track_property("error", "build failed");
- locked_metrics->track_property("build_error", spec_string);
- return BuildResult::BUILD_FAILED;
- }
- }
-
- const BuildInfo build_info = read_build_info(fs, paths.build_info_file_path(action.spec));
- const size_t error_count =
- PostBuildLint::perform_all_checks(action.spec, paths, pre_build_info, build_info, scfl.source_location);
-
- auto find_itr = action.feature_dependencies.find("core");
- Checks::check_exit(VCPKG_LINE_INFO, find_itr != action.feature_dependencies.end());
-
- std::unique_ptr<BinaryControlFile> bcf = create_binary_control_file(*scfl.source_control_file->core_paragraph,
- triplet,
- build_info,
- action.public_abi(),
- std::move(find_itr->second));
-
- if (error_count != 0)
- {
- return BuildResult::POST_BUILD_CHECKS_FAILED;
- }
- for (auto&& feature : action.feature_list)
- {
- for (auto&& f_pgh : scfl.source_control_file->feature_paragraphs)
- {
- if (f_pgh->name == feature)
- {
- find_itr = action.feature_dependencies.find(feature);
- Checks::check_exit(VCPKG_LINE_INFO, find_itr != action.feature_dependencies.end());
-
- bcf->features.emplace_back(
- *scfl.source_control_file->core_paragraph, *f_pgh, triplet, std::move(find_itr->second));
- }
- }
- }
-
- write_binary_control_file(paths, *bcf);
- return {BuildResult::SUCCEEDED, std::move(bcf)};
- }
-
- static ExtendedBuildResult do_build_package_and_clean_buildtrees(const VcpkgPaths& paths,
- const Dependencies::InstallPlanAction& action)
- {
- auto result = do_build_package(paths, action);
-
- if (action.build_options.clean_buildtrees == CleanBuildtrees::YES)
- {
- auto& fs = paths.get_filesystem();
- auto buildtree_files = fs.get_files_non_recursive(paths.build_dir(action.spec));
- for (auto&& file : buildtree_files)
- {
- if (fs.is_directory(file)) // Will only keep the logs
- {
- std::error_code ec;
- fs::path failure_point;
- fs.remove_all(file, ec, failure_point);
- }
- }
- }
-
- return result;
- }
-
- static void abi_entries_from_abi_info(const AbiInfo& abi_info, std::vector<AbiEntry>& abi_tag_entries)
- {
- abi_tag_entries.emplace_back("triplet", abi_info.triplet_abi.value_or_exit(VCPKG_LINE_INFO));
-
- const auto& pre_build_info = *abi_info.pre_build_info;
- if (pre_build_info.public_abi_override)
- {
- abi_tag_entries.emplace_back(
- "public_abi_override",
- Hash::get_string_hash(pre_build_info.public_abi_override.value_or_exit(VCPKG_LINE_INFO),
- Hash::Algorithm::Sha1));
- }
-
- for (const auto& env_var : pre_build_info.passthrough_env_vars)
- {
- abi_tag_entries.emplace_back(
- "ENV:" + env_var,
- Hash::get_string_hash(System::get_environment_variable(env_var).value_or(""), Hash::Algorithm::Sha1));
- }
- }
-
- static Optional<AbiTagAndFile> compute_abi_tag(const VcpkgPaths& paths,
- const Dependencies::InstallPlanAction& action,
- Span<const AbiEntry> dependency_abis)
- {
- auto& fs = paths.get_filesystem();
- Triplet triplet = action.spec.triplet();
-
- std::vector<AbiEntry> abi_tag_entries(dependency_abis.begin(), dependency_abis.end());
-
- abi_entries_from_abi_info(action.abi_info.value_or_exit(VCPKG_LINE_INFO), abi_tag_entries);
-
- // If there is an unusually large number of files in the port then
- // something suspicious is going on. Rather than hash all of them
- // just mark the port as no-hash
- const int max_port_file_count = 100;
-
- auto&& port_dir = action.source_control_file_location.value_or_exit(VCPKG_LINE_INFO).source_location;
- size_t port_file_count = 0;
- for (auto& port_file : fs::stdfs::recursive_directory_iterator(port_dir))
- {
- if (fs::is_regular_file(fs.status(VCPKG_LINE_INFO, port_file)))
- {
- abi_tag_entries.emplace_back(
- port_file.path().filename().u8string(),
- vcpkg::Hash::get_file_hash(VCPKG_LINE_INFO, fs, port_file, Hash::Algorithm::Sha1));
-
- ++port_file_count;
- if (port_file_count > max_port_file_count)
- {
- abi_tag_entries.emplace_back("no_hash_max_portfile", "");
- break;
- }
- }
- }
-
- abi_tag_entries.emplace_back("cmake", paths.get_tool_version(Tools::CMAKE));
-
-#if defined(_WIN32)
- abi_tag_entries.emplace_back("powershell", paths.get_tool_version("powershell-core"));
-#endif
-
- auto& helpers = paths.get_cmake_script_hashes();
- auto portfile_contents =
- fs.read_contents(port_dir / fs::u8path("portfile.cmake")).value_or_exit(VCPKG_LINE_INFO);
- for (auto&& helper : helpers)
- {
- if (Strings::case_insensitive_ascii_contains(portfile_contents, helper.first))
- {
- abi_tag_entries.emplace_back(helper.first, helper.second);
- }
- }
-
- abi_tag_entries.emplace_back("post_build_checks", "2");
- std::vector<std::string> sorted_feature_list = action.feature_list;
- Util::sort(sorted_feature_list);
- abi_tag_entries.emplace_back("features", Strings::join(";", sorted_feature_list));
-
- if (action.build_options.use_head_version == UseHeadVersion::YES) abi_tag_entries.emplace_back("head", "");
-
- Util::sort(abi_tag_entries);
-
- const std::string full_abi_info =
- Strings::join("", abi_tag_entries, [](const AbiEntry& p) { return p.key + " " + p.value + "\n"; });
-
- if (Debug::g_debugging)
- {
- std::string message = Strings::concat("[DEBUG] <abientries for ", action.spec, ">\n");
- for (auto&& entry : abi_tag_entries)
- {
- Strings::append(message, "[DEBUG] ", entry.key, "|", entry.value, "\n");
- }
- Strings::append(message, "[DEBUG] </abientries>\n");
- System::print2(message);
- }
-
- auto abi_tag_entries_missing = Util::filter(abi_tag_entries, [](const AbiEntry& p) { return p.value.empty(); });
-
- if (abi_tag_entries_missing.empty())
- {
- auto current_build_tree = paths.build_dir(action.spec);
- fs.create_directory(current_build_tree, VCPKG_LINE_INFO);
- const auto abi_file_path = current_build_tree / (triplet.canonical_name() + ".vcpkg_abi_info.txt");
- fs.write_contents(abi_file_path, full_abi_info, VCPKG_LINE_INFO);
-
- return AbiTagAndFile{Hash::get_file_hash(VCPKG_LINE_INFO, fs, abi_file_path, Hash::Algorithm::Sha1),
- abi_file_path};
- }
-
- Debug::print(
- "Warning: abi keys are missing values:\n",
- Strings::join("", abi_tag_entries_missing, [](const AbiEntry& e) { return " " + e.key + "\n"; }),
- "\n");
-
- return nullopt;
- }
-
- void compute_all_abis(const VcpkgPaths& paths,
- Dependencies::ActionPlan& action_plan,
- const CMakeVars::CMakeVarProvider& var_provider,
- const StatusParagraphs& status_db)
- {
- using Dependencies::InstallPlanAction;
- for (auto it = action_plan.install_actions.begin(); it != action_plan.install_actions.end(); ++it)
- {
- auto& action = *it;
- if (action.abi_info.has_value()) continue;
-
- std::vector<AbiEntry> dependency_abis;
- if (!Util::Enum::to_bool(action.build_options.only_downloads))
- {
- for (auto&& pspec : action.package_dependencies)
- {
- if (pspec == action.spec) continue;
-
- auto pred = [&](const InstallPlanAction& ipa) { return ipa.spec == pspec; };
- auto it2 = std::find_if(action_plan.install_actions.begin(), it, pred);
- if (it2 == it)
- {
- // Finally, look in current installed
- auto status_it = status_db.find(pspec);
- if (status_it == status_db.end())
- {
- Checks::exit_with_message(
- VCPKG_LINE_INFO, "Failed to find dependency abi for %s -> %s", action.spec, pspec);
- }
- else
- {
- dependency_abis.emplace_back(AbiEntry{pspec.name(), status_it->get()->package.abi});
- }
- }
- else
- {
- dependency_abis.emplace_back(AbiEntry{pspec.name(), it2->public_abi()});
- }
- }
- }
-
- action.abi_info = AbiInfo();
- auto& abi_info = action.abi_info.value_or_exit(VCPKG_LINE_INFO);
-
- abi_info.pre_build_info = std::make_unique<PreBuildInfo>(
- paths, action.spec.triplet(), var_provider.get_tag_vars(action.spec).value_or_exit(VCPKG_LINE_INFO));
- abi_info.toolset = paths.get_toolset(*abi_info.pre_build_info);
- abi_info.triplet_abi = paths.get_triplet_info(abi_info);
-
- auto maybe_abi_tag_and_file = compute_abi_tag(paths, action, dependency_abis);
- if (auto p = maybe_abi_tag_and_file.get())
- {
- abi_info.package_abi = std::move(p->tag);
- abi_info.abi_tag_file = std::move(p->tag_file);
- }
- }
- }
-
- ExtendedBuildResult build_package(const VcpkgPaths& paths,
- const Dependencies::InstallPlanAction& action,
- IBinaryProvider& binaries_provider,
- const IBuildLogsRecorder& build_logs_recorder,
- const StatusParagraphs& status_db)
- {
- auto& fs = paths.get_filesystem();
- auto& spec = action.spec;
- const std::string& name = action.source_control_file_location.value_or_exit(VCPKG_LINE_INFO)
- .source_control_file->core_paragraph->name;
-
- std::vector<FeatureSpec> missing_fspecs;
- for (const auto& kv : action.feature_dependencies)
- {
- for (const FeatureSpec& fspec : kv.second)
- {
- if (!(status_db.is_installed(fspec) || fspec.name() == name))
- {
- missing_fspecs.emplace_back(fspec);
- }
- }
- }
-
- if (!missing_fspecs.empty() && !Util::Enum::to_bool(action.build_options.only_downloads))
- {
- return {BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES, std::move(missing_fspecs)};
- }
-
- std::vector<AbiEntry> dependency_abis;
- for (auto&& pspec : action.package_dependencies)
- {
- if (pspec == spec || Util::Enum::to_bool(action.build_options.only_downloads))
- {
- 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});
- }
-
- auto& abi_info = action.abi_info.value_or_exit(VCPKG_LINE_INFO);
- if (!abi_info.abi_tag_file)
- {
- return do_build_package_and_clean_buildtrees(paths, action);
- }
-
- auto& abi_file = *abi_info.abi_tag_file.get();
-
- std::error_code ec;
- const fs::path abi_package_dir = paths.package_dir(spec) / "share" / spec.name();
- const fs::path abi_file_in_package = paths.package_dir(spec) / "share" / spec.name() / "vcpkg_abi_info.txt";
- if (action.build_options.editable == Build::Editable::NO)
- {
- auto restore = binaries_provider.try_restore(paths, action);
- if (restore == RestoreResult::build_failed)
- {
- return BuildResult::BUILD_FAILED;
- }
- else if (restore == RestoreResult::success)
- {
- auto maybe_bcf = Paragraphs::try_load_cached_package(paths, spec);
- auto bcf = std::make_unique<BinaryControlFile>(std::move(maybe_bcf).value_or_exit(VCPKG_LINE_INFO));
- return {BuildResult::SUCCEEDED, std::move(bcf)};
- }
- else
- {
- // missing package, proceed to build.
- }
- }
-
- ExtendedBuildResult result = do_build_package_and_clean_buildtrees(paths, action);
-
- fs.create_directories(abi_package_dir, ec);
- fs.copy_file(abi_file, abi_file_in_package, fs::copy_options::none, ec);
- Checks::check_exit(VCPKG_LINE_INFO, !ec, "Could not copy into file: %s", abi_file_in_package.u8string());
-
- if (action.build_options.editable == Build::Editable::NO && result.code == BuildResult::SUCCEEDED)
- {
- binaries_provider.push_success(paths, action);
- }
-
- build_logs_recorder.record_build_result(paths, spec, result.code);
-
- return result;
- }
-
- const std::string& to_string(const BuildResult build_result)
- {
- static const std::string NULLVALUE_STRING = Enums::nullvalue_to_string("vcpkg::Commands::Build::BuildResult");
- static const std::string SUCCEEDED_STRING = "SUCCEEDED";
- static const std::string BUILD_FAILED_STRING = "BUILD_FAILED";
- static const std::string FILE_CONFLICTS_STRING = "FILE_CONFLICTS";
- static const std::string POST_BUILD_CHECKS_FAILED_STRING = "POST_BUILD_CHECKS_FAILED";
- static const std::string CASCADED_DUE_TO_MISSING_DEPENDENCIES_STRING = "CASCADED_DUE_TO_MISSING_DEPENDENCIES";
- static const std::string EXCLUDED_STRING = "EXCLUDED";
- static const std::string DOWNLOADED_STRING = "DOWNLOADED";
-
- switch (build_result)
- {
- case BuildResult::NULLVALUE: return NULLVALUE_STRING;
- case BuildResult::SUCCEEDED: return SUCCEEDED_STRING;
- case BuildResult::BUILD_FAILED: return BUILD_FAILED_STRING;
- case BuildResult::POST_BUILD_CHECKS_FAILED: return POST_BUILD_CHECKS_FAILED_STRING;
- case BuildResult::FILE_CONFLICTS: return FILE_CONFLICTS_STRING;
- case BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES: return CASCADED_DUE_TO_MISSING_DEPENDENCIES_STRING;
- case BuildResult::EXCLUDED: return EXCLUDED_STRING;
- case BuildResult::DOWNLOADED: return DOWNLOADED_STRING;
- default: Checks::unreachable(VCPKG_LINE_INFO);
- }
- }
-
- std::string create_error_message(const BuildResult build_result, const PackageSpec& spec)
- {
- return Strings::format("Error: Building package %s failed with: %s", spec, Build::to_string(build_result));
- }
-
- std::string create_user_troubleshooting_message(const PackageSpec& spec)
- {
- return Strings::format("Please ensure you're using the latest portfiles with `.\\vcpkg update`, then\n"
- "submit an issue at https://github.com/Microsoft/vcpkg/issues including:\n"
- " Package: %s\n"
- " Vcpkg version: %s\n"
- "\n"
- "Additionally, attach any relevant sections from the log files above.",
- spec,
- Commands::Version::version());
- }
-
- static BuildInfo inner_create_buildinfo(Parse::Paragraph pgh)
- {
- Parse::ParagraphParser parser(std::move(pgh));
-
- BuildInfo build_info;
-
- {
- std::string crt_linkage_as_string;
- parser.required_field(BuildInfoRequiredField::CRT_LINKAGE, crt_linkage_as_string);
-
- auto crtlinkage = to_linkage_type(crt_linkage_as_string);
- if (const auto p = crtlinkage.get())
- build_info.crt_linkage = *p;
- else
- Checks::exit_with_message(VCPKG_LINE_INFO, "Invalid crt linkage type: [%s]", crt_linkage_as_string);
- }
-
- {
- std::string library_linkage_as_string;
- parser.required_field(BuildInfoRequiredField::LIBRARY_LINKAGE, library_linkage_as_string);
- auto liblinkage = to_linkage_type(library_linkage_as_string);
- if (const auto p = liblinkage.get())
- build_info.library_linkage = *p;
- else
- Checks::exit_with_message(
- VCPKG_LINE_INFO, "Invalid library linkage type: [%s]", library_linkage_as_string);
- }
- std::string version = parser.optional_field("Version");
- if (!version.empty()) build_info.version = std::move(version);
-
- std::map<BuildPolicy, bool> policies;
- for (auto policy : G_ALL_POLICIES)
- {
- const auto setting = parser.optional_field(to_string(policy));
- if (setting.empty()) continue;
- if (setting == "enabled")
- policies.emplace(policy, true);
- else if (setting == "disabled")
- policies.emplace(policy, false);
- else
- Checks::exit_with_message(
- VCPKG_LINE_INFO, "Unknown setting for policy '%s': %s", to_string(policy), setting);
- }
-
- if (const auto err = parser.error_info("PostBuildInformation"))
- {
- print_error_message(err);
- Checks::exit_fail(VCPKG_LINE_INFO);
- }
-
- build_info.policies = BuildPolicies(std::move(policies));
-
- return build_info;
- }
-
- BuildInfo read_build_info(const Files::Filesystem& fs, const fs::path& filepath)
- {
- const ExpectedS<Parse::Paragraph> pghs = Paragraphs::get_single_paragraph(fs, filepath);
- Checks::check_exit(
- VCPKG_LINE_INFO, pghs.get() != nullptr, "Invalid BUILD_INFO file for package: %s", pghs.error());
- return inner_create_buildinfo(*pghs.get());
- }
-
- PreBuildInfo::PreBuildInfo(const VcpkgPaths& paths,
- Triplet triplet,
- const std::unordered_map<std::string, std::string>& cmakevars)
- : m_paths(paths), triplet(triplet)
- {
- enum class VcpkgTripletVar
- {
- TARGET_ARCHITECTURE = 0,
- CMAKE_SYSTEM_NAME,
- CMAKE_SYSTEM_VERSION,
- PLATFORM_TOOLSET,
- VISUAL_STUDIO_PATH,
- CHAINLOAD_TOOLCHAIN_FILE,
- BUILD_TYPE,
- ENV_PASSTHROUGH,
- PUBLIC_ABI_OVERRIDE,
- LOAD_VCVARS_ENV,
- };
-
- static const std::vector<std::pair<std::string, VcpkgTripletVar>> VCPKG_OPTIONS = {
- {"VCPKG_TARGET_ARCHITECTURE", VcpkgTripletVar::TARGET_ARCHITECTURE},
- {"VCPKG_CMAKE_SYSTEM_NAME", VcpkgTripletVar::CMAKE_SYSTEM_NAME},
- {"VCPKG_CMAKE_SYSTEM_VERSION", VcpkgTripletVar::CMAKE_SYSTEM_VERSION},
- {"VCPKG_PLATFORM_TOOLSET", VcpkgTripletVar::PLATFORM_TOOLSET},
- {"VCPKG_VISUAL_STUDIO_PATH", VcpkgTripletVar::VISUAL_STUDIO_PATH},
- {"VCPKG_CHAINLOAD_TOOLCHAIN_FILE", VcpkgTripletVar::CHAINLOAD_TOOLCHAIN_FILE},
- {"VCPKG_BUILD_TYPE", VcpkgTripletVar::BUILD_TYPE},
- {"VCPKG_ENV_PASSTHROUGH", VcpkgTripletVar::ENV_PASSTHROUGH},
- {"VCPKG_PUBLIC_ABI_OVERRIDE", VcpkgTripletVar::PUBLIC_ABI_OVERRIDE},
- {"VCPKG_LOAD_VCVARS_ENV", VcpkgTripletVar::LOAD_VCVARS_ENV},
- };
-
- std::string empty;
- for (auto&& kv : VCPKG_OPTIONS)
- {
- const std::string& variable_value = [&]() -> const std::string& {
- auto find_itr = cmakevars.find(kv.first);
- if (find_itr == cmakevars.end())
- {
- return empty;
- }
- else
- {
- return find_itr->second;
- }
- }();
-
- switch (kv.second)
- {
- case VcpkgTripletVar::TARGET_ARCHITECTURE: target_architecture = variable_value; break;
- case VcpkgTripletVar::CMAKE_SYSTEM_NAME: cmake_system_name = variable_value; break;
- case VcpkgTripletVar::CMAKE_SYSTEM_VERSION: cmake_system_version = variable_value; break;
- case VcpkgTripletVar::PLATFORM_TOOLSET:
- platform_toolset = variable_value.empty() ? nullopt : Optional<std::string>{variable_value};
- break;
- case VcpkgTripletVar::VISUAL_STUDIO_PATH:
- visual_studio_path = variable_value.empty() ? nullopt : Optional<fs::path>{variable_value};
- break;
- case VcpkgTripletVar::CHAINLOAD_TOOLCHAIN_FILE:
- external_toolchain_file = variable_value.empty() ? nullopt : Optional<std::string>{variable_value};
- break;
- case VcpkgTripletVar::BUILD_TYPE:
- if (variable_value.empty())
- build_type = nullopt;
- else if (Strings::case_insensitive_ascii_equals(variable_value, "debug"))
- build_type = ConfigurationType::DEBUG;
- else if (Strings::case_insensitive_ascii_equals(variable_value, "release"))
- build_type = ConfigurationType::RELEASE;
- else
- Checks::exit_with_message(
- VCPKG_LINE_INFO,
- "Unknown setting for VCPKG_BUILD_TYPE: %s. Valid settings are '', 'debug' and 'release'.",
- variable_value);
- break;
- case VcpkgTripletVar::ENV_PASSTHROUGH:
- passthrough_env_vars = Strings::split(variable_value, ';');
- break;
- case VcpkgTripletVar::PUBLIC_ABI_OVERRIDE:
- public_abi_override = variable_value.empty() ? nullopt : Optional<std::string>{variable_value};
- break;
- case VcpkgTripletVar::LOAD_VCVARS_ENV:
- if (variable_value.empty())
- {
- load_vcvars_env = true;
- if (external_toolchain_file) load_vcvars_env = false;
- }
- else if (Strings::case_insensitive_ascii_equals(variable_value, "1") ||
- Strings::case_insensitive_ascii_equals(variable_value, "on") ||
- Strings::case_insensitive_ascii_equals(variable_value, "true"))
- load_vcvars_env = true;
- else if (Strings::case_insensitive_ascii_equals(variable_value, "0") ||
- Strings::case_insensitive_ascii_equals(variable_value, "off") ||
- Strings::case_insensitive_ascii_equals(variable_value, "false"))
- load_vcvars_env = false;
- else
- Checks::exit_with_message(VCPKG_LINE_INFO,
- "Unknown boolean setting for VCPKG_LOAD_VCVARS_ENV: %s. Valid "
- "settings are '', '1', '0', 'ON', 'OFF', 'TRUE', and 'FALSE'.",
- variable_value);
- break;
- }
- }
- }
-
- ExtendedBuildResult::ExtendedBuildResult(BuildResult code) : code(code) { }
- ExtendedBuildResult::ExtendedBuildResult(BuildResult code, std::unique_ptr<BinaryControlFile>&& bcf)
- : code(code), binary_control_file(std::move(bcf))
- {
- }
- ExtendedBuildResult::ExtendedBuildResult(BuildResult code, std::vector<FeatureSpec>&& unmet_deps)
- : code(code), unmet_dependencies(std::move(unmet_deps))
- {
- }
-
- const IBuildLogsRecorder& null_build_logs_recorder() noexcept { return null_build_logs_recorder_instance; }
-}
+#include "pch.h"
+
+#include <vcpkg/base/cache.h>
+#include <vcpkg/base/checks.h>
+#include <vcpkg/base/chrono.h>
+#include <vcpkg/base/enums.h>
+#include <vcpkg/base/hash.h>
+#include <vcpkg/base/optional.h>
+#include <vcpkg/base/stringliteral.h>
+#include <vcpkg/base/system.debug.h>
+#include <vcpkg/base/system.print.h>
+#include <vcpkg/base/system.process.h>
+#include <vcpkg/base/util.h>
+
+#include <vcpkg/binarycaching.h>
+#include <vcpkg/build.h>
+#include <vcpkg/buildenvironment.h>
+#include <vcpkg/commands.h>
+#include <vcpkg/dependencies.h>
+#include <vcpkg/globalstate.h>
+#include <vcpkg/help.h>
+#include <vcpkg/input.h>
+#include <vcpkg/metrics.h>
+#include <vcpkg/paragraphs.h>
+#include <vcpkg/postbuildlint.h>
+#include <vcpkg/statusparagraphs.h>
+#include <vcpkg/vcpkglib.h>
+
+using namespace vcpkg;
+using vcpkg::Build::BuildResult;
+using vcpkg::Parse::ParseControlErrorInfo;
+using vcpkg::Parse::ParseExpected;
+using vcpkg::PortFileProvider::PathsPortFileProvider;
+
+namespace
+{
+ using vcpkg::PackageSpec;
+ using vcpkg::VcpkgPaths;
+ using vcpkg::Build::IBuildLogsRecorder;
+ struct NullBuildLogsRecorder final : IBuildLogsRecorder
+ {
+ void record_build_result(const VcpkgPaths& paths, const PackageSpec& spec, BuildResult result) const override
+ {
+ (void)paths;
+ (void)spec;
+ (void)result;
+ }
+ };
+
+ static const NullBuildLogsRecorder null_build_logs_recorder_instance;
+}
+
+namespace vcpkg::Build
+{
+ using Dependencies::InstallPlanAction;
+ using Dependencies::InstallPlanType;
+
+ void Command::perform_and_exit_ex(const FullPackageSpec& full_spec,
+ const SourceControlFileLocation& scfl,
+ const PathsPortFileProvider& provider,
+ IBinaryProvider& binaryprovider,
+ const IBuildLogsRecorder& build_logs_recorder,
+ const VcpkgPaths& paths)
+ {
+ Checks::exit_with_code(VCPKG_LINE_INFO,
+ perform_ex(full_spec, scfl, provider, binaryprovider, build_logs_recorder, paths));
+ }
+
+ const CommandStructure COMMAND_STRUCTURE = {
+ create_example_string("build zlib:x64-windows"),
+ 1,
+ 1,
+ {{}, {}},
+ nullptr,
+ };
+
+ void Command::perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, Triplet default_triplet)
+ {
+ Checks::exit_with_code(VCPKG_LINE_INFO, perform(args, paths, default_triplet));
+ }
+
+ int Command::perform_ex(const FullPackageSpec& full_spec,
+ const SourceControlFileLocation& scfl,
+ const PathsPortFileProvider& provider,
+ IBinaryProvider& binaryprovider,
+ const IBuildLogsRecorder& build_logs_recorder,
+ const VcpkgPaths& paths)
+ {
+ auto var_provider_storage = CMakeVars::make_triplet_cmake_var_provider(paths);
+ auto& var_provider = *var_provider_storage;
+ var_provider.load_dep_info_vars(std::array<PackageSpec, 1>{full_spec.package_spec});
+
+ StatusParagraphs status_db = database_load_check(paths);
+
+ auto action_plan = Dependencies::create_feature_install_plan(
+ provider, var_provider, std::vector<FullPackageSpec>{full_spec}, status_db);
+
+ var_provider.load_tag_vars(action_plan, provider);
+
+ const PackageSpec& spec = full_spec.package_spec;
+ const SourceControlFile& scf = *scfl.source_control_file;
+
+ Checks::check_exit(VCPKG_LINE_INFO,
+ spec.name() == scf.core_paragraph->name,
+ "The Source field inside the CONTROL file does not match the port directory: '%s' != '%s'",
+ scf.core_paragraph->name,
+ spec.name());
+
+ compute_all_abis(paths, action_plan, var_provider, status_db);
+
+ InstallPlanAction* action = nullptr;
+ for (auto& install_action : action_plan.already_installed)
+ {
+ if (install_action.spec == full_spec.package_spec)
+ {
+ action = &install_action;
+ }
+ }
+ for (auto& install_action : action_plan.install_actions)
+ {
+ if (install_action.spec == full_spec.package_spec)
+ {
+ action = &install_action;
+ }
+ }
+
+ Checks::check_exit(VCPKG_LINE_INFO, action != nullptr);
+ ASSUME(action != nullptr);
+ action->build_options = default_build_package_options;
+ action->build_options.editable = Editable::YES;
+ action->build_options.clean_buildtrees = CleanBuildtrees::NO;
+ action->build_options.clean_packages = CleanPackages::NO;
+
+ const auto build_timer = Chrono::ElapsedTimer::create_started();
+ const auto result = Build::build_package(paths, *action, binaryprovider, build_logs_recorder, status_db);
+ System::print2("Elapsed time for package ", spec, ": ", build_timer, '\n');
+
+ if (result.code == BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES)
+ {
+ System::print2(System::Color::error,
+ "The build command requires all dependencies to be already installed.\n");
+ System::print2("The following dependencies are missing:\n\n");
+ for (const auto& p : result.unmet_dependencies)
+ {
+ System::print2(" ", p, '\n');
+ }
+ System::print2('\n');
+ Checks::exit_fail(VCPKG_LINE_INFO);
+ }
+
+ Checks::check_exit(VCPKG_LINE_INFO, result.code != BuildResult::EXCLUDED);
+
+ if (result.code != BuildResult::SUCCEEDED)
+ {
+ System::print2(System::Color::error, Build::create_error_message(result.code, spec), '\n');
+ System::print2(Build::create_user_troubleshooting_message(spec), '\n');
+ return 1;
+ }
+
+ return 0;
+ }
+
+ int Command::perform(const VcpkgCmdArguments& args, const VcpkgPaths& paths, Triplet default_triplet)
+ {
+ // Build only takes a single package and all dependencies must already be installed
+ const ParsedArguments options = args.parse_arguments(COMMAND_STRUCTURE);
+ std::string first_arg = args.command_arguments.at(0);
+
+ auto binaryprovider = create_binary_provider_from_configs(args.binary_sources).value_or_exit(VCPKG_LINE_INFO);
+
+ const FullPackageSpec spec = Input::check_and_get_full_package_spec(
+ std::move(first_arg), default_triplet, COMMAND_STRUCTURE.example_text);
+
+ Input::check_triplet(spec.package_spec.triplet(), paths);
+
+ PathsPortFileProvider provider(paths, args.overlay_ports);
+ const auto port_name = spec.package_spec.name();
+ const auto* scfl = provider.get_control_file(port_name).get();
+
+ Checks::check_exit(VCPKG_LINE_INFO, scfl != nullptr, "Error: Couldn't find port '%s'", port_name);
+ ASSUME(scfl != nullptr);
+
+ return perform_ex(spec,
+ *scfl,
+ provider,
+ args.binary_caching_enabled() ? *binaryprovider : null_binary_provider(),
+ Build::null_build_logs_recorder(),
+ paths);
+ }
+}
+
+namespace vcpkg::Build
+{
+ static const std::string NAME_EMPTY_PACKAGE = "PolicyEmptyPackage";
+ static const std::string NAME_DLLS_WITHOUT_LIBS = "PolicyDLLsWithoutLIBs";
+ static const std::string NAME_DLLS_WITHOUT_EXPORTS = "PolicyDLLsWithoutExports";
+ static const std::string NAME_ONLY_RELEASE_CRT = "PolicyOnlyReleaseCRT";
+ static const std::string NAME_EMPTY_INCLUDE_FOLDER = "PolicyEmptyIncludeFolder";
+ static const std::string NAME_ALLOW_OBSOLETE_MSVCRT = "PolicyAllowObsoleteMsvcrt";
+ static const std::string NAME_ALLOW_RESTRICTED_HEADERS = "PolicyAllowRestrictedHeaders";
+ static const std::string NAME_SKIP_DUMPBIN_CHECKS = "PolicySkipDumpbinChecks";
+ static const std::string NAME_SKIP_ARCHITECTURE_CHECK = "PolicySkipArchitectureCheck";
+
+ const std::string& to_string(BuildPolicy policy)
+ {
+ switch (policy)
+ {
+ case BuildPolicy::EMPTY_PACKAGE: return NAME_EMPTY_PACKAGE;
+ case BuildPolicy::DLLS_WITHOUT_LIBS: return NAME_DLLS_WITHOUT_LIBS;
+ case BuildPolicy::DLLS_WITHOUT_EXPORTS: return NAME_DLLS_WITHOUT_EXPORTS;
+ case BuildPolicy::ONLY_RELEASE_CRT: return NAME_ONLY_RELEASE_CRT;
+ case BuildPolicy::EMPTY_INCLUDE_FOLDER: return NAME_EMPTY_INCLUDE_FOLDER;
+ case BuildPolicy::ALLOW_OBSOLETE_MSVCRT: return NAME_ALLOW_OBSOLETE_MSVCRT;
+ case BuildPolicy::ALLOW_RESTRICTED_HEADERS: return NAME_ALLOW_RESTRICTED_HEADERS;
+ case BuildPolicy::SKIP_DUMPBIN_CHECKS: return NAME_SKIP_DUMPBIN_CHECKS;
+ case BuildPolicy::SKIP_ARCHITECTURE_CHECK: return NAME_SKIP_ARCHITECTURE_CHECK;
+ default: Checks::unreachable(VCPKG_LINE_INFO);
+ }
+ }
+
+ CStringView to_cmake_variable(BuildPolicy policy)
+ {
+ switch (policy)
+ {
+ case BuildPolicy::EMPTY_PACKAGE: return "VCPKG_POLICY_EMPTY_PACKAGE";
+ case BuildPolicy::DLLS_WITHOUT_LIBS: return "VCPKG_POLICY_DLLS_WITHOUT_LIBS";
+ case BuildPolicy::DLLS_WITHOUT_EXPORTS: return "VCPKG_POLICY_DLLS_WITHOUT_EXPORTS";
+ case BuildPolicy::ONLY_RELEASE_CRT: return "VCPKG_POLICY_ONLY_RELEASE_CRT";
+ case BuildPolicy::EMPTY_INCLUDE_FOLDER: return "VCPKG_POLICY_EMPTY_INCLUDE_FOLDER";
+ case BuildPolicy::ALLOW_OBSOLETE_MSVCRT: return "VCPKG_POLICY_ALLOW_OBSOLETE_MSVCRT";
+ case BuildPolicy::ALLOW_RESTRICTED_HEADERS: return "VCPKG_POLICY_ALLOW_RESTRICTED_HEADERS";
+ case BuildPolicy::SKIP_DUMPBIN_CHECKS: return "VCPKG_POLICY_SKIP_DUMPBIN_CHECKS";
+ case BuildPolicy::SKIP_ARCHITECTURE_CHECK: return "VCPKG_POLICY_SKIP_ARCHITECTURE_CHECK";
+ default: Checks::unreachable(VCPKG_LINE_INFO);
+ }
+ }
+
+ 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;
+ if (str == "static") return LinkageType::STATIC;
+ return nullopt;
+ }
+
+ namespace BuildInfoRequiredField
+ {
+ static const std::string CRT_LINKAGE = "CRTLinkage";
+ static const std::string LIBRARY_LINKAGE = "LibraryLinkage";
+ }
+
+ static CStringView to_vcvarsall_target(const std::string& cmake_system_name)
+ {
+ if (cmake_system_name.empty()) return "";
+ if (cmake_system_name == "Windows") return "";
+ if (cmake_system_name == "WindowsStore") return "store";
+
+ Checks::exit_with_message(VCPKG_LINE_INFO, "Unsupported vcvarsall target %s", cmake_system_name);
+ }
+
+ static CStringView to_vcvarsall_toolchain(const std::string& target_architecture, const Toolset& toolset)
+ {
+ auto maybe_target_arch = System::to_cpu_architecture(target_architecture);
+ Checks::check_exit(
+ VCPKG_LINE_INFO, maybe_target_arch.has_value(), "Invalid architecture string: %s", target_architecture);
+ auto target_arch = maybe_target_arch.value_or_exit(VCPKG_LINE_INFO);
+ auto host_architectures = System::get_supported_host_architectures();
+
+ for (auto&& host : host_architectures)
+ {
+ 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. Target was: %s but supported ones were:\n%s",
+ target_architecture,
+ Strings::join(",", toolset.supported_architectures, [](const ToolsetArchOption& t) {
+ return t.name.c_str();
+ }));
+ }
+
+ const System::Environment& EnvCache::get_action_env(const VcpkgPaths& paths, const AbiInfo& abi_info)
+ {
+#if defined(_WIN32)
+ std::string build_env_cmd =
+ make_build_env_cmd(*abi_info.pre_build_info, abi_info.toolset.value_or_exit(VCPKG_LINE_INFO));
+
+ const auto& base_env = envs.get_lazy(abi_info.pre_build_info->passthrough_env_vars, [&]() -> EnvMapEntry {
+ std::unordered_map<std::string, std::string> env;
+
+ for (auto&& env_var : abi_info.pre_build_info->passthrough_env_vars)
+ {
+ auto env_val = System::get_environment_variable(env_var);
+
+ if (env_val)
+ {
+ env[env_var] = env_val.value_or_exit(VCPKG_LINE_INFO);
+ }
+ }
+
+ return {env};
+ });
+
+ return base_env.cmd_cache.get_lazy(build_env_cmd, [&]() {
+ const fs::path& powershell_exe_path = paths.get_tool_exe("powershell-core");
+ auto& fs = paths.get_filesystem();
+ if (!fs.exists(powershell_exe_path.parent_path() / "powershell.exe"))
+ {
+ fs.copy(
+ powershell_exe_path, powershell_exe_path.parent_path() / "powershell.exe", fs::copy_options::none);
+ }
+
+ auto clean_env = System::get_modified_clean_environment(base_env.env_map,
+ powershell_exe_path.parent_path().u8string() + ";");
+ if (build_env_cmd.empty())
+ return clean_env;
+ else
+ return System::cmd_execute_modify_env(build_env_cmd, clean_env);
+ });
+#else
+ return System::get_clean_environment();
+#endif
+ }
+
+ static std::string load_compiler_hash(const VcpkgPaths& paths, const AbiInfo& abi_info);
+
+ const std::string& EnvCache::get_triplet_info(const VcpkgPaths& paths, const AbiInfo& abi_info)
+ {
+ const auto& fs = paths.get_filesystem();
+ Checks::check_exit(VCPKG_LINE_INFO, abi_info.pre_build_info != nullptr);
+ const fs::path triplet_file_path = paths.get_triplet_file_path(abi_info.pre_build_info->triplet);
+
+ auto tcfile = abi_info.pre_build_info->toolchain_file();
+ auto&& toolchain_hash = m_toolchain_cache.get_lazy(
+ tcfile, [&]() { return Hash::get_file_hash(VCPKG_LINE_INFO, fs, tcfile, Hash::Algorithm::Sha1); });
+
+ auto&& triplet_entry = m_triplet_cache.get_lazy(triplet_file_path, [&]() -> TripletMapEntry {
+ return TripletMapEntry{Hash::get_file_hash(VCPKG_LINE_INFO, fs, triplet_file_path, Hash::Algorithm::Sha1)};
+ });
+
+ return triplet_entry.compiler_hashes.get_lazy(toolchain_hash, [&]() -> std::string {
+ if (m_compiler_tracking)
+ {
+ auto compiler_hash = load_compiler_hash(paths, abi_info);
+ return Strings::concat(triplet_entry.hash, '-', toolchain_hash, '-', compiler_hash);
+ }
+ else
+ {
+ return triplet_entry.hash + "-" + toolchain_hash;
+ }
+ });
+ }
+
+ std::string make_build_env_cmd(const PreBuildInfo& pre_build_info, const Toolset& toolset)
+ {
+ if (!pre_build_info.using_vcvars()) return "";
+
+ const char* tonull = " >nul";
+ if (Debug::g_debugging)
+ {
+ tonull = "";
+ }
+
+ const auto arch = to_vcvarsall_toolchain(pre_build_info.target_architecture, toolset);
+ const auto target = to_vcvarsall_target(pre_build_info.cmake_system_name);
+
+ return Strings::format(R"(cmd /c ""%s" %s %s %s %s 2>&1 <NUL")",
+ toolset.vcvarsall.u8string(),
+ Strings::join(" ", toolset.vcvarsall_options),
+ arch,
+ target,
+ tonull);
+ }
+
+ static std::unique_ptr<BinaryControlFile> create_binary_control_file(
+ const SourceParagraph& source_paragraph,
+ Triplet triplet,
+ const BuildInfo& build_info,
+ const std::string& abi_tag,
+ const std::vector<FeatureSpec>& core_dependencies)
+ {
+ auto bcf = std::make_unique<BinaryControlFile>();
+ BinaryParagraph bpgh(source_paragraph, triplet, abi_tag, core_dependencies);
+ if (const auto p_ver = build_info.version.get())
+ {
+ bpgh.version = *p_ver;
+ }
+
+ bcf->core_paragraph = std::move(bpgh);
+ return bcf;
+ }
+
+ static void write_binary_control_file(const VcpkgPaths& paths, const BinaryControlFile& bcf)
+ {
+ std::string start = Strings::serialize(bcf.core_paragraph);
+ for (auto&& feature : bcf.features)
+ {
+ start += "\n" + Strings::serialize(feature);
+ }
+ const fs::path binary_control_file = paths.packages / bcf.core_paragraph.dir() / fs::u8path("CONTROL");
+ paths.get_filesystem().write_contents(binary_control_file, start, VCPKG_LINE_INFO);
+ }
+
+ static int get_concurrency()
+ {
+ static int concurrency = [] {
+ auto user_defined_concurrency = System::get_environment_variable("VCPKG_MAX_CONCURRENCY");
+ if (user_defined_concurrency)
+ {
+ return std::stoi(user_defined_concurrency.value_or_exit(VCPKG_LINE_INFO));
+ }
+ else
+ {
+ return System::get_num_logical_cores() + 1;
+ }
+ }();
+
+ return concurrency;
+ }
+
+ static void get_generic_cmake_build_args(const VcpkgPaths& paths,
+ Triplet triplet,
+ const Toolset& toolset,
+ std::vector<System::CMakeVariable>& out_vars)
+ {
+ Util::Vectors::append(&out_vars,
+ std::initializer_list<System::CMakeVariable>{
+ {"CMD", "BUILD"},
+ {"TARGET_TRIPLET", triplet.canonical_name()},
+ {"TARGET_TRIPLET_FILE", paths.get_triplet_file_path(triplet).u8string()},
+ {"VCPKG_PLATFORM_TOOLSET", toolset.version.c_str()},
+ {"DOWNLOADS", paths.downloads},
+ {"VCPKG_CONCURRENCY", std::to_string(get_concurrency())},
+ });
+ if (!System::get_environment_variable("VCPKG_FORCE_SYSTEM_BINARIES").has_value())
+ {
+ const fs::path& git_exe_path = paths.get_tool_exe(Tools::GIT);
+ out_vars.push_back({"GIT", git_exe_path});
+ }
+ }
+
+ static std::string load_compiler_hash(const VcpkgPaths& paths, const AbiInfo& abi_info)
+ {
+ auto triplet = abi_info.pre_build_info->triplet;
+ System::print2("Detecting compiler hash for triplet ", triplet, "...\n");
+ auto buildpath = paths.buildtrees / "detect_compiler";
+
+#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<System::CMakeVariable> cmake_args{
+ {"CURRENT_PORT_DIR", paths.scripts / "detect_compiler"},
+ {"CURRENT_BUILDTREES_DIR", buildpath},
+ {"CURRENT_PACKAGES_DIR", paths.packages / ("detect_compiler_" + triplet.canonical_name())},
+ };
+ get_generic_cmake_build_args(paths, triplet, abi_info.toolset.value_or_exit(VCPKG_LINE_INFO), cmake_args);
+
+ auto command = vcpkg::make_cmake_cmd(paths, paths.ports_cmake, std::move(cmake_args));
+
+ const auto& env = paths.get_action_env(abi_info);
+ auto& fs = paths.get_filesystem();
+ if (!fs.exists(buildpath))
+ {
+ std::error_code err;
+ fs.create_directory(buildpath, err);
+ Checks::check_exit(VCPKG_LINE_INFO,
+ !err.value(),
+ "Failed to create directory '%s', code: %d",
+ buildpath.u8string(),
+ err.value());
+ }
+ auto stdoutlog = buildpath / ("stdout-" + triplet.canonical_name() + ".log");
+ std::ofstream out_file(stdoutlog.native().c_str(), std::ios::out | std::ios::binary | std::ios::trunc);
+ Checks::check_exit(VCPKG_LINE_INFO, out_file, "Failed to open '%s' for writing", stdoutlog.u8string());
+ std::string compiler_hash;
+ const int return_code = System::cmd_execute_and_stream_lines(
+ command,
+ [&](const std::string& s) {
+ static const StringLiteral s_marker = "#COMPILER_HASH#";
+ if (Strings::starts_with(s, s_marker))
+ {
+ compiler_hash = s.data() + s_marker.size();
+ }
+ Debug::print(s, '\n');
+ out_file.write(s.data(), s.size()).put('\n');
+ Checks::check_exit(
+ VCPKG_LINE_INFO, out_file, "Error occurred while writing '%s'", stdoutlog.u8string());
+ },
+ env);
+ out_file.close();
+
+ if (compiler_hash.empty())
+ {
+ Debug::print("Compiler information tracking can be disabled by passing --",
+ VcpkgCmdArguments::FEATURE_FLAGS_ARG,
+ "=-",
+ VcpkgCmdArguments::COMPILER_TRACKING_FEATURE,
+ "\n");
+ }
+ Checks::check_exit(VCPKG_LINE_INFO,
+ !compiler_hash.empty(),
+ "Error occured while detecting compiler information. Pass `--debug` for more information.");
+
+ Debug::print("Detecting compiler hash for triplet ", triplet, ": ", compiler_hash, "\n");
+ return compiler_hash;
+ }
+
+ static std::vector<System::CMakeVariable> get_cmake_build_args(const VcpkgPaths& paths,
+ const Dependencies::InstallPlanAction& action,
+ Triplet triplet)
+ {
+#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
+ auto& scfl = action.source_control_file_location.value_or_exit(VCPKG_LINE_INFO);
+ auto& scf = *scfl.source_control_file;
+
+ std::string all_features;
+ for (auto& feature : scf.feature_paragraphs)
+ {
+ all_features.append(feature->name + ";");
+ }
+
+ std::vector<System::CMakeVariable> variables{
+ {"PORT", scf.core_paragraph->name},
+ {"CURRENT_PORT_DIR", scfl.source_location},
+ {"VCPKG_USE_HEAD_VERSION", Util::Enum::to_bool(action.build_options.use_head_version) ? "1" : "0"},
+ {"_VCPKG_NO_DOWNLOADS", !Util::Enum::to_bool(action.build_options.allow_downloads) ? "1" : "0"},
+ {"_VCPKG_DOWNLOAD_TOOL", to_string(action.build_options.download_tool)},
+ {"_VCPKG_EDITABLE", Util::Enum::to_bool(action.build_options.editable) ? "1" : "0"},
+ {"FEATURES", Strings::join(";", action.feature_list)},
+ {"ALL_FEATURES", all_features},
+ };
+ get_generic_cmake_build_args(
+ paths,
+ triplet,
+ action.abi_info.value_or_exit(VCPKG_LINE_INFO).toolset.value_or_exit(VCPKG_LINE_INFO),
+ variables);
+
+ if (Util::Enum::to_bool(action.build_options.only_downloads))
+ {
+ variables.push_back({"VCPKG_DOWNLOAD_MODE", "true"});
+ }
+
+ const Files::Filesystem& fs = paths.get_filesystem();
+
+ std::vector<std::string> port_configs;
+ for (const PackageSpec& dependency : action.package_dependencies)
+ {
+ const fs::path port_config_path = paths.installed / fs::u8path(dependency.triplet().canonical_name()) /
+ fs::u8path("share") / fs::u8path(dependency.name()) /
+ fs::u8path("vcpkg-port-config.cmake");
+
+ if (fs.is_regular_file(port_config_path))
+ {
+ port_configs.emplace_back(port_config_path.u8string());
+ }
+ }
+
+ if (!port_configs.empty())
+ {
+ variables.emplace_back("VCPKG_PORT_CONFIGS", Strings::join(";", port_configs));
+ }
+
+ return variables;
+ }
+
+ bool PreBuildInfo::using_vcvars() const
+ {
+ return (!external_toolchain_file.has_value() || load_vcvars_env) &&
+ (cmake_system_name.empty() || cmake_system_name == "WindowsStore");
+ }
+
+ fs::path PreBuildInfo::toolchain_file() const
+ {
+ if (auto p = external_toolchain_file.get())
+ {
+ return fs::u8path(*p);
+ }
+ else if (cmake_system_name == "Linux")
+ {
+ return m_paths.scripts / fs::u8path("toolchains/linux.cmake");
+ }
+ else if (cmake_system_name == "Darwin")
+ {
+ return m_paths.scripts / fs::u8path("toolchains/osx.cmake");
+ }
+ else if (cmake_system_name == "FreeBSD")
+ {
+ return m_paths.scripts / fs::u8path("toolchains/freebsd.cmake");
+ }
+ else if (cmake_system_name == "Android")
+ {
+ return m_paths.scripts / fs::u8path("toolchains/android.cmake");
+ }
+ else if (cmake_system_name == "iOS")
+ {
+ return m_paths.scripts / fs::u8path("toolchains/ios.cmake");
+ }
+ else if (cmake_system_name.empty() || cmake_system_name == "Windows" || cmake_system_name == "WindowsStore")
+ {
+ return m_paths.scripts / fs::u8path("toolchains/windows.cmake");
+ }
+ else
+ {
+ Checks::exit_with_message(VCPKG_LINE_INFO,
+ "Unable to determine toolchain to use for triplet %s with CMAKE_SYSTEM_NAME %s",
+ triplet,
+ cmake_system_name);
+ }
+ }
+
+ static ExtendedBuildResult do_build_package(const VcpkgPaths& paths, const Dependencies::InstallPlanAction& action)
+ {
+ const auto& pre_build_info = action.pre_build_info(VCPKG_LINE_INFO);
+
+ auto& fs = paths.get_filesystem();
+ auto&& scfl = action.source_control_file_location.value_or_exit(VCPKG_LINE_INFO);
+
+ Triplet triplet = action.spec.triplet();
+ const auto& triplet_file_path = paths.get_triplet_file_path(triplet).u8string();
+
+ if (Strings::case_insensitive_ascii_starts_with(triplet_file_path, paths.community_triplets.u8string()))
+ {
+ System::printf(vcpkg::System::Color::warning,
+ "-- Using community triplet %s. This triplet configuration is not guaranteed to succeed.\n",
+ triplet.canonical_name());
+ System::printf("-- [COMMUNITY] Loading triplet configuration from: %s\n", triplet_file_path);
+ }
+ else if (!Strings::case_insensitive_ascii_starts_with(triplet_file_path, paths.triplets.u8string()))
+ {
+ System::printf("-- [OVERLAY] Loading triplet configuration from: %s\n", triplet_file_path);
+ }
+
+ auto u8portdir = scfl.source_location.u8string();
+ if (!Strings::case_insensitive_ascii_starts_with(u8portdir, paths.ports.u8string()))
+ {
+ System::printf("-- Installing port from location: %s\n", u8portdir);
+ }
+
+ const auto timer = Chrono::ElapsedTimer::create_started();
+
+ auto command = vcpkg::make_cmake_cmd(paths, paths.ports_cmake, get_cmake_build_args(paths, action, triplet));
+
+ const auto& env = paths.get_action_env(action.abi_info.value_or_exit(VCPKG_LINE_INFO));
+
+ auto buildpath = paths.buildtrees / action.spec.name();
+ if (!fs.exists(buildpath))
+ {
+ std::error_code err;
+ fs.create_directory(buildpath, err);
+ Checks::check_exit(VCPKG_LINE_INFO,
+ !err.value(),
+ "Failed to create directory '%s', code: %d",
+ buildpath.u8string(),
+ err.value());
+ }
+ auto stdoutlog = buildpath / ("stdout-" + action.spec.triplet().canonical_name() + ".log");
+ std::ofstream out_file(stdoutlog.native().c_str(), std::ios::out | std::ios::binary | std::ios::trunc);
+ Checks::check_exit(VCPKG_LINE_INFO, out_file, "Failed to open '%s' for writing", stdoutlog.u8string());
+ const int return_code = System::cmd_execute_and_stream_data(
+ command,
+ [&](StringView sv) {
+ System::print2(sv);
+ out_file.write(sv.data(), sv.size());
+ Checks::check_exit(
+ VCPKG_LINE_INFO, out_file, "Error occurred while writing '%s'", stdoutlog.u8string());
+ },
+ env);
+ out_file.close();
+
+ // With the exception of empty packages, builds in "Download Mode" always result in failure.
+ if (action.build_options.only_downloads == Build::OnlyDownloads::YES)
+ {
+ // TODO: Capture executed command output and evaluate whether the failure was intended.
+ // If an unintended error occurs then return a BuildResult::DOWNLOAD_FAILURE status.
+ return BuildResult::DOWNLOADED;
+ }
+
+ const auto buildtimeus = timer.microseconds();
+ const auto spec_string = action.spec.to_string();
+
+ {
+ auto locked_metrics = Metrics::g_metrics.lock();
+
+ locked_metrics->track_buildtime(Hash::get_string_hash(spec_string, Hash::Algorithm::Sha256) + ":[" +
+ Strings::join(",",
+ action.feature_list,
+ [](const std::string& feature) {
+ return Hash::get_string_hash(feature,
+ Hash::Algorithm::Sha256);
+ }) +
+ "]",
+ buildtimeus);
+ if (return_code != 0)
+ {
+ locked_metrics->track_property("error", "build failed");
+ locked_metrics->track_property("build_error", spec_string);
+ return BuildResult::BUILD_FAILED;
+ }
+ }
+
+ const BuildInfo build_info = read_build_info(fs, paths.build_info_file_path(action.spec));
+ const size_t error_count =
+ PostBuildLint::perform_all_checks(action.spec, paths, pre_build_info, build_info, scfl.source_location);
+
+ auto find_itr = action.feature_dependencies.find("core");
+ Checks::check_exit(VCPKG_LINE_INFO, find_itr != action.feature_dependencies.end());
+
+ std::unique_ptr<BinaryControlFile> bcf = create_binary_control_file(*scfl.source_control_file->core_paragraph,
+ triplet,
+ build_info,
+ action.public_abi(),
+ std::move(find_itr->second));
+
+ if (error_count != 0)
+ {
+ return BuildResult::POST_BUILD_CHECKS_FAILED;
+ }
+ for (auto&& feature : action.feature_list)
+ {
+ for (auto&& f_pgh : scfl.source_control_file->feature_paragraphs)
+ {
+ if (f_pgh->name == feature)
+ {
+ find_itr = action.feature_dependencies.find(feature);
+ Checks::check_exit(VCPKG_LINE_INFO, find_itr != action.feature_dependencies.end());
+
+ bcf->features.emplace_back(
+ *scfl.source_control_file->core_paragraph, *f_pgh, triplet, std::move(find_itr->second));
+ }
+ }
+ }
+
+ write_binary_control_file(paths, *bcf);
+ return {BuildResult::SUCCEEDED, std::move(bcf)};
+ }
+
+ static ExtendedBuildResult do_build_package_and_clean_buildtrees(const VcpkgPaths& paths,
+ const Dependencies::InstallPlanAction& action)
+ {
+ auto result = do_build_package(paths, action);
+
+ if (action.build_options.clean_buildtrees == CleanBuildtrees::YES)
+ {
+ auto& fs = paths.get_filesystem();
+ auto buildtree_files = fs.get_files_non_recursive(paths.build_dir(action.spec));
+ for (auto&& file : buildtree_files)
+ {
+ if (fs.is_directory(file)) // Will only keep the logs
+ {
+ std::error_code ec;
+ fs::path failure_point;
+ fs.remove_all(file, ec, failure_point);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ static void abi_entries_from_abi_info(const AbiInfo& abi_info, std::vector<AbiEntry>& abi_tag_entries)
+ {
+ abi_tag_entries.emplace_back("triplet", abi_info.triplet_abi.value_or_exit(VCPKG_LINE_INFO));
+
+ const auto& pre_build_info = *abi_info.pre_build_info;
+ if (pre_build_info.public_abi_override)
+ {
+ abi_tag_entries.emplace_back(
+ "public_abi_override",
+ Hash::get_string_hash(pre_build_info.public_abi_override.value_or_exit(VCPKG_LINE_INFO),
+ Hash::Algorithm::Sha1));
+ }
+
+ for (const auto& env_var : pre_build_info.passthrough_env_vars)
+ {
+ abi_tag_entries.emplace_back(
+ "ENV:" + env_var,
+ Hash::get_string_hash(System::get_environment_variable(env_var).value_or(""), Hash::Algorithm::Sha1));
+ }
+ }
+
+ static Optional<AbiTagAndFile> compute_abi_tag(const VcpkgPaths& paths,
+ const Dependencies::InstallPlanAction& action,
+ Span<const AbiEntry> dependency_abis)
+ {
+ auto& fs = paths.get_filesystem();
+ Triplet triplet = action.spec.triplet();
+
+ std::vector<AbiEntry> abi_tag_entries(dependency_abis.begin(), dependency_abis.end());
+
+ abi_entries_from_abi_info(action.abi_info.value_or_exit(VCPKG_LINE_INFO), abi_tag_entries);
+
+ // If there is an unusually large number of files in the port then
+ // something suspicious is going on. Rather than hash all of them
+ // just mark the port as no-hash
+ const int max_port_file_count = 100;
+
+ auto&& port_dir = action.source_control_file_location.value_or_exit(VCPKG_LINE_INFO).source_location;
+ size_t port_file_count = 0;
+ for (auto& port_file : fs::stdfs::recursive_directory_iterator(port_dir))
+ {
+ if (fs::is_regular_file(fs.status(VCPKG_LINE_INFO, port_file)))
+ {
+ abi_tag_entries.emplace_back(
+ port_file.path().filename().u8string(),
+ vcpkg::Hash::get_file_hash(VCPKG_LINE_INFO, fs, port_file, Hash::Algorithm::Sha1));
+
+ ++port_file_count;
+ if (port_file_count > max_port_file_count)
+ {
+ abi_tag_entries.emplace_back("no_hash_max_portfile", "");
+ break;
+ }
+ }
+ }
+
+ abi_tag_entries.emplace_back("cmake", paths.get_tool_version(Tools::CMAKE));
+
+#if defined(_WIN32)
+ abi_tag_entries.emplace_back("powershell", paths.get_tool_version("powershell-core"));
+#endif
+
+ auto& helpers = paths.get_cmake_script_hashes();
+ auto portfile_contents =
+ fs.read_contents(port_dir / fs::u8path("portfile.cmake")).value_or_exit(VCPKG_LINE_INFO);
+ for (auto&& helper : helpers)
+ {
+ if (Strings::case_insensitive_ascii_contains(portfile_contents, helper.first))
+ {
+ abi_tag_entries.emplace_back(helper.first, helper.second);
+ }
+ }
+
+ abi_tag_entries.emplace_back("post_build_checks", "2");
+ std::vector<std::string> sorted_feature_list = action.feature_list;
+ Util::sort(sorted_feature_list);
+ abi_tag_entries.emplace_back("features", Strings::join(";", sorted_feature_list));
+
+ if (action.build_options.use_head_version == UseHeadVersion::YES) abi_tag_entries.emplace_back("head", "");
+
+ Util::sort(abi_tag_entries);
+
+ const std::string full_abi_info =
+ Strings::join("", abi_tag_entries, [](const AbiEntry& p) { return p.key + " " + p.value + "\n"; });
+
+ if (Debug::g_debugging)
+ {
+ std::string message = Strings::concat("[DEBUG] <abientries for ", action.spec, ">\n");
+ for (auto&& entry : abi_tag_entries)
+ {
+ Strings::append(message, "[DEBUG] ", entry.key, "|", entry.value, "\n");
+ }
+ Strings::append(message, "[DEBUG] </abientries>\n");
+ System::print2(message);
+ }
+
+ auto abi_tag_entries_missing = Util::filter(abi_tag_entries, [](const AbiEntry& p) { return p.value.empty(); });
+
+ if (abi_tag_entries_missing.empty())
+ {
+ auto current_build_tree = paths.build_dir(action.spec);
+ fs.create_directory(current_build_tree, VCPKG_LINE_INFO);
+ const auto abi_file_path = current_build_tree / (triplet.canonical_name() + ".vcpkg_abi_info.txt");
+ fs.write_contents(abi_file_path, full_abi_info, VCPKG_LINE_INFO);
+
+ return AbiTagAndFile{Hash::get_file_hash(VCPKG_LINE_INFO, fs, abi_file_path, Hash::Algorithm::Sha1),
+ abi_file_path};
+ }
+
+ Debug::print(
+ "Warning: abi keys are missing values:\n",
+ Strings::join("", abi_tag_entries_missing, [](const AbiEntry& e) { return " " + e.key + "\n"; }),
+ "\n");
+
+ return nullopt;
+ }
+
+ void compute_all_abis(const VcpkgPaths& paths,
+ Dependencies::ActionPlan& action_plan,
+ const CMakeVars::CMakeVarProvider& var_provider,
+ const StatusParagraphs& status_db)
+ {
+ using Dependencies::InstallPlanAction;
+ for (auto it = action_plan.install_actions.begin(); it != action_plan.install_actions.end(); ++it)
+ {
+ auto& action = *it;
+ if (action.abi_info.has_value()) continue;
+
+ std::vector<AbiEntry> dependency_abis;
+ if (!Util::Enum::to_bool(action.build_options.only_downloads))
+ {
+ for (auto&& pspec : action.package_dependencies)
+ {
+ if (pspec == action.spec) continue;
+
+ auto pred = [&](const InstallPlanAction& ipa) { return ipa.spec == pspec; };
+ auto it2 = std::find_if(action_plan.install_actions.begin(), it, pred);
+ if (it2 == it)
+ {
+ // Finally, look in current installed
+ auto status_it = status_db.find(pspec);
+ if (status_it == status_db.end())
+ {
+ Checks::exit_with_message(
+ VCPKG_LINE_INFO, "Failed to find dependency abi for %s -> %s", action.spec, pspec);
+ }
+ else
+ {
+ dependency_abis.emplace_back(AbiEntry{pspec.name(), status_it->get()->package.abi});
+ }
+ }
+ else
+ {
+ dependency_abis.emplace_back(AbiEntry{pspec.name(), it2->public_abi()});
+ }
+ }
+ }
+
+ action.abi_info = AbiInfo();
+ auto& abi_info = action.abi_info.value_or_exit(VCPKG_LINE_INFO);
+
+ abi_info.pre_build_info = std::make_unique<PreBuildInfo>(
+ paths, action.spec.triplet(), var_provider.get_tag_vars(action.spec).value_or_exit(VCPKG_LINE_INFO));
+ abi_info.toolset = paths.get_toolset(*abi_info.pre_build_info);
+ abi_info.triplet_abi = paths.get_triplet_info(abi_info);
+
+ auto maybe_abi_tag_and_file = compute_abi_tag(paths, action, dependency_abis);
+ if (auto p = maybe_abi_tag_and_file.get())
+ {
+ abi_info.package_abi = std::move(p->tag);
+ abi_info.abi_tag_file = std::move(p->tag_file);
+ }
+ }
+ }
+
+ ExtendedBuildResult build_package(const VcpkgPaths& paths,
+ const Dependencies::InstallPlanAction& action,
+ IBinaryProvider& binaries_provider,
+ const IBuildLogsRecorder& build_logs_recorder,
+ const StatusParagraphs& status_db)
+ {
+ auto& fs = paths.get_filesystem();
+ auto& spec = action.spec;
+ const std::string& name = action.source_control_file_location.value_or_exit(VCPKG_LINE_INFO)
+ .source_control_file->core_paragraph->name;
+
+ std::vector<FeatureSpec> missing_fspecs;
+ for (const auto& kv : action.feature_dependencies)
+ {
+ for (const FeatureSpec& fspec : kv.second)
+ {
+ if (!(status_db.is_installed(fspec) || fspec.name() == name))
+ {
+ missing_fspecs.emplace_back(fspec);
+ }
+ }
+ }
+
+ if (!missing_fspecs.empty() && !Util::Enum::to_bool(action.build_options.only_downloads))
+ {
+ return {BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES, std::move(missing_fspecs)};
+ }
+
+ std::vector<AbiEntry> dependency_abis;
+ for (auto&& pspec : action.package_dependencies)
+ {
+ if (pspec == spec || Util::Enum::to_bool(action.build_options.only_downloads))
+ {
+ 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});
+ }
+
+ auto& abi_info = action.abi_info.value_or_exit(VCPKG_LINE_INFO);
+ if (!abi_info.abi_tag_file)
+ {
+ return do_build_package_and_clean_buildtrees(paths, action);
+ }
+
+ auto& abi_file = *abi_info.abi_tag_file.get();
+
+ std::error_code ec;
+ const fs::path abi_package_dir = paths.package_dir(spec) / "share" / spec.name();
+ const fs::path abi_file_in_package = paths.package_dir(spec) / "share" / spec.name() / "vcpkg_abi_info.txt";
+ if (action.build_options.editable == Build::Editable::NO)
+ {
+ auto restore = binaries_provider.try_restore(paths, action);
+ if (restore == RestoreResult::build_failed)
+ {
+ return BuildResult::BUILD_FAILED;
+ }
+ else if (restore == RestoreResult::success)
+ {
+ auto maybe_bcf = Paragraphs::try_load_cached_package(paths, spec);
+ auto bcf = std::make_unique<BinaryControlFile>(std::move(maybe_bcf).value_or_exit(VCPKG_LINE_INFO));
+ return {BuildResult::SUCCEEDED, std::move(bcf)};
+ }
+ else
+ {
+ // missing package, proceed to build.
+ }
+ }
+
+ ExtendedBuildResult result = do_build_package_and_clean_buildtrees(paths, action);
+
+ fs.create_directories(abi_package_dir, ec);
+ fs.copy_file(abi_file, abi_file_in_package, fs::copy_options::none, ec);
+ Checks::check_exit(VCPKG_LINE_INFO, !ec, "Could not copy into file: %s", abi_file_in_package.u8string());
+
+ if (action.build_options.editable == Build::Editable::NO && result.code == BuildResult::SUCCEEDED)
+ {
+ binaries_provider.push_success(paths, action);
+ }
+
+ build_logs_recorder.record_build_result(paths, spec, result.code);
+
+ return result;
+ }
+
+ const std::string& to_string(const BuildResult build_result)
+ {
+ static const std::string NULLVALUE_STRING = Enums::nullvalue_to_string("vcpkg::Commands::Build::BuildResult");
+ static const std::string SUCCEEDED_STRING = "SUCCEEDED";
+ static const std::string BUILD_FAILED_STRING = "BUILD_FAILED";
+ static const std::string FILE_CONFLICTS_STRING = "FILE_CONFLICTS";
+ static const std::string POST_BUILD_CHECKS_FAILED_STRING = "POST_BUILD_CHECKS_FAILED";
+ static const std::string CASCADED_DUE_TO_MISSING_DEPENDENCIES_STRING = "CASCADED_DUE_TO_MISSING_DEPENDENCIES";
+ static const std::string EXCLUDED_STRING = "EXCLUDED";
+ static const std::string DOWNLOADED_STRING = "DOWNLOADED";
+
+ switch (build_result)
+ {
+ case BuildResult::NULLVALUE: return NULLVALUE_STRING;
+ case BuildResult::SUCCEEDED: return SUCCEEDED_STRING;
+ case BuildResult::BUILD_FAILED: return BUILD_FAILED_STRING;
+ case BuildResult::POST_BUILD_CHECKS_FAILED: return POST_BUILD_CHECKS_FAILED_STRING;
+ case BuildResult::FILE_CONFLICTS: return FILE_CONFLICTS_STRING;
+ case BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES: return CASCADED_DUE_TO_MISSING_DEPENDENCIES_STRING;
+ case BuildResult::EXCLUDED: return EXCLUDED_STRING;
+ case BuildResult::DOWNLOADED: return DOWNLOADED_STRING;
+ default: Checks::unreachable(VCPKG_LINE_INFO);
+ }
+ }
+
+ std::string create_error_message(const BuildResult build_result, const PackageSpec& spec)
+ {
+ return Strings::format("Error: Building package %s failed with: %s", spec, Build::to_string(build_result));
+ }
+
+ std::string create_user_troubleshooting_message(const PackageSpec& spec)
+ {
+ return Strings::format("Please ensure you're using the latest portfiles with `.\\vcpkg update`, then\n"
+ "submit an issue at https://github.com/Microsoft/vcpkg/issues including:\n"
+ " Package: %s\n"
+ " Vcpkg version: %s\n"
+ "\n"
+ "Additionally, attach any relevant sections from the log files above.",
+ spec,
+ Commands::Version::version());
+ }
+
+ static BuildInfo inner_create_buildinfo(Parse::Paragraph pgh)
+ {
+ Parse::ParagraphParser parser(std::move(pgh));
+
+ BuildInfo build_info;
+
+ {
+ std::string crt_linkage_as_string;
+ parser.required_field(BuildInfoRequiredField::CRT_LINKAGE, crt_linkage_as_string);
+
+ auto crtlinkage = to_linkage_type(crt_linkage_as_string);
+ if (const auto p = crtlinkage.get())
+ build_info.crt_linkage = *p;
+ else
+ Checks::exit_with_message(VCPKG_LINE_INFO, "Invalid crt linkage type: [%s]", crt_linkage_as_string);
+ }
+
+ {
+ std::string library_linkage_as_string;
+ parser.required_field(BuildInfoRequiredField::LIBRARY_LINKAGE, library_linkage_as_string);
+ auto liblinkage = to_linkage_type(library_linkage_as_string);
+ if (const auto p = liblinkage.get())
+ build_info.library_linkage = *p;
+ else
+ Checks::exit_with_message(
+ VCPKG_LINE_INFO, "Invalid library linkage type: [%s]", library_linkage_as_string);
+ }
+ std::string version = parser.optional_field("Version");
+ if (!version.empty()) build_info.version = std::move(version);
+
+ std::map<BuildPolicy, bool> policies;
+ for (auto policy : G_ALL_POLICIES)
+ {
+ const auto setting = parser.optional_field(to_string(policy));
+ if (setting.empty()) continue;
+ if (setting == "enabled")
+ policies.emplace(policy, true);
+ else if (setting == "disabled")
+ policies.emplace(policy, false);
+ else
+ Checks::exit_with_message(
+ VCPKG_LINE_INFO, "Unknown setting for policy '%s': %s", to_string(policy), setting);
+ }
+
+ if (const auto err = parser.error_info("PostBuildInformation"))
+ {
+ print_error_message(err);
+ Checks::exit_fail(VCPKG_LINE_INFO);
+ }
+
+ build_info.policies = BuildPolicies(std::move(policies));
+
+ return build_info;
+ }
+
+ BuildInfo read_build_info(const Files::Filesystem& fs, const fs::path& filepath)
+ {
+ const ExpectedS<Parse::Paragraph> pghs = Paragraphs::get_single_paragraph(fs, filepath);
+ Checks::check_exit(
+ VCPKG_LINE_INFO, pghs.get() != nullptr, "Invalid BUILD_INFO file for package: %s", pghs.error());
+ return inner_create_buildinfo(*pghs.get());
+ }
+
+ PreBuildInfo::PreBuildInfo(const VcpkgPaths& paths,
+ Triplet triplet,
+ const std::unordered_map<std::string, std::string>& cmakevars)
+ : m_paths(paths), triplet(triplet)
+ {
+ enum class VcpkgTripletVar
+ {
+ TARGET_ARCHITECTURE = 0,
+ CMAKE_SYSTEM_NAME,
+ CMAKE_SYSTEM_VERSION,
+ PLATFORM_TOOLSET,
+ VISUAL_STUDIO_PATH,
+ CHAINLOAD_TOOLCHAIN_FILE,
+ BUILD_TYPE,
+ ENV_PASSTHROUGH,
+ PUBLIC_ABI_OVERRIDE,
+ LOAD_VCVARS_ENV,
+ };
+
+ static const std::vector<std::pair<std::string, VcpkgTripletVar>> VCPKG_OPTIONS = {
+ {"VCPKG_TARGET_ARCHITECTURE", VcpkgTripletVar::TARGET_ARCHITECTURE},
+ {"VCPKG_CMAKE_SYSTEM_NAME", VcpkgTripletVar::CMAKE_SYSTEM_NAME},
+ {"VCPKG_CMAKE_SYSTEM_VERSION", VcpkgTripletVar::CMAKE_SYSTEM_VERSION},
+ {"VCPKG_PLATFORM_TOOLSET", VcpkgTripletVar::PLATFORM_TOOLSET},
+ {"VCPKG_VISUAL_STUDIO_PATH", VcpkgTripletVar::VISUAL_STUDIO_PATH},
+ {"VCPKG_CHAINLOAD_TOOLCHAIN_FILE", VcpkgTripletVar::CHAINLOAD_TOOLCHAIN_FILE},
+ {"VCPKG_BUILD_TYPE", VcpkgTripletVar::BUILD_TYPE},
+ {"VCPKG_ENV_PASSTHROUGH", VcpkgTripletVar::ENV_PASSTHROUGH},
+ {"VCPKG_PUBLIC_ABI_OVERRIDE", VcpkgTripletVar::PUBLIC_ABI_OVERRIDE},
+ {"VCPKG_LOAD_VCVARS_ENV", VcpkgTripletVar::LOAD_VCVARS_ENV},
+ };
+
+ std::string empty;
+ for (auto&& kv : VCPKG_OPTIONS)
+ {
+ const std::string& variable_value = [&]() -> const std::string& {
+ auto find_itr = cmakevars.find(kv.first);
+ if (find_itr == cmakevars.end())
+ {
+ return empty;
+ }
+ else
+ {
+ return find_itr->second;
+ }
+ }();
+
+ switch (kv.second)
+ {
+ case VcpkgTripletVar::TARGET_ARCHITECTURE: target_architecture = variable_value; break;
+ case VcpkgTripletVar::CMAKE_SYSTEM_NAME: cmake_system_name = variable_value; break;
+ case VcpkgTripletVar::CMAKE_SYSTEM_VERSION: cmake_system_version = variable_value; break;
+ case VcpkgTripletVar::PLATFORM_TOOLSET:
+ platform_toolset = variable_value.empty() ? nullopt : Optional<std::string>{variable_value};
+ break;
+ case VcpkgTripletVar::VISUAL_STUDIO_PATH:
+ visual_studio_path = variable_value.empty() ? nullopt : Optional<fs::path>{variable_value};
+ break;
+ case VcpkgTripletVar::CHAINLOAD_TOOLCHAIN_FILE:
+ external_toolchain_file = variable_value.empty() ? nullopt : Optional<std::string>{variable_value};
+ break;
+ case VcpkgTripletVar::BUILD_TYPE:
+ if (variable_value.empty())
+ build_type = nullopt;
+ else if (Strings::case_insensitive_ascii_equals(variable_value, "debug"))
+ build_type = ConfigurationType::DEBUG;
+ else if (Strings::case_insensitive_ascii_equals(variable_value, "release"))
+ build_type = ConfigurationType::RELEASE;
+ else
+ Checks::exit_with_message(
+ VCPKG_LINE_INFO,
+ "Unknown setting for VCPKG_BUILD_TYPE: %s. Valid settings are '', 'debug' and 'release'.",
+ variable_value);
+ break;
+ case VcpkgTripletVar::ENV_PASSTHROUGH:
+ passthrough_env_vars = Strings::split(variable_value, ';');
+ break;
+ case VcpkgTripletVar::PUBLIC_ABI_OVERRIDE:
+ public_abi_override = variable_value.empty() ? nullopt : Optional<std::string>{variable_value};
+ break;
+ case VcpkgTripletVar::LOAD_VCVARS_ENV:
+ if (variable_value.empty())
+ {
+ load_vcvars_env = true;
+ if (external_toolchain_file) load_vcvars_env = false;
+ }
+ else if (Strings::case_insensitive_ascii_equals(variable_value, "1") ||
+ Strings::case_insensitive_ascii_equals(variable_value, "on") ||
+ Strings::case_insensitive_ascii_equals(variable_value, "true"))
+ load_vcvars_env = true;
+ else if (Strings::case_insensitive_ascii_equals(variable_value, "0") ||
+ Strings::case_insensitive_ascii_equals(variable_value, "off") ||
+ Strings::case_insensitive_ascii_equals(variable_value, "false"))
+ load_vcvars_env = false;
+ else
+ Checks::exit_with_message(VCPKG_LINE_INFO,
+ "Unknown boolean setting for VCPKG_LOAD_VCVARS_ENV: %s. Valid "
+ "settings are '', '1', '0', 'ON', 'OFF', 'TRUE', and 'FALSE'.",
+ variable_value);
+ break;
+ }
+ }
+ }
+
+ ExtendedBuildResult::ExtendedBuildResult(BuildResult code) : code(code) { }
+ ExtendedBuildResult::ExtendedBuildResult(BuildResult code, std::unique_ptr<BinaryControlFile>&& bcf)
+ : code(code), binary_control_file(std::move(bcf))
+ {
+ }
+ ExtendedBuildResult::ExtendedBuildResult(BuildResult code, std::vector<FeatureSpec>&& unmet_deps)
+ : code(code), unmet_dependencies(std::move(unmet_deps))
+ {
+ }
+
+ const IBuildLogsRecorder& null_build_logs_recorder() noexcept { return null_build_logs_recorder_instance; }
+}
diff --git a/toolsrc/src/vcpkg/buildenvironment.cpp b/toolsrc/src/vcpkg/buildenvironment.cpp
index be61ba37c..9ef330e66 100644
--- a/toolsrc/src/vcpkg/buildenvironment.cpp
+++ b/toolsrc/src/vcpkg/buildenvironment.cpp
@@ -1,20 +1,20 @@
-#include "pch.h"
-
-#include <vcpkg/buildenvironment.h>
-
-namespace vcpkg
-{
- std::string make_cmake_cmd(const VcpkgPaths& paths,
- const fs::path& cmake_script,
- std::vector<System::CMakeVariable>&& pass_variables)
- {
- auto local_variables = std::move(pass_variables);
- local_variables.emplace_back("VCPKG_ROOT_DIR", paths.root);
- local_variables.emplace_back("PACKAGES_DIR", paths.packages);
- local_variables.emplace_back("BUILDTREES_DIR", paths.buildtrees);
- local_variables.emplace_back("_VCPKG_INSTALLED_DIR", paths.installed);
- local_variables.emplace_back("DOWNLOADS", paths.downloads);
- local_variables.emplace_back("VCPKG_MANIFEST_INSTALL", "OFF");
- return System::make_basic_cmake_cmd(paths.get_tool_exe(Tools::CMAKE), cmake_script, local_variables);
- }
-}
+#include "pch.h"
+
+#include <vcpkg/buildenvironment.h>
+
+namespace vcpkg
+{
+ std::string make_cmake_cmd(const VcpkgPaths& paths,
+ const fs::path& cmake_script,
+ std::vector<System::CMakeVariable>&& pass_variables)
+ {
+ auto local_variables = std::move(pass_variables);
+ local_variables.emplace_back("VCPKG_ROOT_DIR", paths.root);
+ local_variables.emplace_back("PACKAGES_DIR", paths.packages);
+ local_variables.emplace_back("BUILDTREES_DIR", paths.buildtrees);
+ local_variables.emplace_back("_VCPKG_INSTALLED_DIR", paths.installed);
+ local_variables.emplace_back("DOWNLOADS", paths.downloads);
+ local_variables.emplace_back("VCPKG_MANIFEST_INSTALL", "OFF");
+ return System::make_basic_cmake_cmd(paths.get_tool_exe(Tools::CMAKE), cmake_script, local_variables);
+ }
+}
diff --git a/toolsrc/src/vcpkg/commands.ciclean.cpp b/toolsrc/src/vcpkg/commands.ciclean.cpp
index 6c4a95d19..980e17da8 100644
--- a/toolsrc/src/vcpkg/commands.ciclean.cpp
+++ b/toolsrc/src/vcpkg/commands.ciclean.cpp
@@ -1,42 +1,42 @@
-#include "pch.h"
-
-#include <vcpkg/base/checks.h>
-#include <vcpkg/base/files.h>
-#include <vcpkg/base/system.print.h>
-
-#include <vcpkg/commands.h>
-#include <vcpkg/vcpkgcmdarguments.h>
-
-using namespace vcpkg;
-
-namespace
-{
- void clear_directory(Files::Filesystem& fs, const fs::path& target)
- {
- using vcpkg::System::print2;
- if (fs.is_directory(target))
- {
- print2("Clearing contents of ", target.u8string(), "\n");
- fs.remove_all_inside(target, VCPKG_LINE_INFO);
- }
- else
- {
- print2("Skipping clearing contents of ", target.u8string(), " because it was not a directory\n");
- }
- }
-}
-
-namespace vcpkg::Commands::CIClean
-{
- void perform_and_exit(const VcpkgCmdArguments&, const VcpkgPaths& paths)
- {
- using vcpkg::System::print2;
- auto& fs = paths.get_filesystem();
- print2("Starting vcpkg CI clean\n");
- clear_directory(fs, paths.buildtrees);
- clear_directory(fs, paths.installed);
- clear_directory(fs, paths.packages);
- print2("Completed vcpkg CI clean\n");
- Checks::exit_success(VCPKG_LINE_INFO);
- }
-}
+#include "pch.h"
+
+#include <vcpkg/base/checks.h>
+#include <vcpkg/base/files.h>
+#include <vcpkg/base/system.print.h>
+
+#include <vcpkg/commands.h>
+#include <vcpkg/vcpkgcmdarguments.h>
+
+using namespace vcpkg;
+
+namespace
+{
+ void clear_directory(Files::Filesystem& fs, const fs::path& target)
+ {
+ using vcpkg::System::print2;
+ if (fs.is_directory(target))
+ {
+ print2("Clearing contents of ", target.u8string(), "\n");
+ fs.remove_all_inside(target, VCPKG_LINE_INFO);
+ }
+ else
+ {
+ print2("Skipping clearing contents of ", target.u8string(), " because it was not a directory\n");
+ }
+ }
+}
+
+namespace vcpkg::Commands::CIClean
+{
+ void perform_and_exit(const VcpkgCmdArguments&, const VcpkgPaths& paths)
+ {
+ using vcpkg::System::print2;
+ auto& fs = paths.get_filesystem();
+ print2("Starting vcpkg CI clean\n");
+ clear_directory(fs, paths.buildtrees);
+ clear_directory(fs, paths.installed);
+ clear_directory(fs, paths.packages);
+ print2("Completed vcpkg CI clean\n");
+ Checks::exit_success(VCPKG_LINE_INFO);
+ }
+}
diff --git a/toolsrc/src/vcpkg/commands.dependinfo.cpp b/toolsrc/src/vcpkg/commands.dependinfo.cpp
index 0431e0ad4..a6695cf2d 100644
--- a/toolsrc/src/vcpkg/commands.dependinfo.cpp
+++ b/toolsrc/src/vcpkg/commands.dependinfo.cpp
@@ -1,331 +1,331 @@
-#include "pch.h"
-
-#include <vcpkg/base/strings.h>
-#include <vcpkg/base/system.print.h>
-#include <vcpkg/base/util.h>
-
-#include <vcpkg/commands.h>
-#include <vcpkg/dependencies.h>
-#include <vcpkg/help.h>
-#include <vcpkg/input.h>
-#include <vcpkg/install.h>
-#include <vcpkg/packagespec.h>
-
-#include <vector>
-
-using vcpkg::Dependencies::ActionPlan;
-using vcpkg::Dependencies::InstallPlanAction;
-using vcpkg::PortFileProvider::PathsPortFileProvider;
-
-namespace vcpkg::Commands::DependInfo
-{
- namespace
- {
- constexpr StringLiteral OPTION_DOT = "--dot";
- constexpr StringLiteral OPTION_DGML = "--dgml";
- constexpr StringLiteral OPTION_SHOW_DEPTH = "--show-depth";
- constexpr StringLiteral OPTION_MAX_RECURSE = "--max-recurse";
- constexpr StringLiteral OPTION_SORT = "--sort";
-
- constexpr int NO_RECURSE_LIMIT_VALUE = -1;
-
- constexpr std::array<CommandSwitch, 3> DEPEND_SWITCHES = {
- {{OPTION_DOT, "Creates graph on basis of dot"},
- {OPTION_DGML, "Creates graph on basis of dgml"},
- {OPTION_SHOW_DEPTH, "Show recursion depth in output"}}};
-
- constexpr std::array<CommandSetting, 2> DEPEND_SETTINGS = {
- {{OPTION_MAX_RECURSE, "Set max recursion depth, a value of -1 indicates no limit"},
- {OPTION_SORT,
- "Set sort order for the list of dependencies, accepted values are: lexicographical, topological "
- "(default), "
- "reverse"}}};
-
- struct PackageDependInfo
- {
- std::string package;
- int depth;
- std::unordered_set<std::string> features;
- std::vector<std::string> dependencies;
- };
-
- enum SortMode
- {
- Lexicographical = 0,
- Topological,
- ReverseTopological,
- Default = Topological
- };
-
- int get_max_depth(const ParsedArguments& options)
- {
- auto iter = options.settings.find(OPTION_MAX_RECURSE);
- if (iter != options.settings.end())
- {
- std::string value = iter->second;
- try
- {
- return std::stoi(value);
- }
- catch (std::exception&)
- {
- Checks::exit_with_message(VCPKG_LINE_INFO, "Value of --max-depth must be an integer");
- }
- }
- // No --max-depth set, default to no limit.
- return NO_RECURSE_LIMIT_VALUE;
- }
-
- SortMode get_sort_mode(const ParsedArguments& options)
- {
- constexpr StringLiteral OPTION_SORT_LEXICOGRAPHICAL = "lexicographical";
- constexpr StringLiteral OPTION_SORT_TOPOLOGICAL = "topological";
- constexpr StringLiteral OPTION_SORT_REVERSE = "reverse";
-
- static const std::map<std::string, SortMode> sortModesMap{{OPTION_SORT_LEXICOGRAPHICAL, Lexicographical},
- {OPTION_SORT_TOPOLOGICAL, Topological},
- {OPTION_SORT_REVERSE, ReverseTopological}};
-
- auto iter = options.settings.find(OPTION_SORT);
- if (iter != options.settings.end())
- {
- const std::string value = Strings::ascii_to_lowercase(std::string{iter->second});
- auto it = sortModesMap.find(value);
- if (it != sortModesMap.end())
- {
- return it->second;
- }
- Checks::exit_with_message(VCPKG_LINE_INFO,
- "Value of --sort must be one of `%s`, `%s`, or `%s`",
- OPTION_SORT_LEXICOGRAPHICAL,
- OPTION_SORT_TOPOLOGICAL,
- OPTION_SORT_REVERSE);
- }
- return Default;
- }
-
- std::string create_dot_as_string(const std::vector<PackageDependInfo>& depend_info)
- {
- int empty_node_count = 0;
-
- std::string s;
- s.append("digraph G{ rankdir=LR; edge [minlen=3]; overlap=false;");
-
- for (const auto& package : depend_info)
- {
- if (package.dependencies.empty())
- {
- empty_node_count++;
- continue;
- }
-
- const std::string name = Strings::replace_all(std::string{package.package}, "-", "_");
- s.append(Strings::format("%s;", name));
- for (const auto& d : package.dependencies)
- {
- const std::string dependency_name = Strings::replace_all(std::string{d}, "-", "_");
- s.append(Strings::format("%s -> %s;", name, dependency_name));
- }
- }
-
- s.append(Strings::format("empty [label=\"%d singletons...\"]; }", empty_node_count));
- return s;
- }
-
- std::string create_dgml_as_string(const std::vector<PackageDependInfo>& depend_info)
- {
- std::string s;
- s.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
- s.append("<DirectedGraph xmlns=\"http://schemas.microsoft.com/vs/2009/dgml\">");
-
- std::string nodes, links;
- for (const auto& package : depend_info)
- {
- const std::string name = package.package;
- nodes.append(Strings::format("<Node Id=\"%s\" />", name));
-
- // Iterate over dependencies.
- for (const auto& d : package.dependencies)
- {
- links.append(Strings::format("<Link Source=\"%s\" Target=\"%s\" />", name, d));
- }
- }
-
- s.append(Strings::format("<Nodes>%s</Nodes>", nodes));
-
- s.append(Strings::format("<Links>%s</Links>", links));
-
- s.append("</DirectedGraph>");
- return s;
- }
-
- std::string create_graph_as_string(const std::unordered_set<std::string>& switches,
- const std::vector<PackageDependInfo>& depend_info)
- {
- if (Util::Sets::contains(switches, OPTION_DOT))
- {
- return create_dot_as_string(depend_info);
- }
- else if (Util::Sets::contains(switches, OPTION_DGML))
- {
- return create_dgml_as_string(depend_info);
- }
- return "";
- }
-
- void assign_depth_to_dependencies(const std::string& package,
- const int depth,
- const int max_depth,
- std::map<std::string, PackageDependInfo>& dependencies_map)
- {
- auto iter = dependencies_map.find(package);
- Checks::check_exit(
- VCPKG_LINE_INFO, iter != dependencies_map.end(), "Package not found in dependency graph");
-
- PackageDependInfo& info = iter->second;
-
- if (depth > info.depth)
- {
- info.depth = depth;
- if (depth < max_depth || max_depth == NO_RECURSE_LIMIT_VALUE)
- {
- for (auto&& dependency : info.dependencies)
- {
- assign_depth_to_dependencies(dependency, depth + 1, max_depth, dependencies_map);
- }
- }
- }
- }
-
- std::vector<PackageDependInfo> extract_depend_info(const std::vector<const InstallPlanAction*>& install_actions,
- const int max_depth)
- {
- std::map<std::string, PackageDependInfo> package_dependencies;
- for (const InstallPlanAction* pia : install_actions)
- {
- const InstallPlanAction& install_action = *pia;
-
- const std::vector<std::string> dependencies = Util::fmap(
- install_action.package_dependencies, [](const PackageSpec& spec) { return spec.name(); });
-
- std::unordered_set<std::string> features{install_action.feature_list.begin(),
- install_action.feature_list.end()};
- features.erase("core");
-
- std::string port_name = install_action.spec.name();
-
- PackageDependInfo info{port_name, -1, features, dependencies};
- package_dependencies.emplace(port_name, std::move(info));
- }
-
- const InstallPlanAction& init = *install_actions.back();
- assign_depth_to_dependencies(init.spec.name(), 0, max_depth, package_dependencies);
-
- std::vector<PackageDependInfo> out =
- Util::fmap(package_dependencies, [](auto&& kvpair) -> PackageDependInfo { return kvpair.second; });
- Util::erase_remove_if(out, [](auto&& info) { return info.depth < 0; });
- return out;
- }
- }
-
- const CommandStructure COMMAND_STRUCTURE = {
- create_example_string("depend-info sqlite3"),
- 1,
- 1,
- {DEPEND_SWITCHES, DEPEND_SETTINGS},
- nullptr,
- };
-
- void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, Triplet default_triplet)
- {
- const ParsedArguments options = args.parse_arguments(COMMAND_STRUCTURE);
- const int max_depth = get_max_depth(options);
- const SortMode sort_mode = get_sort_mode(options);
- const bool show_depth = Util::Sets::contains(options.switches, OPTION_SHOW_DEPTH);
-
- const std::vector<FullPackageSpec> specs = Util::fmap(args.command_arguments, [&](auto&& arg) {
- return Input::check_and_get_full_package_spec(
- std::string{arg}, default_triplet, COMMAND_STRUCTURE.example_text);
- });
-
- for (auto&& spec : specs)
- {
- Input::check_triplet(spec.package_spec.triplet(), paths);
- }
-
- PathsPortFileProvider provider(paths, args.overlay_ports);
- auto var_provider_storage = CMakeVars::make_triplet_cmake_var_provider(paths);
- auto& var_provider = *var_provider_storage;
-
- // By passing an empty status_db, we should get a plan containing all dependencies.
- // All actions in the plan should be install actions, as there's no installed packages to remove.
- StatusParagraphs status_db;
- auto action_plan = Dependencies::create_feature_install_plan(provider, var_provider, specs, status_db);
- Checks::check_exit(
- VCPKG_LINE_INFO, action_plan.remove_actions.empty(), "Only install actions should exist in the plan");
- std::vector<const InstallPlanAction*> install_actions =
- Util::fmap(action_plan.already_installed, [&](const auto& action) { return &action; });
- for (auto&& action : action_plan.install_actions)
- install_actions.push_back(&action);
-
- std::vector<PackageDependInfo> depend_info = extract_depend_info(install_actions, max_depth);
-
- if (Util::Sets::contains(options.switches, OPTION_DOT) || Util::Sets::contains(options.switches, OPTION_DGML))
- {
- const std::vector<const SourceControlFile*> source_control_files =
- Util::fmap(install_actions, [](const InstallPlanAction* install_action) {
- const SourceControlFileLocation& scfl =
- install_action->source_control_file_location.value_or_exit(VCPKG_LINE_INFO);
- return const_cast<const SourceControlFile*>(scfl.source_control_file.get());
- });
-
- const std::string graph_as_string = create_graph_as_string(options.switches, depend_info);
- System::print2(graph_as_string, '\n');
- Checks::exit_success(VCPKG_LINE_INFO);
- }
-
- // TODO: Improve this code
- auto lex = [](const PackageDependInfo& lhs, const PackageDependInfo& rhs) -> bool {
- return lhs.package < rhs.package;
- };
- auto topo = [](const PackageDependInfo& lhs, const PackageDependInfo& rhs) -> bool {
- return lhs.depth > rhs.depth;
- };
- auto reverse = [](const PackageDependInfo& lhs, const PackageDependInfo& rhs) -> bool {
- return lhs.depth < rhs.depth;
- };
-
- switch (sort_mode)
- {
- case SortMode::Lexicographical: std::sort(std::begin(depend_info), std::end(depend_info), lex); break;
- case SortMode::ReverseTopological:
- std::sort(std::begin(depend_info), std::end(depend_info), reverse);
- break;
- case SortMode::Topological: std::sort(std::begin(depend_info), std::end(depend_info), topo); break;
- default: Checks::unreachable(VCPKG_LINE_INFO);
- }
-
- for (auto&& info : depend_info)
- {
- if (info.depth >= 0)
- {
- std::string features = Strings::join(", ", info.features);
- const std::string dependencies = Strings::join(", ", info.dependencies);
-
- if (show_depth)
- {
- System::print2(System::Color::error, "(", info.depth, ") ");
- }
- System::print2(System::Color::success, info.package);
- if (!features.empty())
- {
- System::print2("[");
- System::print2(System::Color::warning, features);
- System::print2("]");
- }
- System::print2(": ", dependencies, "\n");
- }
- }
- Checks::exit_success(VCPKG_LINE_INFO);
- }
-}
+#include "pch.h"
+
+#include <vcpkg/base/strings.h>
+#include <vcpkg/base/system.print.h>
+#include <vcpkg/base/util.h>
+
+#include <vcpkg/commands.h>
+#include <vcpkg/dependencies.h>
+#include <vcpkg/help.h>
+#include <vcpkg/input.h>
+#include <vcpkg/install.h>
+#include <vcpkg/packagespec.h>
+
+#include <vector>
+
+using vcpkg::Dependencies::ActionPlan;
+using vcpkg::Dependencies::InstallPlanAction;
+using vcpkg::PortFileProvider::PathsPortFileProvider;
+
+namespace vcpkg::Commands::DependInfo
+{
+ namespace
+ {
+ constexpr StringLiteral OPTION_DOT = "--dot";
+ constexpr StringLiteral OPTION_DGML = "--dgml";
+ constexpr StringLiteral OPTION_SHOW_DEPTH = "--show-depth";
+ constexpr StringLiteral OPTION_MAX_RECURSE = "--max-recurse";
+ constexpr StringLiteral OPTION_SORT = "--sort";
+
+ constexpr int NO_RECURSE_LIMIT_VALUE = -1;
+
+ constexpr std::array<CommandSwitch, 3> DEPEND_SWITCHES = {
+ {{OPTION_DOT, "Creates graph on basis of dot"},
+ {OPTION_DGML, "Creates graph on basis of dgml"},
+ {OPTION_SHOW_DEPTH, "Show recursion depth in output"}}};
+
+ constexpr std::array<CommandSetting, 2> DEPEND_SETTINGS = {
+ {{OPTION_MAX_RECURSE, "Set max recursion depth, a value of -1 indicates no limit"},
+ {OPTION_SORT,
+ "Set sort order for the list of dependencies, accepted values are: lexicographical, topological "
+ "(default), "
+ "reverse"}}};
+
+ struct PackageDependInfo
+ {
+ std::string package;
+ int depth;
+ std::unordered_set<std::string> features;
+ std::vector<std::string> dependencies;
+ };
+
+ enum SortMode
+ {
+ Lexicographical = 0,
+ Topological,
+ ReverseTopological,
+ Default = Topological
+ };
+
+ int get_max_depth(const ParsedArguments& options)
+ {
+ auto iter = options.settings.find(OPTION_MAX_RECURSE);
+ if (iter != options.settings.end())
+ {
+ std::string value = iter->second;
+ try
+ {
+ return std::stoi(value);
+ }
+ catch (std::exception&)
+ {
+ Checks::exit_with_message(VCPKG_LINE_INFO, "Value of --max-depth must be an integer");
+ }
+ }
+ // No --max-depth set, default to no limit.
+ return NO_RECURSE_LIMIT_VALUE;
+ }
+
+ SortMode get_sort_mode(const ParsedArguments& options)
+ {
+ constexpr StringLiteral OPTION_SORT_LEXICOGRAPHICAL = "lexicographical";
+ constexpr StringLiteral OPTION_SORT_TOPOLOGICAL = "topological";
+ constexpr StringLiteral OPTION_SORT_REVERSE = "reverse";
+
+ static const std::map<std::string, SortMode> sortModesMap{{OPTION_SORT_LEXICOGRAPHICAL, Lexicographical},
+ {OPTION_SORT_TOPOLOGICAL, Topological},
+ {OPTION_SORT_REVERSE, ReverseTopological}};
+
+ auto iter = options.settings.find(OPTION_SORT);
+ if (iter != options.settings.end())
+ {
+ const std::string value = Strings::ascii_to_lowercase(std::string{iter->second});
+ auto it = sortModesMap.find(value);
+ if (it != sortModesMap.end())
+ {
+ return it->second;
+ }
+ Checks::exit_with_message(VCPKG_LINE_INFO,
+ "Value of --sort must be one of `%s`, `%s`, or `%s`",
+ OPTION_SORT_LEXICOGRAPHICAL,
+ OPTION_SORT_TOPOLOGICAL,
+ OPTION_SORT_REVERSE);
+ }
+ return Default;
+ }
+
+ std::string create_dot_as_string(const std::vector<PackageDependInfo>& depend_info)
+ {
+ int empty_node_count = 0;
+
+ std::string s;
+ s.append("digraph G{ rankdir=LR; edge [minlen=3]; overlap=false;");
+
+ for (const auto& package : depend_info)
+ {
+ if (package.dependencies.empty())
+ {
+ empty_node_count++;
+ continue;
+ }
+
+ const std::string name = Strings::replace_all(std::string{package.package}, "-", "_");
+ s.append(Strings::format("%s;", name));
+ for (const auto& d : package.dependencies)
+ {
+ const std::string dependency_name = Strings::replace_all(std::string{d}, "-", "_");
+ s.append(Strings::format("%s -> %s;", name, dependency_name));
+ }
+ }
+
+ s.append(Strings::format("empty [label=\"%d singletons...\"]; }", empty_node_count));
+ return s;
+ }
+
+ std::string create_dgml_as_string(const std::vector<PackageDependInfo>& depend_info)
+ {
+ std::string s;
+ s.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
+ s.append("<DirectedGraph xmlns=\"http://schemas.microsoft.com/vs/2009/dgml\">");
+
+ std::string nodes, links;
+ for (const auto& package : depend_info)
+ {
+ const std::string name = package.package;
+ nodes.append(Strings::format("<Node Id=\"%s\" />", name));
+
+ // Iterate over dependencies.
+ for (const auto& d : package.dependencies)
+ {
+ links.append(Strings::format("<Link Source=\"%s\" Target=\"%s\" />", name, d));
+ }
+ }
+
+ s.append(Strings::format("<Nodes>%s</Nodes>", nodes));
+
+ s.append(Strings::format("<Links>%s</Links>", links));
+
+ s.append("</DirectedGraph>");
+ return s;
+ }
+
+ std::string create_graph_as_string(const std::unordered_set<std::string>& switches,
+ const std::vector<PackageDependInfo>& depend_info)
+ {
+ if (Util::Sets::contains(switches, OPTION_DOT))
+ {
+ return create_dot_as_string(depend_info);
+ }
+ else if (Util::Sets::contains(switches, OPTION_DGML))
+ {
+ return create_dgml_as_string(depend_info);
+ }
+ return "";
+ }
+
+ void assign_depth_to_dependencies(const std::string& package,
+ const int depth,
+ const int max_depth,
+ std::map<std::string, PackageDependInfo>& dependencies_map)
+ {
+ auto iter = dependencies_map.find(package);
+ Checks::check_exit(
+ VCPKG_LINE_INFO, iter != dependencies_map.end(), "Package not found in dependency graph");
+
+ PackageDependInfo& info = iter->second;
+
+ if (depth > info.depth)
+ {
+ info.depth = depth;
+ if (depth < max_depth || max_depth == NO_RECURSE_LIMIT_VALUE)
+ {
+ for (auto&& dependency : info.dependencies)
+ {
+ assign_depth_to_dependencies(dependency, depth + 1, max_depth, dependencies_map);
+ }
+ }
+ }
+ }
+
+ std::vector<PackageDependInfo> extract_depend_info(const std::vector<const InstallPlanAction*>& install_actions,
+ const int max_depth)
+ {
+ std::map<std::string, PackageDependInfo> package_dependencies;
+ for (const InstallPlanAction* pia : install_actions)
+ {
+ const InstallPlanAction& install_action = *pia;
+
+ const std::vector<std::string> dependencies = Util::fmap(
+ install_action.package_dependencies, [](const PackageSpec& spec) { return spec.name(); });
+
+ std::unordered_set<std::string> features{install_action.feature_list.begin(),
+ install_action.feature_list.end()};
+ features.erase("core");
+
+ std::string port_name = install_action.spec.name();
+
+ PackageDependInfo info{port_name, -1, features, dependencies};
+ package_dependencies.emplace(port_name, std::move(info));
+ }
+
+ const InstallPlanAction& init = *install_actions.back();
+ assign_depth_to_dependencies(init.spec.name(), 0, max_depth, package_dependencies);
+
+ std::vector<PackageDependInfo> out =
+ Util::fmap(package_dependencies, [](auto&& kvpair) -> PackageDependInfo { return kvpair.second; });
+ Util::erase_remove_if(out, [](auto&& info) { return info.depth < 0; });
+ return out;
+ }
+ }
+
+ const CommandStructure COMMAND_STRUCTURE = {
+ create_example_string("depend-info sqlite3"),
+ 1,
+ 1,
+ {DEPEND_SWITCHES, DEPEND_SETTINGS},
+ nullptr,
+ };
+
+ void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, Triplet default_triplet)
+ {
+ const ParsedArguments options = args.parse_arguments(COMMAND_STRUCTURE);
+ const int max_depth = get_max_depth(options);
+ const SortMode sort_mode = get_sort_mode(options);
+ const bool show_depth = Util::Sets::contains(options.switches, OPTION_SHOW_DEPTH);
+
+ const std::vector<FullPackageSpec> specs = Util::fmap(args.command_arguments, [&](auto&& arg) {
+ return Input::check_and_get_full_package_spec(
+ std::string{arg}, default_triplet, COMMAND_STRUCTURE.example_text);
+ });
+
+ for (auto&& spec : specs)
+ {
+ Input::check_triplet(spec.package_spec.triplet(), paths);
+ }
+
+ PathsPortFileProvider provider(paths, args.overlay_ports);
+ auto var_provider_storage = CMakeVars::make_triplet_cmake_var_provider(paths);
+ auto& var_provider = *var_provider_storage;
+
+ // By passing an empty status_db, we should get a plan containing all dependencies.
+ // All actions in the plan should be install actions, as there's no installed packages to remove.
+ StatusParagraphs status_db;
+ auto action_plan = Dependencies::create_feature_install_plan(provider, var_provider, specs, status_db);
+ Checks::check_exit(
+ VCPKG_LINE_INFO, action_plan.remove_actions.empty(), "Only install actions should exist in the plan");
+ std::vector<const InstallPlanAction*> install_actions =
+ Util::fmap(action_plan.already_installed, [&](const auto& action) { return &action; });
+ for (auto&& action : action_plan.install_actions)
+ install_actions.push_back(&action);
+
+ std::vector<PackageDependInfo> depend_info = extract_depend_info(install_actions, max_depth);
+
+ if (Util::Sets::contains(options.switches, OPTION_DOT) || Util::Sets::contains(options.switches, OPTION_DGML))
+ {
+ const std::vector<const SourceControlFile*> source_control_files =
+ Util::fmap(install_actions, [](const InstallPlanAction* install_action) {
+ const SourceControlFileLocation& scfl =
+ install_action->source_control_file_location.value_or_exit(VCPKG_LINE_INFO);
+ return const_cast<const SourceControlFile*>(scfl.source_control_file.get());
+ });
+
+ const std::string graph_as_string = create_graph_as_string(options.switches, depend_info);
+ System::print2(graph_as_string, '\n');
+ Checks::exit_success(VCPKG_LINE_INFO);
+ }
+
+ // TODO: Improve this code
+ auto lex = [](const PackageDependInfo& lhs, const PackageDependInfo& rhs) -> bool {
+ return lhs.package < rhs.package;
+ };
+ auto topo = [](const PackageDependInfo& lhs, const PackageDependInfo& rhs) -> bool {
+ return lhs.depth > rhs.depth;
+ };
+ auto reverse = [](const PackageDependInfo& lhs, const PackageDependInfo& rhs) -> bool {
+ return lhs.depth < rhs.depth;
+ };
+
+ switch (sort_mode)
+ {
+ case SortMode::Lexicographical: std::sort(std::begin(depend_info), std::end(depend_info), lex); break;
+ case SortMode::ReverseTopological:
+ std::sort(std::begin(depend_info), std::end(depend_info), reverse);
+ break;
+ case SortMode::Topological: std::sort(std::begin(depend_info), std::end(depend_info), topo); break;
+ default: Checks::unreachable(VCPKG_LINE_INFO);
+ }
+
+ for (auto&& info : depend_info)
+ {
+ if (info.depth >= 0)
+ {
+ std::string features = Strings::join(", ", info.features);
+ const std::string dependencies = Strings::join(", ", info.dependencies);
+
+ if (show_depth)
+ {
+ System::print2(System::Color::error, "(", info.depth, ") ");
+ }
+ System::print2(System::Color::success, info.package);
+ if (!features.empty())
+ {
+ System::print2("[");
+ System::print2(System::Color::warning, features);
+ System::print2("]");
+ }
+ System::print2(": ", dependencies, "\n");
+ }
+ }
+ Checks::exit_success(VCPKG_LINE_INFO);
+ }
+}
diff --git a/toolsrc/src/vcpkg/commands.xvsinstances.cpp b/toolsrc/src/vcpkg/commands.xvsinstances.cpp
index 73b71a99d..718c73ec0 100644
--- a/toolsrc/src/vcpkg/commands.xvsinstances.cpp
+++ b/toolsrc/src/vcpkg/commands.xvsinstances.cpp
@@ -1,36 +1,36 @@
-#include "pch.h"
-
-#include <vcpkg/base/system.print.h>
-
-#include <vcpkg/commands.h>
-#include <vcpkg/help.h>
-#include <vcpkg/visualstudio.h>
-
-namespace vcpkg::Commands::X_VSInstances
-{
- const CommandStructure COMMAND_STRUCTURE = {
- create_example_string("x-vsinstances"),
- 0,
- 0,
- {{}, {}},
- nullptr,
- };
-
- void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths)
- {
-#if defined(_WIN32)
- const ParsedArguments parsed_args = args.parse_arguments(COMMAND_STRUCTURE);
-
- const auto instances = vcpkg::VisualStudio::get_visual_studio_instances(paths);
- for (const std::string& instance : instances)
- {
- System::print2(instance, '\n');
- }
-
- Checks::exit_success(VCPKG_LINE_INFO);
-#else
- Util::unused(args, paths);
- Checks::exit_with_message(VCPKG_LINE_INFO, "This command is not supported on non-windows platforms.");
-#endif
- }
-}
+#include "pch.h"
+
+#include <vcpkg/base/system.print.h>
+
+#include <vcpkg/commands.h>
+#include <vcpkg/help.h>
+#include <vcpkg/visualstudio.h>
+
+namespace vcpkg::Commands::X_VSInstances
+{
+ const CommandStructure COMMAND_STRUCTURE = {
+ create_example_string("x-vsinstances"),
+ 0,
+ 0,
+ {{}, {}},
+ nullptr,
+ };
+
+ void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths)
+ {
+#if defined(_WIN32)
+ const ParsedArguments parsed_args = args.parse_arguments(COMMAND_STRUCTURE);
+
+ const auto instances = vcpkg::VisualStudio::get_visual_studio_instances(paths);
+ for (const std::string& instance : instances)
+ {
+ System::print2(instance, '\n');
+ }
+
+ Checks::exit_success(VCPKG_LINE_INFO);
+#else
+ Util::unused(args, paths);
+ Checks::exit_with_message(VCPKG_LINE_INFO, "This command is not supported on non-windows platforms.");
+#endif
+ }
+}
diff --git a/toolsrc/src/vcpkg/export.chocolatey.cpp b/toolsrc/src/vcpkg/export.chocolatey.cpp
index a8b685988..b5a0a0a88 100644
--- a/toolsrc/src/vcpkg/export.chocolatey.cpp
+++ b/toolsrc/src/vcpkg/export.chocolatey.cpp
@@ -1,44 +1,44 @@
-#include "pch.h"
-
-#include <vcpkg/base/system.print.h>
-#include <vcpkg/base/system.process.h>
-
-#include <vcpkg/commands.h>
-#include <vcpkg/export.chocolatey.h>
-#include <vcpkg/export.h>
-#include <vcpkg/install.h>
-
-namespace vcpkg::Export::Chocolatey
-{
- using Dependencies::ExportPlanAction;
- using Dependencies::ExportPlanType;
- using Install::InstallDir;
-
- static std::string create_nuspec_dependencies(const BinaryParagraph& binary_paragraph,
- const std::map<std::string, std::string>& packages_version)
- {
- static constexpr auto CONTENT_TEMPLATE = R"(<dependency id="@PACKAGE_ID@" version="[@PACKAGE_VERSION@]" />)";
-
- std::string nuspec_dependencies;
- for (const std::string& depend : binary_paragraph.dependencies)
- {
- auto found = packages_version.find(depend);
- if (found == packages_version.end())
- {
- Checks::exit_with_message(VCPKG_LINE_INFO, "Cannot find desired dependency version.");
- }
- std::string nuspec_dependency = Strings::replace_all(CONTENT_TEMPLATE, "@PACKAGE_ID@", depend);
- nuspec_dependency = Strings::replace_all(std::move(nuspec_dependency), "@PACKAGE_VERSION@", found->second);
- nuspec_dependencies += nuspec_dependency;
- }
- return nuspec_dependencies;
- }
-
- static std::string create_nuspec_file_contents(const std::string& exported_root_dir,
- const BinaryParagraph& binary_paragraph,
- const std::map<std::string, std::string>& packages_version,
- const Options& chocolatey_options)
- {
+#include "pch.h"
+
+#include <vcpkg/base/system.print.h>
+#include <vcpkg/base/system.process.h>
+
+#include <vcpkg/commands.h>
+#include <vcpkg/export.chocolatey.h>
+#include <vcpkg/export.h>
+#include <vcpkg/install.h>
+
+namespace vcpkg::Export::Chocolatey
+{
+ using Dependencies::ExportPlanAction;
+ using Dependencies::ExportPlanType;
+ using Install::InstallDir;
+
+ static std::string create_nuspec_dependencies(const BinaryParagraph& binary_paragraph,
+ const std::map<std::string, std::string>& packages_version)
+ {
+ static constexpr auto CONTENT_TEMPLATE = R"(<dependency id="@PACKAGE_ID@" version="[@PACKAGE_VERSION@]" />)";
+
+ std::string nuspec_dependencies;
+ for (const std::string& depend : binary_paragraph.dependencies)
+ {
+ auto found = packages_version.find(depend);
+ if (found == packages_version.end())
+ {
+ Checks::exit_with_message(VCPKG_LINE_INFO, "Cannot find desired dependency version.");
+ }
+ std::string nuspec_dependency = Strings::replace_all(CONTENT_TEMPLATE, "@PACKAGE_ID@", depend);
+ nuspec_dependency = Strings::replace_all(std::move(nuspec_dependency), "@PACKAGE_VERSION@", found->second);
+ nuspec_dependencies += nuspec_dependency;
+ }
+ return nuspec_dependencies;
+ }
+
+ static std::string create_nuspec_file_contents(const std::string& exported_root_dir,
+ const BinaryParagraph& binary_paragraph,
+ const std::map<std::string, std::string>& packages_version,
+ const Options& chocolatey_options)
+ {
static constexpr auto CONTENT_TEMPLATE = R"(<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
@@ -57,30 +57,30 @@ namespace vcpkg::Export::Chocolatey
<file src="@EXPORTED_ROOT_DIR@\tools\**" target="tools" />
</files>
</package>
-)";
- auto package_version = packages_version.find(binary_paragraph.spec.name());
- if (package_version == packages_version.end())
- {
- Checks::exit_with_message(VCPKG_LINE_INFO, "Cannot find desired package version.");
- }
- std::string nuspec_file_content =
- Strings::replace_all(CONTENT_TEMPLATE, "@PACKAGE_ID@", binary_paragraph.spec.name());
- nuspec_file_content =
- Strings::replace_all(std::move(nuspec_file_content), "@PACKAGE_VERSION@", package_version->second);
- nuspec_file_content = Strings::replace_all(
- std::move(nuspec_file_content), "@PACKAGE_MAINTAINER@", chocolatey_options.maybe_maintainer.value_or(""));
- nuspec_file_content = Strings::replace_all(
- std::move(nuspec_file_content), "@PACKAGE_DESCRIPTION@", Strings::join("\n", binary_paragraph.description));
- nuspec_file_content =
- Strings::replace_all(std::move(nuspec_file_content), "@EXPORTED_ROOT_DIR@", exported_root_dir);
- nuspec_file_content = Strings::replace_all(std::move(nuspec_file_content),
- "@PACKAGE_DEPENDENCIES@",
- create_nuspec_dependencies(binary_paragraph, packages_version));
- return nuspec_file_content;
- }
-
- static std::string create_chocolatey_install_contents()
- {
+)";
+ auto package_version = packages_version.find(binary_paragraph.spec.name());
+ if (package_version == packages_version.end())
+ {
+ Checks::exit_with_message(VCPKG_LINE_INFO, "Cannot find desired package version.");
+ }
+ std::string nuspec_file_content =
+ Strings::replace_all(CONTENT_TEMPLATE, "@PACKAGE_ID@", binary_paragraph.spec.name());
+ nuspec_file_content =
+ Strings::replace_all(std::move(nuspec_file_content), "@PACKAGE_VERSION@", package_version->second);
+ nuspec_file_content = Strings::replace_all(
+ std::move(nuspec_file_content), "@PACKAGE_MAINTAINER@", chocolatey_options.maybe_maintainer.value_or(""));
+ nuspec_file_content = Strings::replace_all(
+ std::move(nuspec_file_content), "@PACKAGE_DESCRIPTION@", Strings::join("\n", binary_paragraph.description));
+ nuspec_file_content =
+ Strings::replace_all(std::move(nuspec_file_content), "@EXPORTED_ROOT_DIR@", exported_root_dir);
+ nuspec_file_content = Strings::replace_all(std::move(nuspec_file_content),
+ "@PACKAGE_DEPENDENCIES@",
+ create_nuspec_dependencies(binary_paragraph, packages_version));
+ return nuspec_file_content;
+ }
+
+ static std::string create_chocolatey_install_contents()
+ {
static constexpr auto CONTENT_TEMPLATE = R"###(
$ErrorActionPreference = 'Stop';
@@ -93,12 +93,12 @@ $whereToInstall = (pwd).path
$whereToInstallCache = Join-Path $rootDir 'install.txt'
Set-Content -Path $whereToInstallCache -Value $whereToInstall
Copy-Item $installedDir -destination $whereToInstall -recurse -force
-)###";
- return CONTENT_TEMPLATE;
- }
-
- static std::string create_chocolatey_uninstall_contents(const BinaryParagraph& binary_paragraph)
- {
+)###";
+ return CONTENT_TEMPLATE;
+ }
+
+ static std::string create_chocolatey_uninstall_contents(const BinaryParagraph& binary_paragraph)
+ {
static constexpr auto CONTENT_TEMPLATE = R"###(
$ErrorActionPreference = 'Stop';
@@ -143,90 +143,90 @@ if (Test-Path $installedDir)
}
) { $empties | Remove-Item }
}
-)###";
- std::string chocolatey_uninstall_content =
- Strings::replace_all(CONTENT_TEMPLATE, "@PACKAGE_FULLSTEM@", binary_paragraph.fullstem());
- return chocolatey_uninstall_content;
- }
-
- void do_export(const std::vector<ExportPlanAction>& export_plan,
- const VcpkgPaths& paths,
- const Options& chocolatey_options)
- {
- Checks::check_exit(
- VCPKG_LINE_INFO, chocolatey_options.maybe_maintainer.has_value(), "--x-maintainer option is required.");
-
- Files::Filesystem& fs = paths.get_filesystem();
- const fs::path vcpkg_root_path = paths.root;
- const fs::path raw_exported_dir_path = vcpkg_root_path / "chocolatey";
- const fs::path exported_dir_path = vcpkg_root_path / "chocolatey_exports";
- const fs::path& nuget_exe = paths.get_tool_exe(Tools::NUGET);
-
- std::error_code ec;
- fs.remove_all(raw_exported_dir_path, VCPKG_LINE_INFO);
- fs.create_directory(raw_exported_dir_path, ec);
- fs.remove_all(exported_dir_path, VCPKG_LINE_INFO);
- fs.create_directory(exported_dir_path, ec);
-
- // execute the plan
- std::map<std::string, std::string> packages_version;
- for (const ExportPlanAction& action : export_plan)
- {
- if (action.plan_type != ExportPlanType::ALREADY_BUILT)
- {
- Checks::unreachable(VCPKG_LINE_INFO);
- }
-
- const BinaryParagraph& binary_paragraph = action.core_paragraph().value_or_exit(VCPKG_LINE_INFO);
- auto norm_version = binary_paragraph.version;
-
- // normalize the version string to be separated by dots to be compliant with Nusepc.
- norm_version = Strings::replace_all(std::move(norm_version), "-", ".");
- norm_version = Strings::replace_all(std::move(norm_version), "_", ".");
- norm_version = norm_version + chocolatey_options.maybe_version_suffix.value_or("");
- packages_version.insert(std::make_pair(binary_paragraph.spec.name(), norm_version));
- }
-
- for (const ExportPlanAction& action : export_plan)
- {
- const std::string display_name = action.spec.to_string();
- System::print2("Exporting package ", display_name, "...\n");
-
- const fs::path per_package_dir_path = raw_exported_dir_path / action.spec.name();
-
- const BinaryParagraph& binary_paragraph = action.core_paragraph().value_or_exit(VCPKG_LINE_INFO);
-
- const InstallDir dirs = InstallDir::from_destination_root(
- per_package_dir_path / "installed",
- action.spec.triplet().to_string(),
- per_package_dir_path / "installed" / "vcpkg" / "info" / (binary_paragraph.fullstem() + ".list"));
-
- Install::install_package_and_write_listfile(paths, action.spec, dirs);
-
- const std::string nuspec_file_content = create_nuspec_file_contents(
- per_package_dir_path.string(), binary_paragraph, packages_version, chocolatey_options);
- const fs::path nuspec_file_path =
- per_package_dir_path / Strings::concat(binary_paragraph.spec.name(), ".nuspec");
- fs.write_contents(nuspec_file_path, nuspec_file_content, VCPKG_LINE_INFO);
-
- fs.create_directory(per_package_dir_path / "tools", ec);
-
- const std::string chocolatey_install_content = create_chocolatey_install_contents();
- const fs::path chocolatey_install_file_path = per_package_dir_path / "tools" / "chocolateyInstall.ps1";
- fs.write_contents(chocolatey_install_file_path, chocolatey_install_content, VCPKG_LINE_INFO);
-
- const std::string chocolatey_uninstall_content = create_chocolatey_uninstall_contents(binary_paragraph);
- const fs::path chocolatey_uninstall_file_path = per_package_dir_path / "tools" / "chocolateyUninstall.ps1";
- fs.write_contents(chocolatey_uninstall_file_path, chocolatey_uninstall_content, VCPKG_LINE_INFO);
-
- const auto cmd_line = Strings::format(R"("%s" pack -OutputDirectory "%s" "%s" -NoDefaultExcludes)",
- nuget_exe.u8string(),
- exported_dir_path.u8string(),
- nuspec_file_path.u8string());
-
- const int exit_code =
- System::cmd_execute_and_capture_output(cmd_line, System::get_clean_environment()).exit_code;
- Checks::check_exit(VCPKG_LINE_INFO, exit_code == 0, "Error: NuGet package creation failed");
- }
- }
-}
+)###";
+ std::string chocolatey_uninstall_content =
+ Strings::replace_all(CONTENT_TEMPLATE, "@PACKAGE_FULLSTEM@", binary_paragraph.fullstem());
+ return chocolatey_uninstall_content;
+ }
+
+ void do_export(const std::vector<ExportPlanAction>& export_plan,
+ const VcpkgPaths& paths,
+ const Options& chocolatey_options)
+ {
+ Checks::check_exit(
+ VCPKG_LINE_INFO, chocolatey_options.maybe_maintainer.has_value(), "--x-maintainer option is required.");
+
+ Files::Filesystem& fs = paths.get_filesystem();
+ const fs::path vcpkg_root_path = paths.root;
+ const fs::path raw_exported_dir_path = vcpkg_root_path / "chocolatey";
+ const fs::path exported_dir_path = vcpkg_root_path / "chocolatey_exports";
+ const fs::path& nuget_exe = paths.get_tool_exe(Tools::NUGET);
+
+ std::error_code ec;
+ fs.remove_all(raw_exported_dir_path, VCPKG_LINE_INFO);
+ fs.create_directory(raw_exported_dir_path, ec);
+ fs.remove_all(exported_dir_path, VCPKG_LINE_INFO);
+ fs.create_directory(exported_dir_path, ec);
+
+ // execute the plan
+ std::map<std::string, std::string> packages_version;
+ for (const ExportPlanAction& action : export_plan)
+ {
+ if (action.plan_type != ExportPlanType::ALREADY_BUILT)
+ {
+ Checks::unreachable(VCPKG_LINE_INFO);
+ }
+
+ const BinaryParagraph& binary_paragraph = action.core_paragraph().value_or_exit(VCPKG_LINE_INFO);
+ auto norm_version = binary_paragraph.version;
+
+ // normalize the version string to be separated by dots to be compliant with Nusepc.
+ norm_version = Strings::replace_all(std::move(norm_version), "-", ".");
+ norm_version = Strings::replace_all(std::move(norm_version), "_", ".");
+ norm_version = norm_version + chocolatey_options.maybe_version_suffix.value_or("");
+ packages_version.insert(std::make_pair(binary_paragraph.spec.name(), norm_version));
+ }
+
+ for (const ExportPlanAction& action : export_plan)
+ {
+ const std::string display_name = action.spec.to_string();
+ System::print2("Exporting package ", display_name, "...\n");
+
+ const fs::path per_package_dir_path = raw_exported_dir_path / action.spec.name();
+
+ const BinaryParagraph& binary_paragraph = action.core_paragraph().value_or_exit(VCPKG_LINE_INFO);
+
+ const InstallDir dirs = InstallDir::from_destination_root(
+ per_package_dir_path / "installed",
+ action.spec.triplet().to_string(),
+ per_package_dir_path / "installed" / "vcpkg" / "info" / (binary_paragraph.fullstem() + ".list"));
+
+ Install::install_package_and_write_listfile(paths, action.spec, dirs);
+
+ const std::string nuspec_file_content = create_nuspec_file_contents(
+ per_package_dir_path.string(), binary_paragraph, packages_version, chocolatey_options);
+ const fs::path nuspec_file_path =
+ per_package_dir_path / Strings::concat(binary_paragraph.spec.name(), ".nuspec");
+ fs.write_contents(nuspec_file_path, nuspec_file_content, VCPKG_LINE_INFO);
+
+ fs.create_directory(per_package_dir_path / "tools", ec);
+
+ const std::string chocolatey_install_content = create_chocolatey_install_contents();
+ const fs::path chocolatey_install_file_path = per_package_dir_path / "tools" / "chocolateyInstall.ps1";
+ fs.write_contents(chocolatey_install_file_path, chocolatey_install_content, VCPKG_LINE_INFO);
+
+ const std::string chocolatey_uninstall_content = create_chocolatey_uninstall_contents(binary_paragraph);
+ const fs::path chocolatey_uninstall_file_path = per_package_dir_path / "tools" / "chocolateyUninstall.ps1";
+ fs.write_contents(chocolatey_uninstall_file_path, chocolatey_uninstall_content, VCPKG_LINE_INFO);
+
+ const auto cmd_line = Strings::format(R"("%s" pack -OutputDirectory "%s" "%s" -NoDefaultExcludes)",
+ nuget_exe.u8string(),
+ exported_dir_path.u8string(),
+ nuspec_file_path.u8string());
+
+ const int exit_code =
+ System::cmd_execute_and_capture_output(cmd_line, System::get_clean_environment()).exit_code;
+ Checks::check_exit(VCPKG_LINE_INFO, exit_code == 0, "Error: NuGet package creation failed");
+ }
+ }
+}