diff options
Diffstat (limited to 'Source')
-rw-r--r-- | Source/CMakeInstallDestinations.cmake | 8 | ||||
-rw-r--r-- | Source/CMakeLists.txt | 11 | ||||
-rw-r--r-- | Source/CMakeVersion.cmake | 2 | ||||
-rw-r--r-- | Source/CTest/cmCTestMemCheckHandler.cxx | 2 | ||||
-rw-r--r-- | Source/cmExtraCodeBlocksGenerator.cxx | 3 | ||||
-rw-r--r-- | Source/cmFileMonitor.cxx | 3 | ||||
-rw-r--r-- | Source/cmGlobalVisualStudio10Generator.cxx | 14 | ||||
-rw-r--r-- | Source/cmGlobalVisualStudio15Generator.cxx | 56 | ||||
-rw-r--r-- | Source/cmGlobalVisualStudio15Generator.h | 5 | ||||
-rw-r--r-- | Source/cmListFileLexer.c | 2 | ||||
-rw-r--r-- | Source/cmListFileLexer.h | 2 | ||||
-rw-r--r-- | Source/cmListFileLexer.in.l | 2 | ||||
-rw-r--r-- | Source/cmMakefileExecutableTargetGenerator.cxx | 10 | ||||
-rw-r--r-- | Source/cmMakefileLibraryTargetGenerator.cxx | 10 | ||||
-rw-r--r-- | Source/cmNinjaNormalTargetGenerator.cxx | 9 | ||||
-rw-r--r-- | Source/cmNinjaTargetGenerator.cxx | 3 | ||||
-rw-r--r-- | Source/cmVSSetupHelper.cxx | 395 | ||||
-rw-r--r-- | Source/cmVSSetupHelper.h | 154 | ||||
-rw-r--r-- | Source/cmake.cxx | 30 |
19 files changed, 665 insertions, 56 deletions
diff --git a/Source/CMakeInstallDestinations.cmake b/Source/CMakeInstallDestinations.cmake index 023f6c0..28f4e87 100644 --- a/Source/CMakeInstallDestinations.cmake +++ b/Source/CMakeInstallDestinations.cmake @@ -25,6 +25,12 @@ set(CMAKE_DOC_DIR_DESC "docs") set(CMAKE_MAN_DIR_DESC "man pages") set(CMAKE_XDGDATA_DIR_DESC "XDG specific files") +set(CMake_INSTALL_INFIX "" CACHE STRING "") +set_property(CACHE CMake_INSTALL_INFIX PROPERTY HELPSTRING + "Intermediate installation path (empty by default)" + ) +mark_as_advanced(CMake_INSTALL_INFIX) + foreach(v CMAKE_BIN_DIR CMAKE_DATA_DIR @@ -41,7 +47,7 @@ foreach(v # Use the default when the user did not set this variable. if(NOT ${v}) - set(${v} "${${v}_DEFAULT}") + set(${v} "${CMake_INSTALL_INFIX}${${v}_DEFAULT}") endif() # Remove leading slash to treat as relative to install prefix. string(REGEX REPLACE "^/" "" ${v} "${${v}}") diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index d15fdbe..2835ee6 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -710,6 +710,8 @@ if (WIN32) cmGhsMultiTargetGenerator.h cmGhsMultiGpj.cxx cmGhsMultiGpj.h + cmVSSetupHelper.cxx + cmVSSetupHelper.h ) # Add a manifest file to executables on Windows to allow for @@ -785,6 +787,15 @@ target_link_libraries(CMakeLib cmsys ${CMake_KWIML_LIBRARIES} ) +if(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR MATCHES "sparc") + # the atomic instructions are implemented using libatomic on some platforms, + # so linking to that may be required + check_library_exists(atomic __atomic_fetch_add_4 "" LIBATOMIC_NEEDED) + if(LIBATOMIC_NEEDED) + target_link_libraries(CMakeLib atomic) + endif() +endif() + # On Apple we need CoreFoundation if(APPLE) target_link_libraries(CMakeLib "-framework CoreFoundation") diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index fde01c1..0c64d70 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 7) -set(CMake_VERSION_PATCH 20170112) +set(CMake_VERSION_PATCH 20170116) #set(CMake_VERSION_RC 1) diff --git a/Source/CTest/cmCTestMemCheckHandler.cxx b/Source/CTest/cmCTestMemCheckHandler.cxx index 4d23e45..a062e64 100644 --- a/Source/CTest/cmCTestMemCheckHandler.cxx +++ b/Source/CTest/cmCTestMemCheckHandler.cxx @@ -634,7 +634,7 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking() std::string outputFile = envVar + "=log_path=\"" + this->MemoryTesterOutputFile + "\""; this->MemoryTesterEnvironmentVariable = - outputFile + extraOptions + suppressionsOption; + outputFile + suppressionsOption + extraOptions; break; } default: diff --git a/Source/cmExtraCodeBlocksGenerator.cxx b/Source/cmExtraCodeBlocksGenerator.cxx index f544e8a..2dffcaa 100644 --- a/Source/cmExtraCodeBlocksGenerator.cxx +++ b/Source/cmExtraCodeBlocksGenerator.cxx @@ -48,6 +48,7 @@ cmExtraCodeBlocksGenerator::GetFactory() #if defined(_WIN32) factory.AddSupportedGlobalGenerator("MinGW Makefiles"); factory.AddSupportedGlobalGenerator("NMake Makefiles"); + factory.AddSupportedGlobalGenerator("NMake Makefiles JOM"); // disable until somebody actually tests it: // this->AddSupportedGlobalGenerator("MSYS Makefiles"); #endif @@ -741,7 +742,7 @@ std::string cmExtraCodeBlocksGenerator::BuildMakeCommand( } std::string generator = this->GlobalGenerator->GetName(); - if (generator == "NMake Makefiles") { + if (generator == "NMake Makefiles" || generator == "NMake Makefiles JOM") { // For Windows ConvertToOutputPath already adds quotes when required. // These need to be escaped, see // https://gitlab.kitware.com/cmake/cmake/issues/13952 diff --git a/Source/cmFileMonitor.cxx b/Source/cmFileMonitor.cxx index 03bbf42..909be78 100644 --- a/Source/cmFileMonitor.cxx +++ b/Source/cmFileMonitor.cxx @@ -334,6 +334,9 @@ void cmFileMonitor::MonitorPaths(const std::vector<std::string>& paths, rootSegment)); // Can not be both filename and root part of the path! const std::string& currentSegment = pathSegments[i]; + if (currentSegment.empty()) { + continue; + } cmIBaseWatcher* nextWatcher = currentWatcher->Find(currentSegment); if (!nextWatcher) { diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx index dde6e82..e27615a 100644 --- a/Source/cmGlobalVisualStudio10Generator.cxx +++ b/Source/cmGlobalVisualStudio10Generator.cxx @@ -425,20 +425,6 @@ std::string cmGlobalVisualStudio10Generator::FindMSBuildCommand() } } - // Search where VS15Preview places it. - mskey = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\SxS\\VS7;"; - mskey += this->GetIDEVersion(); - if (cmSystemTools::ReadRegistryValue(mskey.c_str(), msbuild, - cmSystemTools::KeyWOW64_32)) { - cmSystemTools::ConvertToUnixSlashes(msbuild); - msbuild += "/MSBuild/"; - msbuild += this->GetIDEVersion(); - msbuild += "/Bin/MSBuild.exe"; - if (cmSystemTools::FileExists(msbuild, true)) { - return msbuild; - } - } - msbuild = "MSBuild.exe"; return msbuild; } diff --git a/Source/cmGlobalVisualStudio15Generator.cxx b/Source/cmGlobalVisualStudio15Generator.cxx index 20d30bc..d11ee7c 100644 --- a/Source/cmGlobalVisualStudio15Generator.cxx +++ b/Source/cmGlobalVisualStudio15Generator.cxx @@ -8,6 +8,7 @@ #include "cmMakefile.h" #include "cmVS141CLFlagTable.h" #include "cmVS141CSharpFlagTable.h" +#include "cmVSSetupHelper.h" static const char vs15generatorName[] = "Visual Studio 15 2017"; @@ -80,11 +81,7 @@ cmGlobalVisualStudio15Generator::cmGlobalVisualStudio15Generator( cmake* cm, const std::string& name, const std::string& platformName) : cmGlobalVisualStudio14Generator(cm, name, platformName) { - std::string vc15Express; - this->ExpressEdition = cmSystemTools::ReadRegistryValue( - "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\15.0\\Setup\\VC;" - "ProductDir", - vc15Express, cmSystemTools::KeyWOW64_32); + this->ExpressEdition = false; this->DefaultPlatformToolset = "v141"; this->DefaultClFlagTable = cmVS141CLFlagTable; this->DefaultCSharpFlagTable = cmVS141CSharpFlagTable; @@ -118,7 +115,7 @@ bool cmGlobalVisualStudio15Generator::SelectWindowsStoreToolset( if (cmHasLiteralPrefix(this->SystemVersion, "10.0")) { if (this->IsWindowsStoreToolsetInstalled() && this->IsWindowsDesktopToolsetInstalled()) { - toolset = "v140"; // VS 15 uses v140 toolset + toolset = "v141"; // VS 15 uses v141 toolset return true; } else { return false; @@ -130,21 +127,44 @@ bool cmGlobalVisualStudio15Generator::SelectWindowsStoreToolset( bool cmGlobalVisualStudio15Generator::IsWindowsDesktopToolsetInstalled() const { - const char desktop10Key[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\" - "VisualStudio\\15.0\\VC\\Runtimes"; - - std::vector<std::string> vc15; - return cmSystemTools::GetRegistrySubKeys(desktop10Key, vc15, - cmSystemTools::KeyWOW64_32); + return vsSetupAPIHelper.IsVS2017Installed(); } bool cmGlobalVisualStudio15Generator::IsWindowsStoreToolsetInstalled() const { - const char universal10Key[] = - "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\" - "VisualStudio\\15.0\\Setup\\Build Tools for Windows 10;SrcPath"; + return vsSetupAPIHelper.IsWin10SDKInstalled(); +} + +std::string cmGlobalVisualStudio15Generator::FindMSBuildCommand() +{ + std::string msbuild; + + // Ask Visual Studio Installer tool. + std::string vs; + if (vsSetupAPIHelper.GetVSInstanceInfo(vs)) { + msbuild = vs + "/MSBuild/15.0/Bin/MSBuild.exe"; + if (cmSystemTools::FileExists(msbuild)) { + return msbuild; + } + } + + msbuild = "MSBuild.exe"; + return msbuild; +} + +std::string cmGlobalVisualStudio15Generator::FindDevEnvCommand() +{ + std::string devenv; + + // Ask Visual Studio Installer tool. + std::string vs; + if (vsSetupAPIHelper.GetVSInstanceInfo(vs)) { + devenv = vs + "/Common7/IDE/devenv.com"; + if (cmSystemTools::FileExists(devenv)) { + return devenv; + } + } - std::string win10SDK; - return cmSystemTools::ReadRegistryValue(universal10Key, win10SDK, - cmSystemTools::KeyWOW64_32); + devenv = "devenv.com"; + return devenv; } diff --git a/Source/cmGlobalVisualStudio15Generator.h b/Source/cmGlobalVisualStudio15Generator.h index 59eb11a..781b41e 100644 --- a/Source/cmGlobalVisualStudio15Generator.h +++ b/Source/cmGlobalVisualStudio15Generator.h @@ -9,6 +9,7 @@ #include <string> #include "cmGlobalVisualStudio14Generator.h" +#include "cmVSSetupHelper.h" class cmGlobalGeneratorFactory; class cmake; @@ -39,7 +40,11 @@ protected: // of the toolset is installed bool IsWindowsStoreToolsetInstalled() const; + std::string FindMSBuildCommand() CM_OVERRIDE; + std::string FindDevEnvCommand() CM_OVERRIDE; + private: class Factory; + mutable cmVSSetupAPIHelper vsSetupAPIHelper; }; #endif diff --git a/Source/cmListFileLexer.c b/Source/cmListFileLexer.c index 31faca1..56559f6 100644 --- a/Source/cmListFileLexer.c +++ b/Source/cmListFileLexer.c @@ -2518,7 +2518,7 @@ static void cmListFileLexerDestroy(cmListFileLexer* lexer) } /*--------------------------------------------------------------------------*/ -cmListFileLexer* cmListFileLexer_New() +cmListFileLexer* cmListFileLexer_New(void) { cmListFileLexer* lexer = (cmListFileLexer*)malloc(sizeof(cmListFileLexer)); if (!lexer) { diff --git a/Source/cmListFileLexer.h b/Source/cmListFileLexer.h index dfbad5e..c9fb6da 100644 --- a/Source/cmListFileLexer.h +++ b/Source/cmListFileLexer.h @@ -46,7 +46,7 @@ typedef struct cmListFileLexer_s cmListFileLexer; extern "C" { #endif -cmListFileLexer* cmListFileLexer_New(); +cmListFileLexer* cmListFileLexer_New(void); int cmListFileLexer_SetFileName(cmListFileLexer*, const char*, cmListFileLexer_BOM* bom); int cmListFileLexer_SetString(cmListFileLexer*, const char*); diff --git a/Source/cmListFileLexer.in.l b/Source/cmListFileLexer.in.l index 4b389b9..dd64923 100644 --- a/Source/cmListFileLexer.in.l +++ b/Source/cmListFileLexer.in.l @@ -398,7 +398,7 @@ static void cmListFileLexerDestroy(cmListFileLexer* lexer) } /*--------------------------------------------------------------------------*/ -cmListFileLexer* cmListFileLexer_New() +cmListFileLexer* cmListFileLexer_New(void) { cmListFileLexer* lexer = (cmListFileLexer*)malloc(sizeof(cmListFileLexer)); if (!lexer) { diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx index 069011d..4bc706c 100644 --- a/Source/cmMakefileExecutableTargetGenerator.cxx +++ b/Source/cmMakefileExecutableTargetGenerator.cxx @@ -104,10 +104,12 @@ void cmMakefileExecutableTargetGenerator::WriteDeviceExecutableRule( // Get the language to use for linking this library. std::string linkLanguage = "CUDA"; + std::string const objExt = + this->Makefile->GetSafeDefinition("CMAKE_CUDA_OUTPUT_EXTENSION"); // Get the name of the device object to generate. std::string const targetOutputReal = - this->GeneratorTarget->ObjectDirectory + "cmake_device_link.o"; + this->GeneratorTarget->ObjectDirectory + "cmake_device_link" + objExt; this->DeviceLinkObject = targetOutputReal; this->NumberOfProgressActions++; @@ -228,6 +230,11 @@ void cmMakefileExecutableTargetGenerator::WriteDeviceExecutableRule( this->LocalGenerator->GetCurrentBinaryDirectory(), targetOutputReal), output); + std::string targetFullPathCompilePDB = this->ComputeTargetCompilePDB(); + std::string targetOutPathCompilePDB = + this->LocalGenerator->ConvertToOutputFormat(targetFullPathCompilePDB, + cmOutputConverter::SHELL); + vars.Language = linkLanguage.c_str(); vars.Objects = buildObjs.c_str(); vars.ObjectDir = objectDir.c_str(); @@ -235,6 +242,7 @@ void cmMakefileExecutableTargetGenerator::WriteDeviceExecutableRule( vars.LinkLibraries = linkLibs.c_str(); vars.Flags = flags.c_str(); vars.LinkFlags = linkFlags.c_str(); + vars.TargetCompilePDB = targetOutPathCompilePDB.c_str(); std::string launcher; diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index 2b0e1b1..27b7c21 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -281,6 +281,8 @@ void cmMakefileLibraryTargetGenerator::WriteDeviceLibraryRules( // Get the language to use for linking this library. std::string linkLanguage = "CUDA"; + std::string const objExt = + this->Makefile->GetSafeDefinition("CMAKE_CUDA_OUTPUT_EXTENSION"); // Create set of linking flags. std::string linkFlags; @@ -288,7 +290,7 @@ void cmMakefileLibraryTargetGenerator::WriteDeviceLibraryRules( // Get the name of the device object to generate. std::string const targetOutputReal = - this->GeneratorTarget->ObjectDirectory + "cmake_device_link.o"; + this->GeneratorTarget->ObjectDirectory + "cmake_device_link" + objExt; this->DeviceLinkObject = targetOutputReal; this->NumberOfProgressActions++; @@ -364,12 +366,18 @@ void cmMakefileLibraryTargetGenerator::WriteDeviceLibraryRules( this->LocalGenerator->GetCurrentBinaryDirectory(), targetOutputReal), output); + std::string targetFullPathCompilePDB = this->ComputeTargetCompilePDB(); + std::string targetOutPathCompilePDB = + this->LocalGenerator->ConvertToOutputFormat(targetFullPathCompilePDB, + cmOutputConverter::SHELL); + vars.Objects = buildObjs.c_str(); vars.ObjectDir = objectDir.c_str(); vars.Target = target.c_str(); vars.LinkLibraries = linkLibs.c_str(); vars.ObjectsQuoted = buildObjs.c_str(); vars.LinkFlags = linkFlags.c_str(); + vars.TargetCompilePDB = targetOutPathCompilePDB.c_str(); // Add language feature flags. std::string langFlags; diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index 0db5687..bc8d8ff 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -229,6 +229,7 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkRule(bool useResponseFile) vars.SONameFlag = "$SONAME_FLAG"; vars.TargetSOName = "$SONAME"; vars.TargetPDB = "$TARGET_PDB"; + vars.TargetCompilePDB = "$TARGET_COMPILE_PDB"; vars.Flags = "$FLAGS"; vars.LinkFlags = "$LINK_FLAGS"; @@ -602,10 +603,12 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement() // First and very important step is to make sure while inside this // step our link language is set to CUDA std::string cudaLinkLanguage = "CUDA"; + std::string const objExt = + this->Makefile->GetSafeDefinition("CMAKE_CUDA_OUTPUT_EXTENSION"); std::string const cfgName = this->GetConfigName(); - std::string const targetOutputReal = - ConvertToNinjaPath(genTarget.ObjectDirectory + "cmake_device_link.o"); + std::string const targetOutputReal = ConvertToNinjaPath( + genTarget.ObjectDirectory + "cmake_device_link" + objExt); std::string const targetOutputImplib = ConvertToNinjaPath(genTarget.GetFullPath(cfgName, @@ -714,6 +717,8 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement() this->ConvertToNinjaPath(objPath), cmOutputConverter::SHELL); EnsureDirectoryExists(objPath); + this->SetMsvcTargetPdbVariable(vars); + if (this->GetGlobalGenerator()->IsGCCOnWindows()) { // ar.exe can't handle backslashes in rsp files (implicitly used by gcc) std::string& linkLibraries = vars["LINK_LIBRARIES"]; diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 23caead..8ad2efe 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -344,7 +344,8 @@ bool cmNinjaTargetGenerator::SetMsvcTargetPdbVariable(cmNinjaVars& vars) const { cmMakefile* mf = this->GetMakefile(); if (mf->GetDefinition("MSVC_C_ARCHITECTURE_ID") || - mf->GetDefinition("MSVC_CXX_ARCHITECTURE_ID")) { + mf->GetDefinition("MSVC_CXX_ARCHITECTURE_ID") || + mf->GetDefinition("MSVC_CUDA_ARCHITECTURE_ID")) { std::string pdbPath; std::string compilePdbPath = this->ComputeTargetCompilePDB(); if (this->GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE || diff --git a/Source/cmVSSetupHelper.cxx b/Source/cmVSSetupHelper.cxx new file mode 100644 index 0000000..d675a2c --- /dev/null +++ b/Source/cmVSSetupHelper.cxx @@ -0,0 +1,395 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmVSSetupHelper.h" + +#ifndef VSSetupConstants +#define VSSetupConstants +/* clang-format off */ +const IID IID_ISetupConfiguration = { + 0x42843719, 0xDB4C, 0x46C2, + { 0x8E, 0x7C, 0x64, 0xF1, 0x81, 0x6E, 0xFD, 0x5B } +}; +const IID IID_ISetupConfiguration2 = { + 0x26AAB78C, 0x4A60, 0x49D6, + { 0xAF, 0x3B, 0x3C, 0x35, 0xBC, 0x93, 0x36, 0x5D } +}; +const IID IID_ISetupPackageReference = { + 0xda8d8a16, 0xb2b6, 0x4487, + { 0xa2, 0xf1, 0x59, 0x4c, 0xcc, 0xcd, 0x6b, 0xf5 } +}; +const IID IID_ISetupHelper = { + 0x42b21b78, 0x6192, 0x463e, + { 0x87, 0xbf, 0xd5, 0x77, 0x83, 0x8f, 0x1d, 0x5c } +}; +const IID IID_IEnumSetupInstances = { + 0x6380BCFF, 0x41D3, 0x4B2E, + { 0x8B, 0x2E, 0xBF, 0x8A, 0x68, 0x10, 0xC8, 0x48 } +}; +const IID IID_ISetupInstance2 = { + 0x89143C9A, 0x05AF, 0x49B0, + { 0xB7, 0x17, 0x72, 0xE2, 0x18, 0xA2, 0x18, 0x5C } +}; +const IID IID_ISetupInstance = { + 0xB41463C3, 0x8866, 0x43B5, + { 0xBC, 0x33, 0x2B, 0x06, 0x76, 0xF7, 0xF4, 0x2E } +}; +const CLSID CLSID_SetupConfiguration = { + 0x177F0C4A, 0x1CD3, 0x4DE7, + { 0xA3, 0x2C, 0x71, 0xDB, 0xBB, 0x9F, 0xA3, 0x6D } +}; +/* clang-format on */ +#endif + +const WCHAR* VCToolsetComponent = + L"Microsoft.VisualStudio.Component.VC.Tools.x86.x64"; +const WCHAR* Win10SDKComponent = + L"Microsoft.VisualStudio.Component.Windows10SDK"; +const WCHAR* Win81SDKComponent = + L"Microsoft.VisualStudio.Component.Windows81SDK"; +const WCHAR* ComponentType = L"Component"; + +cmVSSetupAPIHelper::cmVSSetupAPIHelper() + : setupConfig(NULL) + , setupConfig2(NULL) + , setupHelper(NULL) + , initializationFailure(false) +{ + comInitialized = CoInitializeEx(NULL, 0); + if (SUCCEEDED(comInitialized)) { + Initialize(); + } else { + initializationFailure = true; + } +} + +cmVSSetupAPIHelper::~cmVSSetupAPIHelper() +{ + setupHelper = NULL; + setupConfig2 = NULL; + setupConfig = NULL; + if (SUCCEEDED(comInitialized)) + CoUninitialize(); +} + +bool cmVSSetupAPIHelper::IsVS2017Installed() +{ + bool ret = false; + if (chosenInstanceInfo.VSInstallLocation.compare(L"") == 0) { + ret = EnumerateAndChooseVSInstance(); + } + + return ret; +} + +bool cmVSSetupAPIHelper::IsWin10SDKInstalled() +{ + bool isWin10SDKInstalled = false; + if (chosenInstanceInfo.VSInstallLocation.compare(L"") == 0) { + if (EnumerateAndChooseVSInstance() && + chosenInstanceInfo.VSInstallLocation.compare(L"") != 0) { + isWin10SDKInstalled = chosenInstanceInfo.IsWin10SDKInstalled; + } + } else { + isWin10SDKInstalled = chosenInstanceInfo.IsWin10SDKInstalled; + } + + return isWin10SDKInstalled; +} + +bool cmVSSetupAPIHelper::IsWin81SDKInstalled() +{ + bool isWin81SDKInstalled = false; + if (chosenInstanceInfo.VSInstallLocation.compare(L"") == 0) { + if (EnumerateAndChooseVSInstance() && + chosenInstanceInfo.VSInstallLocation.compare(L"") != 0) { + isWin81SDKInstalled = chosenInstanceInfo.IsWin81SDKInstalled; + } + } else { + isWin81SDKInstalled = chosenInstanceInfo.IsWin81SDKInstalled; + } + + return isWin81SDKInstalled; +} + +bool cmVSSetupAPIHelper::CheckInstalledComponent( + SmartCOMPtr<ISetupPackageReference> package, bool& bVCToolset, + bool& bWin10SDK, bool& bWin81SDK) +{ + bool ret = false; + bVCToolset = bWin10SDK = bWin81SDK = false; + SmartBSTR bstrId; + if (FAILED(package->GetId(&bstrId))) { + return ret; + } + + SmartBSTR bstrType; + if (FAILED(package->GetType(&bstrType))) { + return ret; + } + + std::wstring id = std::wstring(bstrId); + std::wstring type = std::wstring(bstrType); + if (id.compare(VCToolsetComponent) == 0 && + type.compare(ComponentType) == 0) { + bVCToolset = true; + ret = true; + } + + // Checks for any version of Win10 SDK. The version is appended at the end of + // the + // component name ex: Microsoft.VisualStudio.Component.Windows10SDK.10240 + if (id.find(Win10SDKComponent) != std::wstring::npos && + type.compare(ComponentType) == 0) { + bWin10SDK = true; + ret = true; + } + + if (id.compare(Win81SDKComponent) == 0 && type.compare(ComponentType) == 0) { + bWin81SDK = true; + ret = true; + } + + return ret; +} + +// Gather additional info such as if VCToolset, WinSDKs are installed, location +// of VS and version information. +bool cmVSSetupAPIHelper::GetVSInstanceInfo( + SmartCOMPtr<ISetupInstance2> pInstance, VSInstanceInfo& vsInstanceInfo) +{ + bool isVCToolSetInstalled = false; + 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; + } + } + + // Reboot may have been required before the installation path was created. + SmartBSTR bstrInstallationPath; + if ((eLocal & state) == eLocal) { + if (FAILED(pInstance->GetInstallationPath(&bstrInstallationPath))) { + return false; + } else { + vsInstanceInfo.VSInstallLocation = std::wstring(bstrInstallationPath); + } + } + + // Reboot may have been required before the product package was registered + // (last). + if ((eRegistered & state) == eRegistered) { + SmartCOMPtr<ISetupPackageReference> product; + if (FAILED(pInstance->GetProduct(&product)) || !product) { + return false; + } + + LPSAFEARRAY lpsaPackages; + if (FAILED(pInstance->GetPackages(&lpsaPackages)) || + lpsaPackages == NULL) { + return false; + } + + int lower = lpsaPackages->rgsabound[0].lLbound; + int upper = lpsaPackages->rgsabound[0].cElements + lower; + + IUnknown** ppData = (IUnknown**)lpsaPackages->pvData; + for (int i = lower; i < upper; i++) { + SmartCOMPtr<ISetupPackageReference> package = NULL; + if (FAILED(ppData[i]->QueryInterface(IID_ISetupPackageReference, + (void**)&package)) || + package == NULL) + continue; + + bool vcToolsetInstalled = false, win10SDKInstalled = false, + win81SDkInstalled = false; + bool ret = CheckInstalledComponent(package, vcToolsetInstalled, + win10SDKInstalled, win81SDkInstalled); + if (ret) { + isVCToolSetInstalled |= vcToolsetInstalled; + vsInstanceInfo.IsWin10SDKInstalled |= win10SDKInstalled; + vsInstanceInfo.IsWin81SDKInstalled |= win81SDkInstalled; + } + } + + SafeArrayDestroy(lpsaPackages); + } + + return isVCToolSetInstalled; +} + +bool cmVSSetupAPIHelper::GetVSInstanceInfo(std::string& vsInstallLocation) +{ + vsInstallLocation = ""; + bool isInstalled = false; + + if (chosenInstanceInfo.VSInstallLocation.compare(L"") == 0) { + isInstalled = EnumerateAndChooseVSInstance(); + } + + // Enumerate and choose best VS instance + if (chosenInstanceInfo.VSInstallLocation.compare(L"") != 0) { + std::string str(chosenInstanceInfo.VSInstallLocation.begin(), + chosenInstanceInfo.VSInstallLocation.end()); + vsInstallLocation = str; + isInstalled = true; + } + + return isInstalled; +} + +bool cmVSSetupAPIHelper::EnumerateAndChooseVSInstance() +{ + bool isVSInstanceExists = false; + if (chosenInstanceInfo.VSInstallLocation.compare(L"") != 0) { + return true; + } + + if (initializationFailure || setupConfig == NULL || setupConfig2 == NULL || + setupHelper == NULL) + return false; + + std::vector<VSInstanceInfo> vecVSInstances; + SmartCOMPtr<IEnumSetupInstances> enumInstances = NULL; + if (FAILED( + setupConfig2->EnumInstances((IEnumSetupInstances**)&enumInstances)) || + !enumInstances) { + return false; + } + + SmartCOMPtr<ISetupInstance> instance; + while (SUCCEEDED(enumInstances->Next(1, &instance, NULL)) && instance) { + SmartCOMPtr<ISetupInstance2> instance2 = NULL; + if (FAILED( + instance->QueryInterface(IID_ISetupInstance2, (void**)&instance2)) || + !instance2) { + instance = NULL; + continue; + } + + VSInstanceInfo instanceInfo; + bool isInstalled = GetVSInstanceInfo(instance2, instanceInfo); + instance = instance2 = NULL; + + if (isInstalled) { + vecVSInstances.push_back(instanceInfo); + } + } + + if (vecVSInstances.size() > 0) { + isVSInstanceExists = true; + int index = ChooseVSInstance(vecVSInstances); + chosenInstanceInfo = vecVSInstances[index]; + } + + return isVSInstanceExists; +} + +int cmVSSetupAPIHelper::ChooseVSInstance( + const std::vector<VSInstanceInfo>& vecVSInstances) +{ + if (vecVSInstances.size() == 0) + return -1; + + if (vecVSInstances.size() == 1) + return 0; + + unsigned int chosenIndex = 0; + for (unsigned int i = 1; i < vecVSInstances.size(); i++) { + // If the current has Win10 SDK but not the chosen one, then choose the + // current VS instance + if (!vecVSInstances[chosenIndex].IsWin10SDKInstalled && + vecVSInstances[i].IsWin10SDKInstalled) { + chosenIndex = i; + continue; + } + + // If the chosen one has Win10 SDK but the current one is not, then look at + // the next VS instance even the current + // instance version may be higher + if (vecVSInstances[chosenIndex].IsWin10SDKInstalled && + !vecVSInstances[i].IsWin10SDKInstalled) { + continue; + } + + // If both chosen one and current one doesn't have Win10 SDK but the + // current one has Win8.1 SDK installed, + // then choose the current one + if (!vecVSInstances[chosenIndex].IsWin10SDKInstalled && + !vecVSInstances[i].IsWin10SDKInstalled && + !vecVSInstances[chosenIndex].IsWin81SDKInstalled && + vecVSInstances[i].IsWin81SDKInstalled) { + chosenIndex = i; + continue; + } + + // If there is no difference in WinSDKs then look for the highest version + // of installed VS + if ((vecVSInstances[chosenIndex].IsWin10SDKInstalled == + vecVSInstances[i].IsWin10SDKInstalled) && + (vecVSInstances[chosenIndex].IsWin81SDKInstalled == + vecVSInstances[i].IsWin81SDKInstalled) && + vecVSInstances[chosenIndex].Version < vecVSInstances[i].Version) { + chosenIndex = i; + continue; + } + } + + return chosenIndex; +} + +bool cmVSSetupAPIHelper::Initialize() +{ + if (initializationFailure) + return false; + + if (FAILED(comInitialized)) { + initializationFailure = true; + return false; + } + + if (FAILED(setupConfig.CoCreateInstance(CLSID_SetupConfiguration, NULL, + IID_ISetupConfiguration, + CLSCTX_INPROC_SERVER)) || + setupConfig == NULL) { + initializationFailure = true; + return false; + } + + if (FAILED(setupConfig.QueryInterface(IID_ISetupConfiguration2, + (void**)&setupConfig2)) || + setupConfig2 == NULL) { + initializationFailure = true; + return false; + } + + if (FAILED( + setupConfig.QueryInterface(IID_ISetupHelper, (void**)&setupHelper)) || + setupHelper == NULL) { + initializationFailure = true; + return false; + } + + initializationFailure = false; + return true; +} diff --git a/Source/cmVSSetupHelper.h b/Source/cmVSSetupHelper.h new file mode 100644 index 0000000..d2f514c --- /dev/null +++ b/Source/cmVSSetupHelper.h @@ -0,0 +1,154 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmVSSetupHelper_h +#define cmVSSetupHelper_h + +#ifndef NOMINMAX +#define NOMINMAX // Undefine min and max defined by windows.h +#endif + +// Published by Visual Studio Setup team +#include "cmvssetup/Setup.Configuration.h" + +#include <string> +#include <vector> + +#include <windows.h> + +template <class T> +class SmartCOMPtr +{ +public: + SmartCOMPtr() { ptr = NULL; } + SmartCOMPtr(T* p) + { + ptr = p; + if (ptr != NULL) + ptr->AddRef(); + } + SmartCOMPtr(const SmartCOMPtr<T>& sptr) + { + ptr = sptr.ptr; + if (ptr != NULL) + ptr->AddRef(); + } + T** operator&() { return &ptr; } + T* operator->() { return ptr; } + T* operator=(T* p) + { + if (*this != p) { + ptr = p; + if (ptr != NULL) + ptr->AddRef(); + } + return *this; + } + operator T*() const { return ptr; } + template <class I> + HRESULT QueryInterface(REFCLSID rclsid, I** pp) + { + if (pp != NULL) { + return ptr->QueryInterface(rclsid, (void**)pp); + } else { + return E_FAIL; + } + } + HRESULT CoCreateInstance(REFCLSID clsid, IUnknown* pUnknown, + REFIID interfaceId, DWORD dwClsContext = CLSCTX_ALL) + { + HRESULT hr = ::CoCreateInstance(clsid, pUnknown, dwClsContext, interfaceId, + (void**)&ptr); + return hr; + } + ~SmartCOMPtr() + { + if (ptr != NULL) + ptr->Release(); + } + +private: + T* ptr; +}; + +class SmartBSTR +{ +public: + SmartBSTR() { str = NULL; } + SmartBSTR(const SmartBSTR& src) + { + if (src.str != NULL) { + str = ::SysAllocStringByteLen((char*)str, ::SysStringByteLen(str)); + } else { + str = ::SysAllocStringByteLen(NULL, 0); + } + } + SmartBSTR& operator=(const SmartBSTR& src) + { + if (str != src.str) { + ::SysFreeString(str); + if (src.str != NULL) { + str = ::SysAllocStringByteLen((char*)str, ::SysStringByteLen(str)); + } else { + str = ::SysAllocStringByteLen(NULL, 0); + } + } + return *this; + } + operator BSTR() const { return str; } + BSTR* operator&() throw() { return &str; } + ~SmartBSTR() throw() { ::SysFreeString(str); } +private: + BSTR str; +}; + +struct VSInstanceInfo +{ + std::wstring InstanceId; + std::wstring VSInstallLocation; + std::wstring Version; + ULONGLONG ullVersion; + bool IsWin10SDKInstalled; + bool IsWin81SDKInstalled; + + VSInstanceInfo() + { + InstanceId = VSInstallLocation = Version = L""; + ullVersion = 0; + IsWin10SDKInstalled = IsWin81SDKInstalled = false; + } +}; + +class cmVSSetupAPIHelper +{ +public: + cmVSSetupAPIHelper(); + ~cmVSSetupAPIHelper(); + + bool IsVS2017Installed(); + bool GetVSInstanceInfo(std::string& vsInstallLocation); + bool IsWin10SDKInstalled(); + bool IsWin81SDKInstalled(); + +private: + bool Initialize(); + bool GetVSInstanceInfo(SmartCOMPtr<ISetupInstance2> instance2, + VSInstanceInfo& vsInstanceInfo); + bool CheckInstalledComponent(SmartCOMPtr<ISetupPackageReference> package, + bool& bVCToolset, bool& bWin10SDK, + bool& bWin81SDK); + int ChooseVSInstance(const std::vector<VSInstanceInfo>& vecVSInstances); + bool EnumerateAndChooseVSInstance(); + + // COM ptrs to query about VS instances + SmartCOMPtr<ISetupConfiguration> setupConfig; + SmartCOMPtr<ISetupConfiguration2> setupConfig2; + SmartCOMPtr<ISetupHelper> setupHelper; + // used to indicate failure in Initialize(), so we don't have to call again + bool initializationFailure; + // indicated if COM initialization is successful + HRESULT comInitialized; + // current best instance of VS selected + VSInstanceInfo chosenInstanceInfo; +}; + +#endif diff --git a/Source/cmake.cxx b/Source/cmake.cxx index 733e0e4..6141f50 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -64,6 +64,7 @@ #include "cmGlobalVisualStudio71Generator.h" #include "cmGlobalVisualStudio8Generator.h" #include "cmGlobalVisualStudio9Generator.h" +#include "cmVSSetupHelper.h" #define CMAKE_HAVE_VS_GENERATORS #endif @@ -1470,18 +1471,23 @@ void cmake::CreateDefaultGlobalGenerator() "\\Setup\\VC;ProductDir", // ";InstallDir" // }; - for (VSVersionedGenerator const* g = cmArrayBegin(vsGenerators); - found.empty() && g != cmArrayEnd(vsGenerators); ++g) { - for (const char* const* v = cmArrayBegin(vsVariants); - found.empty() && v != cmArrayEnd(vsVariants); ++v) { - for (const char* const* e = cmArrayBegin(vsEntries); - found.empty() && e != cmArrayEnd(vsEntries); ++e) { - std::string const reg = vsregBase + *v + g->MSVersion + *e; - std::string dir; - if (cmSystemTools::ReadRegistryValue(reg, dir, - cmSystemTools::KeyWOW64_32) && - cmSystemTools::PathExists(dir)) { - found = g->GeneratorName; + cmVSSetupAPIHelper vsSetupAPIHelper; + if (vsSetupAPIHelper.IsVS2017Installed()) { + found = "Visual Studio 15 2017"; + } else { + for (VSVersionedGenerator const* g = cmArrayBegin(vsGenerators); + found.empty() && g != cmArrayEnd(vsGenerators); ++g) { + for (const char* const* v = cmArrayBegin(vsVariants); + found.empty() && v != cmArrayEnd(vsVariants); ++v) { + for (const char* const* e = cmArrayBegin(vsEntries); + found.empty() && e != cmArrayEnd(vsEntries); ++e) { + std::string const reg = vsregBase + *v + g->MSVersion + *e; + std::string dir; + if (cmSystemTools::ReadRegistryValue(reg, dir, + cmSystemTools::KeyWOW64_32) && + cmSystemTools::PathExists(dir)) { + found = g->GeneratorName; + } } } } |