diff options
author | Brad King <brad.king@kitware.com> | 2021-11-01 20:24:36 (GMT) |
---|---|---|
committer | Kitware Robot <kwrobot@kitware.com> | 2021-11-01 20:24:54 (GMT) |
commit | e06f186c2048b102ff9f822f3e972b9ca5bfa2c3 (patch) | |
tree | 193c87089fe359eb7c4623d710be369f2b898344 | |
parent | dac334e35c0a47f9de5958554631954257bdb9fb (diff) | |
parent | 195d47e2139171cbae18a7164daac1f59be54ebe (diff) | |
download | CMake-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
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!") |