VS: Support version specification in CMAKE_GENERATOR_INSTANCE

This commit is contained in:
Brad King
2021-10-26 15:22:41 -04:00
parent 8e6d930e8c
commit ec8d37b3b1
22 changed files with 168 additions and 12 deletions

View File

@@ -37,7 +37,12 @@ of the VS installation.
The ``key=value`` pairs form a comma-separated list of options to
specify details of the instance selection.
There are no supported pairs: this syntax is reserved for future use.
Supported pairs are:
``version=<major>.<minor>.<MMMDD>.<BBB>``
.. versionadded:: 3.23
Specify the 4-component VS Build Version.
If the value of ``CMAKE_GENERATOR_INSTANCE`` is not specified explicitly
by the user or a toolchain file, CMake queries the Visual Studio Installer

View File

@@ -6,6 +6,7 @@
#include "cmsys/FStream.hxx"
#include "cmsys/Glob.hxx"
#include "cmsys/RegularExpression.hxx"
#include "cmAlgorithms.h"
#include "cmDocumentationEntry.h"
@@ -109,6 +110,30 @@ static const char* VSVersionToToolset(
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)
{
@@ -445,8 +470,32 @@ bool cmGlobalVisualStudioVersionedGenerator::SetGeneratorInstance(
return false;
}
if (!this->GeneratorInstance.empty()) {
if (!this->vsSetupAPIHelper.SetVSInstance(this->GeneratorInstance)) {
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 <<
@@ -455,13 +504,17 @@ bool cmGlobalVisualStudioVersionedGenerator::SetGeneratorInstance(
"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.";
}
mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
return false;
}
}
std::string vsInstance;
if (!this->vsSetupAPIHelper.GetVSInstanceInfo(vsInstance)) {
} else if (!this->vsSetupAPIHelper.GetVSInstanceInfo(vsInstance)) {
std::ostringstream e;
/* clang-format off */
e <<
@@ -493,6 +546,7 @@ 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();
@@ -563,8 +617,10 @@ bool cmGlobalVisualStudioVersionedGenerator::ParseGeneratorInstance(
bool cmGlobalVisualStudioVersionedGenerator::ProcessGeneratorInstanceField(
std::string const& key, std::string const& value)
{
static_cast<void>(key);
static_cast<void>(value);
if (key == "version") {
this->GeneratorInstanceVersion = value;
return true;
}
return false;
}

View File

@@ -83,5 +83,6 @@ private:
bool ParseGeneratorInstance(std::string const& is, cmMakefile* mf);
std::string GeneratorInstance;
std::string GeneratorInstanceVersion;
cm::optional<std::string> LastGeneratorInstanceString;
};

View File

@@ -102,10 +102,12 @@ cmVSSetupAPIHelper::~cmVSSetupAPIHelper()
CoUninitialize();
}
bool cmVSSetupAPIHelper::SetVSInstance(std::string const& vsInstallLocation)
bool cmVSSetupAPIHelper::SetVSInstance(std::string const& vsInstallLocation,
std::string const& vsInstallVersion)
{
this->SpecifiedVSInstallLocation = vsInstallLocation;
cmSystemTools::ConvertToUnixSlashes(this->SpecifiedVSInstallLocation);
this->SpecifiedVSInstallVersion = vsInstallVersion;
chosenInstanceInfo = VSInstanceInfo();
return this->EnumerateAndChooseVSInstance();
}
@@ -366,6 +368,15 @@ bool cmVSSetupAPIHelper::EnumerateAndChooseVSInstance()
std::string currentVSLocation = instanceInfo.GetInstallLocation();
if (cmSystemTools::ComparePath(currentVSLocation,
this->SpecifiedVSInstallLocation)) {
if (this->SpecifiedVSInstallVersion.empty() ||
instanceInfo.Version == this->SpecifiedVSInstallVersion) {
chosenInstanceInfo = instanceInfo;
return true;
}
}
} else if (!this->SpecifiedVSInstallVersion.empty()) {
// We are looking for a specific version.
if (instanceInfo.Version == this->SpecifiedVSInstallVersion) {
chosenInstanceInfo = instanceInfo;
return true;
}

View File

@@ -99,7 +99,8 @@ public:
cmVSSetupAPIHelper(unsigned int version);
~cmVSSetupAPIHelper();
bool SetVSInstance(std::string const& vsInstallLocation);
bool SetVSInstance(std::string const& vsInstallLocation,
std::string const& vsInstallVersion);
bool IsVSInstalled();
bool GetVSInstanceInfo(std::string& vsInstallLocation);
@@ -132,4 +133,5 @@ private:
bool IsEWDKEnabled();
std::string SpecifiedVSInstallLocation;
std::string SpecifiedVSInstallVersion;
};

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,11 @@
^CMake Error at CMakeLists.txt:[0-9]+ \(project\):
Generator
Visual Studio [^
]+
given instance specification
Test Instance,version=1\.2\.3\.4,version=1\.2\.3\.4
that contains duplicate field key 'version'\.$

View File

@@ -0,0 +1 @@
message(FATAL_ERROR "This should not be reached!")

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,11 @@
^CMake Error at CMakeLists.txt:[0-9]+ \(project\):
Generator
Visual Studio [^
]+
given instance specification
version=1\.2\.3
but the version field is not 4 integer components starting in [0-9]+\.$

View File

@@ -0,0 +1 @@
message(FATAL_ERROR "This should not be reached!")

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,11 @@
^CMake Error at CMakeLists.txt:[0-9]+ \(project\):
Generator
Visual Studio [^
]+
given instance specification
version=1\.2\.3\.x
but the version field is not 4 integer components starting in [0-9]+\.$

View File

@@ -0,0 +1 @@
message(FATAL_ERROR "This should not be reached!")

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,9 @@
^CMake Error at CMakeLists.txt:[0-9] \(project\):
Generator
Visual Studio [^
]+
could not find specified instance of Visual Studio:
version=[0-9]+\.999\.99999\.999$

View File

@@ -0,0 +1 @@
message(FATAL_ERROR "This should not be reached!")

View File

@@ -11,3 +11,4 @@ elseif(NOT IS_DIRECTORY "${CMAKE_GENERATOR_INSTANCE}")
" ${CMAKE_GENERATOR_INSTANCE}\n"
"which is not an existing directory.")
endif()
file(WRITE "${CMAKE_BINARY_DIR}/instance.txt" "${CMAKE_GENERATOR_INSTANCE}")

View File

@@ -1,8 +1,14 @@
include(RunCMake)
if("${RunCMake_GENERATOR}" MATCHES "^Visual Studio 1[56789]")
if("${RunCMake_GENERATOR}" MATCHES "^Visual Studio (1[56789])")
set(vs_major "${CMAKE_MATCH_1}")
set(RunCMake_GENERATOR_INSTANCE "")
run_cmake(DefaultInstance)
set(instance_txt "${RunCMake_BINARY_DIR}/DefaultInstance-build/instance.txt")
if(EXISTS "${instance_txt}")
file(READ "${instance_txt}" default_instance)
endif()
set(RunCMake_GENERATOR_INSTANCE "${RunCMake_SOURCE_DIR}/instance_does_not_exist")
run_cmake(MissingInstance)
@@ -14,6 +20,18 @@ if("${RunCMake_GENERATOR}" MATCHES "^Visual Studio 1[56789]")
run_cmake(BadFieldNoComma)
set(RunCMake_GENERATOR_INSTANCE "Test Instance,unknown=")
run_cmake(BadFieldUnknown)
set(RunCMake_GENERATOR_INSTANCE "Test Instance,version=1.2.3.4,version=1.2.3.4")
run_cmake(BadFieldDuplicate)
set(RunCMake_GENERATOR_INSTANCE "version=1.2.3")
run_cmake(BadVersionFormat1)
set(RunCMake_GENERATOR_INSTANCE "version=1.2.3.x")
run_cmake(BadVersionFormat2)
set(RunCMake_GENERATOR_INSTANCE "version=${vs_major}.999.99999.999")
run_cmake(BadVersionNumber)
if(IS_DIRECTORY "${default_instance}")
set(RunCMake_GENERATOR_INSTANCE "${default_instance},version=${vs_major}.999.99999.999")
run_cmake(WrongVersion)
endif()
else()
set(RunCMake_GENERATOR_INSTANCE "")
run_cmake(NoInstance)

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,10 @@
^CMake Error at CMakeLists.txt:[0-9] \(project\):
Generator
Visual Studio [^
]+
could not find specified instance of Visual Studio:
[^,
]+,version=[0-9]+\.999\.99999\.999$

View File

@@ -0,0 +1 @@
message(FATAL_ERROR "This should not be reached!")