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
This commit is contained in:
Brad King
2021-10-21 12:17:37 -04:00
parent ec8d37b3b1
commit 195d47e213
9 changed files with 70 additions and 1 deletions

View File

@@ -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.

View File

@@ -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

View File

@@ -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;

View File

@@ -2,6 +2,8 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmVSSetupHelper.h"
#include <utility>
#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<ISetupInstance> instance;
while (SUCCEEDED(enumInstances->Next(1, &instance, NULL)) && instance) {
SmartCOMPtr<ISetupInstance2> 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)

View File

@@ -117,6 +117,7 @@ private:
bool& bWin10SDK, bool& bWin81SDK);
int ChooseVSInstance(const std::vector<VSInstanceInfo>& vecVSInstances);
bool EnumerateAndChooseVSInstance();
bool LoadSpecifiedVSInstanceFromDisk();
unsigned int Version;

View File

@@ -0,0 +1 @@
1

View File

@@ -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\.$

View File

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

View File

@@ -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)