aboutsummaryrefslogtreecommitdiff
path: root/toolsrc/src
diff options
context:
space:
mode:
authorPhil Christensen <philc@microsoft.com>2019-02-27 11:56:29 -0800
committerPhil Christensen <philc@microsoft.com>2019-02-27 11:56:29 -0800
commit2cc7fa27e57f1129d1f37ccb009563509ca25720 (patch)
tree3c75e423b71e54f6f65ec085c5d3d190d9d0d1a9 /toolsrc/src
parent3830517ec7519b823f5d8c404710889c6bd00278 (diff)
parent2dfa568d186e4f0d199040929f9b3e44f27c8943 (diff)
downloadvcpkg-2cc7fa27e57f1129d1f37ccb009563509ca25720.tar.gz
vcpkg-2cc7fa27e57f1129d1f37ccb009563509ca25720.zip
Merge branch 'master' of https://github.com/microsoft/vcpkg into dev/philc/5254
Diffstat (limited to 'toolsrc/src')
-rw-r--r--toolsrc/src/vcpkg.cpp2
-rw-r--r--toolsrc/src/vcpkg/base/system.cpp6
-rw-r--r--toolsrc/src/vcpkg/build.cpp1943
-rw-r--r--toolsrc/src/vcpkg/commands.ci.cpp235
-rw-r--r--toolsrc/src/vcpkg/commands.dependinfo.cpp96
-rw-r--r--toolsrc/src/vcpkg/commands.edit.cpp3
-rw-r--r--toolsrc/src/vcpkg/install.cpp10
-rw-r--r--toolsrc/src/vcpkg/sourceparagraph.cpp7
-rw-r--r--toolsrc/src/vcpkg/vcpkgpaths.cpp20
-rw-r--r--toolsrc/src/vcpkg/visualstudio.cpp54
10 files changed, 1335 insertions, 1041 deletions
diff --git a/toolsrc/src/vcpkg.cpp b/toolsrc/src/vcpkg.cpp
index fc7283599..97565bf41 100644
--- a/toolsrc/src/vcpkg.cpp
+++ b/toolsrc/src/vcpkg.cpp
@@ -102,7 +102,7 @@ static void inner(const VcpkgCmdArguments& args)
Debug::println("Using vcpkg-root: %s", vcpkg_root_dir.u8string());
- auto default_vs_path = System::get_environment_variable("VCPKG_DEFAULT_VS_PATH").value_or("");
+ auto default_vs_path = System::get_environment_variable("VCPKG_VISUAL_STUDIO_PATH").value_or("");
const Expected<VcpkgPaths> expected_paths = VcpkgPaths::create(vcpkg_root_dir, default_vs_path);
Checks::check_exit(VCPKG_LINE_INFO,
diff --git a/toolsrc/src/vcpkg/base/system.cpp b/toolsrc/src/vcpkg/base/system.cpp
index 8aa1db53c..90b9c34b3 100644
--- a/toolsrc/src/vcpkg/base/system.cpp
+++ b/toolsrc/src/vcpkg/base/system.cpp
@@ -30,7 +30,7 @@ namespace vcpkg::System
static constexpr const uint32_t buff_size = 1024 * 32;
uint32_t size = buff_size;
char buf[buff_size] = {};
- bool result = _NSGetExecutablePath(buf, &size);
+ int result = _NSGetExecutablePath(buf, &size);
Checks::check_exit(VCPKG_LINE_INFO, result != -1, "Could not determine current executable path.");
std::unique_ptr<char> canonicalPath(realpath(buf, NULL));
Checks::check_exit(VCPKG_LINE_INFO, result != -1, "Could not determine current executable path.");
@@ -74,6 +74,10 @@ namespace vcpkg::System
return CPUArchitecture::X64;
#elif defined(__x86__) || defined(_M_X86)
return CPUArchitecture::X86;
+#elif defined(__arm__) || defined(_M_ARM)
+ return CPUArchitecture::ARM;
+#elif defined(__aarch64__) || defined(_M_ARM64)
+ return CPUArchitecture::ARM64;
#else
#error "Unknown host architecture"
#endif
diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp
index 67d9b63ed..c0afd7772 100644
--- a/toolsrc/src/vcpkg/build.cpp
+++ b/toolsrc/src/vcpkg/build.cpp
@@ -1,941 +1,1002 @@
-#include "pch.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.h>
-
-#include <vcpkg/build.h>
-#include <vcpkg/commands.h>
-#include <vcpkg/dependencies.h>
-#include <vcpkg/globalstate.h>
-#include <vcpkg/help.h>
-#include <vcpkg/input.h>
-#include <vcpkg/metrics.h>
-#include <vcpkg/paragraphs.h>
-#include <vcpkg/postbuildlint.h>
-#include <vcpkg/statusparagraphs.h>
-#include <vcpkg/vcpkglib.h>
-
-using vcpkg::Build::BuildResult;
-using vcpkg::Parse::ParseControlErrorInfo;
-using vcpkg::Parse::ParseExpected;
-
-namespace vcpkg::Build::Command
-{
- using Dependencies::InstallPlanAction;
- using Dependencies::InstallPlanType;
-
- static constexpr StringLiteral OPTION_CHECKS_ONLY = "--checks-only";
-
- void perform_and_exit_ex(const FullPackageSpec& full_spec,
- const fs::path& port_dir,
- const ParsedArguments& options,
- const VcpkgPaths& paths)
- {
- const PackageSpec& spec = full_spec.package_spec;
- if (Util::Sets::contains(options.switches, OPTION_CHECKS_ONLY))
- {
- const auto pre_build_info = Build::PreBuildInfo::from_triplet_file(paths, spec.triplet());
- const auto build_info = Build::read_build_info(paths.get_filesystem(), paths.build_info_file_path(spec));
- const size_t error_count = PostBuildLint::perform_all_checks(spec, paths, pre_build_info, build_info);
- Checks::check_exit(VCPKG_LINE_INFO, error_count == 0);
- Checks::exit_success(VCPKG_LINE_INFO);
- }
-
- const ParseExpected<SourceControlFile> source_control_file =
- Paragraphs::try_load_port(paths.get_filesystem(), port_dir);
-
- if (!source_control_file.has_value())
- {
- print_error_message(source_control_file.error());
- Checks::exit_fail(VCPKG_LINE_INFO);
- }
-
- const auto& scf = source_control_file.value_or_exit(VCPKG_LINE_INFO);
- 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());
-
- const StatusParagraphs status_db = database_load_check(paths);
- const Build::BuildPackageOptions build_package_options{
- Build::UseHeadVersion::NO,
- Build::AllowDownloads::YES,
- Build::CleanBuildtrees::NO,
- Build::CleanPackages::NO,
- Build::DownloadTool::BUILT_IN,
- GlobalState::g_binary_caching ? Build::BinaryCaching::YES : Build::BinaryCaching::NO,
- Build::FailOnTombstone::NO,
- };
-
- std::set<std::string> features_as_set(full_spec.features.begin(), full_spec.features.end());
- features_as_set.emplace("core");
-
- const Build::BuildPackageConfig build_config{
- *scf, spec.triplet(), fs::path{port_dir}, build_package_options, features_as_set};
-
- const auto build_timer = Chrono::ElapsedTimer::create_started();
- const auto result = Build::build_package(paths, build_config, status_db);
- System::println("Elapsed time for package %s: %s", spec.to_string(), build_timer.to_string());
-
- if (result.code == BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES)
- {
- System::println(System::Color::error,
- "The build command requires all dependencies to be already installed.");
- System::println("The following dependencies are missing:");
- System::println();
- for (const auto& p : result.unmet_dependencies)
- {
- System::println(" %s", p);
- }
- System::println();
- Checks::exit_fail(VCPKG_LINE_INFO);
- }
-
- Checks::check_exit(VCPKG_LINE_INFO, result.code != BuildResult::EXCLUDED);
-
- if (result.code != BuildResult::SUCCEEDED)
- {
- System::println(System::Color::error, Build::create_error_message(result.code, spec));
- System::println(Build::create_user_troubleshooting_message(spec));
- Checks::exit_fail(VCPKG_LINE_INFO);
- }
-
- Checks::exit_success(VCPKG_LINE_INFO);
- }
-
- static constexpr std::array<CommandSwitch, 1> BUILD_SWITCHES = {{
- {OPTION_CHECKS_ONLY, "Only run checks, do not rebuild package"},
- }};
-
- const CommandStructure COMMAND_STRUCTURE = {
- Help::create_example_string("build zlib:x64-windows"),
- 1,
- 1,
- {BUILD_SWITCHES, {}},
- nullptr,
- };
-
- void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, const Triplet& default_triplet)
- {
- // Build only takes a single package and all dependencies must already be installed
- const ParsedArguments options = args.parse_arguments(COMMAND_STRUCTURE);
- const std::string command_argument = args.command_arguments.at(0);
- const FullPackageSpec spec =
- Input::check_and_get_full_package_spec(command_argument, default_triplet, COMMAND_STRUCTURE.example_text);
- Input::check_triplet(spec.package_spec.triplet(), paths);
- if (!spec.features.empty() && !GlobalState::feature_packages)
- {
- Checks::exit_with_message(
- VCPKG_LINE_INFO, "Feature packages are experimentally available under the --featurepackages flag.");
- }
- perform_and_exit_ex(spec, paths.port_dir(spec.package_spec), options, 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_ONLY_RELEASE_CRT = "PolicyOnlyReleaseCRT";
- static const std::string NAME_EMPTY_INCLUDE_FOLDER = "PolicyEmptyIncludeFolder";
- static const std::string NAME_ALLOW_OBSOLETE_MSVCRT = "PolicyAllowObsoleteMsvcrt";
-
- 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::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;
- 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::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";
- 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";
- }
-
- 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);
- }
-
- 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();
- }));
- }
-
- std::string make_build_env_cmd(const PreBuildInfo& pre_build_info, const Toolset& toolset)
- {
- if (pre_build_info.external_toolchain_file.has_value()) return "";
- if (!pre_build_info.cmake_system_name.empty() && pre_build_info.cmake_system_name != "WindowsStore") return "";
-
- const char* tonull = " >nul";
- if (GlobalState::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"("%s" %s %s %s %s 2>&1 <NUL)",
- toolset.vcvarsall.u8string(),
- Strings::join(" ", toolset.vcvarsall_options),
- arch,
- target,
- tonull);
- }
-
- static BinaryParagraph create_binary_feature_control_file(const SourceParagraph& source_paragraph,
- const FeatureParagraph& feature_paragraph,
- const Triplet& triplet)
- {
- return BinaryParagraph(source_paragraph, feature_paragraph, triplet);
- }
-
- static std::unique_ptr<BinaryControlFile> create_binary_control_file(const SourceParagraph& source_paragraph,
- const Triplet& triplet,
- const BuildInfo& build_info,
- const std::string& abi_tag)
- {
- auto bcf = std::make_unique<BinaryControlFile>();
- BinaryParagraph bpgh(source_paragraph, triplet, abi_tag);
- 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, 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() / "CONTROL";
- paths.get_filesystem().write_contents(binary_control_file, start);
- }
-
- static std::vector<FeatureSpec> compute_required_feature_specs(const BuildPackageConfig& config,
- const StatusParagraphs& status_db)
- {
- const Triplet& triplet = config.triplet;
-
- const std::vector<std::string> dep_strings =
- Util::fmap_flatten(config.feature_list, [&](std::string const& feature) -> std::vector<std::string> {
- if (feature == "core")
- {
- return filter_dependencies(config.scf.core_paragraph->depends, triplet);
- }
-
- auto maybe_feature = config.scf.find_feature(feature);
- Checks::check_exit(VCPKG_LINE_INFO, maybe_feature.has_value());
-
- return filter_dependencies(maybe_feature.get()->depends, triplet);
- });
-
- auto dep_fspecs = FeatureSpec::from_strings_and_triplet(dep_strings, triplet);
- Util::sort_unique_erase(dep_fspecs);
-
- // expand defaults
- std::vector<FeatureSpec> ret;
- for (auto&& fspec : dep_fspecs)
- {
- if (fspec.feature().empty())
- {
- // reference to default features
- const auto it = status_db.find_installed(fspec.spec());
- if (it == status_db.end())
- {
- // not currently installed, so just leave the default reference so it will fail later
- ret.push_back(fspec);
- }
- else
- {
- ret.emplace_back(fspec.spec(), "core");
- for (auto&& default_feature : it->get()->package.default_features)
- ret.emplace_back(fspec.spec(), default_feature);
- }
- }
- else
- {
- ret.push_back(fspec);
- }
- }
- Util::sort_unique_erase(ret);
-
- return ret;
- }
-
- static ExtendedBuildResult do_build_package(const VcpkgPaths& paths,
- const PreBuildInfo& pre_build_info,
- const PackageSpec& spec,
- const std::string& abi_tag,
- const BuildPackageConfig& config)
- {
- auto& fs = paths.get_filesystem();
- const Triplet& triplet = spec.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
-
- const fs::path& cmake_exe_path = paths.get_tool_exe(Tools::CMAKE);
- const fs::path& git_exe_path = paths.get_tool_exe(Tools::GIT);
-
- std::string all_features;
- for (auto& feature : config.scf.feature_paragraphs)
- {
- all_features.append(feature->name + ";");
- }
-
- const Toolset& toolset = paths.get_toolset(pre_build_info);
- const std::string cmd_launch_cmake = System::make_cmake_cmd(
- cmake_exe_path,
- paths.ports_cmake,
- {
- {"CMD", "BUILD"},
- {"PORT", config.scf.core_paragraph->name},
- {"CURRENT_PORT_DIR", config.port_dir},
- {"TARGET_TRIPLET", spec.triplet().canonical_name()},
- {"VCPKG_PLATFORM_TOOLSET", toolset.version.c_str()},
- {"VCPKG_USE_HEAD_VERSION",
- Util::Enum::to_bool(config.build_package_options.use_head_version) ? "1" : "0"},
- {"DOWNLOADS", paths.downloads},
- {"_VCPKG_NO_DOWNLOADS", !Util::Enum::to_bool(config.build_package_options.allow_downloads) ? "1" : "0"},
- {"_VCPKG_DOWNLOAD_TOOL", to_string(config.build_package_options.download_tool)},
- {"GIT", git_exe_path},
- {"FEATURES", Strings::join(";", config.feature_list)},
- {"ALL_FEATURES", all_features},
- });
-
- auto command = make_build_env_cmd(pre_build_info, toolset);
- if (!command.empty())
- {
-#ifdef _WIN32
- command.append(" & ");
-#else
- command.append(" && ");
-#endif
- }
- command.append(cmd_launch_cmake);
- const auto timer = Chrono::ElapsedTimer::create_started();
-
- const int return_code = System::cmd_execute_clean(command);
- const auto buildtimeus = timer.microseconds();
- const auto spec_string = spec.to_string();
-
- {
- auto locked_metrics = Metrics::g_metrics.lock();
- locked_metrics->track_buildtime(spec.to_string() + ":[" + Strings::join(",", config.feature_list) + "]",
- buildtimeus);
- if (return_code != 0)
- {
- locked_metrics->track_property("error", "build failed");
- locked_metrics->track_property("build_error", spec_string);
- return BuildResult::BUILD_FAILED;
- }
- }
-
- const BuildInfo build_info = read_build_info(fs, paths.build_info_file_path(spec));
- const size_t error_count = PostBuildLint::perform_all_checks(spec, paths, pre_build_info, build_info);
-
- auto bcf = create_binary_control_file(*config.scf.core_paragraph, triplet, build_info, abi_tag);
-
- if (error_count != 0)
- {
- return BuildResult::POST_BUILD_CHECKS_FAILED;
- }
- for (auto&& feature : config.feature_list)
- {
- for (auto&& f_pgh : config.scf.feature_paragraphs)
- {
- if (f_pgh->name == feature)
- bcf->features.push_back(
- create_binary_feature_control_file(*config.scf.core_paragraph, *f_pgh, triplet));
- }
- }
-
- write_binary_control_file(paths, *bcf);
- return {BuildResult::SUCCEEDED, std::move(bcf)};
- }
-
- static ExtendedBuildResult do_build_package_and_clean_buildtrees(const VcpkgPaths& paths,
- const PreBuildInfo& pre_build_info,
- const PackageSpec& spec,
- const std::string& abi_tag,
- const BuildPackageConfig& config)
- {
- auto result = do_build_package(paths, pre_build_info, spec, abi_tag, config);
-
- if (config.build_package_options.clean_buildtrees == CleanBuildtrees::YES)
- {
- auto& fs = paths.get_filesystem();
- const fs::path buildtrees_dir = paths.buildtrees / config.scf.core_paragraph->name;
- auto buildtree_files = fs.get_files_non_recursive(buildtrees_dir);
- for (auto&& file : buildtree_files)
- {
- if (fs.is_directory(file)) // Will only keep the logs
- {
- std::error_code ec;
- fs.remove_all(file, ec);
- }
- }
- }
-
- return result;
- }
-
- Optional<AbiTagAndFile> compute_abi_tag(const VcpkgPaths& paths,
- const BuildPackageConfig& config,
- const PreBuildInfo& pre_build_info,
- Span<const AbiEntry> dependency_abis)
- {
- if (config.build_package_options.binary_caching == BinaryCaching::NO) return nullopt;
-
- auto& fs = paths.get_filesystem();
- const Triplet& triplet = config.triplet;
- const std::string& name = config.scf.core_paragraph->name;
-
- std::vector<AbiEntry> abi_tag_entries(dependency_abis.begin(), dependency_abis.end());
-
- abi_tag_entries.emplace_back(AbiEntry{"cmake", paths.get_tool_version(Tools::CMAKE)});
-
- abi_tag_entries.emplace_back(
- AbiEntry{"portfile", vcpkg::Hash::get_file_hash(fs, config.port_dir / "portfile.cmake", "SHA1")});
- abi_tag_entries.emplace_back(
- AbiEntry{"control", vcpkg::Hash::get_file_hash(fs, config.port_dir / "CONTROL", "SHA1")});
-
- abi_tag_entries.emplace_back(AbiEntry{"vcpkg_fixup_cmake_targets", "1"});
-
- abi_tag_entries.emplace_back(AbiEntry{"triplet", pre_build_info.triplet_abi_tag});
-
- const std::string features = Strings::join(";", config.feature_list);
- abi_tag_entries.emplace_back(AbiEntry{"features", features});
-
- if (config.build_package_options.use_head_version == UseHeadVersion::YES)
- abi_tag_entries.emplace_back(AbiEntry{"head", ""});
-
- 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 (GlobalState::debugging)
- {
- System::println("[DEBUG] <abientries>");
- for (auto&& entry : abi_tag_entries)
- {
- System::println("[DEBUG] %s|%s", entry.key, entry.value);
- }
- System::println("[DEBUG] </abientries>");
- }
-
- auto abi_tag_entries_missing = abi_tag_entries;
- Util::erase_remove_if(abi_tag_entries_missing, [](const AbiEntry& p) { return !p.value.empty(); });
-
- if (abi_tag_entries_missing.empty())
- {
- std::error_code ec;
- fs.create_directories(paths.buildtrees / name, ec);
- const auto abi_file_path = paths.buildtrees / name / (triplet.canonical_name() + ".vcpkg_abi_info.txt");
- fs.write_contents(abi_file_path, full_abi_info);
-
- return AbiTagAndFile{Hash::get_file_hash(fs, abi_file_path, "SHA1"), abi_file_path};
- }
-
- System::println(
- "Warning: binary caching disabled because abi keys are missing values:\n%s",
- Strings::join("", abi_tag_entries_missing, [](const AbiEntry& e) { return " " + e.key + "\n"; }));
-
- return nullopt;
- }
-
- static void decompress_archive(const VcpkgPaths& paths, const PackageSpec& spec, const fs::path& archive_path)
- {
- auto& fs = paths.get_filesystem();
-
- auto pkg_path = paths.package_dir(spec);
- std::error_code ec;
- fs.remove_all(pkg_path, ec);
- fs.create_directories(pkg_path, ec);
- auto files = fs.get_files_non_recursive(pkg_path);
- Checks::check_exit(VCPKG_LINE_INFO, files.empty(), "unable to clear path: %s", pkg_path.u8string());
-
-#if defined(_WIN32)
- auto&& seven_zip_exe = paths.get_tool_exe(Tools::SEVEN_ZIP);
-
- System::cmd_execute_clean(Strings::format(
- R"("%s" x "%s" -o"%s" -y >nul)", seven_zip_exe.u8string(), archive_path.u8string(), pkg_path.u8string()));
-#else
- System::cmd_execute_clean(
- Strings::format(R"(unzip -qq "%s" "-d%s")", archive_path.u8string(), pkg_path.u8string()));
-#endif
- }
-
- static void compress_archive(const VcpkgPaths& paths, const PackageSpec& spec, const fs::path& tmp_archive_path)
- {
- auto& fs = paths.get_filesystem();
-
- std::error_code ec;
-
- fs.remove(tmp_archive_path, ec);
- Checks::check_exit(
- VCPKG_LINE_INFO, !fs.exists(tmp_archive_path), "Could not remove file: %s", tmp_archive_path.u8string());
-#if defined(_WIN32)
- auto&& seven_zip_exe = paths.get_tool_exe(Tools::SEVEN_ZIP);
-
- System::cmd_execute_clean(Strings::format(R"("%s" a "%s" "%s\*" >nul)",
- seven_zip_exe.u8string(),
- tmp_archive_path.u8string(),
- paths.package_dir(spec).u8string()));
-#else
- System::cmd_execute_clean(Strings::format(
- R"(cd '%s' && zip --quiet -r '%s' *)", paths.package_dir(spec).u8string(), tmp_archive_path.u8string()));
-#endif
- }
-
- ExtendedBuildResult build_package(const VcpkgPaths& paths,
- const BuildPackageConfig& config,
- const StatusParagraphs& status_db)
- {
- auto& fs = paths.get_filesystem();
- const Triplet& triplet = config.triplet;
- const std::string& name = config.scf.core_paragraph->name;
-
- std::vector<FeatureSpec> required_fspecs = compute_required_feature_specs(config, status_db);
-
- // extract out the actual package ids
- auto dep_pspecs = Util::fmap(required_fspecs, [](FeatureSpec const& fspec) { return fspec.spec(); });
- Util::sort_unique_erase(dep_pspecs);
-
- // Find all features that aren't installed. This mutates required_fspecs.
- Util::erase_remove_if(required_fspecs, [&](FeatureSpec const& fspec) {
- return status_db.is_installed(fspec) || fspec.name() == name;
- });
-
- if (!required_fspecs.empty())
- {
- return {BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES, std::move(required_fspecs)};
- }
-
- const PackageSpec spec =
- PackageSpec::from_name_and_triplet(config.scf.core_paragraph->name, triplet).value_or_exit(VCPKG_LINE_INFO);
-
- std::vector<AbiEntry> dependency_abis;
-
- // dep_pspecs was not destroyed
- for (auto&& pspec : dep_pspecs)
- {
- if (pspec == spec) continue;
- const auto status_it = status_db.find_installed(pspec);
- Checks::check_exit(VCPKG_LINE_INFO, status_it != status_db.end());
- dependency_abis.emplace_back(
- AbiEntry{status_it->get()->package.spec.name(), status_it->get()->package.abi});
- }
-
- const auto pre_build_info = PreBuildInfo::from_triplet_file(paths, triplet);
-
- auto maybe_abi_tag_and_file = compute_abi_tag(paths, config, pre_build_info, dependency_abis);
-
- const auto abi_tag_and_file = maybe_abi_tag_and_file.get();
-
- if (config.build_package_options.binary_caching == BinaryCaching::YES && abi_tag_and_file)
- {
- const fs::path archives_root_dir = paths.root / "archives";
- const std::string archive_name = abi_tag_and_file->tag + ".zip";
- const fs::path archive_subpath = fs::u8path(abi_tag_and_file->tag.substr(0, 2)) / archive_name;
- const fs::path archive_path = archives_root_dir / archive_subpath;
- const fs::path archive_tombstone_path = archives_root_dir / "fail" / archive_subpath;
-
- if (fs.exists(archive_path))
- {
- System::println("Using cached binary package: %s", archive_path.u8string());
-
- decompress_archive(paths, spec, archive_path);
-
- auto maybe_bcf = Paragraphs::try_load_cached_package(paths, spec);
- std::unique_ptr<BinaryControlFile> bcf =
- std::make_unique<BinaryControlFile>(std::move(maybe_bcf).value_or_exit(VCPKG_LINE_INFO));
- return {BuildResult::SUCCEEDED, std::move(bcf)};
- }
-
- if (fs.exists(archive_tombstone_path))
- {
- if (config.build_package_options.fail_on_tombstone == FailOnTombstone::YES)
- {
- System::println("Found failure tombstone: %s", archive_tombstone_path.u8string());
- return BuildResult::BUILD_FAILED;
- }
- else
- {
- System::println(
- System::Color::warning, "Found failure tombstone: %s", archive_tombstone_path.u8string());
- }
- }
-
- System::println("Could not locate cached archive: %s", archive_path.u8string());
-
- ExtendedBuildResult result = do_build_package_and_clean_buildtrees(
- paths, pre_build_info, spec, maybe_abi_tag_and_file.value_or(AbiTagAndFile{}).tag, config);
-
- std::error_code ec;
- fs.create_directories(paths.package_dir(spec) / "share" / spec.name(), ec);
- auto abi_file_in_package = paths.package_dir(spec) / "share" / spec.name() / "vcpkg_abi_info.txt";
- fs.copy_file(abi_tag_and_file->tag_file, abi_file_in_package, fs::stdfs::copy_options::none, ec);
- Checks::check_exit(VCPKG_LINE_INFO, !ec, "Could not copy into file: %s", abi_file_in_package.u8string());
-
- if (result.code == BuildResult::SUCCEEDED)
- {
- const auto tmp_archive_path = paths.buildtrees / spec.name() / (spec.triplet().to_string() + ".zip");
-
- compress_archive(paths, spec, tmp_archive_path);
-
- fs.create_directories(archive_path.parent_path(), ec);
- fs.rename_or_copy(tmp_archive_path, archive_path, ".tmp", ec);
- if (ec)
- {
- System::println(System::Color::warning,
- "Failed to store binary cache %s: %s",
- archive_path.u8string(),
- ec.message());
- }
- else
- System::println("Stored binary cache: %s", archive_path.u8string());
- }
- else if (result.code == BuildResult::BUILD_FAILED || result.code == BuildResult::POST_BUILD_CHECKS_FAILED)
- {
- // Build failed, so store tombstone archive
- fs.create_directories(archive_tombstone_path.parent_path(), ec);
- fs.write_contents(archive_tombstone_path, "", ec);
- }
-
- return result;
- }
-
- return do_build_package_and_clean_buildtrees(
- paths, pre_build_info, spec, maybe_abi_tag_and_file.value_or(AbiTagAndFile{}).tag, config);
- }
-
- const std::string& to_string(const BuildResult build_result)
- {
- 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";
-
- 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;
- 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(std::unordered_map<std::string, std::string> 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 Expected<std::unordered_map<std::string, std::string>> pghs =
- Paragraphs::get_single_paragraph(fs, filepath);
- Checks::check_exit(VCPKG_LINE_INFO, pghs.get() != nullptr, "Invalid BUILD_INFO file for package");
- return inner_create_buildinfo(*pghs.get());
- }
-
- PreBuildInfo PreBuildInfo::from_triplet_file(const VcpkgPaths& paths, const Triplet& triplet)
- {
- static constexpr CStringView FLAG_GUID = "c35112b6-d1ba-415b-aa5d-81de856ef8eb";
-
- const fs::path& cmake_exe_path = paths.get_tool_exe(Tools::CMAKE);
- const fs::path ports_cmake_script_path = paths.scripts / "get_triplet_environment.cmake";
- const fs::path triplet_file_path = paths.triplets / (triplet.canonical_name() + ".cmake");
-
- const auto cmd_launch_cmake = System::make_cmake_cmd(cmake_exe_path,
- ports_cmake_script_path,
- {
- {"CMAKE_TRIPLET_FILE", triplet_file_path},
- });
- const auto ec_data = System::cmd_execute_and_capture_output(cmd_launch_cmake);
- Checks::check_exit(VCPKG_LINE_INFO, ec_data.exit_code == 0, ec_data.output);
-
- const std::vector<std::string> lines = Strings::split(ec_data.output, "\n");
-
- PreBuildInfo pre_build_info;
-
- const auto e = lines.cend();
- auto cur = std::find(lines.cbegin(), e, FLAG_GUID);
- if (cur != e) ++cur;
-
- for (; cur != e; ++cur)
- {
- auto&& line = *cur;
-
- const std::vector<std::string> s = Strings::split(line, "=");
- Checks::check_exit(VCPKG_LINE_INFO,
- s.size() == 1 || s.size() == 2,
- "Expected format is [VARIABLE_NAME=VARIABLE_VALUE], but was [%s]",
- line);
-
- const bool variable_with_no_value = s.size() == 1;
- const std::string variable_name = s.at(0);
- const std::string variable_value = variable_with_no_value ? "" : s.at(1);
-
- if (variable_name == "VCPKG_TARGET_ARCHITECTURE")
- {
- pre_build_info.target_architecture = variable_value;
- continue;
- }
-
- if (variable_name == "VCPKG_CMAKE_SYSTEM_NAME")
- {
- pre_build_info.cmake_system_name = variable_value;
- continue;
- }
-
- if (variable_name == "VCPKG_CMAKE_SYSTEM_VERSION")
- {
- pre_build_info.cmake_system_version = variable_value;
- continue;
- }
-
- if (variable_name == "VCPKG_PLATFORM_TOOLSET")
- {
- pre_build_info.platform_toolset =
- variable_value.empty() ? nullopt : Optional<std::string>{variable_value};
- continue;
- }
-
- if (variable_name == "VCPKG_VISUAL_STUDIO_PATH")
- {
- pre_build_info.visual_studio_path =
- variable_value.empty() ? nullopt : Optional<fs::path>{variable_value};
- continue;
- }
-
- if (variable_name == "VCPKG_CHAINLOAD_TOOLCHAIN_FILE")
- {
- pre_build_info.external_toolchain_file =
- variable_value.empty() ? nullopt : Optional<std::string>{variable_value};
- continue;
- }
-
- if (variable_name == "VCPKG_BUILD_TYPE")
- {
- if (variable_value.empty())
- pre_build_info.build_type = nullopt;
- else if (Strings::case_insensitive_ascii_equals(variable_value, "debug"))
- pre_build_info.build_type = ConfigurationType::DEBUG;
- else if (Strings::case_insensitive_ascii_equals(variable_value, "release"))
- pre_build_info.build_type = ConfigurationType::RELEASE;
- else
- Checks::exit_with_message(
- VCPKG_LINE_INFO, "Unknown setting for VCPKG_BUILD_TYPE: %s", variable_value);
- continue;
- }
-
- Checks::exit_with_message(VCPKG_LINE_INFO, "Unknown variable name %s", line);
- }
-
- pre_build_info.triplet_abi_tag = [&]() {
- const auto& fs = paths.get_filesystem();
- static std::map<fs::path, std::string> s_hash_cache;
-
- auto it_hash = s_hash_cache.find(triplet_file_path);
- if (it_hash != s_hash_cache.end())
- {
- return it_hash->second;
- }
- auto hash = Hash::get_file_hash(fs, triplet_file_path, "SHA1");
-
- if (auto p = pre_build_info.external_toolchain_file.get())
- {
- hash += "-";
- hash += Hash::get_file_hash(fs, *p, "SHA1");
- }
- else if (pre_build_info.cmake_system_name == "Linux")
- {
- hash += "-";
- hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "linux.cmake", "SHA1");
- }
- else if (pre_build_info.cmake_system_name == "Darwin")
- {
- hash += "-";
- hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "osx.cmake", "SHA1");
- }
- else if (pre_build_info.cmake_system_name == "FreeBSD")
- {
- hash += "-";
- hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "freebsd.cmake", "SHA1");
- }
- else if (pre_build_info.cmake_system_name == "Android")
- {
- hash += "-";
- hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "android.cmake", "SHA1");
- }
-
- s_hash_cache.emplace(triplet_file_path, hash);
- return hash;
- }();
-
- return pre_build_info;
- }
- 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))
- {
- }
-}
+#include "pch.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.h>
+
+#include <vcpkg/build.h>
+#include <vcpkg/commands.h>
+#include <vcpkg/dependencies.h>
+#include <vcpkg/globalstate.h>
+#include <vcpkg/help.h>
+#include <vcpkg/input.h>
+#include <vcpkg/metrics.h>
+#include <vcpkg/paragraphs.h>
+#include <vcpkg/postbuildlint.h>
+#include <vcpkg/statusparagraphs.h>
+#include <vcpkg/vcpkglib.h>
+
+using vcpkg::Build::BuildResult;
+using vcpkg::Parse::ParseControlErrorInfo;
+using vcpkg::Parse::ParseExpected;
+
+namespace vcpkg::Build::Command
+{
+ using Dependencies::InstallPlanAction;
+ using Dependencies::InstallPlanType;
+
+ static constexpr StringLiteral OPTION_CHECKS_ONLY = "--checks-only";
+
+ void perform_and_exit_ex(const FullPackageSpec& full_spec,
+ const fs::path& port_dir,
+ const ParsedArguments& options,
+ const VcpkgPaths& paths)
+ {
+ const PackageSpec& spec = full_spec.package_spec;
+ if (Util::Sets::contains(options.switches, OPTION_CHECKS_ONLY))
+ {
+ const auto pre_build_info = Build::PreBuildInfo::from_triplet_file(paths, spec.triplet());
+ const auto build_info = Build::read_build_info(paths.get_filesystem(), paths.build_info_file_path(spec));
+ const size_t error_count = PostBuildLint::perform_all_checks(spec, paths, pre_build_info, build_info);
+ Checks::check_exit(VCPKG_LINE_INFO, error_count == 0);
+ Checks::exit_success(VCPKG_LINE_INFO);
+ }
+
+ const ParseExpected<SourceControlFile> source_control_file =
+ Paragraphs::try_load_port(paths.get_filesystem(), port_dir);
+
+ if (!source_control_file.has_value())
+ {
+ print_error_message(source_control_file.error());
+ Checks::exit_fail(VCPKG_LINE_INFO);
+ }
+
+ const auto& scf = source_control_file.value_or_exit(VCPKG_LINE_INFO);
+ 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());
+
+ const StatusParagraphs status_db = database_load_check(paths);
+ const Build::BuildPackageOptions build_package_options{
+ Build::UseHeadVersion::NO,
+ Build::AllowDownloads::YES,
+ Build::CleanBuildtrees::NO,
+ Build::CleanPackages::NO,
+ Build::DownloadTool::BUILT_IN,
+ GlobalState::g_binary_caching ? Build::BinaryCaching::YES : Build::BinaryCaching::NO,
+ Build::FailOnTombstone::NO,
+ };
+
+ std::set<std::string> features_as_set(full_spec.features.begin(), full_spec.features.end());
+ features_as_set.emplace("core");
+
+ const Build::BuildPackageConfig build_config{
+ *scf, spec.triplet(), fs::path{port_dir}, build_package_options, features_as_set};
+
+ const auto build_timer = Chrono::ElapsedTimer::create_started();
+ const auto result = Build::build_package(paths, build_config, status_db);
+ System::println("Elapsed time for package %s: %s", spec.to_string(), build_timer.to_string());
+
+ if (result.code == BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES)
+ {
+ System::println(System::Color::error,
+ "The build command requires all dependencies to be already installed.");
+ System::println("The following dependencies are missing:");
+ System::println();
+ for (const auto& p : result.unmet_dependencies)
+ {
+ System::println(" %s", p);
+ }
+ System::println();
+ Checks::exit_fail(VCPKG_LINE_INFO);
+ }
+
+ Checks::check_exit(VCPKG_LINE_INFO, result.code != BuildResult::EXCLUDED);
+
+ if (result.code != BuildResult::SUCCEEDED)
+ {
+ System::println(System::Color::error, Build::create_error_message(result.code, spec));
+ System::println(Build::create_user_troubleshooting_message(spec));
+ Checks::exit_fail(VCPKG_LINE_INFO);
+ }
+
+ Checks::exit_success(VCPKG_LINE_INFO);
+ }
+
+ static constexpr std::array<CommandSwitch, 1> BUILD_SWITCHES = {{
+ {OPTION_CHECKS_ONLY, "Only run checks, do not rebuild package"},
+ }};
+
+ const CommandStructure COMMAND_STRUCTURE = {
+ Help::create_example_string("build zlib:x64-windows"),
+ 1,
+ 1,
+ {BUILD_SWITCHES, {}},
+ nullptr,
+ };
+
+ void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, const Triplet& default_triplet)
+ {
+ // Build only takes a single package and all dependencies must already be installed
+ const ParsedArguments options = args.parse_arguments(COMMAND_STRUCTURE);
+ const std::string command_argument = args.command_arguments.at(0);
+ const FullPackageSpec spec =
+ Input::check_and_get_full_package_spec(command_argument, default_triplet, COMMAND_STRUCTURE.example_text);
+ Input::check_triplet(spec.package_spec.triplet(), paths);
+ if (!spec.features.empty() && !GlobalState::feature_packages)
+ {
+ Checks::exit_with_message(
+ VCPKG_LINE_INFO, "Feature packages are experimentally available under the --featurepackages flag.");
+ }
+ perform_and_exit_ex(spec, paths.port_dir(spec.package_spec), options, 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_ONLY_RELEASE_CRT = "PolicyOnlyReleaseCRT";
+ static const std::string NAME_EMPTY_INCLUDE_FOLDER = "PolicyEmptyIncludeFolder";
+ static const std::string NAME_ALLOW_OBSOLETE_MSVCRT = "PolicyAllowObsoleteMsvcrt";
+
+ 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::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;
+ 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::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";
+ 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";
+ }
+
+ 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);
+ }
+
+ 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();
+ }));
+ }
+
+ std::string make_build_env_cmd(const PreBuildInfo& pre_build_info, const Toolset& toolset)
+ {
+ if (pre_build_info.external_toolchain_file.has_value()) return "";
+ if (!pre_build_info.cmake_system_name.empty() && pre_build_info.cmake_system_name != "WindowsStore") return "";
+
+ const char* tonull = " >nul";
+ if (GlobalState::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"("%s" %s %s %s %s 2>&1 <NUL)",
+ toolset.vcvarsall.u8string(),
+ Strings::join(" ", toolset.vcvarsall_options),
+ arch,
+ target,
+ tonull);
+ }
+
+ static BinaryParagraph create_binary_feature_control_file(const SourceParagraph& source_paragraph,
+ const FeatureParagraph& feature_paragraph,
+ const Triplet& triplet)
+ {
+ return BinaryParagraph(source_paragraph, feature_paragraph, triplet);
+ }
+
+ static std::unique_ptr<BinaryControlFile> create_binary_control_file(const SourceParagraph& source_paragraph,
+ const Triplet& triplet,
+ const BuildInfo& build_info,
+ const std::string& abi_tag)
+ {
+ auto bcf = std::make_unique<BinaryControlFile>();
+ BinaryParagraph bpgh(source_paragraph, triplet, abi_tag);
+ 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, 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() / "CONTROL";
+ paths.get_filesystem().write_contents(binary_control_file, start);
+ }
+
+ static std::vector<FeatureSpec> compute_required_feature_specs(const BuildPackageConfig& config,
+ const StatusParagraphs& status_db)
+ {
+ const Triplet& triplet = config.triplet;
+
+ const std::vector<std::string> dep_strings =
+ Util::fmap_flatten(config.feature_list, [&](std::string const& feature) -> std::vector<std::string> {
+ if (feature == "core")
+ {
+ return filter_dependencies(config.scf.core_paragraph->depends, triplet);
+ }
+
+ auto maybe_feature = config.scf.find_feature(feature);
+ Checks::check_exit(VCPKG_LINE_INFO, maybe_feature.has_value());
+
+ return filter_dependencies(maybe_feature.get()->depends, triplet);
+ });
+
+ auto dep_fspecs = FeatureSpec::from_strings_and_triplet(dep_strings, triplet);
+ Util::sort_unique_erase(dep_fspecs);
+
+ // expand defaults
+ std::vector<FeatureSpec> ret;
+ for (auto&& fspec : dep_fspecs)
+ {
+ if (fspec.feature().empty())
+ {
+ // reference to default features
+ const auto it = status_db.find_installed(fspec.spec());
+ if (it == status_db.end())
+ {
+ // not currently installed, so just leave the default reference so it will fail later
+ ret.push_back(fspec);
+ }
+ else
+ {
+ ret.emplace_back(fspec.spec(), "core");
+ for (auto&& default_feature : it->get()->package.default_features)
+ ret.emplace_back(fspec.spec(), default_feature);
+ }
+ }
+ else
+ {
+ ret.push_back(fspec);
+ }
+ }
+ Util::sort_unique_erase(ret);
+
+ return ret;
+ }
+
+ static ExtendedBuildResult do_build_package(const VcpkgPaths& paths,
+ const PreBuildInfo& pre_build_info,
+ const PackageSpec& spec,
+ const std::string& abi_tag,
+ const BuildPackageConfig& config)
+ {
+ auto& fs = paths.get_filesystem();
+ const Triplet& triplet = spec.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
+
+ const fs::path& cmake_exe_path = paths.get_tool_exe(Tools::CMAKE);
+ const fs::path& git_exe_path = paths.get_tool_exe(Tools::GIT);
+
+ std::string all_features;
+ for (auto& feature : config.scf.feature_paragraphs)
+ {
+ all_features.append(feature->name + ";");
+ }
+
+ const Toolset& toolset = paths.get_toolset(pre_build_info);
+ const std::string cmd_launch_cmake = System::make_cmake_cmd(
+ cmake_exe_path,
+ paths.ports_cmake,
+ {
+ {"CMD", "BUILD"},
+ {"PORT", config.scf.core_paragraph->name},
+ {"CURRENT_PORT_DIR", config.port_dir},
+ {"TARGET_TRIPLET", spec.triplet().canonical_name()},
+ {"VCPKG_PLATFORM_TOOLSET", toolset.version.c_str()},
+ {"VCPKG_USE_HEAD_VERSION",
+ Util::Enum::to_bool(config.build_package_options.use_head_version) ? "1" : "0"},
+ {"DOWNLOADS", paths.downloads},
+ {"_VCPKG_NO_DOWNLOADS", !Util::Enum::to_bool(config.build_package_options.allow_downloads) ? "1" : "0"},
+ {"_VCPKG_DOWNLOAD_TOOL", to_string(config.build_package_options.download_tool)},
+ {"GIT", git_exe_path},
+ {"FEATURES", Strings::join(";", config.feature_list)},
+ {"ALL_FEATURES", all_features},
+ });
+
+ auto command = make_build_env_cmd(pre_build_info, toolset);
+ if (!command.empty())
+ {
+#ifdef _WIN32
+ command.append(" & ");
+#else
+ command.append(" && ");
+#endif
+ }
+ command.append(cmd_launch_cmake);
+ const auto timer = Chrono::ElapsedTimer::create_started();
+
+ const int return_code = System::cmd_execute_clean(command);
+ const auto buildtimeus = timer.microseconds();
+ const auto spec_string = spec.to_string();
+
+ {
+ auto locked_metrics = Metrics::g_metrics.lock();
+ locked_metrics->track_buildtime(spec.to_string() + ":[" + Strings::join(",", config.feature_list) + "]",
+ buildtimeus);
+ if (return_code != 0)
+ {
+ locked_metrics->track_property("error", "build failed");
+ locked_metrics->track_property("build_error", spec_string);
+ return BuildResult::BUILD_FAILED;
+ }
+ }
+
+ const BuildInfo build_info = read_build_info(fs, paths.build_info_file_path(spec));
+ const size_t error_count = PostBuildLint::perform_all_checks(spec, paths, pre_build_info, build_info);
+
+ auto bcf = create_binary_control_file(*config.scf.core_paragraph, triplet, build_info, abi_tag);
+
+ if (error_count != 0)
+ {
+ return BuildResult::POST_BUILD_CHECKS_FAILED;
+ }
+ for (auto&& feature : config.feature_list)
+ {
+ for (auto&& f_pgh : config.scf.feature_paragraphs)
+ {
+ if (f_pgh->name == feature)
+ bcf->features.push_back(
+ create_binary_feature_control_file(*config.scf.core_paragraph, *f_pgh, triplet));
+ }
+ }
+
+ write_binary_control_file(paths, *bcf);
+ return {BuildResult::SUCCEEDED, std::move(bcf)};
+ }
+
+ static ExtendedBuildResult do_build_package_and_clean_buildtrees(const VcpkgPaths& paths,
+ const PreBuildInfo& pre_build_info,
+ const PackageSpec& spec,
+ const std::string& abi_tag,
+ const BuildPackageConfig& config)
+ {
+ auto result = do_build_package(paths, pre_build_info, spec, abi_tag, config);
+
+ if (config.build_package_options.clean_buildtrees == CleanBuildtrees::YES)
+ {
+ auto& fs = paths.get_filesystem();
+ const fs::path buildtrees_dir = paths.buildtrees / config.scf.core_paragraph->name;
+ auto buildtree_files = fs.get_files_non_recursive(buildtrees_dir);
+ for (auto&& file : buildtree_files)
+ {
+ if (fs.is_directory(file)) // Will only keep the logs
+ {
+ std::error_code ec;
+ fs.remove_all(file, ec);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ Optional<AbiTagAndFile> compute_abi_tag(const VcpkgPaths& paths,
+ const BuildPackageConfig& config,
+ const PreBuildInfo& pre_build_info,
+ Span<const AbiEntry> dependency_abis)
+ {
+ if (config.build_package_options.binary_caching == BinaryCaching::NO) return nullopt;
+
+ auto& fs = paths.get_filesystem();
+ const Triplet& triplet = config.triplet;
+ const std::string& name = config.scf.core_paragraph->name;
+
+ std::vector<AbiEntry> abi_tag_entries(dependency_abis.begin(), dependency_abis.end());
+
+ abi_tag_entries.emplace_back(AbiEntry{"cmake", paths.get_tool_version(Tools::CMAKE)});
+
+ // 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;
+
+ // the order of recursive_directory_iterator is undefined so save the names to sort
+ std::vector<fs::path> port_files;
+ for (auto &port_file : fs::stdfs::recursive_directory_iterator(config.port_dir))
+ {
+ if (fs::is_regular_file(status(port_file)))
+ {
+ port_files.push_back(port_file);
+ if (port_files.size() > max_port_file_count)
+ {
+ abi_tag_entries.emplace_back(AbiEntry{ "no_hash_max_portfile", "" });
+ break;
+ }
+ }
+ }
+
+ if (port_files.size() <= max_port_file_count)
+ {
+ std::sort(port_files.begin(), port_files.end());
+
+ int counter = 0;
+ for (auto & port_file : port_files)
+ {
+ // When vcpkg takes a dependency on C++17 it can use fs::relative,
+ // which will give a stable ordering and better names in the key entry.
+ // this is not available in the filesystem TS so instead number the files for the key.
+ std::string key = Strings::format("file_%03d", counter++);
+ if (GlobalState::debugging)
+ {
+ System::println("[DEBUG] mapping %s from %s", key, port_file.string());
+ }
+ abi_tag_entries.emplace_back(AbiEntry{ key, vcpkg::Hash::get_file_hash(fs, port_file, "SHA1") });
+ }
+ }
+
+ abi_tag_entries.emplace_back(AbiEntry{"vcpkg_fixup_cmake_targets", "1"});
+
+ abi_tag_entries.emplace_back(AbiEntry{"triplet", pre_build_info.triplet_abi_tag});
+
+ const std::string features = Strings::join(";", config.feature_list);
+ abi_tag_entries.emplace_back(AbiEntry{"features", features});
+
+ if (config.build_package_options.use_head_version == UseHeadVersion::YES)
+ abi_tag_entries.emplace_back(AbiEntry{"head", ""});
+
+ 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 (GlobalState::debugging)
+ {
+ System::println("[DEBUG] <abientries>");
+ for (auto&& entry : abi_tag_entries)
+ {
+ System::println("[DEBUG] %s|%s", entry.key, entry.value);
+ }
+ System::println("[DEBUG] </abientries>");
+ }
+
+ auto abi_tag_entries_missing = abi_tag_entries;
+ Util::erase_remove_if(abi_tag_entries_missing, [](const AbiEntry& p) { return !p.value.empty(); });
+
+ if (abi_tag_entries_missing.empty())
+ {
+ std::error_code ec;
+ fs.create_directories(paths.buildtrees / name, ec);
+ const auto abi_file_path = paths.buildtrees / name / (triplet.canonical_name() + ".vcpkg_abi_info.txt");
+ fs.write_contents(abi_file_path, full_abi_info);
+
+ return AbiTagAndFile{Hash::get_file_hash(fs, abi_file_path, "SHA1"), abi_file_path};
+ }
+
+ System::println(
+ "Warning: binary caching disabled because abi keys are missing values:\n%s",
+ Strings::join("", abi_tag_entries_missing, [](const AbiEntry& e) { return " " + e.key + "\n"; }));
+
+ return nullopt;
+ }
+
+ static void decompress_archive(const VcpkgPaths& paths, const PackageSpec& spec, const fs::path& archive_path)
+ {
+ auto& fs = paths.get_filesystem();
+
+ auto pkg_path = paths.package_dir(spec);
+ std::error_code ec;
+ fs.remove_all(pkg_path, ec);
+ fs.create_directories(pkg_path, ec);
+ auto files = fs.get_files_non_recursive(pkg_path);
+ Checks::check_exit(VCPKG_LINE_INFO, files.empty(), "unable to clear path: %s", pkg_path.u8string());
+
+#if defined(_WIN32)
+ auto&& seven_zip_exe = paths.get_tool_exe(Tools::SEVEN_ZIP);
+
+ System::cmd_execute_clean(Strings::format(
+ R"("%s" x "%s" -o"%s" -y >nul)", seven_zip_exe.u8string(), archive_path.u8string(), pkg_path.u8string()));
+#else
+ System::cmd_execute_clean(
+ Strings::format(R"(unzip -qq "%s" "-d%s")", archive_path.u8string(), pkg_path.u8string()));
+#endif
+ }
+
+ // 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_clean(Strings::format(R"("%s" a "%s" "%s\*" >nul)",
+ seven_zip_exe.u8string(),
+ destination.u8string(),
+ source.u8string()));
+#else
+ System::cmd_execute_clean(Strings::format(
+ R"(cd '%s' && zip --quiet -r '%s' *)", source.u8string(), destination.u8string()));
+#endif
+ }
+
+ static void compress_archive(const VcpkgPaths& paths, const PackageSpec& spec, const fs::path& destination)
+ {
+ compress_directory(paths, paths.package_dir(spec), destination);
+ }
+
+ ExtendedBuildResult build_package(const VcpkgPaths& paths,
+ const BuildPackageConfig& config,
+ const StatusParagraphs& status_db)
+ {
+ auto& fs = paths.get_filesystem();
+ const Triplet& triplet = config.triplet;
+ const std::string& name = config.scf.core_paragraph->name;
+
+ std::vector<FeatureSpec> required_fspecs = compute_required_feature_specs(config, status_db);
+
+ // extract out the actual package ids
+ auto dep_pspecs = Util::fmap(required_fspecs, [](FeatureSpec const& fspec) { return fspec.spec(); });
+ Util::sort_unique_erase(dep_pspecs);
+
+ // Find all features that aren't installed. This mutates required_fspecs.
+ Util::erase_remove_if(required_fspecs, [&](FeatureSpec const& fspec) {
+ return status_db.is_installed(fspec) || fspec.name() == name;
+ });
+
+ if (!required_fspecs.empty())
+ {
+ return {BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES, std::move(required_fspecs)};
+ }
+
+ const PackageSpec spec =
+ PackageSpec::from_name_and_triplet(config.scf.core_paragraph->name, triplet).value_or_exit(VCPKG_LINE_INFO);
+
+ std::vector<AbiEntry> dependency_abis;
+
+ // dep_pspecs was not destroyed
+ for (auto&& pspec : dep_pspecs)
+ {
+ if (pspec == spec) continue;
+ const auto status_it = status_db.find_installed(pspec);
+ Checks::check_exit(VCPKG_LINE_INFO, status_it != status_db.end());
+ dependency_abis.emplace_back(
+ AbiEntry{status_it->get()->package.spec.name(), status_it->get()->package.abi});
+ }
+
+ const auto pre_build_info = PreBuildInfo::from_triplet_file(paths, triplet);
+
+ auto maybe_abi_tag_and_file = compute_abi_tag(paths, config, pre_build_info, dependency_abis);
+
+ const auto abi_tag_and_file = maybe_abi_tag_and_file.get();
+
+ if (config.build_package_options.binary_caching == BinaryCaching::YES && abi_tag_and_file)
+ {
+ const fs::path archives_root_dir = paths.root / "archives";
+ const std::string archive_name = abi_tag_and_file->tag + ".zip";
+ const fs::path archive_subpath = fs::u8path(abi_tag_and_file->tag.substr(0, 2)) / archive_name;
+ const fs::path archive_path = archives_root_dir / archive_subpath;
+ const fs::path archive_tombstone_path = archives_root_dir / "fail" / archive_subpath;
+
+ if (fs.exists(archive_path))
+ {
+ System::println("Using cached binary package: %s", archive_path.u8string());
+
+ decompress_archive(paths, spec, archive_path);
+
+ auto maybe_bcf = Paragraphs::try_load_cached_package(paths, spec);
+ std::unique_ptr<BinaryControlFile> bcf =
+ std::make_unique<BinaryControlFile>(std::move(maybe_bcf).value_or_exit(VCPKG_LINE_INFO));
+ return {BuildResult::SUCCEEDED, std::move(bcf)};
+ }
+
+ if (fs.exists(archive_tombstone_path))
+ {
+ if (config.build_package_options.fail_on_tombstone == FailOnTombstone::YES)
+ {
+ System::println("Found failure tombstone: %s", archive_tombstone_path.u8string());
+ return BuildResult::BUILD_FAILED;
+ }
+ else
+ {
+ System::println(
+ System::Color::warning, "Found failure tombstone: %s", archive_tombstone_path.u8string());
+ }
+ }
+
+ System::println("Could not locate cached archive: %s", archive_path.u8string());
+
+ ExtendedBuildResult result = do_build_package_and_clean_buildtrees(
+ paths, pre_build_info, spec, maybe_abi_tag_and_file.value_or(AbiTagAndFile{}).tag, config);
+
+ std::error_code ec;
+ fs.create_directories(paths.package_dir(spec) / "share" / spec.name(), ec);
+ auto abi_file_in_package = paths.package_dir(spec) / "share" / spec.name() / "vcpkg_abi_info.txt";
+ fs.copy_file(abi_tag_and_file->tag_file, abi_file_in_package, fs::stdfs::copy_options::none, ec);
+ Checks::check_exit(VCPKG_LINE_INFO, !ec, "Could not copy into file: %s", abi_file_in_package.u8string());
+
+ if (result.code == BuildResult::SUCCEEDED)
+ {
+ const auto tmp_archive_path = paths.buildtrees / spec.name() / (spec.triplet().to_string() + ".zip");
+
+ compress_archive(paths, spec, tmp_archive_path);
+
+ fs.create_directories(archive_path.parent_path(), ec);
+ fs.rename_or_copy(tmp_archive_path, archive_path, ".tmp", ec);
+ if (ec)
+ {
+ System::println(System::Color::warning,
+ "Failed to store binary cache %s: %s",
+ archive_path.u8string(),
+ ec.message());
+ }
+ else
+ System::println("Stored binary cache: %s", archive_path.u8string());
+ }
+ else if (result.code == BuildResult::BUILD_FAILED || result.code == BuildResult::POST_BUILD_CHECKS_FAILED)
+ {
+ if (!fs.exists(archive_tombstone_path))
+ {
+ // Build failed, store all failure logs in the tombstone.
+ const auto tmp_log_path = paths.buildtrees / spec.name() / "tmp_failure_logs";
+ const auto tmp_log_path_destination = tmp_log_path / spec.name();
+ const auto tmp_failure_zip = paths.buildtrees / spec.name() / "failure_logs.zip";
+ fs.create_directories(tmp_log_path_destination, ec);
+
+ for (auto &log_file : fs::stdfs::directory_iterator(paths.buildtrees / spec.name()))
+ {
+ if (log_file.path().extension() == ".log")
+ {
+ fs.copy_file(log_file.path(), tmp_log_path_destination / log_file.path().filename(), fs::stdfs::copy_options::none, ec);
+ }
+ }
+
+ compress_directory(paths, tmp_log_path, paths.buildtrees / spec.name() / "failure_logs.zip");
+
+ fs.create_directories(archive_tombstone_path.parent_path(), ec);
+ fs.rename_or_copy(tmp_failure_zip, archive_tombstone_path, ".tmp", ec);
+
+ // clean up temporary directory
+ fs.remove_all(tmp_log_path, ec);
+ }
+ }
+
+ return result;
+ }
+
+ return do_build_package_and_clean_buildtrees(
+ paths, pre_build_info, spec, maybe_abi_tag_and_file.value_or(AbiTagAndFile{}).tag, config);
+ }
+
+ const std::string& to_string(const BuildResult build_result)
+ {
+ 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";
+
+ 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;
+ 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(std::unordered_map<std::string, std::string> 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 Expected<std::unordered_map<std::string, std::string>> pghs =
+ Paragraphs::get_single_paragraph(fs, filepath);
+ Checks::check_exit(VCPKG_LINE_INFO, pghs.get() != nullptr, "Invalid BUILD_INFO file for package");
+ return inner_create_buildinfo(*pghs.get());
+ }
+
+ PreBuildInfo PreBuildInfo::from_triplet_file(const VcpkgPaths& paths, const Triplet& triplet)
+ {
+ static constexpr CStringView FLAG_GUID = "c35112b6-d1ba-415b-aa5d-81de856ef8eb";
+
+ const fs::path& cmake_exe_path = paths.get_tool_exe(Tools::CMAKE);
+ const fs::path ports_cmake_script_path = paths.scripts / "get_triplet_environment.cmake";
+ const fs::path triplet_file_path = paths.triplets / (triplet.canonical_name() + ".cmake");
+
+ const auto cmd_launch_cmake = System::make_cmake_cmd(cmake_exe_path,
+ ports_cmake_script_path,
+ {
+ {"CMAKE_TRIPLET_FILE", triplet_file_path},
+ });
+ const auto ec_data = System::cmd_execute_and_capture_output(cmd_launch_cmake);
+ Checks::check_exit(VCPKG_LINE_INFO, ec_data.exit_code == 0, ec_data.output);
+
+ const std::vector<std::string> lines = Strings::split(ec_data.output, "\n");
+
+ PreBuildInfo pre_build_info;
+
+ const auto e = lines.cend();
+ auto cur = std::find(lines.cbegin(), e, FLAG_GUID);
+ if (cur != e) ++cur;
+
+ for (; cur != e; ++cur)
+ {
+ auto&& line = *cur;
+
+ const std::vector<std::string> s = Strings::split(line, "=");
+ Checks::check_exit(VCPKG_LINE_INFO,
+ s.size() == 1 || s.size() == 2,
+ "Expected format is [VARIABLE_NAME=VARIABLE_VALUE], but was [%s]",
+ line);
+
+ const bool variable_with_no_value = s.size() == 1;
+ const std::string variable_name = s.at(0);
+ const std::string variable_value = variable_with_no_value ? "" : s.at(1);
+
+ if (variable_name == "VCPKG_TARGET_ARCHITECTURE")
+ {
+ pre_build_info.target_architecture = variable_value;
+ continue;
+ }
+
+ if (variable_name == "VCPKG_CMAKE_SYSTEM_NAME")
+ {
+ pre_build_info.cmake_system_name = variable_value;
+ continue;
+ }
+
+ if (variable_name == "VCPKG_CMAKE_SYSTEM_VERSION")
+ {
+ pre_build_info.cmake_system_version = variable_value;
+ continue;
+ }
+
+ if (variable_name == "VCPKG_PLATFORM_TOOLSET")
+ {
+ pre_build_info.platform_toolset =
+ variable_value.empty() ? nullopt : Optional<std::string>{variable_value};
+ continue;
+ }
+
+ if (variable_name == "VCPKG_VISUAL_STUDIO_PATH")
+ {
+ pre_build_info.visual_studio_path =
+ variable_value.empty() ? nullopt : Optional<fs::path>{variable_value};
+ continue;
+ }
+
+ if (variable_name == "VCPKG_CHAINLOAD_TOOLCHAIN_FILE")
+ {
+ pre_build_info.external_toolchain_file =
+ variable_value.empty() ? nullopt : Optional<std::string>{variable_value};
+ continue;
+ }
+
+ if (variable_name == "VCPKG_BUILD_TYPE")
+ {
+ if (variable_value.empty())
+ pre_build_info.build_type = nullopt;
+ else if (Strings::case_insensitive_ascii_equals(variable_value, "debug"))
+ pre_build_info.build_type = ConfigurationType::DEBUG;
+ else if (Strings::case_insensitive_ascii_equals(variable_value, "release"))
+ pre_build_info.build_type = ConfigurationType::RELEASE;
+ else
+ Checks::exit_with_message(
+ VCPKG_LINE_INFO, "Unknown setting for VCPKG_BUILD_TYPE: %s", variable_value);
+ continue;
+ }
+
+ Checks::exit_with_message(VCPKG_LINE_INFO, "Unknown variable name %s", line);
+ }
+
+ pre_build_info.triplet_abi_tag = [&]() {
+ const auto& fs = paths.get_filesystem();
+ static std::map<fs::path, std::string> s_hash_cache;
+
+ auto it_hash = s_hash_cache.find(triplet_file_path);
+ if (it_hash != s_hash_cache.end())
+ {
+ return it_hash->second;
+ }
+ auto hash = Hash::get_file_hash(fs, triplet_file_path, "SHA1");
+
+ if (auto p = pre_build_info.external_toolchain_file.get())
+ {
+ hash += "-";
+ hash += Hash::get_file_hash(fs, *p, "SHA1");
+ }
+ else if (pre_build_info.cmake_system_name == "Linux")
+ {
+ hash += "-";
+ hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "linux.cmake", "SHA1");
+ }
+ else if (pre_build_info.cmake_system_name == "Darwin")
+ {
+ hash += "-";
+ hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "osx.cmake", "SHA1");
+ }
+ else if (pre_build_info.cmake_system_name == "FreeBSD")
+ {
+ hash += "-";
+ hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "freebsd.cmake", "SHA1");
+ }
+ else if (pre_build_info.cmake_system_name == "Android")
+ {
+ hash += "-";
+ hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "android.cmake", "SHA1");
+ }
+
+ s_hash_cache.emplace(triplet_file_path, hash);
+ return hash;
+ }();
+
+ return pre_build_info;
+ }
+ 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))
+ {
+ }
+}
diff --git a/toolsrc/src/vcpkg/commands.ci.cpp b/toolsrc/src/vcpkg/commands.ci.cpp
index 5ca962744..4ff503e1c 100644
--- a/toolsrc/src/vcpkg/commands.ci.cpp
+++ b/toolsrc/src/vcpkg/commands.ci.cpp
@@ -52,24 +52,176 @@ namespace vcpkg::Commands::CI
nullptr,
};
+ struct XunitTestResults
+ {
+ public:
+
+ XunitTestResults()
+ {
+ m_assembly_run_datetime = Chrono::CTime::get_current_date_time();
+ }
+
+ void add_test_results(const std::string& spec, const Build::BuildResult& build_result, const Chrono::ElapsedTime& elapsed_time, const std::string& abi_tag)
+ {
+ m_collections.back().tests.push_back({ spec, build_result, elapsed_time, abi_tag });
+ }
+
+ // Starting a new test collection
+ void push_collection( const std::string& name)
+ {
+ m_collections.push_back({name});
+ }
+
+ void collection_time(const vcpkg::Chrono::ElapsedTime& time)
+ {
+ m_collections.back().time = time;
+ }
+
+ const std::string& build_xml()
+ {
+ m_xml.clear();
+ xml_start_assembly();
+
+ for (const auto& collection : m_collections)
+ {
+ xml_start_collection(collection);
+ for (const auto& test : collection.tests)
+ {
+ xml_test(test);
+ }
+ xml_finish_collection();
+ }
+
+ xml_finish_assembly();
+ return m_xml;
+ }
+
+ void assembly_time(const vcpkg::Chrono::ElapsedTime& assembly_time)
+ {
+ m_assembly_time = assembly_time;
+ }
+
+ private:
+
+ struct XunitTest
+ {
+ std::string name;
+ vcpkg::Build::BuildResult result;
+ vcpkg::Chrono::ElapsedTime time;
+ std::string abi_tag;
+ };
+
+ struct XunitCollection
+ {
+ std::string name;
+ vcpkg::Chrono::ElapsedTime time;
+ std::vector<XunitTest> tests;
+ };
+
+ void xml_start_assembly()
+ {
+ std::string datetime;
+ if (m_assembly_run_datetime)
+ {
+ auto rawDateTime = m_assembly_run_datetime.get()->to_string();
+ // The expected format is "yyyy-mm-ddThh:mm:ss.0Z"
+ // 0123456789012345678901
+ datetime = Strings::format(R"(run-date="%s" run-time="%s")",
+ rawDateTime.substr(0, 10), rawDateTime.substr(11, 8));
+ }
+
+ std::string time = Strings::format(R"(time="%lld")", m_assembly_time.as<std::chrono::seconds>().count());
+
+ m_xml += Strings::format(
+ R"(<assemblies>)" "\n"
+ R"( <assembly name="vcpkg" %s %s>)" "\n"
+ , datetime, time);
+ }
+ void xml_finish_assembly()
+ {
+ m_xml += " </assembly>\n"
+ "</assemblies>\n";
+ }
+
+ void xml_start_collection(const XunitCollection& collection)
+ {
+ m_xml += Strings::format(R"( <collection name="%s" time="%lld">)"
+ "\n",
+ collection.name,
+ collection.time.as<std::chrono::seconds>().count());
+ }
+ void xml_finish_collection()
+ {
+ m_xml += " </collection>\n";
+ }
+
+ void xml_test(const XunitTest& test)
+ {
+ std::string message_block;
+ const char* result_string = "";
+ switch (test.result)
+ {
+ case BuildResult::POST_BUILD_CHECKS_FAILED:
+ case BuildResult::FILE_CONFLICTS:
+ case BuildResult::BUILD_FAILED:
+ result_string = "Fail";
+ message_block = Strings::format("<failure><message><![CDATA[%s]]></message></failure>", to_string(test.result));
+ break;
+ case BuildResult::EXCLUDED:
+ case BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES:
+ result_string = "Skip";
+ message_block = Strings::format("<reason><![CDATA[%s]]></reason>", to_string(test.result));
+ break;
+ case BuildResult::SUCCEEDED:
+ result_string = "Pass";
+ break;
+ default:
+ Checks::exit_fail(VCPKG_LINE_INFO);
+ break;
+ }
+
+ std::string traits_block;
+ if (test.abi_tag != "") // only adding if there is a known abi tag
+ {
+ traits_block = Strings::format(R"(<traits><trait name="abi_tag" value="%s" /></traits>)", test.abi_tag);
+ }
+
+ m_xml += Strings::format(R"( <test name="%s" method="%s" time="%lld" result="%s">%s%s</test>)"
+ "\n",
+ test.name,
+ test.name,
+ test.time.as<std::chrono::seconds>().count(),
+ result_string,
+ traits_block,
+ message_block);
+ }
+
+ Optional<vcpkg::Chrono::CTime> m_assembly_run_datetime;
+ vcpkg::Chrono::ElapsedTime m_assembly_time;
+ std::vector<XunitCollection> m_collections;
+
+ std::string m_xml;
+ };
+
+
struct UnknownCIPortsResults
{
std::vector<FullPackageSpec> unknown;
std::map<PackageSpec, Build::BuildResult> known;
std::map<PackageSpec, std::vector<std::string>> features;
+ std::map<PackageSpec, std::string> abi_tag_map;
};
- static UnknownCIPortsResults find_unknown_ports_for_ci(const VcpkgPaths& paths,
+ static std::unique_ptr<UnknownCIPortsResults> find_unknown_ports_for_ci(const VcpkgPaths& paths,
const std::set<std::string>& exclusions,
const Dependencies::PortFileProvider& provider,
const std::vector<FeatureSpec>& fspecs,
const bool purge_tombstones)
{
- UnknownCIPortsResults ret;
+ auto ret = std::make_unique<UnknownCIPortsResults>();
auto& fs = paths.get_filesystem();
- std::map<PackageSpec, std::string> abi_tag_map;
std::set<PackageSpec> will_fail;
const Build::BuildPackageOptions build_options = {
@@ -103,9 +255,9 @@ namespace vcpkg::Commands::CI
auto dependency_abis =
Util::fmap(p->computed_dependencies, [&](const PackageSpec& spec) -> Build::AbiEntry {
- auto it = abi_tag_map.find(spec);
+ auto it = ret->abi_tag_map.find(spec);
- if (it == abi_tag_map.end())
+ if (it == ret->abi_tag_map.end())
return {spec.name(), ""};
else
return {spec.name(), it->second};
@@ -118,13 +270,13 @@ namespace vcpkg::Commands::CI
if (auto tag_and_file = maybe_tag_and_file.get())
{
abi = tag_and_file->tag;
- abi_tag_map.emplace(p->spec, abi);
+ ret->abi_tag_map.emplace(p->spec, abi);
}
}
else if (auto ipv = p->installed_package.get())
{
abi = ipv->core->package.abi;
- if (!abi.empty()) abi_tag_map.emplace(p->spec, abi);
+ if (!abi.empty()) ret->abi_tag_map.emplace(p->spec, abi);
}
std::string state;
@@ -143,35 +295,35 @@ namespace vcpkg::Commands::CI
bool b_will_build = false;
- ret.features.emplace(p->spec,
+ ret->features.emplace(p->spec,
std::vector<std::string> {p->feature_list.begin(), p->feature_list.end()});
if (Util::Sets::contains(exclusions, p->spec.name()))
{
- ret.known.emplace(p->spec, BuildResult::EXCLUDED);
+ ret->known.emplace(p->spec, BuildResult::EXCLUDED);
will_fail.emplace(p->spec);
}
else if (std::any_of(p->computed_dependencies.begin(),
p->computed_dependencies.end(),
[&](const PackageSpec& spec) { return Util::Sets::contains(will_fail, spec); }))
{
- ret.known.emplace(p->spec, BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES);
+ ret->known.emplace(p->spec, BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES);
will_fail.emplace(p->spec);
}
else if (fs.exists(archive_path))
{
state += "pass";
- ret.known.emplace(p->spec, BuildResult::SUCCEEDED);
+ ret->known.emplace(p->spec, BuildResult::SUCCEEDED);
}
else if (fs.exists(archive_tombstone_path))
{
state += "fail";
- ret.known.emplace(p->spec, BuildResult::BUILD_FAILED);
+ ret->known.emplace(p->spec, BuildResult::BUILD_FAILED);
will_fail.emplace(p->spec);
}
else
{
- ret.unknown.push_back({p->spec, {p->feature_list.begin(), p->feature_list.end()}});
+ ret->unknown.push_back({p->spec, {p->feature_list.begin(), p->feature_list.end()}});
b_will_build = true;
}
@@ -229,23 +381,29 @@ namespace vcpkg::Commands::CI
};
std::vector<std::map<PackageSpec, BuildResult>> all_known_results;
+ std::map<PackageSpec, std::string> abi_tag_map;
+
+ XunitTestResults xunitTestResults;
std::vector<std::string> all_ports = Install::get_all_port_names(paths);
std::vector<TripletAndSummary> results;
+ auto timer = Chrono::ElapsedTimer::create_started();
for (const Triplet& triplet : triplets)
{
Input::check_triplet(triplet, paths);
+ xunitTestResults.push_collection(triplet.canonical_name());
+
Dependencies::PackageGraph pgraph(paths_port_file, status_db);
std::vector<PackageSpec> specs = PackageSpec::to_package_specs(all_ports, triplet);
// Install the default features for every package
- auto all_fspecs = Util::fmap(specs, [](auto& spec) { return FeatureSpec(spec, ""); });
+ auto all_feature_specs = Util::fmap(specs, [](auto& spec) { return FeatureSpec(spec, ""); });
auto split_specs =
- find_unknown_ports_for_ci(paths, exclusions_set, paths_port_file, all_fspecs, purge_tombstones);
- auto fspecs = FullPackageSpec::to_feature_specs(split_specs.unknown);
+ find_unknown_ports_for_ci(paths, exclusions_set, paths_port_file, all_feature_specs, purge_tombstones);
+ auto feature_specs = FullPackageSpec::to_feature_specs(split_specs->unknown);
- for (auto&& fspec : fspecs)
+ for (auto&& fspec : feature_specs)
pgraph.install(fspec);
Dependencies::CreateInstallPlanOptions serialize_options;
@@ -284,7 +442,7 @@ namespace vcpkg::Commands::CI
p->plan_type = InstallPlanType::EXCLUDED;
}
- for (auto&& feature : split_specs.features[p->spec])
+ for (auto&& feature : split_specs->features[p->spec])
if (p->feature_list.find(feature) == p->feature_list.end())
{
pgraph.install({p->spec, feature});
@@ -304,13 +462,32 @@ namespace vcpkg::Commands::CI
}
else
{
+ auto collection_timer = Chrono::ElapsedTimer::create_started();
auto summary = Install::perform(action_plan, Install::KeepGoing::YES, paths, status_db);
+ auto collection_time_elapsed = collection_timer.elapsed();
+
+ // Adding results for ports that were built or pulled from an archive
for (auto&& result : summary.results)
- split_specs.known.erase(result.spec);
- results.push_back({triplet, std::move(summary)});
- all_known_results.emplace_back(std::move(split_specs.known));
+ {
+ split_specs->known.erase(result.spec);
+ xunitTestResults.add_test_results(result.spec.to_string(), result.build_result.code, result.timing, split_specs->abi_tag_map.at(result.spec));
+ }
+
+ // Adding results for ports that were not built because they have known states
+ for (auto&& port : split_specs->known)
+ {
+ xunitTestResults.add_test_results(port.first.to_string(), port.second, Chrono::ElapsedTime{}, split_specs->abi_tag_map.at(port.first));
+ }
+
+ all_known_results.emplace_back(std::move(split_specs->known));
+ abi_tag_map.insert(split_specs->abi_tag_map.begin(), split_specs->abi_tag_map.end());
+
+ results.push_back({ triplet, std::move(summary)});
+
+ xunitTestResults.collection_time( collection_time_elapsed );
}
}
+ xunitTestResults.assembly_time(timer.elapsed());
for (auto&& result : results)
{
@@ -322,21 +499,7 @@ namespace vcpkg::Commands::CI
auto it_xunit = options.settings.find(OPTION_XUNIT);
if (it_xunit != options.settings.end())
{
- std::string xunit_doc = "<assemblies><assembly><collection>\n";
-
- for (auto&& result : results)
- xunit_doc += result.summary.xunit_results();
- for (auto&& known_result : all_known_results)
- {
- for (auto&& result : known_result)
- {
- xunit_doc +=
- Install::InstallSummary::xunit_result(result.first, Chrono::ElapsedTime {}, result.second);
- }
- }
-
- xunit_doc += "</collection></assembly></assemblies>\n";
- paths.get_filesystem().write_contents(fs::u8path(it_xunit->second), xunit_doc);
+ paths.get_filesystem().write_contents(fs::u8path(it_xunit->second), xunitTestResults.build_xml());
}
Checks::exit_success(VCPKG_LINE_INFO);
diff --git a/toolsrc/src/vcpkg/commands.dependinfo.cpp b/toolsrc/src/vcpkg/commands.dependinfo.cpp
index 5f72e965b..455f3b7c5 100644
--- a/toolsrc/src/vcpkg/commands.dependinfo.cpp
+++ b/toolsrc/src/vcpkg/commands.dependinfo.cpp
@@ -12,16 +12,16 @@ namespace vcpkg::Commands::DependInfo
constexpr StringLiteral OPTION_DOT = "--dot";
constexpr StringLiteral OPTION_DGML = "--dgml";
- constexpr std::array<CommandSwitch, 2> DEPEND_SWITCHES = { {
- { OPTION_DOT, "Creates graph on basis of dot" },
- { OPTION_DGML, "Creates graph on basis of dgml" },
- } };
+ constexpr std::array<CommandSwitch, 2> DEPEND_SWITCHES = {{
+ {OPTION_DOT, "Creates graph on basis of dot"},
+ {OPTION_DGML, "Creates graph on basis of dgml"},
+ }};
const CommandStructure COMMAND_STRUCTURE = {
Help::create_example_string(R"###(depend-info [pat])###"),
0,
- 1,
- { DEPEND_SWITCHES,{} },
+ SIZE_MAX,
+ {DEPEND_SWITCHES, {}},
nullptr,
};
@@ -32,8 +32,7 @@ namespace vcpkg::Commands::DependInfo
return output;
}
- std::string create_dot_as_string(
- const std::vector<std::unique_ptr<SourceControlFile>>& source_control_files)
+ std::string create_dot_as_string(const std::vector<std::unique_ptr<SourceControlFile>>& source_control_files)
{
int empty_node_count = 0;
@@ -53,7 +52,7 @@ namespace vcpkg::Commands::DependInfo
s.append(Strings::format("%s;", name));
for (const Dependency& d : source_paragraph.depends)
{
- const std::string dependency_name = replace_dashes_with_underscore(d.name());
+ const std::string dependency_name = replace_dashes_with_underscore(d.depend.name);
s.append(Strings::format("%s -> %s;", name, dependency_name));
}
}
@@ -62,8 +61,7 @@ namespace vcpkg::Commands::DependInfo
return s;
}
- std::string create_dgml_as_string(
- const std::vector<std::unique_ptr<SourceControlFile>>& source_control_files)
+ std::string create_dgml_as_string(const std::vector<std::unique_ptr<SourceControlFile>>& source_control_files)
{
std::string s;
s.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
@@ -79,16 +77,22 @@ namespace vcpkg::Commands::DependInfo
// Iterate over dependencies.
for (const Dependency& d : source_paragraph.depends)
{
- links.append(Strings::format("<Link Source=\"%s\" Target=\"%s\" />", name, d.name()));
+ if (d.qualifier.empty())
+ links.append(Strings::format("<Link Source=\"%s\" Target=\"%s\" />", name, d.depend.name));
+ else
+ links.append(Strings::format(
+ "<Link Source=\"%s\" Target=\"%s\" StrokeDashArray=\"4\" />", name, d.depend.name));
}
// Iterate over feature dependencies.
- const std::vector<std::unique_ptr<FeatureParagraph>>& feature_paragraphs = source_control_file->feature_paragraphs;
+ const std::vector<std::unique_ptr<FeatureParagraph>>& feature_paragraphs =
+ source_control_file->feature_paragraphs;
for (const auto& feature_paragraph : feature_paragraphs)
{
for (const Dependency& d : feature_paragraph->depends)
{
- links.append(Strings::format("<Link Source=\"%s\" Target=\"%s\" />", name, d.name()));
+ links.append(Strings::format(
+ "<Link Source=\"%s\" Target=\"%s\" StrokeDashArray=\"4\" />", name, d.depend.name));
}
}
}
@@ -101,9 +105,8 @@ namespace vcpkg::Commands::DependInfo
return s;
}
- std::string create_graph_as_string(
- const std::unordered_set<std::string>& switches,
- const std::vector<std::unique_ptr<SourceControlFile>>& source_control_files)
+ std::string create_graph_as_string(const std::unordered_set<std::string>& switches,
+ const std::vector<std::unique_ptr<SourceControlFile>>& source_control_files)
{
if (Util::Sets::contains(switches, OPTION_DOT))
{
@@ -116,35 +119,50 @@ namespace vcpkg::Commands::DependInfo
return "";
}
+ void build_dependencies_list(std::set<std::string>& packages_to_keep,
+ const std::string& requested_package,
+ const std::vector<std::unique_ptr<SourceControlFile>>& source_control_files)
+ {
+ const auto source_control_file =
+ Util::find_if(source_control_files, [&requested_package](const auto& source_control_file) {
+ return source_control_file->core_paragraph->name == requested_package;
+ });
+
+ if (source_control_file != source_control_files.end())
+ {
+ const auto new_package = packages_to_keep.insert(requested_package).second;
+
+ if (new_package)
+ {
+ for (const auto& dependency : (*source_control_file)->core_paragraph->depends)
+ {
+ build_dependencies_list(packages_to_keep, dependency.depend.name, source_control_files);
+ }
+ }
+ }
+ else
+ {
+ System::println(System::Color::warning, "package '%s' does not exist", requested_package);
+ }
+ }
+
void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths)
{
const ParsedArguments options = args.parse_arguments(COMMAND_STRUCTURE);
auto source_control_files = Paragraphs::load_all_ports(paths.get_filesystem(), paths.ports);
- if (args.command_arguments.size() == 1)
+ if (args.command_arguments.size() >= 1)
{
- const std::string filter = args.command_arguments.at(0);
-
- Util::erase_remove_if(source_control_files,
- [&](const std::unique_ptr<SourceControlFile>& source_control_file) {
- const SourceParagraph& source_paragraph = *source_control_file->core_paragraph;
-
- if (Strings::case_insensitive_ascii_contains(source_paragraph.name, filter))
- {
- return false;
- }
-
- for (const Dependency& dependency : source_paragraph.depends)
- {
- if (Strings::case_insensitive_ascii_contains(dependency.name(), filter))
- {
- return false;
- }
- }
-
- return true;
- });
+ std::set<std::string> packages_to_keep;
+ for (const auto& requested_package : args.command_arguments)
+ {
+ build_dependencies_list(packages_to_keep, requested_package, source_control_files);
+ }
+
+ Util::erase_remove_if(source_control_files, [&packages_to_keep](const auto& source_control_file) {
+ return !Util::Sets::contains(packages_to_keep, source_control_file->core_paragraph->name);
+ });
}
if (!options.switches.empty())
diff --git a/toolsrc/src/vcpkg/commands.edit.cpp b/toolsrc/src/vcpkg/commands.edit.cpp
index 044ae1c47..c9d52c572 100644
--- a/toolsrc/src/vcpkg/commands.edit.cpp
+++ b/toolsrc/src/vcpkg/commands.edit.cpp
@@ -157,6 +157,9 @@ namespace vcpkg::Commands::Edit
#elif defined(__APPLE__)
candidate_paths.push_back(fs::path{"/Applications/Visual Studio Code - Insiders.app/Contents/Resources/app/bin/code"});
candidate_paths.push_back(fs::path{"/Applications/Visual Studio Code.app/Contents/Resources/app/bin/code"});
+#elif defined(__linux__)
+ candidate_paths.push_back(fs::path{"/usr/share/code/bin/code"});
+ candidate_paths.push_back(fs::path{"/usr/bin/code"});
#endif
const auto it = Util::find_if(candidate_paths, [&](const fs::path& p) { return fs.exists(p); });
diff --git a/toolsrc/src/vcpkg/install.cpp b/toolsrc/src/vcpkg/install.cpp
index 1cfa2bf71..434876871 100644
--- a/toolsrc/src/vcpkg/install.cpp
+++ b/toolsrc/src/vcpkg/install.cpp
@@ -719,9 +719,9 @@ namespace vcpkg::Install
return nullptr;
}
- std::string InstallSummary::xunit_result(const PackageSpec& spec, Chrono::ElapsedTime time, BuildResult code)
+ static std::string xunit_result(const PackageSpec& spec, Chrono::ElapsedTime time, BuildResult code)
{
- std::string inner_block;
+ std::string message_block;
const char* result_string = "";
switch (code)
{
@@ -729,12 +729,12 @@ namespace vcpkg::Install
case BuildResult::FILE_CONFLICTS:
case BuildResult::BUILD_FAILED:
result_string = "Fail";
- inner_block = Strings::format("<failure><message><![CDATA[%s]]></message></failure>", to_string(code));
+ message_block = Strings::format("<failure><message><![CDATA[%s]]></message></failure>", to_string(code));
break;
case BuildResult::EXCLUDED:
case BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES:
result_string = "Skip";
- inner_block = Strings::format("<reason><![CDATA[%s]]></reason>", to_string(code));
+ message_block = Strings::format("<reason><![CDATA[%s]]></reason>", to_string(code));
break;
case BuildResult::SUCCEEDED: result_string = "Pass"; break;
default: Checks::exit_fail(VCPKG_LINE_INFO);
@@ -746,7 +746,7 @@ namespace vcpkg::Install
spec,
time.as<std::chrono::seconds>().count(),
result_string,
- inner_block);
+ message_block);
}
std::string InstallSummary::xunit_results() const
diff --git a/toolsrc/src/vcpkg/sourceparagraph.cpp b/toolsrc/src/vcpkg/sourceparagraph.cpp
index ed61cb42a..baa8b070b 100644
--- a/toolsrc/src/vcpkg/sourceparagraph.cpp
+++ b/toolsrc/src/vcpkg/sourceparagraph.cpp
@@ -194,16 +194,13 @@ namespace vcpkg
auto pos = depend_string.find(' ');
if (pos == std::string::npos) return Dependency::parse_dependency(depend_string, "");
// expect of the form "\w+ \[\w+\]"
- Dependency dep;
-
- dep.depend.name = depend_string.substr(0, pos);
if (depend_string.c_str()[pos + 1] != '(' || depend_string[depend_string.size() - 1] != ')')
{
// Error, but for now just slurp the entire string.
return Dependency::parse_dependency(depend_string, "");
}
- dep.qualifier = depend_string.substr(pos + 2, depend_string.size() - pos - 3);
- return dep;
+ return Dependency::parse_dependency(depend_string.substr(0, pos),
+ depend_string.substr(pos + 2, depend_string.size() - pos - 3));
});
}
diff --git a/toolsrc/src/vcpkg/vcpkgpaths.cpp b/toolsrc/src/vcpkg/vcpkgpaths.cpp
index a92a5673e..47994660c 100644
--- a/toolsrc/src/vcpkg/vcpkgpaths.cpp
+++ b/toolsrc/src/vcpkg/vcpkgpaths.cpp
@@ -192,6 +192,26 @@ namespace vcpkg
vs_root_path.generic_string());
}
+ if (prebuildinfo.cmake_system_name == "WindowsStore")
+ {
+ // For now, cmake does not support VS 2019 when using the MSBuild generator.
+ Util::erase_remove_if(candidates, [&](const Toolset* t) { return t->version == "v142"; });
+ Checks::check_exit(VCPKG_LINE_INFO,
+ !candidates.empty(),
+ "With the current CMake version, UWP binaries can only be built with toolset version "
+ "v141 or below. Please install the v141 toolset in VS 2019.");
+ }
+
+ if (System::get_host_processor() == System::CPUArchitecture::X86)
+ {
+ // For now, cmake does not support VS 2019 when using the MSBuild generator.
+ Util::erase_remove_if(candidates, [&](const Toolset* t) { return t->version == "v142"; });
+ Checks::check_exit(VCPKG_LINE_INFO,
+ !candidates.empty(),
+ "With the current CMake version, 32-bit machines can build with toolset version "
+ "v141 or below. Please install the v141 toolset in VS 2019.");
+ }
+
Checks::check_exit(VCPKG_LINE_INFO, !candidates.empty(), "No suitable Visual Studio instances were found");
return *candidates.front();
diff --git a/toolsrc/src/vcpkg/visualstudio.cpp b/toolsrc/src/vcpkg/visualstudio.cpp
index 83a530a10..d2fccc716 100644
--- a/toolsrc/src/vcpkg/visualstudio.cpp
+++ b/toolsrc/src/vcpkg/visualstudio.cpp
@@ -12,6 +12,7 @@ namespace vcpkg::VisualStudio
static constexpr CStringView V_120 = "v120";
static constexpr CStringView V_140 = "v140";
static constexpr CStringView V_141 = "v141";
+ static constexpr CStringView V_142 = "v142";
struct VisualStudioInstance
{
@@ -213,35 +214,62 @@ namespace vcpkg::VisualStudio
for (const fs::path& subdir : msvc_subdirectories)
{
+ auto toolset_version_full = subdir.filename().u8string();
+ auto toolset_version_prefix = toolset_version_full.substr(0, 4);
+ CStringView toolset_version;
+ std::string vcvars_option;
+ if (toolset_version_prefix.size() != 4)
+ {
+ // unknown toolset
+ continue;
+ }
+ else if (toolset_version_prefix[3] == '1')
+ {
+ toolset_version = V_141;
+ vcvars_option = "-vcvars_ver=14.1";
+ }
+ else if (toolset_version_prefix[3] == '2')
+ {
+ toolset_version = V_142;
+ vcvars_option = "-vcvars_ver=14.2";
+ }
+ else
+ {
+ // unknown toolset minor version
+ continue;
+ }
const fs::path dumpbin_path = subdir / "bin" / "HostX86" / "x86" / "dumpbin.exe";
paths_examined.push_back(dumpbin_path);
if (fs.exists(dumpbin_path))
{
- const Toolset v141_toolset{
- vs_instance.root_path, dumpbin_path, vcvarsall_bat, {}, V_141, supported_architectures};
+ Toolset toolset{vs_instance.root_path,
+ dumpbin_path,
+ vcvarsall_bat,
+ {vcvars_option},
+ toolset_version,
+ supported_architectures};
const auto english_language_pack = dumpbin_path.parent_path() / "1033";
if (!fs.exists(english_language_pack))
{
- excluded_toolsets.push_back(v141_toolset);
- break;
+ excluded_toolsets.push_back(std::move(toolset));
+ continue;
}
- found_toolsets.push_back(v141_toolset);
+ found_toolsets.push_back(std::move(toolset));
if (v140_is_available)
{
- const Toolset v140_toolset{vs_instance.root_path,
- dumpbin_path,
- vcvarsall_bat,
- {"-vcvars_ver=14.0"},
- V_140,
- supported_architectures};
- found_toolsets.push_back(v140_toolset);
+ found_toolsets.push_back({vs_instance.root_path,
+ dumpbin_path,
+ vcvarsall_bat,
+ {"-vcvars_ver=14.0"},
+ V_140,
+ supported_architectures});
}
- break;
+ continue;
}
}