| /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying | |
| file LICENSE.rst or https://cmake.org/licensing for details. */ | |
| #include "cmGlobalVisualStudio14Generator.h" | |
| #include <cstring> | |
| #include <cm/vector> | |
| #include <cmext/string_view> | |
| #include "cmGlobalGenerator.h" | |
| #include "cmGlobalVisualStudioGenerator.h" | |
| #include "cmMakefile.h" | |
| #include "cmMessageType.h" | |
| #include "cmPolicies.h" | |
| #include "cmStringAlgorithms.h" | |
| #include "cmSystemTools.h" | |
| #include "cmValue.h" | |
| cmGlobalVisualStudio14Generator::cmGlobalVisualStudio14Generator( | |
| cmake* cm, std::string const& name) | |
| : cmGlobalVisualStudio12Generator(cm, name) | |
| { | |
| } | |
| bool cmGlobalVisualStudio14Generator::InitializePlatformWindows(cmMakefile* mf) | |
| { | |
| // If a Windows SDK version is explicitly requested, search for it. | |
| if (this->GeneratorPlatformVersion) { | |
| std::string const& version = *this->GeneratorPlatformVersion; | |
| // VS 2019 and above support specifying plain "10.0". | |
| if (version == "10.0"_s) { | |
| if (this->Version >= VSVersion::VS16) { | |
| this->SetWindowsTargetPlatformVersion("10.0", mf); | |
| return true; | |
| } | |
| /* clang-format off */ | |
| mf->IssueMessage(MessageType::FATAL_ERROR, cmStrCat( | |
| "Generator\n" | |
| " ", this->GetName(), "\n" | |
| "given platform specification containing a\n" | |
| " version=10.0\n" | |
| "field. The value 10.0 is only supported by VS 2019 and above.\n" | |
| )); | |
| /* clang-format on */ | |
| return false; | |
| } | |
| if (cmHasLiteralPrefix(version, "10.0.")) { | |
| return this->SelectWindows10SDK(mf); | |
| } | |
| if (version == "8.1"_s) { | |
| if (this->IsWin81SDKInstalled()) { | |
| this->SetWindowsTargetPlatformVersion("8.1", mf); | |
| return true; | |
| } | |
| /* clang-format off */ | |
| mf->IssueMessage(MessageType::FATAL_ERROR, cmStrCat( | |
| "Generator\n" | |
| " ", this->GetName(), "\n" | |
| "given platform specification containing a\n" | |
| " version=8.1\n" | |
| "field, but the Windows 8.1 SDK is not installed.\n" | |
| )); | |
| /* clang-format on */ | |
| return false; | |
| } | |
| if (version.empty()) { | |
| /* clang-format off */ | |
| mf->IssueMessage(MessageType::FATAL_ERROR, cmStrCat( | |
| "Generator\n" | |
| " ", this->GetName(), "\n" | |
| "given platform specification with empty\n" | |
| " version=\n" | |
| "field.\n" | |
| )); | |
| /* clang-format on */ | |
| return false; | |
| } | |
| /* clang-format off */ | |
| mf->IssueMessage(MessageType::FATAL_ERROR, cmStrCat( | |
| "Generator\n" | |
| " ", this->GetName(), "\n" | |
| "given platform specification containing a\n" | |
| " version=", version, "\n" | |
| "field with unsupported value.\n" | |
| )); | |
| /* clang-format on */ | |
| return false; | |
| } | |
| // If we are targeting Windows 10+, we select a Windows 10 SDK. | |
| // If no Windows 8.1 SDK is installed, which is possible with VS 2017 and | |
| // higher, then we must choose a Windows 10 SDK anyway. | |
| if (cmHasLiteralPrefix(this->SystemVersion, "10.0") || | |
| !this->IsWin81SDKInstalled()) { | |
| return this->SelectWindows10SDK(mf); | |
| } | |
| // Under CMP0149 NEW behavior, we search for a Windows 10 SDK even | |
| // when targeting older Windows versions, but it is not required. | |
| if (mf->GetPolicyStatus(cmPolicies::CMP0149) == cmPolicies::NEW) { | |
| std::string const version = this->GetWindows10SDKVersion(mf); | |
| if (!version.empty()) { | |
| this->SetWindowsTargetPlatformVersion(version, mf); | |
| return true; | |
| } | |
| } | |
| // We are not targeting Windows 10+, so fall back to the Windows 8.1 SDK. | |
| // For VS 2019 and above we must explicitly specify it. | |
| if (this->Version >= cmGlobalVisualStudioGenerator::VSVersion::VS16 && | |
| !cmSystemTools::VersionCompareGreater(this->SystemVersion, "8.1")) { | |
| this->SetWindowsTargetPlatformVersion("8.1", mf); | |
| } | |
| return true; | |
| } | |
| bool cmGlobalVisualStudio14Generator::VerifyNoGeneratorPlatformVersion( | |
| cmMakefile* mf) const | |
| { | |
| if (!this->GeneratorPlatformVersion) { | |
| return true; | |
| } | |
| mf->IssueMessage( | |
| MessageType::FATAL_ERROR, | |
| cmStrCat("Generator\n" | |
| " ", | |
| this->GetName(), | |
| "\n" | |
| "given platform specification containing a\n" | |
| " version=", | |
| *this->GeneratorPlatformVersion, | |
| "\n" | |
| "field. The version field is not supported when targeting\n" | |
| " ", | |
| this->SystemName, ' ', this->SystemVersion, '\n')); | |
| return false; | |
| } | |
| bool cmGlobalVisualStudio14Generator::InitializeWindowsStore(cmMakefile* mf) | |
| { | |
| if (!this->SelectWindowsStoreToolset(this->DefaultPlatformToolset)) { | |
| std::string e; | |
| if (this->DefaultPlatformToolset.empty()) { | |
| e = cmStrCat(this->GetName(), | |
| " supports Windows Store '8.0', '8.1' and " | |
| "'10.0', but not '", | |
| this->SystemVersion, "'. Check CMAKE_SYSTEM_VERSION."); | |
| } else { | |
| e = cmStrCat( | |
| "A Windows Store component with CMake requires both the Windows " | |
| "Desktop SDK as well as the Windows Store '", | |
| this->SystemVersion, | |
| "' SDK. Please make sure that you have both installed"); | |
| } | |
| mf->IssueMessage(MessageType::FATAL_ERROR, e); | |
| return false; | |
| } | |
| return true; | |
| } | |
| bool cmGlobalVisualStudio14Generator::InitializeAndroid(cmMakefile*) | |
| { | |
| return true; | |
| } | |
| bool cmGlobalVisualStudio14Generator::ProcessGeneratorPlatformField( | |
| std::string const& key, std::string const& value) | |
| { | |
| if (key == "version"_s) { | |
| this->GeneratorPlatformVersion = value; | |
| return true; | |
| } | |
| return false; | |
| } | |
| bool cmGlobalVisualStudio14Generator::SelectWindows10SDK(cmMakefile* mf) | |
| { | |
| // Find the default version of the Windows 10 SDK. | |
| std::string const version = this->GetWindows10SDKVersion(mf); | |
| if (version.empty()) { | |
| if (this->GeneratorPlatformVersion) { | |
| mf->IssueMessage( | |
| MessageType::FATAL_ERROR, | |
| cmStrCat("Generator\n ", this->GetName(), | |
| "\ngiven platform specification with\n version=", | |
| *this->GeneratorPlatformVersion, | |
| "\nfield, but no Windows SDK with that version was found.")); | |
| return false; | |
| } | |
| if (this->SystemName == "WindowsStore"_s) { | |
| mf->IssueMessage( | |
| MessageType::FATAL_ERROR, | |
| "Could not find an appropriate version of the Windows 10 SDK" | |
| " installed on this machine"); | |
| return false; | |
| } | |
| } | |
| this->SetWindowsTargetPlatformVersion(version, mf); | |
| return true; | |
| } | |
| void cmGlobalVisualStudio14Generator::SetWindowsTargetPlatformVersion( | |
| std::string const& version, cmMakefile* mf) | |
| { | |
| this->WindowsTargetPlatformVersion = version; | |
| if (!this->WindowsTargetPlatformVersion.empty() && | |
| !cmSystemTools::VersionCompareEqual(this->WindowsTargetPlatformVersion, | |
| this->SystemVersion)) { | |
| mf->DisplayStatus(cmStrCat("Selecting Windows SDK version ", | |
| this->WindowsTargetPlatformVersion, | |
| " to target Windows ", this->SystemVersion, | |
| '.'), | |
| -1); | |
| } | |
| mf->AddDefinition("CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION", | |
| this->WindowsTargetPlatformVersion); | |
| } | |
| bool cmGlobalVisualStudio14Generator::SelectWindowsStoreToolset( | |
| std::string& toolset) const | |
| { | |
| if (cmHasLiteralPrefix(this->SystemVersion, "10.0")) { | |
| if (this->IsWindowsStoreToolsetInstalled() && | |
| this->IsWindowsDesktopToolsetInstalled()) { | |
| toolset = "v140"; | |
| return true; | |
| } | |
| return false; | |
| } | |
| return this->cmGlobalVisualStudio12Generator::SelectWindowsStoreToolset( | |
| toolset); | |
| } | |
| bool cmGlobalVisualStudio14Generator::IsWindowsDesktopToolsetInstalled() const | |
| { | |
| char const desktop10Key[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\" | |
| "VisualStudio\\14.0\\VC\\Runtimes"; | |
| std::vector<std::string> vc14; | |
| return cmSystemTools::GetRegistrySubKeys(desktop10Key, vc14, | |
| cmSystemTools::KeyWOW64_32); | |
| } | |
| bool cmGlobalVisualStudio14Generator::IsWindowsStoreToolsetInstalled() const | |
| { | |
| char const universal10Key[] = | |
| "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\" | |
| "VisualStudio\\14.0\\Setup\\Build Tools for Windows 10;SrcPath"; | |
| std::string win10SDK; | |
| return cmSystemTools::ReadRegistryValue(universal10Key, win10SDK, | |
| cmSystemTools::KeyWOW64_32); | |
| } | |
| bool cmGlobalVisualStudio14Generator::IsWin81SDKInstalled() const | |
| { | |
| return true; | |
| } | |
| std::string cmGlobalVisualStudio14Generator::GetWindows10SDKMaxVersion( | |
| cmMakefile* mf) const | |
| { | |
| // if the given value is set, it can either be OFF/FALSE or a valid SDK | |
| // string | |
| if (cmValue value = mf->GetDefinition( | |
| "CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION_MAXIMUM")) { | |
| // If the value is some off/false value, then there is NO maximum set. | |
| if (value.IsOff()) { | |
| return std::string(); | |
| } | |
| // If the value is something else, trust that it is a valid SDK value. | |
| if (value) { | |
| return *value; | |
| } | |
| // If value is an invalid pointer, leave result unchanged. | |
| } | |
| return this->GetWindows10SDKMaxVersionDefault(mf); | |
| } | |
| #if defined(_WIN32) && !defined(__CYGWIN__) | |
| struct NoWindowsH | |
| { | |
| bool operator()(std::string const& p) | |
| { | |
| return !cmSystemTools::FileExists(cmStrCat(p, "/um/windows.h"), true); | |
| } | |
| }; | |
| class WindowsSDKTooRecent | |
| { | |
| std::string const& MaxVersion; | |
| public: | |
| WindowsSDKTooRecent(std::string const& maxVersion) | |
| : MaxVersion(maxVersion) | |
| { | |
| } | |
| bool operator()(std::string const& v) | |
| { | |
| return cmSystemTools::VersionCompareGreater(v, MaxVersion); | |
| } | |
| }; | |
| #endif | |
| std::string cmGlobalVisualStudio14Generator::GetWindows10SDKVersion( | |
| cmMakefile* mf) | |
| { | |
| #if defined(_WIN32) && !defined(__CYGWIN__) | |
| std::vector<std::string> win10Roots; | |
| { | |
| std::string win10Root; | |
| if (cmSystemTools::GetEnv("CMAKE_WINDOWS_KITS_10_DIR", win10Root)) { | |
| cmSystemTools::ConvertToUnixSlashes(win10Root); | |
| win10Roots.push_back(win10Root); | |
| } | |
| } | |
| { | |
| // This logic is taken from the vcvarsqueryregistry.bat file from VS2015 | |
| // Try HKLM and then HKCU. | |
| std::string win10Root; | |
| if (cmSystemTools::ReadRegistryValue( | |
| "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\" | |
| "Windows Kits\\Installed Roots;KitsRoot10", | |
| win10Root, cmSystemTools::KeyWOW64_32) || | |
| cmSystemTools::ReadRegistryValue( | |
| "HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\" | |
| "Windows Kits\\Installed Roots;KitsRoot10", | |
| win10Root, cmSystemTools::KeyWOW64_32)) { | |
| cmSystemTools::ConvertToUnixSlashes(win10Root); | |
| win10Roots.push_back(win10Root); | |
| } | |
| } | |
| if (win10Roots.empty()) { | |
| return std::string(); | |
| } | |
| std::vector<std::string> sdks; | |
| // Grab the paths of the different SDKs that are installed | |
| for (std::string const& i : win10Roots) { | |
| std::string path = cmStrCat(i, "/Include/*"); | |
| cmSystemTools::GlobDirs(path, sdks); | |
| } | |
| // Skip SDKs that do not contain <um/windows.h> because that indicates that | |
| // only the UCRT MSIs were installed for them. | |
| cm::erase_if(sdks, NoWindowsH()); | |
| // Only use the filename, which will be the SDK version. | |
| for (std::string& i : sdks) { | |
| i = cmSystemTools::GetFilenameName(i); | |
| } | |
| // Skip SDKs that cannot be used with our toolset, unless the user does not | |
| // want to limit the highest supported SDK according to the Microsoft | |
| // documentation. | |
| std::string maxVersion = this->GetWindows10SDKMaxVersion(mf); | |
| if (!maxVersion.empty()) { | |
| cm::erase_if(sdks, WindowsSDKTooRecent(maxVersion)); | |
| } | |
| // Sort the results to make sure we select the most recent one. | |
| std::sort(sdks.begin(), sdks.end(), cmSystemTools::VersionCompareGreater); | |
| // Look for a SDK exactly matching the requested version, if any. | |
| if (this->GeneratorPlatformVersion) { | |
| for (std::string const& i : sdks) { | |
| if (cmSystemTools::VersionCompareEqual( | |
| i, *this->GeneratorPlatformVersion)) { | |
| return i; | |
| } | |
| } | |
| // An exact version was requested but not found. | |
| // Our caller will issue the error message. | |
| return std::string(); | |
| } | |
| if (mf->GetPolicyStatus(cmPolicies::CMP0149) == cmPolicies::NEW) { | |
| if (cm::optional<std::string> const envVer = | |
| cmSystemTools::GetEnvVar("WindowsSDKVersion")) { | |
| // Look for a SDK exactly matching the environment variable. | |
| for (std::string const& i : sdks) { | |
| if (cmSystemTools::VersionCompareEqual(i, *envVer)) { | |
| return i; | |
| } | |
| } | |
| } | |
| } else { | |
| // Look for a SDK exactly matching the target Windows version. | |
| for (std::string const& i : sdks) { | |
| if (cmSystemTools::VersionCompareEqual(i, this->SystemVersion)) { | |
| return i; | |
| } | |
| } | |
| } | |
| if (!sdks.empty()) { | |
| // Use the latest Windows 10 SDK since the exact version is not available. | |
| return sdks.at(0); | |
| } | |
| #endif | |
| (void)mf; | |
| // Return an empty string | |
| return std::string(); | |
| } |