Introduce stringrange.h/cpp and visualstudio.h/cpp

This commit is contained in:
Alexander Karatarakis 2018-06-19 17:51:20 -07:00
parent dbae3bfe56
commit c256ccf452
9 changed files with 457 additions and 381 deletions

View File

@ -0,0 +1,33 @@
#pragma once
#include <vcpkg/base/optional.h>
#include <string>
#include <vector>
namespace vcpkg
{
struct VcpkgStringRange
{
static std::vector<VcpkgStringRange> find_all_enclosed(const VcpkgStringRange& input,
const std::string& left_delim,
const std::string& right_delim);
static VcpkgStringRange find_exactly_one_enclosed(const VcpkgStringRange& input,
const std::string& left_tag,
const std::string& right_tag);
static Optional<VcpkgStringRange> find_at_most_one_enclosed(const VcpkgStringRange& input,
const std::string& left_tag,
const std::string& right_tag);
VcpkgStringRange() = default;
VcpkgStringRange(const std::string& s); // Implicit by design
VcpkgStringRange(const std::string::const_iterator begin, const std::string::const_iterator end);
std::string::const_iterator begin;
std::string::const_iterator end;
std::string to_string() const;
};
}

View File

@ -139,7 +139,6 @@ namespace vcpkg::Commands
namespace Fetch
{
std::vector<Toolset> find_toolset_instances_preferred_first(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);
}

View File

@ -0,0 +1,12 @@
#pragma once
#if defined(_WIN32)
#include <vcpkg/vcpkgpaths.h>
namespace vcpkg::VisualStudio
{
std::vector<Toolset> find_toolset_instances_preferred_first(const VcpkgPaths& paths);
}
#endif

View File

@ -0,0 +1,79 @@
#include "pch.h"
#include <vcpkg/base/checks.h>
#include <vcpkg/base/stringrange.h>
namespace vcpkg
{
std::vector<VcpkgStringRange> VcpkgStringRange::find_all_enclosed(const VcpkgStringRange& input,
const std::string& left_delim,
const std::string& right_delim)
{
std::string::const_iterator it_left = input.begin;
std::string::const_iterator it_right = input.begin;
std::vector<VcpkgStringRange> output;
while (true)
{
it_left = std::search(it_right, input.end, left_delim.cbegin(), left_delim.cend());
if (it_left == input.end) break;
it_left += left_delim.length();
it_right = std::search(it_left, input.end, right_delim.cbegin(), right_delim.cend());
if (it_right == input.end) break;
output.emplace_back(it_left, it_right);
++it_right;
}
return output;
}
VcpkgStringRange VcpkgStringRange::find_exactly_one_enclosed(const VcpkgStringRange& input,
const std::string& left_tag,
const std::string& right_tag)
{
std::vector<VcpkgStringRange> result = find_all_enclosed(input, left_tag, right_tag);
Checks::check_exit(VCPKG_LINE_INFO,
result.size() == 1,
"Found %d sets of %s.*%s but expected exactly 1, in block:\n%s",
result.size(),
left_tag,
right_tag,
input);
return result.front();
}
Optional<VcpkgStringRange> VcpkgStringRange::find_at_most_one_enclosed(const VcpkgStringRange& input,
const std::string& left_tag,
const std::string& right_tag)
{
std::vector<VcpkgStringRange> result = find_all_enclosed(input, left_tag, right_tag);
Checks::check_exit(VCPKG_LINE_INFO,
result.size() <= 1,
"Found %d sets of %s.*%s but expected at most 1, in block:\n%s",
result.size(),
left_tag,
right_tag,
input);
if (result.empty())
{
return nullopt;
}
return result.front();
}
VcpkgStringRange::VcpkgStringRange(const std::string& s) : begin(s.cbegin()), end(s.cend()) {}
VcpkgStringRange::VcpkgStringRange(const std::string::const_iterator begin, const std::string::const_iterator end)
: begin(begin), end(end)
{
}
std::string VcpkgStringRange::to_string() const { return std::string(this->begin, this->end); }
}

View File

@ -3,7 +3,7 @@
#include <vcpkg/base/archives.h>
#include <vcpkg/base/checks.h>
#include <vcpkg/base/downloads.h>
#include <vcpkg/base/sortedvector.h>
#include <vcpkg/base/stringrange.h>
#include <vcpkg/base/strings.h>
#include <vcpkg/base/system.h>
#include <vcpkg/base/util.h>
@ -13,10 +13,6 @@
namespace vcpkg::Commands::Fetch
{
static constexpr CStringView V_120 = "v120";
static constexpr CStringView V_140 = "v140";
static constexpr CStringView V_141 = "v141";
struct ToolData
{
std::array<int, 3> version;
@ -46,87 +42,6 @@ namespace vcpkg::Commands::Fetch
return result;
}
struct VcpkgStringRange
{
VcpkgStringRange() = default;
// Implicit by design
VcpkgStringRange(const std::string& s) : begin(s.cbegin()), end(s.cend()) {}
VcpkgStringRange(const std::string::const_iterator begin, const std::string::const_iterator end)
: begin(begin), end(end)
{
}
std::string::const_iterator begin;
std::string::const_iterator end;
std::string to_string() const { return std::string(this->begin, this->end); }
};
static std::vector<VcpkgStringRange> find_all_enclosed(const VcpkgStringRange& input,
const std::string& left_delim,
const std::string& right_delim)
{
std::string::const_iterator it_left = input.begin;
std::string::const_iterator it_right = input.begin;
std::vector<VcpkgStringRange> output;
while (true)
{
it_left = std::search(it_right, input.end, left_delim.cbegin(), left_delim.cend());
if (it_left == input.end) break;
it_left += left_delim.length();
it_right = std::search(it_left, input.end, right_delim.cbegin(), right_delim.cend());
if (it_right == input.end) break;
output.emplace_back(it_left, it_right);
++it_right;
}
return output;
}
static VcpkgStringRange find_exactly_one_enclosed(const VcpkgStringRange& input,
const std::string& left_tag,
const std::string& right_tag)
{
std::vector<VcpkgStringRange> result = find_all_enclosed(input, left_tag, right_tag);
Checks::check_exit(VCPKG_LINE_INFO,
result.size() == 1,
"Found %d sets of %s.*%s but expected exactly 1, in block:\n%s",
result.size(),
left_tag,
right_tag,
input);
return std::move(result.front());
}
static Optional<VcpkgStringRange> find_at_most_one_enclosed(const VcpkgStringRange& input,
const std::string& left_tag,
const std::string& right_tag)
{
std::vector<VcpkgStringRange> result = find_all_enclosed(input, left_tag, right_tag);
Checks::check_exit(VCPKG_LINE_INFO,
result.size() <= 1,
"Found %d sets of %s.*%s but expected at most 1, in block:\n%s",
result.size(),
left_tag,
right_tag,
input);
if (result.empty())
{
return nullopt;
}
return result.front();
}
static ToolData parse_tool_data_from_xml(const VcpkgPaths& paths, const std::string& tool)
{
#if defined(_WIN32)
@ -167,14 +82,17 @@ namespace vcpkg::Commands::Fetch
tool,
XML_PATH.generic_string());
const std::string tool_data = find_exactly_one_enclosed(XML, match_tool_entry[0], "</tool>").to_string();
const std::string tool_data =
VcpkgStringRange::find_exactly_one_enclosed(XML, match_tool_entry[0], "</tool>").to_string();
const std::string version_as_string =
find_exactly_one_enclosed(tool_data, "<version>", "</version>").to_string();
VcpkgStringRange::find_exactly_one_enclosed(tool_data, "<version>", "</version>").to_string();
const std::string exe_relative_path =
find_exactly_one_enclosed(tool_data, "<exeRelativePath>", "</exeRelativePath>").to_string();
const std::string url = find_exactly_one_enclosed(tool_data, "<url>", "</url>").to_string();
const std::string sha512 = find_exactly_one_enclosed(tool_data, "<sha512>", "</sha512>").to_string();
auto archive_name = find_at_most_one_enclosed(tool_data, "<archiveName>", "</archiveName>");
VcpkgStringRange::find_exactly_one_enclosed(tool_data, "<exeRelativePath>", "</exeRelativePath>")
.to_string();
const std::string url = VcpkgStringRange::find_exactly_one_enclosed(tool_data, "<url>", "</url>").to_string();
const std::string sha512 =
VcpkgStringRange::find_exactly_one_enclosed(tool_data, "<sha512>", "</sha512>").to_string();
auto archive_name = VcpkgStringRange::find_at_most_one_enclosed(tool_data, "<archiveName>", "</archiveName>");
const Optional<std::array<int, 3>> version = parse_version_string(version_as_string);
Checks::check_exit(VCPKG_LINE_INFO,
@ -420,292 +338,6 @@ namespace vcpkg::Commands::Fetch
return fetch_tool(paths, "installerbase", TOOL_DATA);
}
struct VisualStudioInstance
{
enum class ReleaseType
{
STABLE,
PRERELEASE,
LEGACY
};
static bool preferred_first_comparator(const VisualStudioInstance& left, const VisualStudioInstance& right)
{
const auto get_preference_weight = [](const ReleaseType& type) -> int {
switch (type)
{
case ReleaseType::STABLE: return 3;
case ReleaseType::PRERELEASE: return 2;
case ReleaseType::LEGACY: return 1;
default: Checks::unreachable(VCPKG_LINE_INFO);
}
};
if (left.release_type != right.release_type)
{
return get_preference_weight(left.release_type) > get_preference_weight(right.release_type);
}
return left.version > right.version;
}
VisualStudioInstance(fs::path&& root_path, std::string&& version, const ReleaseType& release_type)
: root_path(std::move(root_path)), version(std::move(version)), release_type(release_type)
{
}
fs::path root_path;
std::string version;
ReleaseType release_type;
std::string major_version() const { return version.substr(0, 2); }
};
#if defined(WIN32)
static std::vector<VisualStudioInstance> get_visual_studio_instances(const VcpkgPaths& paths)
{
const auto& fs = paths.get_filesystem();
std::vector<VisualStudioInstance> instances;
const auto& program_files_32_bit = System::get_program_files_32_bit().value_or_exit(VCPKG_LINE_INFO);
// Instances from vswhere
const fs::path vswhere_exe = program_files_32_bit / "Microsoft Visual Studio" / "Installer" / "vswhere.exe";
if (fs.exists(vswhere_exe))
{
const auto code_and_output = System::cmd_execute_and_capture_output(
Strings::format(R"("%s" -prerelease -legacy -products * -format xml)", vswhere_exe.u8string()));
Checks::check_exit(VCPKG_LINE_INFO,
code_and_output.exit_code == 0,
"Running vswhere.exe failed with message:\n%s",
code_and_output.output);
const auto instance_entries = find_all_enclosed(code_and_output.output, "<instance>", "</instance>");
for (const VcpkgStringRange& instance : instance_entries)
{
auto maybe_is_prerelease = find_at_most_one_enclosed(instance, "<isPrerelease>", "</isPrerelease>");
VisualStudioInstance::ReleaseType release_type = VisualStudioInstance::ReleaseType::LEGACY;
if (const auto p = maybe_is_prerelease.get())
{
const auto s = p->to_string();
if (s == "0")
release_type = VisualStudioInstance::ReleaseType::STABLE;
else if (s == "1")
release_type = VisualStudioInstance::ReleaseType::PRERELEASE;
else
Checks::unreachable(VCPKG_LINE_INFO);
}
instances.emplace_back(
find_exactly_one_enclosed(instance, "<installationPath>", "</installationPath>").to_string(),
find_exactly_one_enclosed(instance, "<installationVersion>", "</installationVersion>").to_string(),
release_type);
}
}
const auto append_if_has_cl = [&](fs::path&& path_root) {
const auto cl_exe = path_root / "VC" / "bin" / "cl.exe";
const auto vcvarsall_bat = path_root / "VC" / "vcvarsall.bat";
if (fs.exists(cl_exe) && fs.exists(vcvarsall_bat))
instances.emplace_back(std::move(path_root), "14.0", VisualStudioInstance::ReleaseType::LEGACY);
};
// VS2015 instance from environment variable
auto maybe_vs140_comntools = System::get_environment_variable("vs140comntools");
if (const auto path_as_string = maybe_vs140_comntools.get())
{
// We want lexically_normal(), but it is not available
// Correct root path might be 2 or 3 levels up, depending on if the path has trailing backslash. Try both.
auto common7_tools = fs::path{*path_as_string};
append_if_has_cl(fs::path{*path_as_string}.parent_path().parent_path());
append_if_has_cl(fs::path{*path_as_string}.parent_path().parent_path().parent_path());
}
// VS2015 instance from Program Files
append_if_has_cl(program_files_32_bit / "Microsoft Visual Studio 14.0");
return instances;
}
#endif
#if defined(_WIN32)
std::vector<Toolset> find_toolset_instances_preferred_first(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 SortedVector<VisualStudioInstance> sorted{get_visual_studio_instances(paths),
VisualStudioInstance::preferred_first_comparator};
const bool v140_is_available = Util::find_if(sorted, [&](const VisualStudioInstance& vs_instance) {
return vs_instance.major_version() == "14";
}) != sorted.end();
for (const VisualStudioInstance& vs_instance : sorted)
{
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{
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{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;
}
#endif
fs::path get_tool_path(const VcpkgPaths& paths, const std::string& tool)
{
// First deal with specially handled tools.

View File

@ -9,6 +9,7 @@
#include <vcpkg/metrics.h>
#include <vcpkg/packagespec.h>
#include <vcpkg/vcpkgpaths.h>
#include <vcpkg/visualstudio.h>
namespace vcpkg
{
@ -117,8 +118,8 @@ namespace vcpkg
#if !defined(_WIN32)
Checks::exit_with_message(VCPKG_LINE_INFO, "Cannot build windows triplets from non-windows.");
#else
const std::vector<Toolset>& vs_toolsets = this->toolsets.get_lazy(
[this]() { return Commands::Fetch::find_toolset_instances_preferred_first(*this); });
const std::vector<Toolset>& vs_toolsets =
this->toolsets.get_lazy([this]() { return VisualStudio::find_toolset_instances_preferred_first(*this); });
std::vector<const Toolset*> candidates = Util::element_pointers(vs_toolsets);
const auto tsv = prebuildinfo.platform_toolset.get();

View File

@ -0,0 +1,304 @@
#include "pch.h"
#if defined(_WIN32)
#include <vcpkg/base/sortedvector.h>
#include <vcpkg/base/stringrange.h>
#include <vcpkg/base/util.h>
#include <vcpkg/visualstudio.h>
namespace vcpkg::VisualStudio
{
static constexpr CStringView V_120 = "v120";
static constexpr CStringView V_140 = "v140";
static constexpr CStringView V_141 = "v141";
struct VisualStudioInstance
{
enum class ReleaseType
{
STABLE,
PRERELEASE,
LEGACY
};
static bool preferred_first_comparator(const VisualStudioInstance& left, const VisualStudioInstance& right)
{
const auto get_preference_weight = [](const ReleaseType& type) -> int {
switch (type)
{
case ReleaseType::STABLE: return 3;
case ReleaseType::PRERELEASE: return 2;
case ReleaseType::LEGACY: return 1;
default: Checks::unreachable(VCPKG_LINE_INFO);
}
};
if (left.release_type != right.release_type)
{
return get_preference_weight(left.release_type) > get_preference_weight(right.release_type);
}
return left.version > right.version;
}
VisualStudioInstance(fs::path&& root_path, std::string&& version, const ReleaseType& release_type)
: root_path(std::move(root_path)), version(std::move(version)), release_type(release_type)
{
}
fs::path root_path;
std::string version;
ReleaseType release_type;
std::string major_version() const { return version.substr(0, 2); }
};
static std::vector<VisualStudioInstance> get_visual_studio_instances(const VcpkgPaths& paths)
{
const auto& fs = paths.get_filesystem();
std::vector<VisualStudioInstance> instances;
const auto& program_files_32_bit = System::get_program_files_32_bit().value_or_exit(VCPKG_LINE_INFO);
// Instances from vswhere
const fs::path vswhere_exe = program_files_32_bit / "Microsoft Visual Studio" / "Installer" / "vswhere.exe";
if (fs.exists(vswhere_exe))
{
const auto code_and_output = System::cmd_execute_and_capture_output(
Strings::format(R"("%s" -prerelease -legacy -products * -format xml)", vswhere_exe.u8string()));
Checks::check_exit(VCPKG_LINE_INFO,
code_and_output.exit_code == 0,
"Running vswhere.exe failed with message:\n%s",
code_and_output.output);
const auto instance_entries =
VcpkgStringRange::find_all_enclosed(code_and_output.output, "<instance>", "</instance>");
for (const VcpkgStringRange& instance : instance_entries)
{
auto maybe_is_prerelease =
VcpkgStringRange::find_at_most_one_enclosed(instance, "<isPrerelease>", "</isPrerelease>");
VisualStudioInstance::ReleaseType release_type = VisualStudioInstance::ReleaseType::LEGACY;
if (const auto p = maybe_is_prerelease.get())
{
const auto s = p->to_string();
if (s == "0")
release_type = VisualStudioInstance::ReleaseType::STABLE;
else if (s == "1")
release_type = VisualStudioInstance::ReleaseType::PRERELEASE;
else
Checks::unreachable(VCPKG_LINE_INFO);
}
instances.emplace_back(
VcpkgStringRange::find_exactly_one_enclosed(instance, "<installationPath>", "</installationPath>")
.to_string(),
VcpkgStringRange::find_exactly_one_enclosed(
instance, "<installationVersion>", "</installationVersion>")
.to_string(),
release_type);
}
}
const auto append_if_has_cl = [&](fs::path&& path_root) {
const auto cl_exe = path_root / "VC" / "bin" / "cl.exe";
const auto vcvarsall_bat = path_root / "VC" / "vcvarsall.bat";
if (fs.exists(cl_exe) && fs.exists(vcvarsall_bat))
instances.emplace_back(std::move(path_root), "14.0", VisualStudioInstance::ReleaseType::LEGACY);
};
// VS2015 instance from environment variable
auto maybe_vs140_comntools = System::get_environment_variable("vs140comntools");
if (const auto path_as_string = maybe_vs140_comntools.get())
{
// We want lexically_normal(), but it is not available
// Correct root path might be 2 or 3 levels up, depending on if the path has trailing backslash. Try both.
auto common7_tools = fs::path{*path_as_string};
append_if_has_cl(fs::path{*path_as_string}.parent_path().parent_path());
append_if_has_cl(fs::path{*path_as_string}.parent_path().parent_path().parent_path());
}
// VS2015 instance from Program Files
append_if_has_cl(program_files_32_bit / "Microsoft Visual Studio 14.0");
return instances;
}
std::vector<Toolset> find_toolset_instances_preferred_first(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 SortedVector<VisualStudioInstance> sorted{get_visual_studio_instances(paths),
VisualStudioInstance::preferred_first_comparator};
const bool v140_is_available = Util::find_if(sorted, [&](const VisualStudioInstance& vs_instance) {
return vs_instance.major_version() == "14";
}) != sorted.end();
for (const VisualStudioInstance& vs_instance : sorted)
{
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 v141_toolset{
vs_instance.root_path, dumpbin_path, vcvarsall_bat, {}, V_141, 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;
}
found_toolsets.push_back(v141_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);
}
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};
const 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;
}
}
#endif

View File

@ -154,6 +154,7 @@
<ClInclude Include="..\include\vcpkg\base\sortedvector.h" />
<ClInclude Include="..\include\vcpkg\base\span.h" />
<ClInclude Include="..\include\vcpkg\base\stringliteral.h" />
<ClInclude Include="..\include\vcpkg\base\stringrange.h" />
<ClInclude Include="..\include\vcpkg\base\strings.h" />
<ClInclude Include="..\include\vcpkg\base\system.h" />
<ClInclude Include="..\include\vcpkg\base\util.h" />
@ -186,6 +187,7 @@
<ClInclude Include="..\include\vcpkg\vcpkglib.h" />
<ClInclude Include="..\include\vcpkg\vcpkgpaths.h" />
<ClInclude Include="..\include\vcpkg\versiont.h" />
<ClInclude Include="..\include\vcpkg\visualstudio.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\src\pch.cpp">
@ -203,6 +205,7 @@
<ClCompile Include="..\src\vcpkg\base\files.cpp" />
<ClCompile Include="..\src\vcpkg\base\lineinfo.cpp" />
<ClCompile Include="..\src\vcpkg\base\machinetype.cpp" />
<ClCompile Include="..\src\vcpkg\base\stringrange.cpp" />
<ClCompile Include="..\src\vcpkg\base\strings.cpp" />
<ClCompile Include="..\src\vcpkg\base\system.cpp" />
<ClCompile Include="..\src\vcpkg\binaryparagraph.cpp" />
@ -253,6 +256,7 @@
<ClCompile Include="..\src\vcpkg\vcpkglib.cpp" />
<ClCompile Include="..\src\vcpkg\vcpkgpaths.cpp" />
<ClCompile Include="..\src\vcpkg\versiont.cpp" />
<ClCompile Include="..\src\vcpkg\visualstudio.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">

View File

@ -207,6 +207,12 @@
<ClCompile Include="..\src\vcpkg\base\archives.cpp">
<Filter>Source Files\vcpkg\base</Filter>
</ClCompile>
<ClCompile Include="..\src\vcpkg\visualstudio.cpp">
<Filter>Source Files\vcpkg</Filter>
</ClCompile>
<ClCompile Include="..\src\vcpkg\base\stringrange.cpp">
<Filter>Source Files\vcpkg\base</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\include\pch.h">
@ -359,5 +365,11 @@
<ClInclude Include="..\include\vcpkg\base\archives.h">
<Filter>Header Files\vcpkg\base</Filter>
</ClInclude>
<ClInclude Include="..\include\vcpkg\visualstudio.h">
<Filter>Header Files\vcpkg\base</Filter>
</ClInclude>
<ClInclude Include="..\include\vcpkg\base\stringrange.h">
<Filter>Header Files\vcpkg\base</Filter>
</ClInclude>
</ItemGroup>
</Project>