summaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
Diffstat (limited to 'Source')
-rw-r--r--Source/CMakeInstallDestinations.cmake8
-rw-r--r--Source/CMakeLists.txt11
-rw-r--r--Source/CMakeVersion.cmake2
-rw-r--r--Source/CTest/cmCTestMemCheckHandler.cxx2
-rw-r--r--Source/cmExtraCodeBlocksGenerator.cxx3
-rw-r--r--Source/cmFileMonitor.cxx3
-rw-r--r--Source/cmGlobalVisualStudio10Generator.cxx14
-rw-r--r--Source/cmGlobalVisualStudio15Generator.cxx56
-rw-r--r--Source/cmGlobalVisualStudio15Generator.h5
-rw-r--r--Source/cmListFileLexer.c2
-rw-r--r--Source/cmListFileLexer.h2
-rw-r--r--Source/cmListFileLexer.in.l2
-rw-r--r--Source/cmMakefileExecutableTargetGenerator.cxx10
-rw-r--r--Source/cmMakefileLibraryTargetGenerator.cxx10
-rw-r--r--Source/cmNinjaNormalTargetGenerator.cxx9
-rw-r--r--Source/cmNinjaTargetGenerator.cxx3
-rw-r--r--Source/cmVSSetupHelper.cxx395
-rw-r--r--Source/cmVSSetupHelper.h154
-rw-r--r--Source/cmake.cxx30
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;
+ }
}
}
}