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