From 152f9978dde5ff085db28835c797827870978e9c Mon Sep 17 00:00:00 2001 From: Brad King Date: Fri, 29 Oct 2021 10:19:48 -0400 Subject: Help: De-duplicate VS instance selection documentation Add a section to `CMAKE_GENERATOR_INSTANCE` for VS instance selection, and reference it from the corresponding sections of each VS generator. --- Help/generator/Visual Studio 15 2017.rst | 14 ++------------ Help/generator/Visual Studio 16 2019.rst | 14 ++------------ Help/generator/Visual Studio 17 2022.rst | 14 ++------------ Help/variable/CMAKE_GENERATOR_INSTANCE.rst | 21 ++++++++++++++++----- 4 files changed, 22 insertions(+), 41 deletions(-) diff --git a/Help/generator/Visual Studio 15 2017.rst b/Help/generator/Visual Studio 15 2017.rst index b4d6f6d..912afad 100644 --- a/Help/generator/Visual Studio 15 2017.rst +++ b/Help/generator/Visual Studio 15 2017.rst @@ -17,18 +17,8 @@ Instance Selection .. versionadded:: 3.11 -VS 2017 supports multiple installations on the same machine. -The :variable:`CMAKE_GENERATOR_INSTANCE` variable may be set as a -cache entry containing the absolute path to a Visual Studio instance. -If the value is not specified explicitly by the user or a toolchain file, -CMake queries the Visual Studio Installer to locate VS instances, chooses -one, and sets the variable as a cache entry to hold the value persistently. - -When CMake first chooses an instance, if the ``VS150COMNTOOLS`` environment -variable is set and points to the ``Common7/Tools`` directory within -one of the instances, that instance will be used. Otherwise, if more -than one instance is installed we do not define which one is chosen -by default. +VS 2017 supports multiple installations on the same machine. The +:variable:`CMAKE_GENERATOR_INSTANCE` variable may be used to select one. Platform Selection ^^^^^^^^^^^^^^^^^^ diff --git a/Help/generator/Visual Studio 16 2019.rst b/Help/generator/Visual Studio 16 2019.rst index 72399e0..6cefe6d 100644 --- a/Help/generator/Visual Studio 16 2019.rst +++ b/Help/generator/Visual Studio 16 2019.rst @@ -15,18 +15,8 @@ Powershell, Python, etc.) are not supported. Instance Selection ^^^^^^^^^^^^^^^^^^ -VS 2019 supports multiple installations on the same machine. -The :variable:`CMAKE_GENERATOR_INSTANCE` variable may be set as a -cache entry containing the absolute path to a Visual Studio instance. -If the value is not specified explicitly by the user or a toolchain file, -CMake queries the Visual Studio Installer to locate VS instances, chooses -one, and sets the variable as a cache entry to hold the value persistently. - -When CMake first chooses an instance, if the ``VS160COMNTOOLS`` environment -variable is set and points to the ``Common7/Tools`` directory within -one of the instances, that instance will be used. Otherwise, if more -than one instance is installed we do not define which one is chosen -by default. +VS 2019 supports multiple installations on the same machine. The +:variable:`CMAKE_GENERATOR_INSTANCE` variable may be used to select one. Platform Selection ^^^^^^^^^^^^^^^^^^ diff --git a/Help/generator/Visual Studio 17 2022.rst b/Help/generator/Visual Studio 17 2022.rst index b3f49f3..edf9d60 100644 --- a/Help/generator/Visual Studio 17 2022.rst +++ b/Help/generator/Visual Studio 17 2022.rst @@ -15,18 +15,8 @@ Powershell, Python, etc.) are not supported. Instance Selection ^^^^^^^^^^^^^^^^^^ -VS 2022 supports multiple installations on the same machine. -The :variable:`CMAKE_GENERATOR_INSTANCE` variable may be set as a -cache entry containing the absolute path to a Visual Studio instance. -If the value is not specified explicitly by the user or a toolchain file, -CMake queries the Visual Studio Installer to locate VS instances, chooses -one, and sets the variable as a cache entry to hold the value persistently. - -When CMake first chooses an instance, if the ``VS170COMNTOOLS`` environment -variable is set and points to the ``Common7/Tools`` directory within -one of the instances, that instance will be used. Otherwise, if more -than one instance is installed we do not define which one is chosen -by default. +VS 2022 supports multiple installations on the same machine. The +:variable:`CMAKE_GENERATOR_INSTANCE` variable may be used to select one. Platform Selection ^^^^^^^^^^^^^^^^^^ diff --git a/Help/variable/CMAKE_GENERATOR_INSTANCE.rst b/Help/variable/CMAKE_GENERATOR_INSTANCE.rst index 5858d7a..5a76f09 100644 --- a/Help/variable/CMAKE_GENERATOR_INSTANCE.rst +++ b/Help/variable/CMAKE_GENERATOR_INSTANCE.rst @@ -18,10 +18,21 @@ variable may initialize ``CMAKE_GENERATOR_INSTANCE`` as a cache entry. Once a given build tree has been initialized with a particular value for this variable, changing the value has undefined behavior. -Instance specification is supported only on specific generators: +Instance specification is supported only on specific generators. -* For the :generator:`Visual Studio 15 2017` generator (and above) - this specifies the absolute path to the VS installation directory - of the selected VS instance. +Visual Studio Instance Selection +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -See native build system documentation for allowed instance values. +:ref:`Visual Studio Generators` support instance specification for +Visual Studio 2017 and above. The ``CMAKE_GENERATOR_INSTANCE`` variable +may be set as a cache entry selecting an instance of Visual Studio +via the absolute path to the top-level directory of the VS installation. + +If the value of ``CMAKE_GENERATOR_INSTANCE`` is not specified explicitly +by the user or a toolchain file, CMake queries the Visual Studio Installer +to locate VS instances, chooses one, and sets the variable as a cache entry +to hold the value persistently. If an environment variable of the form +``VS##0COMNTOOLS``, where ``##`` the Visual Studio major version number, +is set and points to the ``Common7/Tools`` directory within one of the +VS instances, that instance will be used. Otherwise, if more than one +VS instance is installed we do not define which one is chosen by default. -- cgit v0.12 From 3213e2595da3ce75af489a63f53b05c5560aa547 Mon Sep 17 00:00:00 2001 From: Brad King Date: Wed, 20 Oct 2021 13:47:16 -0400 Subject: cmVSSetupHelper: Drop unused ullVersion field The field has not been used since commit 3fd65f5ca6 (VS: Compare VS instance versions as strings, 2021-06-17, v3.21.0-rc1~11^2~1). --- Source/cmVSSetupHelper.cxx | 7 ------- Source/cmVSSetupHelper.h | 1 - 2 files changed, 8 deletions(-) diff --git a/Source/cmVSSetupHelper.cxx b/Source/cmVSSetupHelper.cxx index 969a2c2..1b67611 100644 --- a/Source/cmVSSetupHelper.cxx +++ b/Source/cmVSSetupHelper.cxx @@ -164,17 +164,11 @@ bool cmVSSetupAPIHelper::GetVSInstanceInfo( return false; } - ULONGLONG ullVersion = 0; SmartBSTR bstrVersion; if (FAILED(pInstance->GetInstallationVersion(&bstrVersion))) { return false; } else { vsInstanceInfo.Version = std::wstring(bstrVersion); - if (FAILED(setupHelper->ParseVersion(bstrVersion, &ullVersion))) { - vsInstanceInfo.ullVersion = 0; - } else { - vsInstanceInfo.ullVersion = ullVersion; - } } // Reboot may have been required before the installation path was created. @@ -316,7 +310,6 @@ bool cmVSSetupAPIHelper::EnumerateAndChooseVSInstance() chosenInstanceInfo.Version = std::wstring(envVSVersion.begin(), envVSVersion.end()); chosenInstanceInfo.VCToolsetVersion = envVSVersion; - chosenInstanceInfo.ullVersion = std::stoi(envVSVersion); chosenInstanceInfo.IsWin10SDKInstalled = true; chosenInstanceInfo.IsWin81SDKInstalled = !envWindowsSdkDir81.empty(); return true; diff --git a/Source/cmVSSetupHelper.h b/Source/cmVSSetupHelper.h index 61a3ac7..b2ba086 100644 --- a/Source/cmVSSetupHelper.h +++ b/Source/cmVSSetupHelper.h @@ -88,7 +88,6 @@ struct VSInstanceInfo std::wstring VSInstallLocation; std::wstring Version; std::string VCToolsetVersion; - ULONGLONG ullVersion = 0; // A.B.C.D = (A<<48)|(B<<32)|(C<<16)|D bool IsWin10SDKInstalled = false; bool IsWin81SDKInstalled = false; -- cgit v0.12 From f5dfc788b8bb455f7accc21a07d8a74f05651467 Mon Sep 17 00:00:00 2001 From: Brad King Date: Wed, 20 Oct 2021 13:50:08 -0400 Subject: cmVSSetupHelper: Drop unused InstanceId field Minimize the amount of information needed about a VS instance. --- Source/cmVSSetupHelper.cxx | 7 ------- Source/cmVSSetupHelper.h | 1 - 2 files changed, 8 deletions(-) diff --git a/Source/cmVSSetupHelper.cxx b/Source/cmVSSetupHelper.cxx index 1b67611..f1b22b9 100644 --- a/Source/cmVSSetupHelper.cxx +++ b/Source/cmVSSetupHelper.cxx @@ -152,13 +152,6 @@ bool cmVSSetupAPIHelper::GetVSInstanceInfo( if (pInstance == NULL) return false; - SmartBSTR bstrId; - if (SUCCEEDED(pInstance->GetInstanceId(&bstrId))) { - vsInstanceInfo.InstanceId = std::wstring(bstrId); - } else { - return false; - } - InstanceState state; if (FAILED(pInstance->GetState(&state))) { return false; diff --git a/Source/cmVSSetupHelper.h b/Source/cmVSSetupHelper.h index b2ba086..5a7daa2 100644 --- a/Source/cmVSSetupHelper.h +++ b/Source/cmVSSetupHelper.h @@ -84,7 +84,6 @@ private: struct VSInstanceInfo { - std::wstring InstanceId; std::wstring VSInstallLocation; std::wstring Version; std::string VCToolsetVersion; -- cgit v0.12 From 006fe1e919f3d326f9a8d749b59324b5512a0d87 Mon Sep 17 00:00:00 2001 From: Brad King Date: Thu, 21 Oct 2021 11:48:06 -0400 Subject: cmVSSetupHelper: Convert wide to narrow strings early --- Source/cmVSSetupHelper.cxx | 23 +++++++++++------------ Source/cmVSSetupHelper.h | 4 ++-- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/Source/cmVSSetupHelper.cxx b/Source/cmVSSetupHelper.cxx index f1b22b9..d0932ba 100644 --- a/Source/cmVSSetupHelper.cxx +++ b/Source/cmVSSetupHelper.cxx @@ -54,9 +54,7 @@ const WCHAR* ComponentType = L"Component"; std::string VSInstanceInfo::GetInstallLocation() const { - std::string loc = cmsys::Encoding::ToNarrow(this->VSInstallLocation); - cmSystemTools::ConvertToUnixSlashes(loc); - return loc; + return this->VSInstallLocation; } cmVSSetupAPIHelper::cmVSSetupAPIHelper(unsigned int version) @@ -161,7 +159,8 @@ bool cmVSSetupAPIHelper::GetVSInstanceInfo( if (FAILED(pInstance->GetInstallationVersion(&bstrVersion))) { return false; } else { - vsInstanceInfo.Version = std::wstring(bstrVersion); + vsInstanceInfo.Version = + cmsys::Encoding::ToNarrow(std::wstring(bstrVersion)); } // Reboot may have been required before the installation path was created. @@ -170,7 +169,9 @@ bool cmVSSetupAPIHelper::GetVSInstanceInfo( if (FAILED(pInstance->GetInstallationPath(&bstrInstallationPath))) { return false; } else { - vsInstanceInfo.VSInstallLocation = std::wstring(bstrInstallationPath); + vsInstanceInfo.VSInstallLocation = + cmsys::Encoding::ToNarrow(std::wstring(bstrInstallationPath)); + cmSystemTools::ConvertToUnixSlashes(vsInstanceInfo.VSInstallLocation); } } @@ -251,7 +252,7 @@ bool cmVSSetupAPIHelper::GetVSInstanceVersion(std::string& vsInstanceVersion) bool isInstalled = this->EnumerateAndChooseVSInstance(); if (isInstalled) { - vsInstanceVersion = cmsys::Encoding::ToNarrow(chosenInstanceInfo.Version); + vsInstanceVersion = chosenInstanceInfo.Version; } return isInstalled; @@ -285,7 +286,7 @@ bool cmVSSetupAPIHelper::IsEWDKEnabled() bool cmVSSetupAPIHelper::EnumerateAndChooseVSInstance() { bool isVSInstanceExists = false; - if (chosenInstanceInfo.VSInstallLocation.compare(L"") != 0) { + if (chosenInstanceInfo.VSInstallLocation.compare("") != 0) { return true; } @@ -298,10 +299,8 @@ bool cmVSSetupAPIHelper::EnumerateAndChooseVSInstance() if (envVSVersion.empty() || envVsInstallDir.empty()) return false; - chosenInstanceInfo.VSInstallLocation = - std::wstring(envVsInstallDir.begin(), envVsInstallDir.end()); - chosenInstanceInfo.Version = - std::wstring(envVSVersion.begin(), envVSVersion.end()); + chosenInstanceInfo.VSInstallLocation = envVsInstallDir; + chosenInstanceInfo.Version = envVSVersion; chosenInstanceInfo.VCToolsetVersion = envVSVersion; chosenInstanceInfo.IsWin10SDKInstalled = true; chosenInstanceInfo.IsWin81SDKInstalled = !envWindowsSdkDir81.empty(); @@ -329,7 +328,7 @@ bool cmVSSetupAPIHelper::EnumerateAndChooseVSInstance() return false; } - std::wstring const wantVersion = std::to_wstring(this->Version) + L'.'; + std::string const wantVersion = std::to_string(this->Version) + '.'; SmartCOMPtr instance; while (SUCCEEDED(enumInstances->Next(1, &instance, NULL)) && instance) { diff --git a/Source/cmVSSetupHelper.h b/Source/cmVSSetupHelper.h index 5a7daa2..ad242a5 100644 --- a/Source/cmVSSetupHelper.h +++ b/Source/cmVSSetupHelper.h @@ -84,8 +84,8 @@ private: struct VSInstanceInfo { - std::wstring VSInstallLocation; - std::wstring Version; + std::string VSInstallLocation; + std::string Version; std::string VCToolsetVersion; bool IsWin10SDKInstalled = false; bool IsWin81SDKInstalled = false; -- cgit v0.12 From 5d1f377737a9d1d14f4925072c46201d6b7b3c30 Mon Sep 17 00:00:00 2001 From: Brad King Date: Thu, 21 Oct 2021 11:54:19 -0400 Subject: cmVSSetupHelper: Factor out helper to load MSVC toolset version --- Source/cmVSSetupHelper.cxx | 42 ++++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/Source/cmVSSetupHelper.cxx b/Source/cmVSSetupHelper.cxx index d0932ba..b9443d6 100644 --- a/Source/cmVSSetupHelper.cxx +++ b/Source/cmVSSetupHelper.cxx @@ -46,12 +46,33 @@ const CLSID CLSID_SetupConfiguration = { /* clang-format on */ #endif +namespace { const WCHAR* Win10SDKComponent = L"Microsoft.VisualStudio.Component.Windows10SDK"; const WCHAR* Win81SDKComponent = L"Microsoft.VisualStudio.Component.Windows81SDK"; const WCHAR* ComponentType = L"Component"; +bool LoadVSInstanceVCToolsetVersion(VSInstanceInfo& vsInstanceInfo) +{ + std::string const vcRoot = vsInstanceInfo.GetInstallLocation(); + std::string vcToolsVersionFile = + vcRoot + "/VC/Auxiliary/Build/Microsoft.VCToolsVersion.default.txt"; + std::string vcToolsVersion; + cmsys::ifstream fin(vcToolsVersionFile.c_str()); + if (!fin || !cmSystemTools::GetLineFromStream(fin, vcToolsVersion)) { + return false; + } + vcToolsVersion = cmTrimWhitespace(vcToolsVersion); + std::string const vcToolsDir = vcRoot + "/VC/Tools/MSVC/" + vcToolsVersion; + if (!cmSystemTools::FileIsDirectory(vcToolsDir)) { + return false; + } + vsInstanceInfo.VCToolsetVersion = vcToolsVersion; + return true; +} +} + std::string VSInstanceInfo::GetInstallLocation() const { return this->VSInstallLocation; @@ -176,21 +197,8 @@ bool cmVSSetupAPIHelper::GetVSInstanceInfo( } // Check if a compiler is installed with this instance. - { - std::string const vcRoot = vsInstanceInfo.GetInstallLocation(); - std::string vcToolsVersionFile = - vcRoot + "/VC/Auxiliary/Build/Microsoft.VCToolsVersion.default.txt"; - std::string vcToolsVersion; - cmsys::ifstream fin(vcToolsVersionFile.c_str()); - if (!fin || !cmSystemTools::GetLineFromStream(fin, vcToolsVersion)) { - return false; - } - vcToolsVersion = cmTrimWhitespace(vcToolsVersion); - std::string const vcToolsDir = vcRoot + "/VC/Tools/MSVC/" + vcToolsVersion; - if (!cmSystemTools::FileIsDirectory(vcToolsDir)) { - return false; - } - vsInstanceInfo.VCToolsetVersion = vcToolsVersion; + if (!LoadVSInstanceVCToolsetVersion(vsInstanceInfo)) { + return false; } // Reboot may have been required before the product package was registered @@ -301,7 +309,9 @@ bool cmVSSetupAPIHelper::EnumerateAndChooseVSInstance() chosenInstanceInfo.VSInstallLocation = envVsInstallDir; chosenInstanceInfo.Version = envVSVersion; - chosenInstanceInfo.VCToolsetVersion = envVSVersion; + if (!LoadVSInstanceVCToolsetVersion(chosenInstanceInfo)) { + return false; + } chosenInstanceInfo.IsWin10SDKInstalled = true; chosenInstanceInfo.IsWin81SDKInstalled = !envWindowsSdkDir81.empty(); return true; -- cgit v0.12 From 8e6d930e8c3fb951e3c4388cc6a9a96dedcb412b Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 26 Oct 2021 15:13:53 -0400 Subject: VS: Parse comma-separated fields from CMAKE_GENERATOR_INSTANCE --- Help/variable/CMAKE_GENERATOR_INSTANCE.rst | 13 +++- Source/cmGlobalVisualStudioVersionedGenerator.cxx | 87 +++++++++++++++++++++- Source/cmGlobalVisualStudioVersionedGenerator.h | 7 ++ .../GeneratorInstance/BadFieldNoComma-result.txt | 1 + .../GeneratorInstance/BadFieldNoComma-stderr.txt | 11 +++ .../GeneratorInstance/BadFieldNoComma.cmake | 1 + .../GeneratorInstance/BadFieldUnknown-result.txt | 1 + .../GeneratorInstance/BadFieldUnknown-stderr.txt | 11 +++ .../GeneratorInstance/BadFieldUnknown.cmake | 1 + .../RunCMake/GeneratorInstance/RunCMakeTest.cmake | 5 ++ 10 files changed, 135 insertions(+), 3 deletions(-) create mode 100644 Tests/RunCMake/GeneratorInstance/BadFieldNoComma-result.txt create mode 100644 Tests/RunCMake/GeneratorInstance/BadFieldNoComma-stderr.txt create mode 100644 Tests/RunCMake/GeneratorInstance/BadFieldNoComma.cmake create mode 100644 Tests/RunCMake/GeneratorInstance/BadFieldUnknown-result.txt create mode 100644 Tests/RunCMake/GeneratorInstance/BadFieldUnknown-stderr.txt create mode 100644 Tests/RunCMake/GeneratorInstance/BadFieldUnknown.cmake diff --git a/Help/variable/CMAKE_GENERATOR_INSTANCE.rst b/Help/variable/CMAKE_GENERATOR_INSTANCE.rst index 5a76f09..57dba53 100644 --- a/Help/variable/CMAKE_GENERATOR_INSTANCE.rst +++ b/Help/variable/CMAKE_GENERATOR_INSTANCE.rst @@ -26,7 +26,18 @@ Visual Studio Instance Selection :ref:`Visual Studio Generators` support instance specification for Visual Studio 2017 and above. The ``CMAKE_GENERATOR_INSTANCE`` variable may be set as a cache entry selecting an instance of Visual Studio -via the absolute path to the top-level directory of the VS installation. +via one of the following forms: + +* ``location`` +* ``location[,key=value]*`` +* ``key=value[,key=value]*`` + +The ``location`` specifies the absolute path to the top-level directory +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. 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 f27b2c4..78bebac 100644 --- a/Source/cmGlobalVisualStudioVersionedGenerator.cxx +++ b/Source/cmGlobalVisualStudioVersionedGenerator.cxx @@ -441,8 +441,12 @@ bool cmGlobalVisualStudioVersionedGenerator::SetGeneratorInstance( return true; } - if (!i.empty()) { - if (!this->vsSetupAPIHelper.SetVSInstance(i)) { + if (!this->ParseGeneratorInstance(i, mf)) { + return false; + } + + if (!this->GeneratorInstance.empty()) { + if (!this->vsSetupAPIHelper.SetVSInstance(this->GeneratorInstance)) { std::ostringstream e; /* clang-format off */ e << @@ -485,6 +489,85 @@ bool cmGlobalVisualStudioVersionedGenerator::SetGeneratorInstance( return true; } +bool cmGlobalVisualStudioVersionedGenerator::ParseGeneratorInstance( + std::string const& is, cmMakefile* mf) +{ + this->GeneratorInstance.clear(); + + std::vector const fields = cmTokenize(is, ","); + std::vector::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 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) +{ + static_cast(key); + static_cast(value); + return false; +} + bool cmGlobalVisualStudioVersionedGenerator::GetVSInstance( std::string& dir) const { diff --git a/Source/cmGlobalVisualStudioVersionedGenerator.h b/Source/cmGlobalVisualStudioVersionedGenerator.h index 2aed65b..a19e506 100644 --- a/Source/cmGlobalVisualStudioVersionedGenerator.h +++ b/Source/cmGlobalVisualStudioVersionedGenerator.h @@ -65,6 +65,9 @@ protected: std::string GetWindows10SDKMaxVersionDefault(cmMakefile*) const override; + virtual bool ProcessGeneratorInstanceField(std::string const& key, + std::string const& value); + std::string FindMSBuildCommand() override; std::string FindDevEnvCommand() override; @@ -76,5 +79,9 @@ private: class Factory17; friend class Factory17; mutable cmVSSetupAPIHelper vsSetupAPIHelper; + + bool ParseGeneratorInstance(std::string const& is, cmMakefile* mf); + + std::string GeneratorInstance; cm::optional LastGeneratorInstanceString; }; diff --git a/Tests/RunCMake/GeneratorInstance/BadFieldNoComma-result.txt b/Tests/RunCMake/GeneratorInstance/BadFieldNoComma-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GeneratorInstance/BadFieldNoComma-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GeneratorInstance/BadFieldNoComma-stderr.txt b/Tests/RunCMake/GeneratorInstance/BadFieldNoComma-stderr.txt new file mode 100644 index 0000000..d6c73c8 --- /dev/null +++ b/Tests/RunCMake/GeneratorInstance/BadFieldNoComma-stderr.txt @@ -0,0 +1,11 @@ +^CMake Error at CMakeLists.txt:[0-9]+ \(project\): + Generator + + Visual Studio [^ +]+ + + given instance specification + + Test Instance,nocomma + + that contains a field after the first ',' with no '='\.$ diff --git a/Tests/RunCMake/GeneratorInstance/BadFieldNoComma.cmake b/Tests/RunCMake/GeneratorInstance/BadFieldNoComma.cmake new file mode 100644 index 0000000..2fc38e5 --- /dev/null +++ b/Tests/RunCMake/GeneratorInstance/BadFieldNoComma.cmake @@ -0,0 +1 @@ +message(FATAL_ERROR "This should not be reached!") diff --git a/Tests/RunCMake/GeneratorInstance/BadFieldUnknown-result.txt b/Tests/RunCMake/GeneratorInstance/BadFieldUnknown-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GeneratorInstance/BadFieldUnknown-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GeneratorInstance/BadFieldUnknown-stderr.txt b/Tests/RunCMake/GeneratorInstance/BadFieldUnknown-stderr.txt new file mode 100644 index 0000000..ecfe229 --- /dev/null +++ b/Tests/RunCMake/GeneratorInstance/BadFieldUnknown-stderr.txt @@ -0,0 +1,11 @@ +^CMake Error at CMakeLists.txt:[0-9]+ \(project\): + Generator + + Visual Studio [^ +]+ + + given instance specification + + Test Instance,unknown= + + that contains invalid field 'unknown='\.$ diff --git a/Tests/RunCMake/GeneratorInstance/BadFieldUnknown.cmake b/Tests/RunCMake/GeneratorInstance/BadFieldUnknown.cmake new file mode 100644 index 0000000..2fc38e5 --- /dev/null +++ b/Tests/RunCMake/GeneratorInstance/BadFieldUnknown.cmake @@ -0,0 +1 @@ +message(FATAL_ERROR "This should not be reached!") diff --git a/Tests/RunCMake/GeneratorInstance/RunCMakeTest.cmake b/Tests/RunCMake/GeneratorInstance/RunCMakeTest.cmake index e7f9ccb..5eeac8e 100644 --- a/Tests/RunCMake/GeneratorInstance/RunCMakeTest.cmake +++ b/Tests/RunCMake/GeneratorInstance/RunCMakeTest.cmake @@ -9,6 +9,11 @@ if("${RunCMake_GENERATOR}" MATCHES "^Visual Studio 1[56789]") set(RunCMake_TEST_OPTIONS -DCMAKE_TOOLCHAIN_FILE=${RunCMake_SOURCE_DIR}/MissingInstance-toolchain.cmake) run_cmake(MissingInstanceToolchain) unset(RunCMake_TEST_OPTIONS) + + set(RunCMake_GENERATOR_INSTANCE "Test Instance,nocomma") + run_cmake(BadFieldNoComma) + set(RunCMake_GENERATOR_INSTANCE "Test Instance,unknown=") + run_cmake(BadFieldUnknown) else() set(RunCMake_GENERATOR_INSTANCE "") run_cmake(NoInstance) -- cgit v0.12 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 57dba53..3596bf6 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 78bebac..806871d 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 a19e506..54c38d9 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 b9443d6..39ddce3 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 ad242a5..d7e82d0 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 0000000..d00491f --- /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 0000000..ef71404 --- /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 0000000..2fc38e5 --- /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 0000000..d00491f --- /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 0000000..a0894b6 --- /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 0000000..2fc38e5 --- /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 0000000..d00491f --- /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 0000000..2b3a23b --- /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 0000000..2fc38e5 --- /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 0000000..d00491f --- /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 0000000..3a27341 --- /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 0000000..2fc38e5 --- /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 7750c2e..9761f0c 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 5eeac8e..cdcaac8 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 0000000..d00491f --- /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 0000000..156a9ee --- /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 0000000..2fc38e5 --- /dev/null +++ b/Tests/RunCMake/GeneratorInstance/WrongVersion.cmake @@ -0,0 +1 @@ +message(FATAL_ERROR "This should not be reached!") -- cgit v0.12 From 195d47e2139171cbae18a7164daac1f59be54ebe Mon Sep 17 00:00:00 2001 From: Brad King Date: Thu, 21 Oct 2021 12:17:37 -0400 Subject: VS: Allow CMAKE_GENERATOR_INSTANCE to specify portable instance 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 --- Help/release/dev/vs-instance.rst | 6 ++++ Help/variable/CMAKE_GENERATOR_INSTANCE.rst | 6 ++++ Source/cmGlobalVisualStudioVersionedGenerator.cxx | 2 +- Source/cmVSSetupHelper.cxx | 38 ++++++++++++++++++++++ Source/cmVSSetupHelper.h | 1 + .../GeneratorInstance/PortableNoVersion-result.txt | 1 + .../GeneratorInstance/PortableNoVersion-stderr.txt | 13 ++++++++ .../GeneratorInstance/PortableNoVersion.cmake | 1 + .../RunCMake/GeneratorInstance/RunCMakeTest.cmake | 3 ++ 9 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 Help/release/dev/vs-instance.rst create mode 100644 Tests/RunCMake/GeneratorInstance/PortableNoVersion-result.txt create mode 100644 Tests/RunCMake/GeneratorInstance/PortableNoVersion-stderr.txt create mode 100644 Tests/RunCMake/GeneratorInstance/PortableNoVersion.cmake diff --git a/Help/release/dev/vs-instance.rst b/Help/release/dev/vs-instance.rst new file mode 100644 index 0000000..0b9ff4b --- /dev/null +++ b/Help/release/dev/vs-instance.rst @@ -0,0 +1,6 @@ +vs-instance +----------- + +* The :ref:`Visual Studio Generators` for VS 2017 and above learned to + use portable instances of Visual Studio not known to the VS installer. + See the :variable:`CMAKE_GENERATOR_INSTANCE` variable. diff --git a/Help/variable/CMAKE_GENERATOR_INSTANCE.rst b/Help/variable/CMAKE_GENERATOR_INSTANCE.rst index 3596bf6..6a35f17 100644 --- a/Help/variable/CMAKE_GENERATOR_INSTANCE.rst +++ b/Help/variable/CMAKE_GENERATOR_INSTANCE.rst @@ -44,6 +44,12 @@ Supported pairs are: Specify the 4-component VS Build Version. +.. versionadded:: 3.23 + + A portable VS instance may be specified that is not known to the + Visual Studio Installer tool. The ``location`` and ``version=`` + values must both be provided. + If the value of ``CMAKE_GENERATOR_INSTANCE`` is not specified explicitly by the user or a toolchain file, CMake queries the Visual Studio Installer to locate VS instances, chooses one, and sets the variable as a cache entry diff --git a/Source/cmGlobalVisualStudioVersionedGenerator.cxx b/Source/cmGlobalVisualStudioVersionedGenerator.cxx index 806871d..f2ce83e 100644 --- a/Source/cmGlobalVisualStudioVersionedGenerator.cxx +++ b/Source/cmGlobalVisualStudioVersionedGenerator.cxx @@ -509,7 +509,7 @@ bool cmGlobalVisualStudioVersionedGenerator::SetGeneratorInstance( cmSystemTools::FileIsDirectory(this->GeneratorInstance)) { e << "\n" "The directory exists, but the instance is not known to the " - "Visual Studio Installer."; + "Visual Studio Installer, and no 'version=' field was given."; } mf->IssueMessage(MessageType::FATAL_ERROR, e.str()); return false; diff --git a/Source/cmVSSetupHelper.cxx b/Source/cmVSSetupHelper.cxx index 39ddce3..cbd241b 100644 --- a/Source/cmVSSetupHelper.cxx +++ b/Source/cmVSSetupHelper.cxx @@ -2,6 +2,8 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmVSSetupHelper.h" +#include + #include "cmsys/Encoding.hxx" #include "cmsys/FStream.hxx" @@ -342,6 +344,8 @@ bool cmVSSetupAPIHelper::EnumerateAndChooseVSInstance() std::string const wantVersion = std::to_string(this->Version) + '.'; + bool specifiedLocationNotSpecifiedVersion = false; + SmartCOMPtr instance; while (SUCCEEDED(enumInstances->Next(1, &instance, NULL)) && instance) { SmartCOMPtr instance2 = NULL; @@ -373,6 +377,7 @@ bool cmVSSetupAPIHelper::EnumerateAndChooseVSInstance() chosenInstanceInfo = instanceInfo; return true; } + specifiedLocationNotSpecifiedVersion = true; } } else if (!this->SpecifiedVSInstallVersion.empty()) { // We are looking for a specific version. @@ -398,6 +403,13 @@ bool cmVSSetupAPIHelper::EnumerateAndChooseVSInstance() } } + if (!this->SpecifiedVSInstallLocation.empty() && + !specifiedLocationNotSpecifiedVersion) { + // The VS Installer does not know about the specified location. + // Check for one directly on disk. + return this->LoadSpecifiedVSInstanceFromDisk(); + } + if (vecVSInstances.size() > 0) { isVSInstanceExists = true; int index = ChooseVSInstance(vecVSInstances); @@ -460,6 +472,32 @@ int cmVSSetupAPIHelper::ChooseVSInstance( return chosenIndex; } +bool cmVSSetupAPIHelper::LoadSpecifiedVSInstanceFromDisk() +{ + if (!cmSystemTools::FileIsDirectory(this->SpecifiedVSInstallLocation)) { + return false; + } + VSInstanceInfo vsInstanceInfo; + vsInstanceInfo.VSInstallLocation = this->SpecifiedVSInstallLocation; + // FIXME: Is there a better way to get SDK information? + vsInstanceInfo.IsWin10SDKInstalled = true; + vsInstanceInfo.IsWin81SDKInstalled = false; + + if (!this->SpecifiedVSInstallVersion.empty()) { + // Assume the version specified by the user is correct. + vsInstanceInfo.Version = this->SpecifiedVSInstallVersion; + } else { + return false; + } + + if (!LoadVSInstanceVCToolsetVersion(vsInstanceInfo)) { + return false; + } + + chosenInstanceInfo = std::move(vsInstanceInfo); + return true; +} + bool cmVSSetupAPIHelper::Initialize() { if (initializationFailure) diff --git a/Source/cmVSSetupHelper.h b/Source/cmVSSetupHelper.h index d7e82d0..44c883b 100644 --- a/Source/cmVSSetupHelper.h +++ b/Source/cmVSSetupHelper.h @@ -117,6 +117,7 @@ private: bool& bWin10SDK, bool& bWin81SDK); int ChooseVSInstance(const std::vector& vecVSInstances); bool EnumerateAndChooseVSInstance(); + bool LoadSpecifiedVSInstanceFromDisk(); unsigned int Version; diff --git a/Tests/RunCMake/GeneratorInstance/PortableNoVersion-result.txt b/Tests/RunCMake/GeneratorInstance/PortableNoVersion-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GeneratorInstance/PortableNoVersion-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GeneratorInstance/PortableNoVersion-stderr.txt b/Tests/RunCMake/GeneratorInstance/PortableNoVersion-stderr.txt new file mode 100644 index 0000000..baa17aa --- /dev/null +++ b/Tests/RunCMake/GeneratorInstance/PortableNoVersion-stderr.txt @@ -0,0 +1,13 @@ +^CMake Error at CMakeLists.txt:[0-9]+ \(project\): + Generator + + Visual Studio [^ +]+ + + could not find specified instance of Visual Studio: + + [^ +]+/Tests/RunCMake/GeneratorInstance + + The directory exists, but the instance is not known to the Visual Studio + Installer, and no 'version=' field was given\.$ diff --git a/Tests/RunCMake/GeneratorInstance/PortableNoVersion.cmake b/Tests/RunCMake/GeneratorInstance/PortableNoVersion.cmake new file mode 100644 index 0000000..2fc38e5 --- /dev/null +++ b/Tests/RunCMake/GeneratorInstance/PortableNoVersion.cmake @@ -0,0 +1 @@ +message(FATAL_ERROR "This should not be reached!") diff --git a/Tests/RunCMake/GeneratorInstance/RunCMakeTest.cmake b/Tests/RunCMake/GeneratorInstance/RunCMakeTest.cmake index cdcaac8..dfcdcf8 100644 --- a/Tests/RunCMake/GeneratorInstance/RunCMakeTest.cmake +++ b/Tests/RunCMake/GeneratorInstance/RunCMakeTest.cmake @@ -32,6 +32,9 @@ if("${RunCMake_GENERATOR}" MATCHES "^Visual Studio (1[56789])") set(RunCMake_GENERATOR_INSTANCE "${default_instance},version=${vs_major}.999.99999.999") run_cmake(WrongVersion) endif() + + set(RunCMake_GENERATOR_INSTANCE "${RunCMake_SOURCE_DIR}") + run_cmake(PortableNoVersion) else() set(RunCMake_GENERATOR_INSTANCE "") run_cmake(NoInstance) -- cgit v0.12