mirror of
https://github.com/microsoft/vcpkg.git
synced 2024-11-24 22:09:00 +08:00
Introduce "vcpkg fetch"
This commit is contained in:
parent
54c68da907
commit
0c0f68939e
@ -135,6 +135,13 @@ namespace vcpkg::Commands
|
||||
std::string get_file_hash(const VcpkgPaths& paths, fs::path const& path, std::string const& hash_type);
|
||||
}
|
||||
|
||||
namespace Fetch
|
||||
{
|
||||
std::vector<Toolset> find_toolset_instances(const VcpkgPaths& paths);
|
||||
fs::path get_tool_path(const VcpkgPaths& paths, const std::string& tool);
|
||||
void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
struct PackageNameAndFunction
|
||||
{
|
||||
|
@ -7,8 +7,22 @@
|
||||
#include <vcpkg/base/files.h>
|
||||
#include <vcpkg/base/lazy.h>
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace vcpkg
|
||||
{
|
||||
namespace Tools
|
||||
{
|
||||
static const std::string SEVEN_ZIP = "7zip";
|
||||
static const std::string CMAKE = "cmake";
|
||||
static const std::string GIT = "git";
|
||||
static const std::string NINJA = "ninja";
|
||||
static const std::string NUGET = "nuget";
|
||||
static const std::string IFW_INSTALLER_BASE = "ifw_installerbase";
|
||||
static const std::string IFW_BINARYCREATOR = "ifw_binarycreator";
|
||||
static const std::string IFW_REPOGEN = "ifw_repogen";
|
||||
}
|
||||
|
||||
struct ToolsetArchOption
|
||||
{
|
||||
CStringView name;
|
||||
@ -63,14 +77,7 @@ namespace vcpkg
|
||||
|
||||
fs::path ports_cmake;
|
||||
|
||||
const fs::path& get_7za_exe() const;
|
||||
const fs::path& get_cmake_exe() const;
|
||||
const fs::path& get_git_exe() const;
|
||||
const fs::path& get_ninja_exe() const;
|
||||
const fs::path& get_nuget_exe() const;
|
||||
const fs::path& get_ifw_installerbase_exe() const;
|
||||
const fs::path& get_ifw_binarycreator_exe() const;
|
||||
const fs::path& get_ifw_repogen_exe() const;
|
||||
const fs::path& get_tool_exe(const std::string& tool) const;
|
||||
|
||||
/// <summary>Retrieve a toolset matching a VS version</summary>
|
||||
/// <remarks>
|
||||
@ -82,14 +89,7 @@ namespace vcpkg
|
||||
|
||||
private:
|
||||
Lazy<std::vector<std::string>> available_triplets;
|
||||
Lazy<fs::path> _7za_exe;
|
||||
Lazy<fs::path> cmake_exe;
|
||||
Lazy<fs::path> git_exe;
|
||||
Lazy<fs::path> ninja_exe;
|
||||
Lazy<fs::path> nuget_exe;
|
||||
Lazy<fs::path> ifw_installerbase_exe;
|
||||
Lazy<fs::path> ifw_binarycreator_exe;
|
||||
Lazy<fs::path> ifw_repogen_exe;
|
||||
mutable std::map<std::string, fs::path> tool_paths;
|
||||
Lazy<std::vector<Toolset>> toolsets;
|
||||
Lazy<std::vector<Toolset>> toolsets_vs2013;
|
||||
|
||||
|
@ -341,8 +341,8 @@ namespace vcpkg::Build
|
||||
vcpkg::Util::unused(paths.get_ninja_exe());
|
||||
#endif
|
||||
|
||||
const fs::path& cmake_exe_path = paths.get_cmake_exe();
|
||||
const fs::path& git_exe_path = paths.get_git_exe();
|
||||
const fs::path& cmake_exe_path = paths.get_tool_exe(Tools::CMAKE);
|
||||
const fs::path& git_exe_path = paths.get_tool_exe(Tools::GIT);
|
||||
|
||||
std::string all_features;
|
||||
for (auto& feature : config.scf.feature_paragraphs)
|
||||
@ -361,9 +361,8 @@ namespace vcpkg::Build
|
||||
{"TARGET_TRIPLET", spec.triplet().canonical_name()},
|
||||
{"VCPKG_PLATFORM_TOOLSET", toolset.version.c_str()},
|
||||
{"VCPKG_USE_HEAD_VERSION",
|
||||
Util::Enum::to_bool(config.build_package_options.use_head_version) ? "1" : "0"},
|
||||
{"_VCPKG_NO_DOWNLOADS",
|
||||
!Util::Enum::to_bool(config.build_package_options.allow_downloads) ? "1" : "0"},
|
||||
Util::Enum::to_bool(config.build_package_options.use_head_version) ? "1" : "0"},
|
||||
{"_VCPKG_NO_DOWNLOADS", !Util::Enum::to_bool(config.build_package_options.allow_downloads) ? "1" : "0"},
|
||||
{"_VCPKG_DOWNLOAD_TOOL", to_string(config.build_package_options.download_tool)},
|
||||
{"GIT", git_exe_path},
|
||||
{"FEATURES", Strings::join(";", config.feature_list)},
|
||||
@ -519,7 +518,7 @@ namespace vcpkg::Build
|
||||
Checks::check_exit(VCPKG_LINE_INFO, files.empty(), "unable to clear path: %s", pkg_path.u8string());
|
||||
|
||||
#if defined(_WIN32)
|
||||
auto&& _7za = paths.get_7za_exe();
|
||||
auto&& _7za = paths.get_tool_exe(Tools::SEVEN_ZIP);
|
||||
|
||||
System::cmd_execute_clean(Strings::format(
|
||||
R"("%s" x "%s" -o"%s" -y >nul)", _7za.u8string(), archive_path.u8string(), pkg_path.u8string()));
|
||||
@ -539,7 +538,7 @@ namespace vcpkg::Build
|
||||
Checks::check_exit(
|
||||
VCPKG_LINE_INFO, !fs.exists(tmp_archive_path), "Could not remove file: %s", tmp_archive_path.u8string());
|
||||
#if defined(_WIN32)
|
||||
auto&& _7za = paths.get_7za_exe();
|
||||
auto&& _7za = paths.get_tool_exe(Tools::SEVEN_ZIP);
|
||||
|
||||
System::cmd_execute_clean(Strings::format(
|
||||
R"("%s" a "%s" "%s\*" >nul)",
|
||||
@ -771,7 +770,7 @@ namespace vcpkg::Build
|
||||
{
|
||||
static constexpr CStringView FLAG_GUID = "c35112b6-d1ba-415b-aa5d-81de856ef8eb";
|
||||
|
||||
const fs::path& cmake_exe_path = paths.get_cmake_exe();
|
||||
const fs::path& cmake_exe_path = paths.get_tool_exe(Tools::CMAKE);
|
||||
const fs::path ports_cmake_script_path = paths.scripts / "get_triplet_environment.cmake";
|
||||
const fs::path triplet_file_path = paths.triplets / (triplet.canonical_name() + ".cmake");
|
||||
|
||||
|
@ -43,16 +43,15 @@ namespace vcpkg::Commands
|
||||
{"portsdiff", &PortsDiff::perform_and_exit},
|
||||
{"autocomplete", &Autocomplete::perform_and_exit},
|
||||
{"hash", &Hash::perform_and_exit},
|
||||
};
|
||||
{"fetch", &Fetch::perform_and_exit},
|
||||
};
|
||||
return t;
|
||||
}
|
||||
|
||||
Span<const PackageNameAndFunction<CommandTypeC>> get_available_commands_type_c()
|
||||
{
|
||||
static std::vector<PackageNameAndFunction<CommandTypeC>> t = {
|
||||
{"version", &Version::perform_and_exit},
|
||||
{"contact", &Contact::perform_and_exit}
|
||||
};
|
||||
static std::vector<PackageNameAndFunction<CommandTypeC>> t = {{"version", &Version::perform_and_exit},
|
||||
{"contact", &Contact::perform_and_exit}};
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ namespace vcpkg::Commands::Create
|
||||
const std::string port_name = args.command_arguments.at(0);
|
||||
const std::string url = args.command_arguments.at(1);
|
||||
|
||||
const fs::path& cmake_exe = paths.get_cmake_exe();
|
||||
const fs::path& cmake_exe = paths.get_tool_exe(Tools::CMAKE);
|
||||
|
||||
std::vector<System::CMakeVariable> cmake_args{{"CMD", "CREATE"}, {"PORT", port_name}, {"URL", url}};
|
||||
|
||||
|
@ -291,7 +291,7 @@ namespace vcpkg::Export::IFW
|
||||
std::error_code ec;
|
||||
Files::Filesystem& fs = paths.get_filesystem();
|
||||
|
||||
const fs::path& installerbase_exe = paths.get_ifw_installerbase_exe();
|
||||
const fs::path& installerbase_exe = paths.get_tool_exe(Tools::IFW_INSTALLER_BASE);
|
||||
fs::path tempmaintenancetool = ifw_packages_dir_path / "maintenance" / "data" / "tempmaintenancetool.exe";
|
||||
fs.create_directories(tempmaintenancetool.parent_path(), ec);
|
||||
Checks::check_exit(VCPKG_LINE_INFO,
|
||||
@ -335,7 +335,7 @@ namespace vcpkg::Export::IFW
|
||||
|
||||
void do_repository(const std::string& export_id, const Options& ifw_options, const VcpkgPaths& paths)
|
||||
{
|
||||
const fs::path& repogen_exe = paths.get_ifw_repogen_exe();
|
||||
const fs::path& repogen_exe = paths.get_tool_exe(Tools::IFW_REPOGEN);
|
||||
const fs::path packages_dir = get_packages_dir_path(export_id, ifw_options, paths);
|
||||
const fs::path repository_dir = get_repository_dir_path(export_id, ifw_options, paths);
|
||||
|
||||
@ -361,7 +361,7 @@ namespace vcpkg::Export::IFW
|
||||
|
||||
void do_installer(const std::string& export_id, const Options& ifw_options, const VcpkgPaths& paths)
|
||||
{
|
||||
const fs::path& binarycreator_exe = paths.get_ifw_binarycreator_exe();
|
||||
const fs::path& binarycreator_exe = paths.get_tool_exe(Tools::IFW_BINARYCREATOR);
|
||||
const fs::path config_file = get_config_file_path(export_id, ifw_options, paths);
|
||||
const fs::path packages_dir = get_packages_dir_path(export_id, ifw_options, paths);
|
||||
const fs::path repository_dir = get_repository_dir_path(export_id, ifw_options, paths);
|
||||
|
656
toolsrc/src/vcpkg/commands.fetch.cpp
Normal file
656
toolsrc/src/vcpkg/commands.fetch.cpp
Normal file
@ -0,0 +1,656 @@
|
||||
#include "pch.h"
|
||||
|
||||
#include <vcpkg/base/checks.h>
|
||||
#include <vcpkg/base/strings.h>
|
||||
#include <vcpkg/base/system.h>
|
||||
#include <vcpkg/base/util.h>
|
||||
#include <vcpkg/commands.h>
|
||||
#include <vcpkg/help.h>
|
||||
|
||||
namespace vcpkg::Commands::Fetch
|
||||
{
|
||||
static constexpr CStringView V_120 = "v120";
|
||||
static constexpr CStringView V_140 = "v140";
|
||||
static constexpr CStringView V_141 = "v141";
|
||||
|
||||
struct ToolData
|
||||
{
|
||||
std::array<int, 3> required_version;
|
||||
fs::path exe_path;
|
||||
std::string url;
|
||||
fs::path downloaded_path;
|
||||
fs::path tool_dir_path;
|
||||
};
|
||||
|
||||
static Optional<std::array<int, 3>> parse_version_string(const std::string& version_as_string)
|
||||
{
|
||||
static const std::regex RE(R"###((\d+)\.(\d+)\.(\d+))###");
|
||||
|
||||
std::match_results<std::string::const_iterator> match;
|
||||
const auto found = std::regex_search(version_as_string, match, RE);
|
||||
if (!found)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
const int d1 = atoi(match[1].str().c_str());
|
||||
const int d2 = atoi(match[2].str().c_str());
|
||||
const int d3 = atoi(match[3].str().c_str());
|
||||
const std::array<int, 3> result = {d1, d2, d3};
|
||||
return result;
|
||||
}
|
||||
|
||||
static ToolData parse_tool_data_from_xml(const VcpkgPaths& paths, const std::string& tool)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
static constexpr StringLiteral OS_STRING = "windows";
|
||||
#elif defined(__APPLE__)
|
||||
static constexpr StringLiteral OS_STRING = "osx";
|
||||
#else // assume linux
|
||||
static constexpr StringLiteral OS_STRING = "linux";
|
||||
#endif
|
||||
|
||||
static const fs::path XML_PATH = paths.scripts / "vcpkgTools.xml";
|
||||
|
||||
const auto maybe_get_string_inside_tags = [](const std::string& input,
|
||||
const std::regex& regex) -> Optional<std::string> {
|
||||
std::smatch match;
|
||||
const bool has_match = std::regex_search(input.cbegin(), input.cend(), match, regex);
|
||||
if (!has_match) return nullopt;
|
||||
return match[1];
|
||||
};
|
||||
|
||||
const auto get_string_inside_tags =
|
||||
[](const std::string& input, const std::regex& regex, const std::string& tag_name) -> std::string {
|
||||
std::smatch match;
|
||||
const bool has_match = std::regex_search(input.cbegin(), input.cend(), match, regex);
|
||||
Checks::check_exit(
|
||||
VCPKG_LINE_INFO, has_match, "Could not find tag <%s> in %s", tag_name, XML_PATH.generic_string());
|
||||
|
||||
return match[1];
|
||||
};
|
||||
|
||||
static const std::string XML = paths.get_filesystem().read_contents(XML_PATH).value_or_exit(VCPKG_LINE_INFO);
|
||||
static const std::regex VERSION_REGEX{R"###(<requiredVersion>([\s\S]*?)</requiredVersion>)###"};
|
||||
static const std::regex EXE_RELATIVE_PATH_REGEX{
|
||||
Strings::format(R"###(<exeRelativePath>([\s\S]*?)</exeRelativePath>)###")};
|
||||
static const std::regex ARCHIVE_RELATIVE_PATH_REGEX{
|
||||
Strings::format(R"###(<archiveRelativePath>([\s\S]*?)</archiveRelativePath>)###")};
|
||||
static const std::regex URL_REGEX{Strings::format(R"###(<url>([\s\S]*?)</url>)###")};
|
||||
|
||||
std::regex tool_regex{
|
||||
Strings::format(R"###(<tool[\s]+name="%s"[\s]+os="%s">([\s\S]*?)<\/tool>)###", tool, OS_STRING)};
|
||||
|
||||
std::smatch match_tool;
|
||||
bool has_match_tool = std::regex_search(XML.cbegin(), XML.cend(), match_tool, tool_regex);
|
||||
if (!has_match_tool && OS_STRING == "windows") // Legacy support. Change introduced in vcpkg v0.0.107.
|
||||
{
|
||||
tool_regex = Strings::format(R"###(<tool[\s]+name="%s">([\s\S]*?)<\/tool>)###", tool);
|
||||
has_match_tool = std::regex_search(XML.cbegin(), XML.cend(), match_tool, tool_regex);
|
||||
}
|
||||
Checks::check_exit(VCPKG_LINE_INFO,
|
||||
has_match_tool,
|
||||
"Could not find entry for tool [%s] in %s",
|
||||
tool,
|
||||
XML_PATH.generic_string());
|
||||
|
||||
const std::string tool_data_as_string = get_string_inside_tags(XML, tool_regex, tool);
|
||||
|
||||
const std::string required_version_as_string =
|
||||
get_string_inside_tags(tool_data_as_string, VERSION_REGEX, "requiredVersion");
|
||||
|
||||
const std::string url = get_string_inside_tags(tool_data_as_string, URL_REGEX, "url");
|
||||
|
||||
const std::string exe_relative_path =
|
||||
get_string_inside_tags(tool_data_as_string, EXE_RELATIVE_PATH_REGEX, "exeRelativePath");
|
||||
|
||||
auto archive_relative_path = maybe_get_string_inside_tags(tool_data_as_string, ARCHIVE_RELATIVE_PATH_REGEX);
|
||||
|
||||
const Optional<std::array<int, 3>> required_version = parse_version_string(required_version_as_string);
|
||||
Checks::check_exit(VCPKG_LINE_INFO,
|
||||
required_version.has_value(),
|
||||
"Could not parse version for tool %s. Version string was: %s",
|
||||
tool,
|
||||
required_version_as_string);
|
||||
|
||||
const std::string tool_dir_name = Strings::format("%s-%s-%s", tool, required_version_as_string, OS_STRING);
|
||||
const fs::path tool_dir_path = paths.downloads / "tools" / tool_dir_name;
|
||||
const fs::path exe_path = tool_dir_path / exe_relative_path;
|
||||
return ToolData{*required_version.get(),
|
||||
exe_path,
|
||||
url,
|
||||
paths.downloads / archive_relative_path.value_or(exe_relative_path),
|
||||
tool_dir_path};
|
||||
}
|
||||
|
||||
static bool exists_and_has_equal_or_greater_version(const std::string& version_cmd,
|
||||
const std::array<int, 3>& expected_version)
|
||||
{
|
||||
const auto rc = System::cmd_execute_and_capture_output(Strings::format(R"(%s)", version_cmd));
|
||||
if (rc.exit_code != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const Optional<std::array<int, 3>> v = parse_version_string(rc.output);
|
||||
if (!v.has_value())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::array<int, 3> actual_version = *v.get();
|
||||
return (actual_version[0] > expected_version[0] ||
|
||||
(actual_version[0] == expected_version[0] && actual_version[1] > expected_version[1]) ||
|
||||
(actual_version[0] == expected_version[0] && actual_version[1] == expected_version[1] &&
|
||||
actual_version[2] >= expected_version[2]));
|
||||
}
|
||||
|
||||
static Optional<fs::path> find_if_has_equal_or_greater_version(const std::vector<fs::path>& candidate_paths,
|
||||
const std::string& version_check_arguments,
|
||||
const std::array<int, 3>& expected_version)
|
||||
{
|
||||
auto it = Util::find_if(candidate_paths, [&](const fs::path& p) {
|
||||
const std::string cmd = Strings::format(R"("%s" %s)", p.u8string(), version_check_arguments);
|
||||
return exists_and_has_equal_or_greater_version(cmd, expected_version);
|
||||
});
|
||||
|
||||
if (it != candidate_paths.cend())
|
||||
{
|
||||
return std::move(*it);
|
||||
}
|
||||
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
static std::vector<std::string> keep_data_lines(const std::string& data_blob)
|
||||
{
|
||||
static const std::regex DATA_LINE_REGEX(R"(<sol>::(.+?)(?=::<eol>))");
|
||||
|
||||
std::vector<std::string> data_lines;
|
||||
|
||||
const std::sregex_iterator it(data_blob.cbegin(), data_blob.cend(), DATA_LINE_REGEX);
|
||||
const std::sregex_iterator end;
|
||||
for (std::sregex_iterator i = it; i != end; ++i)
|
||||
{
|
||||
const std::smatch match = *i;
|
||||
data_lines.push_back(match[1].str());
|
||||
}
|
||||
|
||||
return data_lines;
|
||||
}
|
||||
|
||||
static void extract_archive(const VcpkgPaths& paths, const fs::path& archive, const fs::path& to_path)
|
||||
{
|
||||
Files::Filesystem& fs = paths.get_filesystem();
|
||||
const fs::path to_path_partial = to_path.u8string() + ".partial";
|
||||
|
||||
std::error_code ec;
|
||||
fs.remove_all(to_path_partial, ec);
|
||||
fs.create_directories(to_path_partial, ec);
|
||||
|
||||
const auto ext = archive.extension();
|
||||
if (ext == ".gz" && ext.extension() != ".tar")
|
||||
{
|
||||
const auto code = System::cmd_execute(
|
||||
Strings::format(R"(cd '%s' && tar xzf '%s')", to_path_partial.u8string(), archive.u8string()));
|
||||
Checks::check_exit(VCPKG_LINE_INFO, code == 0, "tar failed while extracting %s", archive.u8string());
|
||||
}
|
||||
else if (ext == ".zip")
|
||||
{
|
||||
const auto code = System::cmd_execute(
|
||||
Strings::format(R"(cd '%s' && unzip -qqo '%s')", to_path_partial.u8string(), archive.u8string()));
|
||||
Checks::check_exit(VCPKG_LINE_INFO, code == 0, "unzip failed while extracting %s", archive.u8string());
|
||||
}
|
||||
else
|
||||
{
|
||||
Checks::exit_with_message(VCPKG_LINE_INFO, "Unexpected archive extension: %s", ext.u8string());
|
||||
}
|
||||
|
||||
fs.rename(to_path_partial, to_path);
|
||||
}
|
||||
|
||||
static fs::path fetch_tool(const VcpkgPaths& paths, const std::string& tool_name, const ToolData& tool_data)
|
||||
{
|
||||
const auto& fs = paths.get_filesystem();
|
||||
const fs::path& scripts_folder = paths.scripts;
|
||||
const std::array<int, 3>& version = tool_data.required_version;
|
||||
|
||||
const std::string version_as_string = Strings::format("%d.%d.%d", version[0], version[1], version[2]);
|
||||
System::println("A suitable version of %s was not found (required v%s). Downloading portable %s v%s...",
|
||||
tool_name,
|
||||
version_as_string,
|
||||
tool_name,
|
||||
version_as_string);
|
||||
#if defined(_WIN32)
|
||||
const fs::path script = scripts_folder / "fetchtool.ps1";
|
||||
const std::string title = Strings::format(
|
||||
"Fetching %s version %s (No sufficient installed version was found)", tool_name, version_as_string);
|
||||
const System::PowershellParameter tool_param("tool", tool_name);
|
||||
const std::string output = System::powershell_execute_and_capture_output(title, script, {tool_param});
|
||||
|
||||
const std::vector<std::string> tool_path = keep_data_lines(output);
|
||||
Checks::check_exit(VCPKG_LINE_INFO, tool_path.size() == 1, "Expected tool path, but got %s", output);
|
||||
|
||||
const fs::path actual_downloaded_path = Strings::trim(std::string{tool_path.at(0)});
|
||||
const fs::path& expected_downloaded_path = tool_data.exe_path;
|
||||
std::error_code ec;
|
||||
const auto eq = fs::stdfs::equivalent(expected_downloaded_path, actual_downloaded_path, ec);
|
||||
Checks::check_exit(VCPKG_LINE_INFO,
|
||||
eq && !ec,
|
||||
"Expected tool downloaded path to be %s, but was %s",
|
||||
expected_downloaded_path.u8string(),
|
||||
actual_downloaded_path.u8string());
|
||||
return actual_downloaded_path;
|
||||
#else
|
||||
if (!fs.exists(tool_data.downloaded_path))
|
||||
{
|
||||
auto code = System::cmd_execute(Strings::format(
|
||||
R"(curl -L '%s' --create-dirs --output '%s')", tool_data.url, tool_data.downloaded_path));
|
||||
Checks::check_exit(VCPKG_LINE_INFO, code == 0, "curl failed while downloading %s", tool_data.url);
|
||||
}
|
||||
|
||||
System::println("Extracting %s...", tool_name);
|
||||
extract_archive(paths, tool_data.downloaded_path, tool_data.tool_dir_path);
|
||||
System::println("Extracting %s... done.", tool_name);
|
||||
|
||||
Checks::check_exit(VCPKG_LINE_INFO,
|
||||
fs.exists(tool_data.exe_path),
|
||||
"Expected %s to exist after extracting",
|
||||
tool_data.exe_path);
|
||||
|
||||
return tool_data.exe_path;
|
||||
#endif
|
||||
}
|
||||
|
||||
static fs::path get_cmake_path(const VcpkgPaths& paths)
|
||||
{
|
||||
std::vector<fs::path> candidate_paths;
|
||||
#if defined(_WIN32) || defined(__APPLE__) || defined(__linux__)
|
||||
static const ToolData TOOL_DATA = parse_tool_data_from_xml(paths, "cmake");
|
||||
candidate_paths.push_back(TOOL_DATA.exe_path);
|
||||
#else
|
||||
static const ToolData TOOL_DATA = ToolData{{3, 5, 1}, ""};
|
||||
#endif
|
||||
static const std::string VERSION_CHECK_ARGUMENTS = "--version";
|
||||
|
||||
const std::vector<fs::path> from_path = Files::find_from_PATH("cmake");
|
||||
candidate_paths.insert(candidate_paths.end(), from_path.cbegin(), from_path.cend());
|
||||
|
||||
const auto& program_files = System::get_program_files_platform_bitness();
|
||||
if (const auto pf = program_files.get()) candidate_paths.push_back(*pf / "CMake" / "bin" / "cmake.exe");
|
||||
const auto& program_files_32_bit = System::get_program_files_32_bit();
|
||||
if (const auto pf = program_files_32_bit.get()) candidate_paths.push_back(*pf / "CMake" / "bin" / "cmake.exe");
|
||||
|
||||
const Optional<fs::path> path =
|
||||
find_if_has_equal_or_greater_version(candidate_paths, VERSION_CHECK_ARGUMENTS, TOOL_DATA.required_version);
|
||||
if (const auto p = path.get())
|
||||
{
|
||||
return *p;
|
||||
}
|
||||
|
||||
return fetch_tool(paths, "cmake", TOOL_DATA);
|
||||
}
|
||||
|
||||
static fs::path get_7za_path(const VcpkgPaths& paths)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
static const ToolData TOOL_DATA = parse_tool_data_from_xml(paths, "7zip");
|
||||
if (!paths.get_filesystem().exists(TOOL_DATA.exe_path))
|
||||
{
|
||||
return fetch_tool(paths, "7zip", TOOL_DATA);
|
||||
}
|
||||
return TOOL_DATA.exe_path;
|
||||
#else
|
||||
Checks::exit_with_message(VCPKG_LINE_INFO, "Cannot download 7zip for non-Windows platforms.");
|
||||
#endif
|
||||
}
|
||||
|
||||
static fs::path get_ninja_path(const VcpkgPaths& paths)
|
||||
{
|
||||
static const ToolData TOOL_DATA = parse_tool_data_from_xml(paths, "ninja");
|
||||
|
||||
std::vector<fs::path> candidate_paths;
|
||||
candidate_paths.push_back(TOOL_DATA.exe_path);
|
||||
const std::vector<fs::path> from_path = Files::find_from_PATH("ninja");
|
||||
candidate_paths.insert(candidate_paths.end(), from_path.cbegin(), from_path.cend());
|
||||
|
||||
auto path = find_if_has_equal_or_greater_version(candidate_paths, "--version", TOOL_DATA.required_version);
|
||||
if (const auto p = path.get())
|
||||
{
|
||||
return *p;
|
||||
}
|
||||
|
||||
return fetch_tool(paths, "ninja", TOOL_DATA);
|
||||
}
|
||||
|
||||
static fs::path get_nuget_path(const VcpkgPaths& paths)
|
||||
{
|
||||
static const ToolData TOOL_DATA = parse_tool_data_from_xml(paths, "nuget");
|
||||
|
||||
std::vector<fs::path> candidate_paths;
|
||||
candidate_paths.push_back(TOOL_DATA.exe_path);
|
||||
const std::vector<fs::path> from_path = Files::find_from_PATH("nuget");
|
||||
candidate_paths.insert(candidate_paths.end(), from_path.cbegin(), from_path.cend());
|
||||
|
||||
auto path = find_if_has_equal_or_greater_version(candidate_paths, "", TOOL_DATA.required_version);
|
||||
if (const auto p = path.get())
|
||||
{
|
||||
return *p;
|
||||
}
|
||||
|
||||
return fetch_tool(paths, "nuget", TOOL_DATA);
|
||||
}
|
||||
|
||||
static fs::path get_git_path(const VcpkgPaths& paths)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
static const ToolData TOOL_DATA = parse_tool_data_from_xml(paths, "git");
|
||||
#else
|
||||
static const ToolData TOOL_DATA = ToolData{{2, 7, 4}, ""};
|
||||
#endif
|
||||
static const std::string VERSION_CHECK_ARGUMENTS = "--version";
|
||||
|
||||
std::vector<fs::path> candidate_paths;
|
||||
#if defined(_WIN32)
|
||||
candidate_paths.push_back(TOOL_DATA.exe_path);
|
||||
#endif
|
||||
const std::vector<fs::path> from_path = Files::find_from_PATH("git");
|
||||
candidate_paths.insert(candidate_paths.end(), from_path.cbegin(), from_path.cend());
|
||||
|
||||
const auto& program_files = System::get_program_files_platform_bitness();
|
||||
if (const auto pf = program_files.get()) candidate_paths.push_back(*pf / "git" / "cmd" / "git.exe");
|
||||
const auto& program_files_32_bit = System::get_program_files_32_bit();
|
||||
if (const auto pf = program_files_32_bit.get()) candidate_paths.push_back(*pf / "git" / "cmd" / "git.exe");
|
||||
|
||||
const Optional<fs::path> path =
|
||||
find_if_has_equal_or_greater_version(candidate_paths, VERSION_CHECK_ARGUMENTS, TOOL_DATA.required_version);
|
||||
if (const auto p = path.get())
|
||||
{
|
||||
return *p;
|
||||
}
|
||||
|
||||
return fetch_tool(paths, "git", TOOL_DATA);
|
||||
}
|
||||
|
||||
static fs::path get_ifw_installerbase_path(const VcpkgPaths& paths)
|
||||
{
|
||||
static const ToolData TOOL_DATA = parse_tool_data_from_xml(paths, "installerbase");
|
||||
|
||||
static const std::string VERSION_CHECK_ARGUMENTS = "--framework-version";
|
||||
|
||||
std::vector<fs::path> candidate_paths;
|
||||
candidate_paths.push_back(TOOL_DATA.exe_path);
|
||||
// TODO: Uncomment later
|
||||
// const std::vector<fs::path> from_path = Files::find_from_PATH("installerbase");
|
||||
// candidate_paths.insert(candidate_paths.end(), from_path.cbegin(), from_path.cend());
|
||||
// candidate_paths.push_back(fs::path(System::get_environment_variable("HOMEDRIVE").value_or("C:")) / "Qt" /
|
||||
// "Tools" / "QtInstallerFramework" / "3.1" / "bin" / "installerbase.exe");
|
||||
// candidate_paths.push_back(fs::path(System::get_environment_variable("HOMEDRIVE").value_or("C:")) / "Qt" /
|
||||
// "QtIFW-3.1.0" / "bin" / "installerbase.exe");
|
||||
|
||||
const Optional<fs::path> path =
|
||||
find_if_has_equal_or_greater_version(candidate_paths, VERSION_CHECK_ARGUMENTS, TOOL_DATA.required_version);
|
||||
if (const auto p = path.get())
|
||||
{
|
||||
return *p;
|
||||
}
|
||||
|
||||
return fetch_tool(paths, "installerbase", TOOL_DATA);
|
||||
}
|
||||
|
||||
struct VisualStudioInstance
|
||||
{
|
||||
fs::path root_path;
|
||||
std::string version;
|
||||
std::string release_type;
|
||||
std::string preference_weight; // Mostly unused, just for verification that order is as intended
|
||||
|
||||
std::string major_version() const { return version.substr(0, 2); }
|
||||
};
|
||||
|
||||
static std::vector<VisualStudioInstance> get_visual_studio_instances(const VcpkgPaths& paths)
|
||||
{
|
||||
const fs::path script = paths.scripts / "findVisualStudioInstallationInstances.ps1";
|
||||
const std::string output =
|
||||
System::powershell_execute_and_capture_output("Detecting Visual Studio instances", script);
|
||||
|
||||
const std::vector<std::string> instances_as_strings = keep_data_lines(output);
|
||||
Checks::check_exit(VCPKG_LINE_INFO,
|
||||
!instances_as_strings.empty(),
|
||||
"Could not detect any Visual Studio instances.\n"
|
||||
"Powershell script:\n"
|
||||
" %s\n"
|
||||
"returned:\n"
|
||||
"%s",
|
||||
script.generic_string(),
|
||||
output);
|
||||
|
||||
std::vector<VisualStudioInstance> instances;
|
||||
for (const std::string& instance_as_string : instances_as_strings)
|
||||
{
|
||||
const std::vector<std::string> split = Strings::split(instance_as_string, "::");
|
||||
Checks::check_exit(VCPKG_LINE_INFO,
|
||||
split.size() == 4,
|
||||
"Invalid Visual Studio instance format.\n"
|
||||
"Expected: PreferenceWeight::ReleaseType::Version::PathToVisualStudio\n"
|
||||
"Actual : %s\n",
|
||||
instance_as_string);
|
||||
instances.push_back({split.at(3), split.at(2), split.at(1), split.at(0)});
|
||||
}
|
||||
|
||||
return instances;
|
||||
}
|
||||
|
||||
std::vector<Toolset> find_toolset_instances(const VcpkgPaths& paths)
|
||||
{
|
||||
using CPU = System::CPUArchitecture;
|
||||
|
||||
const auto& fs = paths.get_filesystem();
|
||||
|
||||
// Note: this will contain a mix of vcvarsall.bat locations and dumpbin.exe locations.
|
||||
std::vector<fs::path> paths_examined;
|
||||
|
||||
std::vector<Toolset> found_toolsets;
|
||||
std::vector<Toolset> excluded_toolsets;
|
||||
|
||||
const std::vector<VisualStudioInstance> vs_instances = get_visual_studio_instances(paths);
|
||||
const bool v140_is_available = Util::find_if(vs_instances, [&](const VisualStudioInstance& vs_instance) {
|
||||
return vs_instance.major_version() == "14";
|
||||
}) != vs_instances.cend();
|
||||
|
||||
for (const VisualStudioInstance& vs_instance : vs_instances)
|
||||
{
|
||||
const std::string major_version = vs_instance.major_version();
|
||||
if (major_version == "15")
|
||||
{
|
||||
const fs::path vc_dir = vs_instance.root_path / "VC";
|
||||
|
||||
// Skip any instances that do not have vcvarsall.
|
||||
const fs::path vcvarsall_dir = vc_dir / "Auxiliary" / "Build";
|
||||
const fs::path vcvarsall_bat = vcvarsall_dir / "vcvarsall.bat";
|
||||
paths_examined.push_back(vcvarsall_bat);
|
||||
if (!fs.exists(vcvarsall_bat)) continue;
|
||||
|
||||
// Get all supported architectures
|
||||
std::vector<ToolsetArchOption> supported_architectures;
|
||||
if (fs.exists(vcvarsall_dir / "vcvars32.bat"))
|
||||
supported_architectures.push_back({"x86", CPU::X86, CPU::X86});
|
||||
if (fs.exists(vcvarsall_dir / "vcvars64.bat"))
|
||||
supported_architectures.push_back({"amd64", CPU::X64, CPU::X64});
|
||||
if (fs.exists(vcvarsall_dir / "vcvarsx86_amd64.bat"))
|
||||
supported_architectures.push_back({"x86_amd64", CPU::X86, CPU::X64});
|
||||
if (fs.exists(vcvarsall_dir / "vcvarsx86_arm.bat"))
|
||||
supported_architectures.push_back({"x86_arm", CPU::X86, CPU::ARM});
|
||||
if (fs.exists(vcvarsall_dir / "vcvarsx86_arm64.bat"))
|
||||
supported_architectures.push_back({"x86_arm64", CPU::X86, CPU::ARM64});
|
||||
if (fs.exists(vcvarsall_dir / "vcvarsamd64_x86.bat"))
|
||||
supported_architectures.push_back({"amd64_x86", CPU::X64, CPU::X86});
|
||||
if (fs.exists(vcvarsall_dir / "vcvarsamd64_arm.bat"))
|
||||
supported_architectures.push_back({"amd64_arm", CPU::X64, CPU::ARM});
|
||||
if (fs.exists(vcvarsall_dir / "vcvarsamd64_arm64.bat"))
|
||||
supported_architectures.push_back({"amd64_arm64", CPU::X64, CPU::ARM64});
|
||||
|
||||
// Locate the "best" MSVC toolchain version
|
||||
const fs::path msvc_path = vc_dir / "Tools" / "MSVC";
|
||||
std::vector<fs::path> msvc_subdirectories = fs.get_files_non_recursive(msvc_path);
|
||||
Util::unstable_keep_if(msvc_subdirectories,
|
||||
[&fs](const fs::path& path) { return fs.is_directory(path); });
|
||||
|
||||
// Sort them so that latest comes first
|
||||
std::sort(
|
||||
msvc_subdirectories.begin(),
|
||||
msvc_subdirectories.end(),
|
||||
[](const fs::path& left, const fs::path& right) { return left.filename() > right.filename(); });
|
||||
|
||||
for (const fs::path& subdir : msvc_subdirectories)
|
||||
{
|
||||
const fs::path dumpbin_path = subdir / "bin" / "HostX86" / "x86" / "dumpbin.exe";
|
||||
paths_examined.push_back(dumpbin_path);
|
||||
if (fs.exists(dumpbin_path))
|
||||
{
|
||||
const Toolset v141toolset = Toolset{
|
||||
vs_instance.root_path, dumpbin_path, vcvarsall_bat, {}, V_141, supported_architectures};
|
||||
|
||||
auto english_language_pack = dumpbin_path.parent_path() / "1033";
|
||||
|
||||
if (!fs.exists(english_language_pack))
|
||||
{
|
||||
excluded_toolsets.push_back(v141toolset);
|
||||
break;
|
||||
}
|
||||
|
||||
found_toolsets.push_back(v141toolset);
|
||||
|
||||
if (v140_is_available)
|
||||
{
|
||||
const Toolset v140toolset = Toolset{vs_instance.root_path,
|
||||
dumpbin_path,
|
||||
vcvarsall_bat,
|
||||
{"-vcvars_ver=14.0"},
|
||||
V_140,
|
||||
supported_architectures};
|
||||
found_toolsets.push_back(v140toolset);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (major_version == "14" || major_version == "12")
|
||||
{
|
||||
const fs::path vcvarsall_bat = vs_instance.root_path / "VC" / "vcvarsall.bat";
|
||||
|
||||
paths_examined.push_back(vcvarsall_bat);
|
||||
if (fs.exists(vcvarsall_bat))
|
||||
{
|
||||
const fs::path vs_dumpbin_exe = vs_instance.root_path / "VC" / "bin" / "dumpbin.exe";
|
||||
paths_examined.push_back(vs_dumpbin_exe);
|
||||
|
||||
const fs::path vs_bin_dir = vcvarsall_bat.parent_path() / "bin";
|
||||
std::vector<ToolsetArchOption> supported_architectures;
|
||||
if (fs.exists(vs_bin_dir / "vcvars32.bat"))
|
||||
supported_architectures.push_back({"x86", CPU::X86, CPU::X86});
|
||||
if (fs.exists(vs_bin_dir / "amd64\\vcvars64.bat"))
|
||||
supported_architectures.push_back({"x64", CPU::X64, CPU::X64});
|
||||
if (fs.exists(vs_bin_dir / "x86_amd64\\vcvarsx86_amd64.bat"))
|
||||
supported_architectures.push_back({"x86_amd64", CPU::X86, CPU::X64});
|
||||
if (fs.exists(vs_bin_dir / "x86_arm\\vcvarsx86_arm.bat"))
|
||||
supported_architectures.push_back({"x86_arm", CPU::X86, CPU::ARM});
|
||||
if (fs.exists(vs_bin_dir / "amd64_x86\\vcvarsamd64_x86.bat"))
|
||||
supported_architectures.push_back({"amd64_x86", CPU::X64, CPU::X86});
|
||||
if (fs.exists(vs_bin_dir / "amd64_arm\\vcvarsamd64_arm.bat"))
|
||||
supported_architectures.push_back({"amd64_arm", CPU::X64, CPU::ARM});
|
||||
|
||||
if (fs.exists(vs_dumpbin_exe))
|
||||
{
|
||||
const Toolset toolset = {vs_instance.root_path,
|
||||
vs_dumpbin_exe,
|
||||
vcvarsall_bat,
|
||||
{},
|
||||
major_version == "14" ? V_140 : V_120,
|
||||
supported_architectures};
|
||||
|
||||
auto english_language_pack = vs_dumpbin_exe.parent_path() / "1033";
|
||||
|
||||
if (!fs.exists(english_language_pack))
|
||||
{
|
||||
excluded_toolsets.push_back(toolset);
|
||||
break;
|
||||
}
|
||||
|
||||
found_toolsets.push_back(toolset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!excluded_toolsets.empty())
|
||||
{
|
||||
System::println(
|
||||
System::Color::warning,
|
||||
"Warning: The following VS instances are excluded because the English language pack is unavailable.");
|
||||
for (const Toolset& toolset : excluded_toolsets)
|
||||
{
|
||||
System::println(" %s", toolset.visual_studio_root_path.u8string());
|
||||
}
|
||||
System::println(System::Color::warning, "Please install the English language pack.");
|
||||
}
|
||||
|
||||
if (found_toolsets.empty())
|
||||
{
|
||||
System::println(System::Color::error, "Could not locate a complete toolset.");
|
||||
System::println("The following paths were examined:");
|
||||
for (const fs::path& path : paths_examined)
|
||||
{
|
||||
System::println(" %s", path.u8string());
|
||||
}
|
||||
Checks::exit_fail(VCPKG_LINE_INFO);
|
||||
}
|
||||
|
||||
return found_toolsets;
|
||||
}
|
||||
|
||||
fs::path get_tool_path(const VcpkgPaths& paths, const std::string& tool)
|
||||
{
|
||||
// First deal with specially handled tools.
|
||||
// For these we may look in locations like Program Files, the PATH etc as well as the auto-downloaded location.
|
||||
if (tool == Tools::SEVEN_ZIP) return get_7za_path(paths);
|
||||
if (tool == Tools::CMAKE) return get_cmake_path(paths);
|
||||
if (tool == Tools::GIT) return get_git_path(paths);
|
||||
if (tool == Tools::NINJA) return get_ninja_path(paths);
|
||||
if (tool == Tools::NUGET) return get_nuget_path(paths);
|
||||
if (tool == Tools::IFW_INSTALLER_BASE) return get_ifw_installerbase_path(paths);
|
||||
if (tool == Tools::IFW_BINARYCREATOR)
|
||||
return get_ifw_installerbase_path(paths).parent_path() / "binarycreator.exe";
|
||||
if (tool == Tools::IFW_REPOGEN) return get_ifw_installerbase_path(paths).parent_path() / "repogen.exe";
|
||||
|
||||
// For other tools, we simply always auto-download them.
|
||||
const ToolData tool_data = parse_tool_data_from_xml(paths, tool);
|
||||
if (paths.get_filesystem().exists(tool_data.exe_path))
|
||||
{
|
||||
return tool_data.exe_path;
|
||||
}
|
||||
return fetch_tool(paths, tool, tool_data);
|
||||
}
|
||||
|
||||
const CommandStructure COMMAND_STRUCTURE = {
|
||||
Strings::format("The argument should be tool name\n%s", Help::create_example_string("fetch cmake")),
|
||||
1,
|
||||
1,
|
||||
{},
|
||||
nullptr,
|
||||
};
|
||||
|
||||
void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths)
|
||||
{
|
||||
Util::unused(args.parse_arguments(COMMAND_STRUCTURE));
|
||||
|
||||
const std::string tool = args.command_arguments[0];
|
||||
const fs::path tool_path = get_tool_path(paths, tool);
|
||||
System::println(tool_path.u8string());
|
||||
Checks::exit_success(VCPKG_LINE_INFO);
|
||||
}
|
||||
}
|
@ -276,7 +276,7 @@ CMake projects should use: "-DCMAKE_TOOLCHAIN_FILE=%s")",
|
||||
{
|
||||
auto& fs = paths.get_filesystem();
|
||||
|
||||
const fs::path& nuget_exe = paths.get_nuget_exe();
|
||||
const fs::path& nuget_exe = paths.get_tool_exe(Tools::NUGET);
|
||||
|
||||
const fs::path& buildsystems_dir = paths.buildsystems;
|
||||
const fs::path tmp_dir = buildsystems_dir / "tmp";
|
||||
|
@ -79,7 +79,7 @@ namespace vcpkg::Commands::PortsDiff
|
||||
{
|
||||
std::error_code ec;
|
||||
auto& fs = paths.get_filesystem();
|
||||
const fs::path& git_exe = paths.get_git_exe();
|
||||
const fs::path& git_exe = paths.get_tool_exe(Tools::GIT);
|
||||
const fs::path dot_git_dir = paths.root / ".git";
|
||||
const std::string ports_dir_name_as_string = paths.ports.filename().u8string();
|
||||
const fs::path temp_checkout_path =
|
||||
@ -130,7 +130,7 @@ namespace vcpkg::Commands::PortsDiff
|
||||
{
|
||||
args.parse_arguments(COMMAND_STRUCTURE);
|
||||
|
||||
const fs::path& git_exe = paths.get_git_exe();
|
||||
const fs::path& git_exe = paths.get_tool_exe(Tools::GIT);
|
||||
|
||||
const std::string git_commit_id_for_previous_snapshot = args.command_arguments.at(0);
|
||||
const std::string git_commit_id_for_current_snapshot =
|
||||
|
@ -123,7 +123,7 @@ namespace vcpkg::Export
|
||||
const fs::path& output_dir)
|
||||
{
|
||||
Files::Filesystem& fs = paths.get_filesystem();
|
||||
const fs::path& nuget_exe = paths.get_nuget_exe();
|
||||
const fs::path& nuget_exe = paths.get_tool_exe(Tools::NUGET);
|
||||
|
||||
// This file will be placed in "build\native" in the nuget package. Therefore, go up two dirs.
|
||||
const std::string targets_redirect_content =
|
||||
@ -189,7 +189,7 @@ namespace vcpkg::Export
|
||||
const fs::path& output_dir,
|
||||
const ArchiveFormat& format)
|
||||
{
|
||||
const fs::path& cmake_exe = paths.get_cmake_exe();
|
||||
const fs::path& cmake_exe = paths.get_tool_exe(Tools::CMAKE);
|
||||
|
||||
const std::string exported_dir_filename = raw_exported_dir.filename().u8string();
|
||||
const std::string exported_archive_filename =
|
||||
|
@ -5,401 +5,13 @@
|
||||
#include <vcpkg/base/system.h>
|
||||
#include <vcpkg/base/util.h>
|
||||
#include <vcpkg/build.h>
|
||||
#include <vcpkg/commands.h>
|
||||
#include <vcpkg/metrics.h>
|
||||
#include <vcpkg/packagespec.h>
|
||||
#include <vcpkg/vcpkgpaths.h>
|
||||
|
||||
namespace vcpkg
|
||||
{
|
||||
static constexpr CStringView V_120 = "v120";
|
||||
static constexpr CStringView V_140 = "v140";
|
||||
static constexpr CStringView V_141 = "v141";
|
||||
|
||||
struct ToolData
|
||||
{
|
||||
std::array<int, 3> required_version;
|
||||
fs::path exe_path;
|
||||
std::string url;
|
||||
fs::path downloaded_path;
|
||||
fs::path tool_dir_path;
|
||||
};
|
||||
|
||||
static Optional<std::array<int, 3>> parse_version_string(const std::string& version_as_string)
|
||||
{
|
||||
static const std::regex RE(R"###((\d+)\.(\d+)\.(\d+))###");
|
||||
|
||||
std::match_results<std::string::const_iterator> match;
|
||||
const auto found = std::regex_search(version_as_string, match, RE);
|
||||
if (!found)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
const int d1 = atoi(match[1].str().c_str());
|
||||
const int d2 = atoi(match[2].str().c_str());
|
||||
const int d3 = atoi(match[3].str().c_str());
|
||||
const std::array<int, 3> result = {d1, d2, d3};
|
||||
return result;
|
||||
}
|
||||
|
||||
static ToolData parse_tool_data_from_xml(const VcpkgPaths& paths, const std::string& tool)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
static constexpr StringLiteral OS_STRING = "windows";
|
||||
#elif defined(__APPLE__)
|
||||
static constexpr StringLiteral OS_STRING = "osx";
|
||||
#else // assume linux
|
||||
static constexpr StringLiteral OS_STRING = "linux";
|
||||
#endif
|
||||
|
||||
static const fs::path XML_PATH = paths.scripts / "vcpkgTools.xml";
|
||||
|
||||
const auto maybe_get_string_inside_tags = [](const std::string& input,
|
||||
const std::regex& regex) -> Optional<std::string> {
|
||||
std::smatch match;
|
||||
const bool has_match = std::regex_search(input.cbegin(), input.cend(), match, regex);
|
||||
if (!has_match) return nullopt;
|
||||
return match[1];
|
||||
};
|
||||
|
||||
const auto get_string_inside_tags =
|
||||
[](const std::string& input, const std::regex& regex, const std::string& tag_name) -> std::string {
|
||||
std::smatch match;
|
||||
const bool has_match = std::regex_search(input.cbegin(), input.cend(), match, regex);
|
||||
Checks::check_exit(
|
||||
VCPKG_LINE_INFO, has_match, "Could not find tag <%s> in %s", tag_name, XML_PATH.generic_string());
|
||||
|
||||
return match[1];
|
||||
};
|
||||
|
||||
static const std::string XML = paths.get_filesystem().read_contents(XML_PATH).value_or_exit(VCPKG_LINE_INFO);
|
||||
static const std::regex VERSION_REGEX{R"###(<requiredVersion>([\s\S]*?)</requiredVersion>)###"};
|
||||
static const std::regex EXE_RELATIVE_PATH_REGEX{
|
||||
Strings::format(R"###(<exeRelativePath>([\s\S]*?)</exeRelativePath>)###")};
|
||||
static const std::regex ARCHIVE_RELATIVE_PATH_REGEX{
|
||||
Strings::format(R"###(<archiveRelativePath>([\s\S]*?)</archiveRelativePath>)###")};
|
||||
static const std::regex URL_REGEX{Strings::format(R"###(<url>([\s\S]*?)</url>)###")};
|
||||
|
||||
std::regex tool_regex{
|
||||
Strings::format(R"###(<tool[\s]+name="%s"[\s]+os="%s">([\s\S]*?)<\/tool>)###", tool, OS_STRING)};
|
||||
|
||||
std::smatch match_tool;
|
||||
bool has_match_tool = std::regex_search(XML.cbegin(), XML.cend(), match_tool, tool_regex);
|
||||
if (!has_match_tool && OS_STRING == "windows") // Legacy support. Change introduced in vcpkg v0.0.107.
|
||||
{
|
||||
tool_regex = Strings::format(R"###(<tool[\s]+name="%s">([\s\S]*?)<\/tool>)###", tool);
|
||||
has_match_tool = std::regex_search(XML.cbegin(), XML.cend(), match_tool, tool_regex);
|
||||
}
|
||||
Checks::check_exit(VCPKG_LINE_INFO,
|
||||
has_match_tool,
|
||||
"Could not find entry for tool [%s] in %s",
|
||||
tool,
|
||||
XML_PATH.generic_string());
|
||||
|
||||
const std::string tool_data_as_string = get_string_inside_tags(XML, tool_regex, tool);
|
||||
|
||||
const std::string required_version_as_string =
|
||||
get_string_inside_tags(tool_data_as_string, VERSION_REGEX, "requiredVersion");
|
||||
|
||||
const std::string url = get_string_inside_tags(tool_data_as_string, URL_REGEX, "url");
|
||||
|
||||
const std::string exe_relative_path =
|
||||
get_string_inside_tags(tool_data_as_string, EXE_RELATIVE_PATH_REGEX, "exeRelativePath");
|
||||
|
||||
auto archive_relative_path = maybe_get_string_inside_tags(tool_data_as_string, ARCHIVE_RELATIVE_PATH_REGEX);
|
||||
|
||||
const Optional<std::array<int, 3>> required_version = parse_version_string(required_version_as_string);
|
||||
Checks::check_exit(VCPKG_LINE_INFO,
|
||||
required_version.has_value(),
|
||||
"Could not parse version for tool %s. Version string was: %s",
|
||||
tool,
|
||||
required_version_as_string);
|
||||
|
||||
const std::string tool_dir_name = Strings::format("%s-%s-%s", tool, required_version_as_string, OS_STRING);
|
||||
const fs::path tool_dir_path = paths.downloads / "tools" / tool_dir_name;
|
||||
const fs::path exe_path = tool_dir_path / exe_relative_path;
|
||||
return ToolData{*required_version.get(),
|
||||
exe_path,
|
||||
url,
|
||||
paths.downloads / archive_relative_path.value_or(exe_relative_path),
|
||||
tool_dir_path};
|
||||
}
|
||||
|
||||
static bool exists_and_has_equal_or_greater_version(const std::string& version_cmd,
|
||||
const std::array<int, 3>& expected_version)
|
||||
{
|
||||
const auto rc = System::cmd_execute_and_capture_output(Strings::format(R"(%s)", version_cmd));
|
||||
if (rc.exit_code != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const Optional<std::array<int, 3>> v = parse_version_string(rc.output);
|
||||
if (!v.has_value())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::array<int, 3> actual_version = *v.get();
|
||||
return (actual_version[0] > expected_version[0] ||
|
||||
(actual_version[0] == expected_version[0] && actual_version[1] > expected_version[1]) ||
|
||||
(actual_version[0] == expected_version[0] && actual_version[1] == expected_version[1] &&
|
||||
actual_version[2] >= expected_version[2]));
|
||||
}
|
||||
|
||||
static Optional<fs::path> find_if_has_equal_or_greater_version(const std::vector<fs::path>& candidate_paths,
|
||||
const std::string& version_check_arguments,
|
||||
const std::array<int, 3>& expected_version)
|
||||
{
|
||||
auto it = Util::find_if(candidate_paths, [&](const fs::path& p) {
|
||||
const std::string cmd = Strings::format(R"("%s" %s)", p.u8string(), version_check_arguments);
|
||||
return exists_and_has_equal_or_greater_version(cmd, expected_version);
|
||||
});
|
||||
|
||||
if (it != candidate_paths.cend())
|
||||
{
|
||||
return std::move(*it);
|
||||
}
|
||||
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
static std::vector<std::string> keep_data_lines(const std::string& data_blob)
|
||||
{
|
||||
static const std::regex DATA_LINE_REGEX(R"(<sol>::(.+?)(?=::<eol>))");
|
||||
|
||||
std::vector<std::string> data_lines;
|
||||
|
||||
const std::sregex_iterator it(data_blob.cbegin(), data_blob.cend(), DATA_LINE_REGEX);
|
||||
const std::sregex_iterator end;
|
||||
for (std::sregex_iterator i = it; i != end; ++i)
|
||||
{
|
||||
const std::smatch match = *i;
|
||||
data_lines.push_back(match[1].str());
|
||||
}
|
||||
|
||||
return data_lines;
|
||||
}
|
||||
|
||||
static void extract_archive(const VcpkgPaths& paths, const fs::path& archive, const fs::path& to_path)
|
||||
{
|
||||
Files::Filesystem& fs = paths.get_filesystem();
|
||||
const fs::path to_path_partial = to_path.u8string() + ".partial";
|
||||
|
||||
std::error_code ec;
|
||||
fs.remove_all(to_path_partial, ec);
|
||||
fs.create_directories(to_path_partial, ec);
|
||||
|
||||
const auto ext = archive.extension();
|
||||
if (ext == ".gz" && ext.extension() != ".tar")
|
||||
{
|
||||
const auto code = System::cmd_execute(
|
||||
Strings::format(R"(cd '%s' && tar xzf '%s')", to_path_partial.u8string(), archive.u8string()));
|
||||
Checks::check_exit(VCPKG_LINE_INFO, code == 0, "tar failed while extracting %s", archive.u8string());
|
||||
}
|
||||
else if (ext == ".zip")
|
||||
{
|
||||
const auto code = System::cmd_execute(
|
||||
Strings::format(R"(cd '%s' && unzip -qqo '%s')", to_path_partial.u8string(), archive.u8string()));
|
||||
Checks::check_exit(VCPKG_LINE_INFO, code == 0, "unzip failed while extracting %s", archive.u8string());
|
||||
}
|
||||
else
|
||||
{
|
||||
Checks::exit_with_message(VCPKG_LINE_INFO, "Unexpected archive extension: %s", ext.u8string());
|
||||
}
|
||||
|
||||
fs.rename(to_path_partial, to_path);
|
||||
}
|
||||
|
||||
static fs::path fetch_tool(const VcpkgPaths& paths, const std::string& tool_name, const ToolData& tool_data)
|
||||
{
|
||||
const auto& fs = paths.get_filesystem();
|
||||
const fs::path& scripts_folder = paths.scripts;
|
||||
const std::array<int, 3>& version = tool_data.required_version;
|
||||
|
||||
const std::string version_as_string = Strings::format("%d.%d.%d", version[0], version[1], version[2]);
|
||||
System::println("A suitable version of %s was not found (required v%s). Downloading portable %s v%s...",
|
||||
tool_name,
|
||||
version_as_string,
|
||||
tool_name,
|
||||
version_as_string);
|
||||
#if defined(_WIN32)
|
||||
const fs::path script = scripts_folder / "fetchtool.ps1";
|
||||
const std::string title = Strings::format(
|
||||
"Fetching %s version %s (No sufficient installed version was found)", tool_name, version_as_string);
|
||||
const System::PowershellParameter tool_param("tool", tool_name);
|
||||
const std::string output = System::powershell_execute_and_capture_output(title, script, {tool_param});
|
||||
|
||||
const std::vector<std::string> tool_path = keep_data_lines(output);
|
||||
Checks::check_exit(VCPKG_LINE_INFO, tool_path.size() == 1, "Expected tool path, but got %s", output);
|
||||
|
||||
const fs::path actual_downloaded_path = Strings::trim(std::string{tool_path.at(0)});
|
||||
const fs::path& expected_downloaded_path = tool_data.exe_path;
|
||||
std::error_code ec;
|
||||
const auto eq = fs::stdfs::equivalent(expected_downloaded_path, actual_downloaded_path, ec);
|
||||
Checks::check_exit(VCPKG_LINE_INFO,
|
||||
eq && !ec,
|
||||
"Expected tool downloaded path to be %s, but was %s",
|
||||
expected_downloaded_path.u8string(),
|
||||
actual_downloaded_path.u8string());
|
||||
return actual_downloaded_path;
|
||||
#else
|
||||
if (!fs.exists(tool_data.downloaded_path))
|
||||
{
|
||||
auto code = System::cmd_execute(Strings::format(
|
||||
R"(curl -L '%s' --create-dirs --output '%s')", tool_data.url, tool_data.downloaded_path));
|
||||
Checks::check_exit(VCPKG_LINE_INFO, code == 0, "curl failed while downloading %s", tool_data.url);
|
||||
}
|
||||
|
||||
System::println("Extracting %s...", tool_name);
|
||||
extract_archive(paths, tool_data.downloaded_path, tool_data.tool_dir_path);
|
||||
System::println("Extracting %s... done.", tool_name);
|
||||
|
||||
Checks::check_exit(VCPKG_LINE_INFO,
|
||||
fs.exists(tool_data.exe_path),
|
||||
"Expected %s to exist after extracting",
|
||||
tool_data.exe_path);
|
||||
|
||||
return tool_data.exe_path;
|
||||
#endif
|
||||
}
|
||||
|
||||
static fs::path get_cmake_path(const VcpkgPaths& paths)
|
||||
{
|
||||
std::vector<fs::path> candidate_paths;
|
||||
#if defined(_WIN32) || defined(__APPLE__) || defined(__linux__)
|
||||
static const ToolData TOOL_DATA = parse_tool_data_from_xml(paths, "cmake");
|
||||
candidate_paths.push_back(TOOL_DATA.exe_path);
|
||||
#else
|
||||
static const ToolData TOOL_DATA = ToolData{{3, 5, 1}, ""};
|
||||
#endif
|
||||
static const std::string VERSION_CHECK_ARGUMENTS = "--version";
|
||||
|
||||
const std::vector<fs::path> from_path = Files::find_from_PATH("cmake");
|
||||
candidate_paths.insert(candidate_paths.end(), from_path.cbegin(), from_path.cend());
|
||||
|
||||
const auto& program_files = System::get_program_files_platform_bitness();
|
||||
if (const auto pf = program_files.get()) candidate_paths.push_back(*pf / "CMake" / "bin" / "cmake.exe");
|
||||
const auto& program_files_32_bit = System::get_program_files_32_bit();
|
||||
if (const auto pf = program_files_32_bit.get()) candidate_paths.push_back(*pf / "CMake" / "bin" / "cmake.exe");
|
||||
|
||||
const Optional<fs::path> path =
|
||||
find_if_has_equal_or_greater_version(candidate_paths, VERSION_CHECK_ARGUMENTS, TOOL_DATA.required_version);
|
||||
if (const auto p = path.get())
|
||||
{
|
||||
return *p;
|
||||
}
|
||||
|
||||
return fetch_tool(paths, "cmake", TOOL_DATA);
|
||||
}
|
||||
|
||||
static fs::path get_7za_path(const VcpkgPaths& paths)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
static const ToolData TOOL_DATA = parse_tool_data_from_xml(paths, "7zip");
|
||||
if (!paths.get_filesystem().exists(TOOL_DATA.exe_path))
|
||||
{
|
||||
return fetch_tool(paths, "7zip", TOOL_DATA);
|
||||
}
|
||||
return TOOL_DATA.exe_path;
|
||||
#else
|
||||
Checks::exit_with_message(VCPKG_LINE_INFO, "Cannot download 7zip for non-Windows platforms.");
|
||||
#endif
|
||||
}
|
||||
|
||||
static fs::path get_ninja_path(const VcpkgPaths& paths)
|
||||
{
|
||||
static const ToolData TOOL_DATA = parse_tool_data_from_xml(paths, "ninja");
|
||||
|
||||
std::vector<fs::path> candidate_paths;
|
||||
candidate_paths.push_back(TOOL_DATA.exe_path);
|
||||
const std::vector<fs::path> from_path = Files::find_from_PATH("ninja");
|
||||
candidate_paths.insert(candidate_paths.end(), from_path.cbegin(), from_path.cend());
|
||||
|
||||
auto path = find_if_has_equal_or_greater_version(candidate_paths, "--version", TOOL_DATA.required_version);
|
||||
if (const auto p = path.get())
|
||||
{
|
||||
return *p;
|
||||
}
|
||||
|
||||
return fetch_tool(paths, "ninja", TOOL_DATA);
|
||||
}
|
||||
|
||||
static fs::path get_nuget_path(const VcpkgPaths& paths)
|
||||
{
|
||||
static const ToolData TOOL_DATA = parse_tool_data_from_xml(paths, "nuget");
|
||||
|
||||
std::vector<fs::path> candidate_paths;
|
||||
candidate_paths.push_back(TOOL_DATA.exe_path);
|
||||
const std::vector<fs::path> from_path = Files::find_from_PATH("nuget");
|
||||
candidate_paths.insert(candidate_paths.end(), from_path.cbegin(), from_path.cend());
|
||||
|
||||
auto path = find_if_has_equal_or_greater_version(candidate_paths, "", TOOL_DATA.required_version);
|
||||
if (const auto p = path.get())
|
||||
{
|
||||
return *p;
|
||||
}
|
||||
|
||||
return fetch_tool(paths, "nuget", TOOL_DATA);
|
||||
}
|
||||
|
||||
static fs::path get_git_path(const VcpkgPaths& paths)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
static const ToolData TOOL_DATA = parse_tool_data_from_xml(paths, "git");
|
||||
#else
|
||||
static const ToolData TOOL_DATA = ToolData{{2, 7, 4}, ""};
|
||||
#endif
|
||||
static const std::string VERSION_CHECK_ARGUMENTS = "--version";
|
||||
|
||||
std::vector<fs::path> candidate_paths;
|
||||
#if defined(_WIN32)
|
||||
candidate_paths.push_back(TOOL_DATA.exe_path);
|
||||
#endif
|
||||
const std::vector<fs::path> from_path = Files::find_from_PATH("git");
|
||||
candidate_paths.insert(candidate_paths.end(), from_path.cbegin(), from_path.cend());
|
||||
|
||||
const auto& program_files = System::get_program_files_platform_bitness();
|
||||
if (const auto pf = program_files.get()) candidate_paths.push_back(*pf / "git" / "cmd" / "git.exe");
|
||||
const auto& program_files_32_bit = System::get_program_files_32_bit();
|
||||
if (const auto pf = program_files_32_bit.get()) candidate_paths.push_back(*pf / "git" / "cmd" / "git.exe");
|
||||
|
||||
const Optional<fs::path> path =
|
||||
find_if_has_equal_or_greater_version(candidate_paths, VERSION_CHECK_ARGUMENTS, TOOL_DATA.required_version);
|
||||
if (const auto p = path.get())
|
||||
{
|
||||
return *p;
|
||||
}
|
||||
|
||||
return fetch_tool(paths, "git", TOOL_DATA);
|
||||
}
|
||||
|
||||
static fs::path get_ifw_installerbase_path(const VcpkgPaths& paths)
|
||||
{
|
||||
static const ToolData TOOL_DATA = parse_tool_data_from_xml(paths, "installerbase");
|
||||
|
||||
static const std::string VERSION_CHECK_ARGUMENTS = "--framework-version";
|
||||
|
||||
std::vector<fs::path> candidate_paths;
|
||||
candidate_paths.push_back(TOOL_DATA.exe_path);
|
||||
// TODO: Uncomment later
|
||||
// const std::vector<fs::path> from_path = Files::find_from_PATH("installerbase");
|
||||
// candidate_paths.insert(candidate_paths.end(), from_path.cbegin(), from_path.cend());
|
||||
// candidate_paths.push_back(fs::path(System::get_environment_variable("HOMEDRIVE").value_or("C:")) / "Qt" /
|
||||
// "Tools" / "QtInstallerFramework" / "3.1" / "bin" / "installerbase.exe");
|
||||
// candidate_paths.push_back(fs::path(System::get_environment_variable("HOMEDRIVE").value_or("C:")) / "Qt" /
|
||||
// "QtIFW-3.1.0" / "bin" / "installerbase.exe");
|
||||
|
||||
const Optional<fs::path> path =
|
||||
find_if_has_equal_or_greater_version(candidate_paths, VERSION_CHECK_ARGUMENTS, TOOL_DATA.required_version);
|
||||
if (const auto p = path.get())
|
||||
{
|
||||
return *p;
|
||||
}
|
||||
|
||||
return fetch_tool(paths, "installerbase", TOOL_DATA);
|
||||
}
|
||||
|
||||
Expected<VcpkgPaths> VcpkgPaths::create(const fs::path& vcpkg_root_dir, const std::string& default_vs_path)
|
||||
{
|
||||
std::error_code ec;
|
||||
@ -471,266 +83,22 @@ namespace vcpkg
|
||||
|
||||
bool VcpkgPaths::is_valid_triplet(const Triplet& t) const
|
||||
{
|
||||
auto it = Util::find_if(this->get_available_triplets(),
|
||||
[&](auto&& available_triplet) { return t.canonical_name() == available_triplet; });
|
||||
const auto it = Util::find_if(this->get_available_triplets(), [&](auto&& available_triplet) {
|
||||
return t.canonical_name() == available_triplet;
|
||||
});
|
||||
return it != this->get_available_triplets().cend();
|
||||
}
|
||||
|
||||
const fs::path& VcpkgPaths::get_7za_exe() const
|
||||
const fs::path& VcpkgPaths::get_tool_exe(const std::string& tool) const
|
||||
{
|
||||
return this->_7za_exe.get_lazy([this]() { return get_7za_path(*this); });
|
||||
}
|
||||
|
||||
const fs::path& VcpkgPaths::get_cmake_exe() const
|
||||
{
|
||||
return this->cmake_exe.get_lazy([this]() { return get_cmake_path(*this); });
|
||||
}
|
||||
|
||||
const fs::path& VcpkgPaths::get_git_exe() const
|
||||
{
|
||||
return this->git_exe.get_lazy([this]() { return get_git_path(*this); });
|
||||
}
|
||||
|
||||
const fs::path& VcpkgPaths::get_ninja_exe() const
|
||||
{
|
||||
return this->ninja_exe.get_lazy([this]() { return get_ninja_path(*this); });
|
||||
}
|
||||
|
||||
const fs::path& VcpkgPaths::get_nuget_exe() const
|
||||
{
|
||||
return this->nuget_exe.get_lazy([this]() { return get_nuget_path(*this); });
|
||||
}
|
||||
|
||||
const fs::path& VcpkgPaths::get_ifw_installerbase_exe() const
|
||||
{
|
||||
return this->ifw_installerbase_exe.get_lazy([this]() { return get_ifw_installerbase_path(*this); });
|
||||
}
|
||||
|
||||
const fs::path& VcpkgPaths::get_ifw_binarycreator_exe() const
|
||||
{
|
||||
return this->ifw_binarycreator_exe.get_lazy(
|
||||
[this]() { return get_ifw_installerbase_exe().parent_path() / "binarycreator.exe"; });
|
||||
}
|
||||
|
||||
const fs::path& VcpkgPaths::get_ifw_repogen_exe() const
|
||||
{
|
||||
return this->ifw_repogen_exe.get_lazy(
|
||||
[this]() { return get_ifw_installerbase_exe().parent_path() / "repogen.exe"; });
|
||||
}
|
||||
|
||||
struct VisualStudioInstance
|
||||
{
|
||||
fs::path root_path;
|
||||
std::string version;
|
||||
std::string release_type;
|
||||
std::string preference_weight; // Mostly unused, just for verification that order is as intended
|
||||
|
||||
std::string major_version() const { return version.substr(0, 2); }
|
||||
};
|
||||
|
||||
static std::vector<VisualStudioInstance> get_visual_studio_instances(const VcpkgPaths& paths)
|
||||
{
|
||||
const fs::path script = paths.scripts / "findVisualStudioInstallationInstances.ps1";
|
||||
const std::string output =
|
||||
System::powershell_execute_and_capture_output("Detecting Visual Studio instances", script);
|
||||
|
||||
const std::vector<std::string> instances_as_strings = keep_data_lines(output);
|
||||
Checks::check_exit(VCPKG_LINE_INFO,
|
||||
!instances_as_strings.empty(),
|
||||
"Could not detect any Visual Studio instances.\n"
|
||||
"Powershell script:\n"
|
||||
" %s\n"
|
||||
"returned:\n"
|
||||
"%s",
|
||||
script.generic_string(),
|
||||
output);
|
||||
|
||||
std::vector<VisualStudioInstance> instances;
|
||||
for (const std::string& instance_as_string : instances_as_strings)
|
||||
const auto it = this->tool_paths.find(tool);
|
||||
if (it != this->tool_paths.cend())
|
||||
{
|
||||
const std::vector<std::string> split = Strings::split(instance_as_string, "::");
|
||||
Checks::check_exit(VCPKG_LINE_INFO,
|
||||
split.size() == 4,
|
||||
"Invalid Visual Studio instance format.\n"
|
||||
"Expected: PreferenceWeight::ReleaseType::Version::PathToVisualStudio\n"
|
||||
"Actual : %s\n",
|
||||
instance_as_string);
|
||||
instances.push_back({split.at(3), split.at(2), split.at(1), split.at(0)});
|
||||
return it->second;
|
||||
}
|
||||
|
||||
return instances;
|
||||
}
|
||||
|
||||
static std::vector<Toolset> find_toolset_instances(const VcpkgPaths& paths)
|
||||
{
|
||||
using CPU = System::CPUArchitecture;
|
||||
|
||||
const auto& fs = paths.get_filesystem();
|
||||
|
||||
// Note: this will contain a mix of vcvarsall.bat locations and dumpbin.exe locations.
|
||||
std::vector<fs::path> paths_examined;
|
||||
|
||||
std::vector<Toolset> found_toolsets;
|
||||
std::vector<Toolset> excluded_toolsets;
|
||||
|
||||
const std::vector<VisualStudioInstance> vs_instances = get_visual_studio_instances(paths);
|
||||
const bool v140_is_available = Util::find_if(vs_instances, [&](const VisualStudioInstance& vs_instance) {
|
||||
return vs_instance.major_version() == "14";
|
||||
}) != vs_instances.cend();
|
||||
|
||||
for (const VisualStudioInstance& vs_instance : vs_instances)
|
||||
{
|
||||
const std::string major_version = vs_instance.major_version();
|
||||
if (major_version == "15")
|
||||
{
|
||||
const fs::path vc_dir = vs_instance.root_path / "VC";
|
||||
|
||||
// Skip any instances that do not have vcvarsall.
|
||||
const fs::path vcvarsall_dir = vc_dir / "Auxiliary" / "Build";
|
||||
const fs::path vcvarsall_bat = vcvarsall_dir / "vcvarsall.bat";
|
||||
paths_examined.push_back(vcvarsall_bat);
|
||||
if (!fs.exists(vcvarsall_bat)) continue;
|
||||
|
||||
// Get all supported architectures
|
||||
std::vector<ToolsetArchOption> supported_architectures;
|
||||
if (fs.exists(vcvarsall_dir / "vcvars32.bat"))
|
||||
supported_architectures.push_back({"x86", CPU::X86, CPU::X86});
|
||||
if (fs.exists(vcvarsall_dir / "vcvars64.bat"))
|
||||
supported_architectures.push_back({"amd64", CPU::X64, CPU::X64});
|
||||
if (fs.exists(vcvarsall_dir / "vcvarsx86_amd64.bat"))
|
||||
supported_architectures.push_back({"x86_amd64", CPU::X86, CPU::X64});
|
||||
if (fs.exists(vcvarsall_dir / "vcvarsx86_arm.bat"))
|
||||
supported_architectures.push_back({"x86_arm", CPU::X86, CPU::ARM});
|
||||
if (fs.exists(vcvarsall_dir / "vcvarsx86_arm64.bat"))
|
||||
supported_architectures.push_back({"x86_arm64", CPU::X86, CPU::ARM64});
|
||||
if (fs.exists(vcvarsall_dir / "vcvarsamd64_x86.bat"))
|
||||
supported_architectures.push_back({"amd64_x86", CPU::X64, CPU::X86});
|
||||
if (fs.exists(vcvarsall_dir / "vcvarsamd64_arm.bat"))
|
||||
supported_architectures.push_back({"amd64_arm", CPU::X64, CPU::ARM});
|
||||
if (fs.exists(vcvarsall_dir / "vcvarsamd64_arm64.bat"))
|
||||
supported_architectures.push_back({"amd64_arm64", CPU::X64, CPU::ARM64});
|
||||
|
||||
// Locate the "best" MSVC toolchain version
|
||||
const fs::path msvc_path = vc_dir / "Tools" / "MSVC";
|
||||
std::vector<fs::path> msvc_subdirectories = fs.get_files_non_recursive(msvc_path);
|
||||
Util::unstable_keep_if(msvc_subdirectories,
|
||||
[&fs](const fs::path& path) { return fs.is_directory(path); });
|
||||
|
||||
// Sort them so that latest comes first
|
||||
std::sort(
|
||||
msvc_subdirectories.begin(),
|
||||
msvc_subdirectories.end(),
|
||||
[](const fs::path& left, const fs::path& right) { return left.filename() > right.filename(); });
|
||||
|
||||
for (const fs::path& subdir : msvc_subdirectories)
|
||||
{
|
||||
const fs::path dumpbin_path = subdir / "bin" / "HostX86" / "x86" / "dumpbin.exe";
|
||||
paths_examined.push_back(dumpbin_path);
|
||||
if (fs.exists(dumpbin_path))
|
||||
{
|
||||
const Toolset v141toolset = Toolset{
|
||||
vs_instance.root_path, dumpbin_path, vcvarsall_bat, {}, V_141, supported_architectures};
|
||||
|
||||
auto english_language_pack = dumpbin_path.parent_path() / "1033";
|
||||
|
||||
if (!fs.exists(english_language_pack))
|
||||
{
|
||||
excluded_toolsets.push_back(v141toolset);
|
||||
break;
|
||||
}
|
||||
|
||||
found_toolsets.push_back(v141toolset);
|
||||
|
||||
if (v140_is_available)
|
||||
{
|
||||
const Toolset v140toolset = Toolset{vs_instance.root_path,
|
||||
dumpbin_path,
|
||||
vcvarsall_bat,
|
||||
{"-vcvars_ver=14.0"},
|
||||
V_140,
|
||||
supported_architectures};
|
||||
found_toolsets.push_back(v140toolset);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (major_version == "14" || major_version == "12")
|
||||
{
|
||||
const fs::path vcvarsall_bat = vs_instance.root_path / "VC" / "vcvarsall.bat";
|
||||
|
||||
paths_examined.push_back(vcvarsall_bat);
|
||||
if (fs.exists(vcvarsall_bat))
|
||||
{
|
||||
const fs::path vs_dumpbin_exe = vs_instance.root_path / "VC" / "bin" / "dumpbin.exe";
|
||||
paths_examined.push_back(vs_dumpbin_exe);
|
||||
|
||||
const fs::path vs_bin_dir = vcvarsall_bat.parent_path() / "bin";
|
||||
std::vector<ToolsetArchOption> supported_architectures;
|
||||
if (fs.exists(vs_bin_dir / "vcvars32.bat"))
|
||||
supported_architectures.push_back({"x86", CPU::X86, CPU::X86});
|
||||
if (fs.exists(vs_bin_dir / "amd64\\vcvars64.bat"))
|
||||
supported_architectures.push_back({"x64", CPU::X64, CPU::X64});
|
||||
if (fs.exists(vs_bin_dir / "x86_amd64\\vcvarsx86_amd64.bat"))
|
||||
supported_architectures.push_back({"x86_amd64", CPU::X86, CPU::X64});
|
||||
if (fs.exists(vs_bin_dir / "x86_arm\\vcvarsx86_arm.bat"))
|
||||
supported_architectures.push_back({"x86_arm", CPU::X86, CPU::ARM});
|
||||
if (fs.exists(vs_bin_dir / "amd64_x86\\vcvarsamd64_x86.bat"))
|
||||
supported_architectures.push_back({"amd64_x86", CPU::X64, CPU::X86});
|
||||
if (fs.exists(vs_bin_dir / "amd64_arm\\vcvarsamd64_arm.bat"))
|
||||
supported_architectures.push_back({"amd64_arm", CPU::X64, CPU::ARM});
|
||||
|
||||
if (fs.exists(vs_dumpbin_exe))
|
||||
{
|
||||
const Toolset toolset = {vs_instance.root_path,
|
||||
vs_dumpbin_exe,
|
||||
vcvarsall_bat,
|
||||
{},
|
||||
major_version == "14" ? V_140 : V_120,
|
||||
supported_architectures};
|
||||
|
||||
auto english_language_pack = vs_dumpbin_exe.parent_path() / "1033";
|
||||
|
||||
if (!fs.exists(english_language_pack))
|
||||
{
|
||||
excluded_toolsets.push_back(toolset);
|
||||
break;
|
||||
}
|
||||
|
||||
found_toolsets.push_back(toolset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!excluded_toolsets.empty())
|
||||
{
|
||||
System::println(
|
||||
System::Color::warning,
|
||||
"Warning: The following VS instances are excluded because the English language pack is unavailable.");
|
||||
for (const Toolset& toolset : excluded_toolsets)
|
||||
{
|
||||
System::println(" %s", toolset.visual_studio_root_path.u8string());
|
||||
}
|
||||
System::println(System::Color::warning, "Please install the English language pack.");
|
||||
}
|
||||
|
||||
if (found_toolsets.empty())
|
||||
{
|
||||
System::println(System::Color::error, "Could not locate a complete toolset.");
|
||||
System::println("The following paths were examined:");
|
||||
for (const fs::path& path : paths_examined)
|
||||
{
|
||||
System::println(" %s", path.u8string());
|
||||
}
|
||||
Checks::exit_fail(VCPKG_LINE_INFO);
|
||||
}
|
||||
|
||||
return found_toolsets;
|
||||
this->tool_paths[tool] = Commands::Fetch::get_tool_path(*this, tool);
|
||||
return this->tool_paths[tool];
|
||||
}
|
||||
|
||||
const Toolset& VcpkgPaths::get_toolset(const Build::PreBuildInfo& prebuildinfo) const
|
||||
@ -754,7 +122,7 @@ namespace vcpkg
|
||||
|
||||
// Invariant: toolsets are non-empty and sorted with newest at back()
|
||||
const std::vector<Toolset>& vs_toolsets =
|
||||
this->toolsets.get_lazy([this]() { return find_toolset_instances(*this); });
|
||||
this->toolsets.get_lazy([this]() { return Commands::Fetch::find_toolset_instances(*this); });
|
||||
|
||||
std::vector<const Toolset*> candidates = Util::element_pointers(vs_toolsets);
|
||||
const auto tsv = prebuildinfo.platform_toolset.get();
|
||||
|
@ -214,6 +214,7 @@
|
||||
<ClCompile Include="..\src\vcpkg\commands.edit.cpp" />
|
||||
<ClCompile Include="..\src\vcpkg\commands.env.cpp" />
|
||||
<ClCompile Include="..\src\vcpkg\commands.exportifw.cpp" />
|
||||
<ClCompile Include="..\src\vcpkg\commands.fetch.cpp" />
|
||||
<ClCompile Include="..\src\vcpkg\commands.hash.cpp" />
|
||||
<ClCompile Include="..\src\vcpkg\commands.import.cpp" />
|
||||
<ClCompile Include="..\src\vcpkg\commands.integrate.cpp" />
|
||||
|
@ -198,6 +198,9 @@
|
||||
<ClCompile Include="..\src\vcpkg\commands.upgrade.cpp">
|
||||
<Filter>Source Files\vcpkg</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\vcpkg\commands.fetch.cpp">
|
||||
<Filter>Source Files\vcpkg</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\include\pch.h">
|
||||
|
Loading…
Reference in New Issue
Block a user