From ec8d37b3b1ca10535e219b37cf4889d59b1dfedb Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 26 Oct 2021 15:22:41 -0400 Subject: VS: Support version specification in CMAKE_GENERATOR_INSTANCE --- Help/variable/CMAKE_GENERATOR_INSTANCE.rst | 7 ++- Source/cmGlobalVisualStudioVersionedGenerator.cxx | 70 +++++++++++++++++++--- Source/cmGlobalVisualStudioVersionedGenerator.h | 1 + Source/cmVSSetupHelper.cxx | 13 +++- Source/cmVSSetupHelper.h | 4 +- .../GeneratorInstance/BadFieldDuplicate-result.txt | 1 + .../GeneratorInstance/BadFieldDuplicate-stderr.txt | 11 ++++ .../GeneratorInstance/BadFieldDuplicate.cmake | 1 + .../GeneratorInstance/BadVersionFormat1-result.txt | 1 + .../GeneratorInstance/BadVersionFormat1-stderr.txt | 11 ++++ .../GeneratorInstance/BadVersionFormat1.cmake | 1 + .../GeneratorInstance/BadVersionFormat2-result.txt | 1 + .../GeneratorInstance/BadVersionFormat2-stderr.txt | 11 ++++ .../GeneratorInstance/BadVersionFormat2.cmake | 1 + .../GeneratorInstance/BadVersionNumber-result.txt | 1 + .../GeneratorInstance/BadVersionNumber-stderr.txt | 9 +++ .../GeneratorInstance/BadVersionNumber.cmake | 1 + .../GeneratorInstance/DefaultInstance.cmake | 1 + .../RunCMake/GeneratorInstance/RunCMakeTest.cmake | 20 ++++++- .../GeneratorInstance/WrongVersion-result.txt | 1 + .../GeneratorInstance/WrongVersion-stderr.txt | 10 ++++ .../RunCMake/GeneratorInstance/WrongVersion.cmake | 1 + 22 files changed, 167 insertions(+), 11 deletions(-) create mode 100644 Tests/RunCMake/GeneratorInstance/BadFieldDuplicate-result.txt create mode 100644 Tests/RunCMake/GeneratorInstance/BadFieldDuplicate-stderr.txt create mode 100644 Tests/RunCMake/GeneratorInstance/BadFieldDuplicate.cmake create mode 100644 Tests/RunCMake/GeneratorInstance/BadVersionFormat1-result.txt create mode 100644 Tests/RunCMake/GeneratorInstance/BadVersionFormat1-stderr.txt create mode 100644 Tests/RunCMake/GeneratorInstance/BadVersionFormat1.cmake create mode 100644 Tests/RunCMake/GeneratorInstance/BadVersionFormat2-result.txt create mode 100644 Tests/RunCMake/GeneratorInstance/BadVersionFormat2-stderr.txt create mode 100644 Tests/RunCMake/GeneratorInstance/BadVersionFormat2.cmake create mode 100644 Tests/RunCMake/GeneratorInstance/BadVersionNumber-result.txt create mode 100644 Tests/RunCMake/GeneratorInstance/BadVersionNumber-stderr.txt create mode 100644 Tests/RunCMake/GeneratorInstance/BadVersionNumber.cmake create mode 100644 Tests/RunCMake/GeneratorInstance/WrongVersion-result.txt create mode 100644 Tests/RunCMake/GeneratorInstance/WrongVersion-stderr.txt create mode 100644 Tests/RunCMake/GeneratorInstance/WrongVersion.cmake diff --git a/Help/variable/CMAKE_GENERATOR_INSTANCE.rst b/Help/variable/CMAKE_GENERATOR_INSTANCE.rst index 57dba538ba..3596bf6b94 100644 --- a/Help/variable/CMAKE_GENERATOR_INSTANCE.rst +++ b/Help/variable/CMAKE_GENERATOR_INSTANCE.rst @@ -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=...`` + .. 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 diff --git a/Source/cmGlobalVisualStudioVersionedGenerator.cxx b/Source/cmGlobalVisualStudioVersionedGenerator.cxx index 78bebacd2a..806871df48 100644 --- a/Source/cmGlobalVisualStudioVersionedGenerator.cxx +++ b/Source/cmGlobalVisualStudioVersionedGenerator.cxx @@ -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,15 +470,21 @@ 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" - "could not find specified instance of Visual Studio:\n" - " " << i; + "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; @@ -461,7 +492,29 @@ bool cmGlobalVisualStudioVersionedGenerator::SetGeneratorInstance( } std::string vsInstance; - if (!this->vsSetupAPIHelper.GetVSInstanceInfo(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."; + } + mf->IssueMessage(MessageType::FATAL_ERROR, e.str()); + return false; + } + } 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 const fields = cmTokenize(is, ","); std::vector::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(key); - static_cast(value); + if (key == "version") { + this->GeneratorInstanceVersion = value; + return true; + } return false; } diff --git a/Source/cmGlobalVisualStudioVersionedGenerator.h b/Source/cmGlobalVisualStudioVersionedGenerator.h index a19e506ef6..54c38d93ce 100644 --- a/Source/cmGlobalVisualStudioVersionedGenerator.h +++ b/Source/cmGlobalVisualStudioVersionedGenerator.h @@ -83,5 +83,6 @@ private: bool ParseGeneratorInstance(std::string const& is, cmMakefile* mf); std::string GeneratorInstance; + std::string GeneratorInstanceVersion; cm::optional LastGeneratorInstanceString; }; diff --git a/Source/cmVSSetupHelper.cxx b/Source/cmVSSetupHelper.cxx index b9443d642e..39ddce3069 100644 --- a/Source/cmVSSetupHelper.cxx +++ b/Source/cmVSSetupHelper.cxx @@ -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; } diff --git a/Source/cmVSSetupHelper.h b/Source/cmVSSetupHelper.h index ad242a55ca..d7e82d0be6 100644 --- a/Source/cmVSSetupHelper.h +++ b/Source/cmVSSetupHelper.h @@ -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; }; diff --git a/Tests/RunCMake/GeneratorInstance/BadFieldDuplicate-result.txt b/Tests/RunCMake/GeneratorInstance/BadFieldDuplicate-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/GeneratorInstance/BadFieldDuplicate-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GeneratorInstance/BadFieldDuplicate-stderr.txt b/Tests/RunCMake/GeneratorInstance/BadFieldDuplicate-stderr.txt new file mode 100644 index 0000000000..ef71404d0b --- /dev/null +++ b/Tests/RunCMake/GeneratorInstance/BadFieldDuplicate-stderr.txt @@ -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'\.$ diff --git a/Tests/RunCMake/GeneratorInstance/BadFieldDuplicate.cmake b/Tests/RunCMake/GeneratorInstance/BadFieldDuplicate.cmake new file mode 100644 index 0000000000..2fc38e5c59 --- /dev/null +++ b/Tests/RunCMake/GeneratorInstance/BadFieldDuplicate.cmake @@ -0,0 +1 @@ +message(FATAL_ERROR "This should not be reached!") diff --git a/Tests/RunCMake/GeneratorInstance/BadVersionFormat1-result.txt b/Tests/RunCMake/GeneratorInstance/BadVersionFormat1-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/GeneratorInstance/BadVersionFormat1-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GeneratorInstance/BadVersionFormat1-stderr.txt b/Tests/RunCMake/GeneratorInstance/BadVersionFormat1-stderr.txt new file mode 100644 index 0000000000..a0894b62ed --- /dev/null +++ b/Tests/RunCMake/GeneratorInstance/BadVersionFormat1-stderr.txt @@ -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]+\.$ diff --git a/Tests/RunCMake/GeneratorInstance/BadVersionFormat1.cmake b/Tests/RunCMake/GeneratorInstance/BadVersionFormat1.cmake new file mode 100644 index 0000000000..2fc38e5c59 --- /dev/null +++ b/Tests/RunCMake/GeneratorInstance/BadVersionFormat1.cmake @@ -0,0 +1 @@ +message(FATAL_ERROR "This should not be reached!") diff --git a/Tests/RunCMake/GeneratorInstance/BadVersionFormat2-result.txt b/Tests/RunCMake/GeneratorInstance/BadVersionFormat2-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/GeneratorInstance/BadVersionFormat2-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GeneratorInstance/BadVersionFormat2-stderr.txt b/Tests/RunCMake/GeneratorInstance/BadVersionFormat2-stderr.txt new file mode 100644 index 0000000000..2b3a23b5d3 --- /dev/null +++ b/Tests/RunCMake/GeneratorInstance/BadVersionFormat2-stderr.txt @@ -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]+\.$ diff --git a/Tests/RunCMake/GeneratorInstance/BadVersionFormat2.cmake b/Tests/RunCMake/GeneratorInstance/BadVersionFormat2.cmake new file mode 100644 index 0000000000..2fc38e5c59 --- /dev/null +++ b/Tests/RunCMake/GeneratorInstance/BadVersionFormat2.cmake @@ -0,0 +1 @@ +message(FATAL_ERROR "This should not be reached!") diff --git a/Tests/RunCMake/GeneratorInstance/BadVersionNumber-result.txt b/Tests/RunCMake/GeneratorInstance/BadVersionNumber-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/GeneratorInstance/BadVersionNumber-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GeneratorInstance/BadVersionNumber-stderr.txt b/Tests/RunCMake/GeneratorInstance/BadVersionNumber-stderr.txt new file mode 100644 index 0000000000..3a27341ec5 --- /dev/null +++ b/Tests/RunCMake/GeneratorInstance/BadVersionNumber-stderr.txt @@ -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$ diff --git a/Tests/RunCMake/GeneratorInstance/BadVersionNumber.cmake b/Tests/RunCMake/GeneratorInstance/BadVersionNumber.cmake new file mode 100644 index 0000000000..2fc38e5c59 --- /dev/null +++ b/Tests/RunCMake/GeneratorInstance/BadVersionNumber.cmake @@ -0,0 +1 @@ +message(FATAL_ERROR "This should not be reached!") diff --git a/Tests/RunCMake/GeneratorInstance/DefaultInstance.cmake b/Tests/RunCMake/GeneratorInstance/DefaultInstance.cmake index 7750c2e142..9761f0ccd9 100644 --- a/Tests/RunCMake/GeneratorInstance/DefaultInstance.cmake +++ b/Tests/RunCMake/GeneratorInstance/DefaultInstance.cmake @@ -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}") diff --git a/Tests/RunCMake/GeneratorInstance/RunCMakeTest.cmake b/Tests/RunCMake/GeneratorInstance/RunCMakeTest.cmake index 5eeac8edab..cdcaac8a3d 100644 --- a/Tests/RunCMake/GeneratorInstance/RunCMakeTest.cmake +++ b/Tests/RunCMake/GeneratorInstance/RunCMakeTest.cmake @@ -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) diff --git a/Tests/RunCMake/GeneratorInstance/WrongVersion-result.txt b/Tests/RunCMake/GeneratorInstance/WrongVersion-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/GeneratorInstance/WrongVersion-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GeneratorInstance/WrongVersion-stderr.txt b/Tests/RunCMake/GeneratorInstance/WrongVersion-stderr.txt new file mode 100644 index 0000000000..156a9ee5c0 --- /dev/null +++ b/Tests/RunCMake/GeneratorInstance/WrongVersion-stderr.txt @@ -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$ diff --git a/Tests/RunCMake/GeneratorInstance/WrongVersion.cmake b/Tests/RunCMake/GeneratorInstance/WrongVersion.cmake new file mode 100644 index 0000000000..2fc38e5c59 --- /dev/null +++ b/Tests/RunCMake/GeneratorInstance/WrongVersion.cmake @@ -0,0 +1 @@ +message(FATAL_ERROR "This should not be reached!") -- cgit v1.2.1