summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2021-11-01 20:24:36 (GMT)
committerKitware Robot <kwrobot@kitware.com>2021-11-01 20:24:54 (GMT)
commite06f186c2048b102ff9f822f3e972b9ca5bfa2c3 (patch)
tree193c87089fe359eb7c4623d710be369f2b898344
parentdac334e35c0a47f9de5958554631954257bdb9fb (diff)
parent195d47e2139171cbae18a7164daac1f59be54ebe (diff)
downloadCMake-e06f186c2048b102ff9f822f3e972b9ca5bfa2c3.zip
CMake-e06f186c2048b102ff9f822f3e972b9ca5bfa2c3.tar.gz
CMake-e06f186c2048b102ff9f822f3e972b9ca5bfa2c3.tar.bz2
Merge topic 'vs-instance'
195d47e213 VS: Allow CMAKE_GENERATOR_INSTANCE to specify portable instance ec8d37b3b1 VS: Support version specification in CMAKE_GENERATOR_INSTANCE 8e6d930e8c VS: Parse comma-separated fields from CMAKE_GENERATOR_INSTANCE 5d1f377737 cmVSSetupHelper: Factor out helper to load MSVC toolset version 006fe1e919 cmVSSetupHelper: Convert wide to narrow strings early f5dfc788b8 cmVSSetupHelper: Drop unused InstanceId field 3213e2595d cmVSSetupHelper: Drop unused ullVersion field 152f9978dd Help: De-duplicate VS instance selection documentation Acked-by: Kitware Robot <kwrobot@kitware.com> Merge-request: !6651
-rw-r--r--Help/generator/Visual Studio 15 2017.rst14
-rw-r--r--Help/generator/Visual Studio 16 2019.rst14
-rw-r--r--Help/generator/Visual Studio 17 2022.rst14
-rw-r--r--Help/release/dev/vs-instance.rst6
-rw-r--r--Help/variable/CMAKE_GENERATOR_INSTANCE.rst43
-rw-r--r--Source/cmGlobalVisualStudioVersionedGenerator.cxx149
-rw-r--r--Source/cmGlobalVisualStudioVersionedGenerator.h8
-rw-r--r--Source/cmVSSetupHelper.cxx130
-rw-r--r--Source/cmVSSetupHelper.h11
-rw-r--r--Tests/RunCMake/GeneratorInstance/BadFieldDuplicate-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorInstance/BadFieldDuplicate-stderr.txt11
-rw-r--r--Tests/RunCMake/GeneratorInstance/BadFieldDuplicate.cmake1
-rw-r--r--Tests/RunCMake/GeneratorInstance/BadFieldNoComma-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorInstance/BadFieldNoComma-stderr.txt11
-rw-r--r--Tests/RunCMake/GeneratorInstance/BadFieldNoComma.cmake1
-rw-r--r--Tests/RunCMake/GeneratorInstance/BadFieldUnknown-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorInstance/BadFieldUnknown-stderr.txt11
-rw-r--r--Tests/RunCMake/GeneratorInstance/BadFieldUnknown.cmake1
-rw-r--r--Tests/RunCMake/GeneratorInstance/BadVersionFormat1-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorInstance/BadVersionFormat1-stderr.txt11
-rw-r--r--Tests/RunCMake/GeneratorInstance/BadVersionFormat1.cmake1
-rw-r--r--Tests/RunCMake/GeneratorInstance/BadVersionFormat2-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorInstance/BadVersionFormat2-stderr.txt11
-rw-r--r--Tests/RunCMake/GeneratorInstance/BadVersionFormat2.cmake1
-rw-r--r--Tests/RunCMake/GeneratorInstance/BadVersionNumber-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorInstance/BadVersionNumber-stderr.txt9
-rw-r--r--Tests/RunCMake/GeneratorInstance/BadVersionNumber.cmake1
-rw-r--r--Tests/RunCMake/GeneratorInstance/DefaultInstance.cmake1
-rw-r--r--Tests/RunCMake/GeneratorInstance/PortableNoVersion-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorInstance/PortableNoVersion-stderr.txt13
-rw-r--r--Tests/RunCMake/GeneratorInstance/PortableNoVersion.cmake1
-rw-r--r--Tests/RunCMake/GeneratorInstance/RunCMakeTest.cmake28
-rw-r--r--Tests/RunCMake/GeneratorInstance/WrongVersion-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorInstance/WrongVersion-stderr.txt10
-rw-r--r--Tests/RunCMake/GeneratorInstance/WrongVersion.cmake1
35 files changed, 426 insertions, 95 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/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 5858d7a..6a35f17 100644
--- a/Help/variable/CMAKE_GENERATOR_INSTANCE.rst
+++ b/Help/variable/CMAKE_GENERATOR_INSTANCE.rst
@@ -18,10 +18,43 @@ 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 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.
+Supported pairs are:
+
+``version=<major>.<minor>.<MMMDD>.<BBB>``
+ .. versionadded:: 3.23
+
+ 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
+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.
diff --git a/Source/cmGlobalVisualStudioVersionedGenerator.cxx b/Source/cmGlobalVisualStudioVersionedGenerator.cxx
index f27b2c4..f2ce83e 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)
{
@@ -441,15 +466,25 @@ bool cmGlobalVisualStudioVersionedGenerator::SetGeneratorInstance(
return true;
}
- if (!i.empty()) {
- if (!this->vsSetupAPIHelper.SetVSInstance(i)) {
+ if (!this->ParseGeneratorInstance(i, mf)) {
+ return false;
+ }
+
+ 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;
@@ -457,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, and no 'version=' field was given.";
+ }
+ mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return false;
+ }
+ } else if (!this->vsSetupAPIHelper.GetVSInstanceInfo(vsInstance)) {
std::ostringstream e;
/* clang-format off */
e <<
@@ -485,6 +542,88 @@ bool cmGlobalVisualStudioVersionedGenerator::SetGeneratorInstance(
return true;
}
+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();
+ 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<std::string> 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)
+{
+ if (key == "version") {
+ this->GeneratorInstanceVersion = value;
+ return true;
+ }
+ return false;
+}
+
bool cmGlobalVisualStudioVersionedGenerator::GetVSInstance(
std::string& dir) const
{
diff --git a/Source/cmGlobalVisualStudioVersionedGenerator.h b/Source/cmGlobalVisualStudioVersionedGenerator.h
index 2aed65b..54c38d9 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,10 @@ private:
class Factory17;
friend class Factory17;
mutable cmVSSetupAPIHelper vsSetupAPIHelper;
+
+ bool ParseGeneratorInstance(std::string const& is, cmMakefile* mf);
+
+ std::string GeneratorInstance;
+ std::string GeneratorInstanceVersion;
cm::optional<std::string> LastGeneratorInstanceString;
};
diff --git a/Source/cmVSSetupHelper.cxx b/Source/cmVSSetupHelper.cxx
index 969a2c2..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 <utility>
+
#include "cmsys/Encoding.hxx"
#include "cmsys/FStream.hxx"
@@ -46,17 +48,36 @@ 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
{
- std::string loc = cmsys::Encoding::ToNarrow(this->VSInstallLocation);
- cmSystemTools::ConvertToUnixSlashes(loc);
- return loc;
+ return this->VSInstallLocation;
}
cmVSSetupAPIHelper::cmVSSetupAPIHelper(unsigned int version)
@@ -83,10 +104,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();
}
@@ -152,29 +175,17 @@ 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;
}
- 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;
- }
+ vsInstanceInfo.Version =
+ cmsys::Encoding::ToNarrow(std::wstring(bstrVersion));
}
// Reboot may have been required before the installation path was created.
@@ -183,26 +194,15 @@ 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);
}
}
// 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
@@ -264,7 +264,7 @@ bool cmVSSetupAPIHelper::GetVSInstanceVersion(std::string& vsInstanceVersion)
bool isInstalled = this->EnumerateAndChooseVSInstance();
if (isInstalled) {
- vsInstanceVersion = cmsys::Encoding::ToNarrow(chosenInstanceInfo.Version);
+ vsInstanceVersion = chosenInstanceInfo.Version;
}
return isInstalled;
@@ -298,7 +298,7 @@ bool cmVSSetupAPIHelper::IsEWDKEnabled()
bool cmVSSetupAPIHelper::EnumerateAndChooseVSInstance()
{
bool isVSInstanceExists = false;
- if (chosenInstanceInfo.VSInstallLocation.compare(L"") != 0) {
+ if (chosenInstanceInfo.VSInstallLocation.compare("") != 0) {
return true;
}
@@ -311,12 +311,11 @@ 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.VCToolsetVersion = envVSVersion;
- chosenInstanceInfo.ullVersion = std::stoi(envVSVersion);
+ chosenInstanceInfo.VSInstallLocation = envVsInstallDir;
+ chosenInstanceInfo.Version = envVSVersion;
+ if (!LoadVSInstanceVCToolsetVersion(chosenInstanceInfo)) {
+ return false;
+ }
chosenInstanceInfo.IsWin10SDKInstalled = true;
chosenInstanceInfo.IsWin81SDKInstalled = !envWindowsSdkDir81.empty();
return true;
@@ -343,7 +342,9 @@ bool cmVSSetupAPIHelper::EnumerateAndChooseVSInstance()
return false;
}
- std::wstring const wantVersion = std::to_wstring(this->Version) + L'.';
+ std::string const wantVersion = std::to_string(this->Version) + '.';
+
+ bool specifiedLocationNotSpecifiedVersion = false;
SmartCOMPtr<ISetupInstance> instance;
while (SUCCEEDED(enumInstances->Next(1, &instance, NULL)) && instance) {
@@ -371,6 +372,16 @@ 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;
+ }
+ specifiedLocationNotSpecifiedVersion = true;
+ }
+ } else if (!this->SpecifiedVSInstallVersion.empty()) {
+ // We are looking for a specific version.
+ if (instanceInfo.Version == this->SpecifiedVSInstallVersion) {
chosenInstanceInfo = instanceInfo;
return true;
}
@@ -392,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);
@@ -454,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 61a3ac7..44c883b 100644
--- a/Source/cmVSSetupHelper.h
+++ b/Source/cmVSSetupHelper.h
@@ -84,11 +84,9 @@ private:
struct VSInstanceInfo
{
- std::wstring InstanceId;
- std::wstring VSInstallLocation;
- std::wstring Version;
+ std::string VSInstallLocation;
+ std::string Version;
std::string VCToolsetVersion;
- ULONGLONG ullVersion = 0; // A.B.C.D = (A<<48)|(B<<32)|(C<<16)|D
bool IsWin10SDKInstalled = false;
bool IsWin81SDKInstalled = false;
@@ -101,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);
@@ -118,6 +117,7 @@ private:
bool& bWin10SDK, bool& bWin81SDK);
int ChooseVSInstance(const std::vector<VSInstanceInfo>& vecVSInstances);
bool EnumerateAndChooseVSInstance();
+ bool LoadSpecifiedVSInstanceFromDisk();
unsigned int Version;
@@ -134,4 +134,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/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/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/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 e7f9ccb..dfcdcf8 100644
--- a/Tests/RunCMake/GeneratorInstance/RunCMakeTest.cmake
+++ b/Tests/RunCMake/GeneratorInstance/RunCMakeTest.cmake
@@ -1,14 +1,40 @@
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)
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)
+ 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()
+
+ set(RunCMake_GENERATOR_INSTANCE "${RunCMake_SOURCE_DIR}")
+ run_cmake(PortableNoVersion)
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!")