
Previously the `CMAKE_GENERATOR_INSTANCE` value was used only to filter the instances reported by the Visual Studio Installer tool. If the specified install location is not known to the VS Installer, but the user provided a `version=` field, check for the installation directly on disk. Fixes: #21639, #22197
918 lines
27 KiB
C++
918 lines
27 KiB
C++
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
|
file Copyright.txt or https://cmake.org/licensing for details. */
|
|
#include "cmGlobalVisualStudioVersionedGenerator.h"
|
|
|
|
#include <cmext/string_view>
|
|
|
|
#include "cmsys/FStream.hxx"
|
|
#include "cmsys/Glob.hxx"
|
|
#include "cmsys/RegularExpression.hxx"
|
|
|
|
#include "cmAlgorithms.h"
|
|
#include "cmDocumentationEntry.h"
|
|
#include "cmLocalVisualStudio10Generator.h"
|
|
#include "cmMakefile.h"
|
|
#include "cmStringAlgorithms.h"
|
|
#include "cmVSSetupHelper.h"
|
|
#include "cmake.h"
|
|
|
|
#if defined(_M_ARM64)
|
|
# define HOST_PLATFORM_NAME "ARM64"
|
|
# define HOST_TOOLS_ARCH ""
|
|
#elif defined(_M_ARM)
|
|
# define HOST_PLATFORM_NAME "ARM"
|
|
# define HOST_TOOLS_ARCH ""
|
|
#elif defined(_M_IA64)
|
|
# define HOST_PLATFORM_NAME "Itanium"
|
|
# define HOST_TOOLS_ARCH ""
|
|
#elif defined(_WIN64)
|
|
# define HOST_PLATFORM_NAME "x64"
|
|
# define HOST_TOOLS_ARCH "x64"
|
|
#else
|
|
static bool VSIsWow64()
|
|
{
|
|
BOOL isWow64 = false;
|
|
return IsWow64Process(GetCurrentProcess(), &isWow64) && isWow64;
|
|
}
|
|
#endif
|
|
|
|
static std::string VSHostPlatformName()
|
|
{
|
|
#ifdef HOST_PLATFORM_NAME
|
|
return HOST_PLATFORM_NAME;
|
|
#else
|
|
if (VSIsWow64()) {
|
|
return "x64";
|
|
} else {
|
|
return "Win32";
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static std::string VSHostArchitecture()
|
|
{
|
|
#ifdef HOST_TOOLS_ARCH
|
|
return HOST_TOOLS_ARCH;
|
|
#else
|
|
if (VSIsWow64()) {
|
|
return "x64";
|
|
} else {
|
|
return "x86";
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static unsigned int VSVersionToMajor(
|
|
cmGlobalVisualStudioGenerator::VSVersion v)
|
|
{
|
|
switch (v) {
|
|
case cmGlobalVisualStudioGenerator::VS9:
|
|
return 9;
|
|
case cmGlobalVisualStudioGenerator::VS10:
|
|
return 10;
|
|
case cmGlobalVisualStudioGenerator::VS11:
|
|
return 11;
|
|
case cmGlobalVisualStudioGenerator::VS12:
|
|
return 12;
|
|
case cmGlobalVisualStudioGenerator::VS14:
|
|
return 14;
|
|
case cmGlobalVisualStudioGenerator::VS15:
|
|
return 15;
|
|
case cmGlobalVisualStudioGenerator::VS16:
|
|
return 16;
|
|
case cmGlobalVisualStudioGenerator::VS17:
|
|
return 17;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static const char* VSVersionToToolset(
|
|
cmGlobalVisualStudioGenerator::VSVersion v)
|
|
{
|
|
switch (v) {
|
|
case cmGlobalVisualStudioGenerator::VS9:
|
|
return "v90";
|
|
case cmGlobalVisualStudioGenerator::VS10:
|
|
return "v100";
|
|
case cmGlobalVisualStudioGenerator::VS11:
|
|
return "v110";
|
|
case cmGlobalVisualStudioGenerator::VS12:
|
|
return "v120";
|
|
case cmGlobalVisualStudioGenerator::VS14:
|
|
return "v140";
|
|
case cmGlobalVisualStudioGenerator::VS15:
|
|
return "v141";
|
|
case cmGlobalVisualStudioGenerator::VS16:
|
|
return "v142";
|
|
case cmGlobalVisualStudioGenerator::VS17:
|
|
return "v143";
|
|
}
|
|
return "";
|
|
}
|
|
|
|
static std::string VSVersionToMajorString(
|
|
cmGlobalVisualStudioGenerator::VSVersion v)
|
|
{
|
|
switch (v) {
|
|
case cmGlobalVisualStudioGenerator::VS9:
|
|
return "9";
|
|
case cmGlobalVisualStudioGenerator::VS10:
|
|
return "10";
|
|
case cmGlobalVisualStudioGenerator::VS11:
|
|
return "11";
|
|
case cmGlobalVisualStudioGenerator::VS12:
|
|
return "12";
|
|
case cmGlobalVisualStudioGenerator::VS14:
|
|
return "14";
|
|
case cmGlobalVisualStudioGenerator::VS15:
|
|
return "15";
|
|
case cmGlobalVisualStudioGenerator::VS16:
|
|
return "16";
|
|
case cmGlobalVisualStudioGenerator::VS17:
|
|
return "17";
|
|
}
|
|
return "";
|
|
}
|
|
|
|
static const char* VSVersionToAndroidToolset(
|
|
cmGlobalVisualStudioGenerator::VSVersion v)
|
|
{
|
|
switch (v) {
|
|
case cmGlobalVisualStudioGenerator::VS9:
|
|
case cmGlobalVisualStudioGenerator::VS10:
|
|
case cmGlobalVisualStudioGenerator::VS11:
|
|
case cmGlobalVisualStudioGenerator::VS12:
|
|
return "";
|
|
case cmGlobalVisualStudioGenerator::VS14:
|
|
return "Clang_3_8";
|
|
case cmGlobalVisualStudioGenerator::VS15:
|
|
case cmGlobalVisualStudioGenerator::VS16:
|
|
case cmGlobalVisualStudioGenerator::VS17:
|
|
return "Clang_5_0";
|
|
}
|
|
return "";
|
|
}
|
|
|
|
static const char vs15generatorName[] = "Visual Studio 15 2017";
|
|
|
|
// Map generator name without year to name with year.
|
|
static const char* cmVS15GenName(const std::string& name, std::string& genName)
|
|
{
|
|
if (strncmp(name.c_str(), vs15generatorName,
|
|
sizeof(vs15generatorName) - 6) != 0) {
|
|
return 0;
|
|
}
|
|
const char* p = name.c_str() + sizeof(vs15generatorName) - 6;
|
|
if (cmHasLiteralPrefix(p, " 2017")) {
|
|
p += 5;
|
|
}
|
|
genName = std::string(vs15generatorName) + p;
|
|
return p;
|
|
}
|
|
|
|
class cmGlobalVisualStudioVersionedGenerator::Factory15
|
|
: public cmGlobalGeneratorFactory
|
|
{
|
|
public:
|
|
std::unique_ptr<cmGlobalGenerator> CreateGlobalGenerator(
|
|
const std::string& name, bool allowArch, cmake* cm) const override
|
|
{
|
|
std::string genName;
|
|
const char* p = cmVS15GenName(name, genName);
|
|
if (!p) {
|
|
return std::unique_ptr<cmGlobalGenerator>();
|
|
}
|
|
if (!*p) {
|
|
return std::unique_ptr<cmGlobalGenerator>(
|
|
new cmGlobalVisualStudioVersionedGenerator(
|
|
cmGlobalVisualStudioGenerator::VS15, cm, genName, ""));
|
|
}
|
|
if (!allowArch || *p++ != ' ') {
|
|
return std::unique_ptr<cmGlobalGenerator>();
|
|
}
|
|
if (strcmp(p, "Win64") == 0) {
|
|
return std::unique_ptr<cmGlobalGenerator>(
|
|
new cmGlobalVisualStudioVersionedGenerator(
|
|
cmGlobalVisualStudioGenerator::VS15, cm, genName, "x64"));
|
|
}
|
|
if (strcmp(p, "ARM") == 0) {
|
|
return std::unique_ptr<cmGlobalGenerator>(
|
|
new cmGlobalVisualStudioVersionedGenerator(
|
|
cmGlobalVisualStudioGenerator::VS15, cm, genName, "ARM"));
|
|
}
|
|
return std::unique_ptr<cmGlobalGenerator>();
|
|
}
|
|
|
|
void GetDocumentation(cmDocumentationEntry& entry) const override
|
|
{
|
|
entry.Name = std::string(vs15generatorName) + " [arch]";
|
|
entry.Brief = "Generates Visual Studio 2017 project files. "
|
|
"Optional [arch] can be \"Win64\" or \"ARM\".";
|
|
}
|
|
|
|
std::vector<std::string> GetGeneratorNames() const override
|
|
{
|
|
std::vector<std::string> names;
|
|
names.push_back(vs15generatorName);
|
|
return names;
|
|
}
|
|
|
|
std::vector<std::string> GetGeneratorNamesWithPlatform() const override
|
|
{
|
|
std::vector<std::string> names;
|
|
names.push_back(vs15generatorName + std::string(" ARM"));
|
|
names.push_back(vs15generatorName + std::string(" Win64"));
|
|
return names;
|
|
}
|
|
|
|
bool SupportsToolset() const override { return true; }
|
|
bool SupportsPlatform() const override { return true; }
|
|
|
|
std::vector<std::string> GetKnownPlatforms() const override
|
|
{
|
|
std::vector<std::string> platforms;
|
|
platforms.emplace_back("x64");
|
|
platforms.emplace_back("Win32");
|
|
platforms.emplace_back("ARM");
|
|
platforms.emplace_back("ARM64");
|
|
return platforms;
|
|
}
|
|
|
|
std::string GetDefaultPlatformName() const override { return "Win32"; }
|
|
};
|
|
|
|
std::unique_ptr<cmGlobalGeneratorFactory>
|
|
cmGlobalVisualStudioVersionedGenerator::NewFactory15()
|
|
{
|
|
return std::unique_ptr<cmGlobalGeneratorFactory>(new Factory15);
|
|
}
|
|
|
|
static const char vs16generatorName[] = "Visual Studio 16 2019";
|
|
static const char vs17generatorName[] = "Visual Studio 17 2022";
|
|
|
|
// Map generator name without year to name with year.
|
|
static const char* cmVS16GenName(const std::string& name, std::string& genName)
|
|
{
|
|
if (strncmp(name.c_str(), vs16generatorName,
|
|
sizeof(vs16generatorName) - 6) != 0) {
|
|
return 0;
|
|
}
|
|
const char* p = name.c_str() + sizeof(vs16generatorName) - 6;
|
|
if (cmHasLiteralPrefix(p, " 2019")) {
|
|
p += 5;
|
|
}
|
|
genName = std::string(vs16generatorName) + p;
|
|
return p;
|
|
}
|
|
|
|
static const char* cmVS17GenName(const std::string& name, std::string& genName)
|
|
{
|
|
if (strncmp(name.c_str(), vs17generatorName,
|
|
sizeof(vs17generatorName) - 6) != 0) {
|
|
return 0;
|
|
}
|
|
const char* p = name.c_str() + sizeof(vs17generatorName) - 6;
|
|
if (cmHasLiteralPrefix(p, " 2022")) {
|
|
p += 5;
|
|
}
|
|
genName = std::string(vs17generatorName) + p;
|
|
return p;
|
|
}
|
|
|
|
class cmGlobalVisualStudioVersionedGenerator::Factory16
|
|
: public cmGlobalGeneratorFactory
|
|
{
|
|
public:
|
|
std::unique_ptr<cmGlobalGenerator> CreateGlobalGenerator(
|
|
const std::string& name, bool /*allowArch*/, cmake* cm) const override
|
|
{
|
|
std::string genName;
|
|
const char* p = cmVS16GenName(name, genName);
|
|
if (!p) {
|
|
return std::unique_ptr<cmGlobalGenerator>();
|
|
}
|
|
if (!*p) {
|
|
return std::unique_ptr<cmGlobalGenerator>(
|
|
new cmGlobalVisualStudioVersionedGenerator(
|
|
cmGlobalVisualStudioGenerator::VS16, cm, genName, ""));
|
|
}
|
|
return std::unique_ptr<cmGlobalGenerator>();
|
|
}
|
|
|
|
void GetDocumentation(cmDocumentationEntry& entry) const override
|
|
{
|
|
entry.Name = std::string(vs16generatorName);
|
|
entry.Brief = "Generates Visual Studio 2019 project files. "
|
|
"Use -A option to specify architecture.";
|
|
}
|
|
|
|
std::vector<std::string> GetGeneratorNames() const override
|
|
{
|
|
std::vector<std::string> names;
|
|
names.push_back(vs16generatorName);
|
|
return names;
|
|
}
|
|
|
|
std::vector<std::string> GetGeneratorNamesWithPlatform() const override
|
|
{
|
|
return std::vector<std::string>();
|
|
}
|
|
|
|
bool SupportsToolset() const override { return true; }
|
|
bool SupportsPlatform() const override { return true; }
|
|
|
|
std::vector<std::string> GetKnownPlatforms() const override
|
|
{
|
|
std::vector<std::string> platforms;
|
|
platforms.emplace_back("x64");
|
|
platforms.emplace_back("Win32");
|
|
platforms.emplace_back("ARM");
|
|
platforms.emplace_back("ARM64");
|
|
platforms.emplace_back("ARM64EC");
|
|
return platforms;
|
|
}
|
|
|
|
std::string GetDefaultPlatformName() const override
|
|
{
|
|
return VSHostPlatformName();
|
|
}
|
|
};
|
|
|
|
std::unique_ptr<cmGlobalGeneratorFactory>
|
|
cmGlobalVisualStudioVersionedGenerator::NewFactory16()
|
|
{
|
|
return std::unique_ptr<cmGlobalGeneratorFactory>(new Factory16);
|
|
}
|
|
|
|
class cmGlobalVisualStudioVersionedGenerator::Factory17
|
|
: public cmGlobalGeneratorFactory
|
|
{
|
|
public:
|
|
std::unique_ptr<cmGlobalGenerator> CreateGlobalGenerator(
|
|
const std::string& name, bool /*allowArch*/, cmake* cm) const override
|
|
{
|
|
std::string genName;
|
|
const char* p = cmVS17GenName(name, genName);
|
|
if (!p) {
|
|
return std::unique_ptr<cmGlobalGenerator>();
|
|
}
|
|
if (!*p) {
|
|
return std::unique_ptr<cmGlobalGenerator>(
|
|
new cmGlobalVisualStudioVersionedGenerator(
|
|
cmGlobalVisualStudioGenerator::VS17, cm, genName, ""));
|
|
}
|
|
return std::unique_ptr<cmGlobalGenerator>();
|
|
}
|
|
|
|
void GetDocumentation(cmDocumentationEntry& entry) const override
|
|
{
|
|
entry.Name = std::string(vs17generatorName);
|
|
entry.Brief = "Generates Visual Studio 2022 project files. "
|
|
"Use -A option to specify architecture.";
|
|
}
|
|
|
|
std::vector<std::string> GetGeneratorNames() const override
|
|
{
|
|
std::vector<std::string> names;
|
|
names.push_back(vs17generatorName);
|
|
return names;
|
|
}
|
|
|
|
std::vector<std::string> GetGeneratorNamesWithPlatform() const override
|
|
{
|
|
return std::vector<std::string>();
|
|
}
|
|
|
|
bool SupportsToolset() const override { return true; }
|
|
bool SupportsPlatform() const override { return true; }
|
|
|
|
std::vector<std::string> GetKnownPlatforms() const override
|
|
{
|
|
std::vector<std::string> platforms;
|
|
platforms.emplace_back("x64");
|
|
platforms.emplace_back("Win32");
|
|
platforms.emplace_back("ARM");
|
|
platforms.emplace_back("ARM64");
|
|
platforms.emplace_back("ARM64EC");
|
|
return platforms;
|
|
}
|
|
|
|
std::string GetDefaultPlatformName() const override
|
|
{
|
|
return VSHostPlatformName();
|
|
}
|
|
};
|
|
|
|
std::unique_ptr<cmGlobalGeneratorFactory>
|
|
cmGlobalVisualStudioVersionedGenerator::NewFactory17()
|
|
{
|
|
return std::unique_ptr<cmGlobalGeneratorFactory>(new Factory17);
|
|
}
|
|
|
|
cmGlobalVisualStudioVersionedGenerator::cmGlobalVisualStudioVersionedGenerator(
|
|
VSVersion version, cmake* cm, const std::string& name,
|
|
std::string const& platformInGeneratorName)
|
|
: cmGlobalVisualStudio14Generator(cm, name, platformInGeneratorName)
|
|
, vsSetupAPIHelper(VSVersionToMajor(version))
|
|
{
|
|
this->Version = version;
|
|
this->ExpressEdition = false;
|
|
this->DefaultPlatformToolset = VSVersionToToolset(this->Version);
|
|
this->DefaultAndroidToolset = VSVersionToAndroidToolset(this->Version);
|
|
this->DefaultCLFlagTableName = VSVersionToToolset(this->Version);
|
|
this->DefaultCSharpFlagTableName = VSVersionToToolset(this->Version);
|
|
this->DefaultLinkFlagTableName = VSVersionToToolset(this->Version);
|
|
if (this->Version >= cmGlobalVisualStudioGenerator::VS16) {
|
|
this->DefaultPlatformName = VSHostPlatformName();
|
|
this->DefaultPlatformToolsetHostArchitecture = VSHostArchitecture();
|
|
}
|
|
}
|
|
|
|
bool cmGlobalVisualStudioVersionedGenerator::MatchesGeneratorName(
|
|
const std::string& name) const
|
|
{
|
|
std::string genName;
|
|
switch (this->Version) {
|
|
case cmGlobalVisualStudioGenerator::VS9:
|
|
case cmGlobalVisualStudioGenerator::VS10:
|
|
case cmGlobalVisualStudioGenerator::VS11:
|
|
case cmGlobalVisualStudioGenerator::VS12:
|
|
case cmGlobalVisualStudioGenerator::VS14:
|
|
break;
|
|
case cmGlobalVisualStudioGenerator::VS15:
|
|
if (cmVS15GenName(name, genName)) {
|
|
return genName == this->GetName();
|
|
}
|
|
break;
|
|
case cmGlobalVisualStudioGenerator::VS16:
|
|
if (cmVS16GenName(name, genName)) {
|
|
return genName == this->GetName();
|
|
}
|
|
break;
|
|
case cmGlobalVisualStudioGenerator::VS17:
|
|
if (cmVS17GenName(name, genName)) {
|
|
return genName == this->GetName();
|
|
}
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool cmGlobalVisualStudioVersionedGenerator::SetGeneratorInstance(
|
|
std::string const& i, cmMakefile* mf)
|
|
{
|
|
if (this->LastGeneratorInstanceString &&
|
|
i == *(this->LastGeneratorInstanceString)) {
|
|
return true;
|
|
}
|
|
|
|
if (!this->ParseGeneratorInstance(i, mf)) {
|
|
return false;
|
|
}
|
|
|
|
if (!this->GeneratorInstanceVersion.empty()) {
|
|
std::string const majorStr = VSVersionToMajorString(this->Version);
|
|
cmsys::RegularExpression versionRegex(
|
|
cmStrCat("^", majorStr, "\\.[0-9]+\\.[0-9]+\\.[0-9]+$"));
|
|
if (!versionRegex.find(this->GeneratorInstanceVersion)) {
|
|
std::ostringstream e;
|
|
/* clang-format off */
|
|
e <<
|
|
"Generator\n"
|
|
" " << this->GetName() << "\n"
|
|
"given instance specification\n"
|
|
" " << i << "\n"
|
|
"but the version field is not 4 integer components"
|
|
" starting in " << majorStr << "."
|
|
;
|
|
/* clang-format on */
|
|
mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
|
|
return false;
|
|
}
|
|
}
|
|
|
|
std::string vsInstance;
|
|
if (!i.empty()) {
|
|
vsInstance = i;
|
|
if (!this->vsSetupAPIHelper.SetVSInstance(
|
|
this->GeneratorInstance, this->GeneratorInstanceVersion)) {
|
|
std::ostringstream e;
|
|
/* clang-format off */
|
|
e <<
|
|
"Generator\n"
|
|
" " << this->GetName() << "\n"
|
|
"could not find specified instance of Visual Studio:\n"
|
|
" " << i;
|
|
/* clang-format on */
|
|
if (!this->GeneratorInstance.empty() &&
|
|
this->GeneratorInstanceVersion.empty() &&
|
|
cmSystemTools::FileIsDirectory(this->GeneratorInstance)) {
|
|
e << "\n"
|
|
"The directory exists, but the instance is not known to the "
|
|
"Visual Studio Installer, and no 'version=' field was given.";
|
|
}
|
|
mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
|
|
return false;
|
|
}
|
|
} else if (!this->vsSetupAPIHelper.GetVSInstanceInfo(vsInstance)) {
|
|
std::ostringstream e;
|
|
/* clang-format off */
|
|
e <<
|
|
"Generator\n"
|
|
" " << this->GetName() << "\n"
|
|
"could not find any instance of Visual Studio.\n";
|
|
/* clang-format on */
|
|
mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
|
|
return false;
|
|
}
|
|
|
|
// Save the selected instance persistently.
|
|
std::string genInstance = mf->GetSafeDefinition("CMAKE_GENERATOR_INSTANCE");
|
|
if (vsInstance != genInstance) {
|
|
this->CMakeInstance->AddCacheEntry("CMAKE_GENERATOR_INSTANCE", vsInstance,
|
|
"Generator instance identifier.",
|
|
cmStateEnums::INTERNAL);
|
|
}
|
|
|
|
// The selected instance may have a different MSBuild than previously found.
|
|
this->MSBuildCommandInitialized = false;
|
|
|
|
this->LastGeneratorInstanceString = i;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool cmGlobalVisualStudioVersionedGenerator::ParseGeneratorInstance(
|
|
std::string const& is, cmMakefile* mf)
|
|
{
|
|
this->GeneratorInstance.clear();
|
|
this->GeneratorInstanceVersion.clear();
|
|
|
|
std::vector<std::string> const fields = cmTokenize(is, ",");
|
|
std::vector<std::string>::const_iterator fi = fields.begin();
|
|
if (fi == fields.end()) {
|
|
return true;
|
|
}
|
|
|
|
// The first field may be the VS instance.
|
|
if (fi->find('=') == fi->npos) {
|
|
this->GeneratorInstance = *fi;
|
|
++fi;
|
|
}
|
|
|
|
std::set<std::string> handled;
|
|
|
|
// The rest of the fields must be key=value pairs.
|
|
for (; fi != fields.end(); ++fi) {
|
|
std::string::size_type pos = fi->find('=');
|
|
if (pos == fi->npos) {
|
|
std::ostringstream e;
|
|
/* clang-format off */
|
|
e <<
|
|
"Generator\n"
|
|
" " << this->GetName() << "\n"
|
|
"given instance specification\n"
|
|
" " << is << "\n"
|
|
"that contains a field after the first ',' with no '='."
|
|
;
|
|
/* clang-format on */
|
|
mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
|
|
return false;
|
|
}
|
|
std::string const key = fi->substr(0, pos);
|
|
std::string const value = fi->substr(pos + 1);
|
|
if (!handled.insert(key).second) {
|
|
std::ostringstream e;
|
|
/* clang-format off */
|
|
e <<
|
|
"Generator\n"
|
|
" " << this->GetName() << "\n"
|
|
"given instance specification\n"
|
|
" " << is << "\n"
|
|
"that contains duplicate field key '" << key << "'."
|
|
;
|
|
/* clang-format on */
|
|
mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
|
|
return false;
|
|
}
|
|
if (!this->ProcessGeneratorInstanceField(key, value)) {
|
|
std::ostringstream e;
|
|
/* clang-format off */
|
|
e <<
|
|
"Generator\n"
|
|
" " << this->GetName() << "\n"
|
|
"given instance specification\n"
|
|
" " << is << "\n"
|
|
"that contains invalid field '" << *fi << "'."
|
|
;
|
|
/* clang-format on */
|
|
mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool cmGlobalVisualStudioVersionedGenerator::ProcessGeneratorInstanceField(
|
|
std::string const& key, std::string const& value)
|
|
{
|
|
if (key == "version") {
|
|
this->GeneratorInstanceVersion = value;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool cmGlobalVisualStudioVersionedGenerator::GetVSInstance(
|
|
std::string& dir) const
|
|
{
|
|
return vsSetupAPIHelper.GetVSInstanceInfo(dir);
|
|
}
|
|
|
|
cm::optional<std::string>
|
|
cmGlobalVisualStudioVersionedGenerator::GetVSInstanceVersion() const
|
|
{
|
|
cm::optional<std::string> result;
|
|
std::string vsInstanceVersion;
|
|
if (vsSetupAPIHelper.GetVSInstanceVersion(vsInstanceVersion)) {
|
|
result = vsInstanceVersion;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
bool cmGlobalVisualStudioVersionedGenerator::IsStdOutEncodingSupported() const
|
|
{
|
|
// Supported from Visual Studio 16.7 Preview 3.
|
|
if (this->Version > cmGlobalVisualStudioGenerator::VSVersion::VS16) {
|
|
return true;
|
|
}
|
|
if (this->Version < cmGlobalVisualStudioGenerator::VSVersion::VS16) {
|
|
return false;
|
|
}
|
|
static std::string const vsVer16_7_P2 = "16.7.30128.36";
|
|
cm::optional<std::string> vsVer = this->GetVSInstanceVersion();
|
|
return (vsVer &&
|
|
cmSystemTools::VersionCompareGreaterEq(*vsVer, vsVer16_7_P2));
|
|
}
|
|
|
|
bool cmGlobalVisualStudioVersionedGenerator::IsUtf8EncodingSupported() const
|
|
{
|
|
// Supported from Visual Studio 16.10 Preview 2.
|
|
if (this->Version > cmGlobalVisualStudioGenerator::VSVersion::VS16) {
|
|
return true;
|
|
}
|
|
if (this->Version < cmGlobalVisualStudioGenerator::VSVersion::VS16) {
|
|
return false;
|
|
}
|
|
static std::string const vsVer16_10_P2 = "16.10.31213.239";
|
|
cm::optional<std::string> vsVer = this->GetVSInstanceVersion();
|
|
return (vsVer &&
|
|
cmSystemTools::VersionCompareGreaterEq(*vsVer, vsVer16_10_P2));
|
|
}
|
|
|
|
const char*
|
|
cmGlobalVisualStudioVersionedGenerator::GetAndroidApplicationTypeRevision()
|
|
const
|
|
{
|
|
switch (this->Version) {
|
|
case cmGlobalVisualStudioGenerator::VS9:
|
|
case cmGlobalVisualStudioGenerator::VS10:
|
|
case cmGlobalVisualStudioGenerator::VS11:
|
|
case cmGlobalVisualStudioGenerator::VS12:
|
|
return "";
|
|
case cmGlobalVisualStudioGenerator::VS14:
|
|
return "2.0";
|
|
case cmGlobalVisualStudioGenerator::VS15:
|
|
case cmGlobalVisualStudioGenerator::VS16:
|
|
case cmGlobalVisualStudioGenerator::VS17:
|
|
return "3.0";
|
|
}
|
|
return "";
|
|
}
|
|
|
|
cmGlobalVisualStudioVersionedGenerator::AuxToolset
|
|
cmGlobalVisualStudioVersionedGenerator::FindAuxToolset(
|
|
std::string& version, std::string& props) const
|
|
{
|
|
if (version.empty()) {
|
|
return AuxToolset::None;
|
|
}
|
|
|
|
std::string instancePath;
|
|
this->GetVSInstance(instancePath);
|
|
cmSystemTools::ConvertToUnixSlashes(instancePath);
|
|
|
|
// Translate three-component format accepted by "vcvarsall -vcvars_ver=".
|
|
cmsys::RegularExpression threeComponent(
|
|
"^([0-9]+\\.[0-9]+)\\.[0-9][0-9][0-9][0-9][0-9]$");
|
|
if (threeComponent.find(version)) {
|
|
// Load "VC/Auxiliary/Build/*/Microsoft.VCToolsVersion.*.txt" files
|
|
// with two matching components to check their three-component version.
|
|
std::string const& twoComponent = threeComponent.match(1);
|
|
std::string pattern =
|
|
cmStrCat(instancePath, "/VC/Auxiliary/Build/"_s, twoComponent,
|
|
"*/Microsoft.VCToolsVersion."_s, twoComponent, "*.txt"_s);
|
|
cmsys::Glob glob;
|
|
glob.SetRecurseThroughSymlinks(false);
|
|
if (glob.FindFiles(pattern)) {
|
|
for (std::string const& txt : glob.GetFiles()) {
|
|
std::string ver;
|
|
cmsys::ifstream fin(txt.c_str());
|
|
if (fin && std::getline(fin, ver)) {
|
|
// Strip trailing whitespace.
|
|
ver = ver.substr(0, ver.find_first_not_of("0123456789."));
|
|
// If the three-component version matches, translate it to
|
|
// that used by the "Microsoft.VCToolsVersion.*.txt" file name.
|
|
if (ver == version) {
|
|
cmsys::RegularExpression extractVersion(
|
|
"VCToolsVersion\\.([0-9.]+)\\.txt$");
|
|
if (extractVersion.find(txt)) {
|
|
version = extractVersion.match(1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (cmSystemTools::VersionCompareGreaterEq(version, "14.20")) {
|
|
props = cmStrCat(instancePath, "/VC/Auxiliary/Build."_s, version,
|
|
"/Microsoft.VCToolsVersion."_s, version, ".props"_s);
|
|
if (cmSystemTools::PathExists(props)) {
|
|
return AuxToolset::PropsExist;
|
|
}
|
|
}
|
|
props = cmStrCat(instancePath, "/VC/Auxiliary/Build/"_s, version,
|
|
"/Microsoft.VCToolsVersion."_s, version, ".props"_s);
|
|
if (cmSystemTools::PathExists(props)) {
|
|
return AuxToolset::PropsExist;
|
|
}
|
|
|
|
// Accept the toolset version that is default in the current VS version
|
|
// by matching the name later VS versions will use for the SxS props files.
|
|
std::string vcToolsetVersion;
|
|
if (this->vsSetupAPIHelper.GetVCToolsetVersion(vcToolsetVersion)) {
|
|
// Accept an exact-match (three-component version).
|
|
if (version == vcToolsetVersion) {
|
|
return AuxToolset::Default;
|
|
}
|
|
|
|
// Accept known SxS props file names using four version components
|
|
// in VS versions later than the current.
|
|
if (version == "14.28.16.9" && vcToolsetVersion == "14.28.29910") {
|
|
return AuxToolset::Default;
|
|
}
|
|
if (version == "14.29.16.10" && vcToolsetVersion == "14.29.30037") {
|
|
return AuxToolset::Default;
|
|
}
|
|
if (version == "14.29.16.11" && vcToolsetVersion == "14.29.30133") {
|
|
return AuxToolset::Default;
|
|
}
|
|
|
|
// The first two components of the default toolset version typically
|
|
// match the name used by later VS versions for the SxS props files.
|
|
cmsys::RegularExpression twoComponent("^([0-9]+\\.[0-9]+)");
|
|
if (twoComponent.find(version)) {
|
|
std::string const versionPrefix = cmStrCat(twoComponent.match(1), '.');
|
|
if (cmHasPrefix(vcToolsetVersion, versionPrefix)) {
|
|
return AuxToolset::Default;
|
|
}
|
|
}
|
|
}
|
|
|
|
return AuxToolset::PropsMissing;
|
|
}
|
|
|
|
bool cmGlobalVisualStudioVersionedGenerator::InitializeWindows(cmMakefile* mf)
|
|
{
|
|
// If the Win 8.1 SDK is installed then we can select a SDK matching
|
|
// the target Windows version.
|
|
if (this->IsWin81SDKInstalled()) {
|
|
// VS 2019 does not default to 8.1 so specify it explicitly when needed.
|
|
if (this->Version >= cmGlobalVisualStudioGenerator::VS16 &&
|
|
!cmSystemTools::VersionCompareGreater(this->SystemVersion, "8.1")) {
|
|
this->SetWindowsTargetPlatformVersion("8.1", mf);
|
|
return true;
|
|
}
|
|
return cmGlobalVisualStudio14Generator::InitializeWindows(mf);
|
|
}
|
|
// Otherwise we must choose a Win 10 SDK even if we are not targeting
|
|
// Windows 10.
|
|
return this->SelectWindows10SDK(mf, false);
|
|
}
|
|
|
|
bool cmGlobalVisualStudioVersionedGenerator::SelectWindowsStoreToolset(
|
|
std::string& toolset) const
|
|
{
|
|
if (cmHasLiteralPrefix(this->SystemVersion, "10.0")) {
|
|
if (this->IsWindowsStoreToolsetInstalled() &&
|
|
this->IsWindowsDesktopToolsetInstalled()) {
|
|
toolset = VSVersionToToolset(this->Version);
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
return this->cmGlobalVisualStudio14Generator::SelectWindowsStoreToolset(
|
|
toolset);
|
|
}
|
|
|
|
bool cmGlobalVisualStudioVersionedGenerator::IsWindowsDesktopToolsetInstalled()
|
|
const
|
|
{
|
|
return vsSetupAPIHelper.IsVSInstalled();
|
|
}
|
|
|
|
bool cmGlobalVisualStudioVersionedGenerator::IsWindowsStoreToolsetInstalled()
|
|
const
|
|
{
|
|
return vsSetupAPIHelper.IsWin10SDKInstalled();
|
|
}
|
|
|
|
bool cmGlobalVisualStudioVersionedGenerator::IsWin81SDKInstalled() const
|
|
{
|
|
// Does the VS installer tool know about one?
|
|
if (vsSetupAPIHelper.IsWin81SDKInstalled()) {
|
|
return true;
|
|
}
|
|
|
|
// Does the registry know about one (e.g. from VS 2015)?
|
|
std::string win81Root;
|
|
if (cmSystemTools::ReadRegistryValue(
|
|
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\"
|
|
"Windows Kits\\Installed Roots;KitsRoot81",
|
|
win81Root, cmSystemTools::KeyWOW64_32) ||
|
|
cmSystemTools::ReadRegistryValue(
|
|
"HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\"
|
|
"Windows Kits\\Installed Roots;KitsRoot81",
|
|
win81Root, cmSystemTools::KeyWOW64_32)) {
|
|
return cmSystemTools::FileExists(win81Root + "/include/um/windows.h",
|
|
true);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
std::string
|
|
cmGlobalVisualStudioVersionedGenerator::GetWindows10SDKMaxVersionDefault(
|
|
cmMakefile*) const
|
|
{
|
|
return std::string();
|
|
}
|
|
|
|
cm::optional<std::string>
|
|
cmGlobalVisualStudioVersionedGenerator::FindMSBuildCommandEarly(cmMakefile* mf)
|
|
{
|
|
std::string instance = mf->GetSafeDefinition("CMAKE_GENERATOR_INSTANCE");
|
|
if (!this->SetGeneratorInstance(instance, mf)) {
|
|
cmSystemTools::SetFatalErrorOccured();
|
|
return {};
|
|
}
|
|
return this->cmGlobalVisualStudio14Generator::FindMSBuildCommandEarly(mf);
|
|
}
|
|
|
|
std::string cmGlobalVisualStudioVersionedGenerator::FindMSBuildCommand()
|
|
{
|
|
std::string msbuild;
|
|
|
|
// Ask Visual Studio Installer tool.
|
|
std::string vs;
|
|
if (vsSetupAPIHelper.GetVSInstanceInfo(vs)) {
|
|
if (this->Version >= cmGlobalVisualStudioGenerator::VS17) {
|
|
msbuild = vs + "/MSBuild/Current/Bin/amd64/MSBuild.exe";
|
|
if (cmSystemTools::FileExists(msbuild)) {
|
|
return msbuild;
|
|
}
|
|
}
|
|
msbuild = vs + "/MSBuild/Current/Bin/MSBuild.exe";
|
|
if (cmSystemTools::FileExists(msbuild)) {
|
|
return msbuild;
|
|
}
|
|
msbuild = vs + "/MSBuild/15.0/Bin/MSBuild.exe";
|
|
if (cmSystemTools::FileExists(msbuild)) {
|
|
return msbuild;
|
|
}
|
|
}
|
|
|
|
msbuild = "MSBuild.exe";
|
|
return msbuild;
|
|
}
|
|
|
|
std::string cmGlobalVisualStudioVersionedGenerator::FindDevEnvCommand()
|
|
{
|
|
std::string devenv;
|
|
|
|
// Ask Visual Studio Installer tool.
|
|
std::string vs;
|
|
if (vsSetupAPIHelper.GetVSInstanceInfo(vs)) {
|
|
devenv = vs + "/Common7/IDE/devenv.com";
|
|
if (cmSystemTools::FileExists(devenv)) {
|
|
return devenv;
|
|
}
|
|
}
|
|
|
|
devenv = "devenv.com";
|
|
return devenv;
|
|
}
|