Index: include/llvm/Support/MSVC.h =================================================================== --- /dev/null +++ include/llvm/Support/MSVC.h @@ -0,0 +1,26 @@ +//===-- llvm/Support/MSVC.h - Utility functions for MSVC --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_MSVC_H +#define LLVM_SUPPORT_MSVC_H + +#include + +namespace llvm { + +// Get Visual Studio installation directory from VCINSTALLDIR or +// the registory. +bool getVisualStudioInstallDir(std::string &Path); + +// Get Windows SDK installation directory from the registry. +bool getWindowsSDKDir(std::string &Path, int &Major, int &Minor); + +} + +#endif Index: lib/Support/CMakeLists.txt =================================================================== --- lib/Support/CMakeLists.txt +++ lib/Support/CMakeLists.txt @@ -64,6 +64,7 @@ LineIterator.cpp Locale.cpp LockFileManager.cpp + MSVC.cpp ManagedStatic.cpp MathExtras.cpp MemoryBuffer.cpp Index: lib/Support/MSVC.cpp =================================================================== --- /dev/null +++ lib/Support/MSVC.cpp @@ -0,0 +1,213 @@ +//===- llvm/Support/MSVC.cpp - Utility functions for MSVC -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/MSVC.h" +#include + +#ifdef LLVM_ON_WIN32 + +#define WIN32_LEAN_AND_MEAN +#define NOGDI +#ifndef NOMINMAX +#define NOMINMAX +#endif +#include + +namespace llvm { + +static bool readFullStringValue(HKEY HKey, const char *ValueName, + std::string &Value) { + // FIXME: We should be using the W versions of the registry functions, but + // doing so requires UTF8 / UTF16 conversions similar to how we handle command + // line arguments. The UTF8 conversion functions are not exposed publicly + // from LLVM though, so in order to do this we will probably need to create + // a registry abstraction in LLVMSupport that is Windows only. + DWORD Result = 0; + DWORD ValueSize = 0; + DWORD Type = 0; + // First just query for the required size. + Result = RegQueryValueEx(HKey, ValueName, NULL, &Type, NULL, &ValueSize); + if (Result != ERROR_SUCCESS || Type != REG_SZ) + return false; + std::vector Buffer(ValueSize); + Result = RegQueryValueEx(HKey, ValueName, NULL, NULL, &Buffer[0], &ValueSize); + if (Result == ERROR_SUCCESS) + Value.assign(reinterpret_cast(Buffer.data())); + return Result; +} + +/// \brief Read registry string. +/// This also supports a means to look for high-versioned keys by use +/// of a $VERSION placeholder in the key path. +/// $VERSION in the key path is a placeholder for the version number, +/// causing the highest value path to be searched for and used. +/// I.e. "SOFTWARE\\Microsoft\\VisualStudio\\$VERSION". +/// There can be additional characters in the component. Only the numeric +/// characters are compared. This function only searches HKLM. +static bool getSystemRegistryString(const char *KeyPath, const char *ValueName, + std::string &Value, std::string *PHValue) { + HKEY HRootKey = HKEY_LOCAL_MACHINE; + HKEY HKey = NULL; + long LResult; + bool ReturnValue = false; + + const char *PlaceHolder = strstr(KeyPath, "$VERSION"); + std::string BestName; + // If we have a $VERSION placeholder, do the highest-version search. + if (PlaceHolder) { + const char *KeyEnd = PlaceHolder - 1; + const char *NextKey = PlaceHolder; + // Find end of previous key. + while ((KeyEnd > KeyPath) && (*KeyEnd != '\\')) + KeyEnd--; + // Find end of key containing $VERSION. + while (*NextKey && (*NextKey != '\\')) + NextKey++; + size_t PartialKeyLength = KeyEnd - KeyPath; + char PartialKey[256]; + if (PartialKeyLength > sizeof(PartialKey)) + PartialKeyLength = sizeof(PartialKey); + strncpy(PartialKey, KeyPath, PartialKeyLength); + PartialKey[PartialKeyLength] = '\0'; + HKEY HTopKey = NULL; + LResult = RegOpenKeyEx(HRootKey, PartialKey, 0, KEY_READ | KEY_WOW64_32KEY, + &HTopKey); + if (LResult == ERROR_SUCCESS) { + char keyName[256]; + double bestValue = 0.0; + DWORD index, size = sizeof(keyName) - 1; + for (index = 0; RegEnumKeyEx(HTopKey, index, keyName, &size, NULL, + NULL, NULL, NULL) == ERROR_SUCCESS; index++) { + const char *sp = keyName; + while (*sp && !isDigit(*sp)) + sp++; + if (!*sp) + continue; + const char *ep = sp + 1; + while (*ep && (isDigit(*ep) || (*ep == '.'))) + ep++; + char numBuf[32]; + strncpy(numBuf, sp, sizeof(numBuf) - 1); + numBuf[sizeof(numBuf) - 1] = '\0'; + double dvalue = strtod(numBuf, NULL); + if (dvalue > bestValue) { + // Test that InstallDir is indeed there before keeping this index. + // Open the chosen key path remainder. + bestName = keyName; + // Append rest of key. + bestName.append(NextKey); + LResult = RegOpenKeyEx(HTopKey, BestName.c_str(), 0, + KEY_READ | KEY_WOW64_32KEY, &HKey); + if (LResult == ERROR_SUCCESS) { + LResult = readFullStringValue(HKey, ValueName, value); + if (LResult == ERROR_SUCCESS) { + bestValue = dvalue; + if (phValue) + *phValue = bestName; + ReturnValue = true; + } + RegCloseKey(HKey); + } + } + Size = sizeof(KeyName) - 1; + } + RegCloseKey(HTopKey); + } + } else { + LResult = + RegOpenKeyEx(hRootKey, KeyPath, 0, KEY_READ | KEY_WOW64_32KEY, &HKey); + if (LResult == ERROR_SUCCESS) { + LResult = readFullStringValue(HKey, ValueName, value); + if (LResult == ERROR_SUCCESS) + ReturnValue = true; + if (phValue) + phValue->clear(); + RegCloseKey(HKey); + } + } + return ReturnValue; +} + +bool getVisualStudioInstallDir(std::string &Path) { + // First check the environment variables that vsvars32.bat sets. + const char *VCInstallDir = getenv("VCINSTALLDIR"); + if (VCInstallDir) { + Path = VCInstallDir; + Path = Path.substr(0, Path.find("\\VC")); + return true; + } + + std::string VSIDEInstallDir; + std::string VSExpressIDEInstallDir; + // Then try the windows registry. + bool HasVCDir = + getSystemRegistryString("SOFTWARE\\Microsoft\\VisualStudio\\$VERSION", + "InstallDir", VSIDEInstallDir, nullptr); + if (HasVCDir && !VSIDEInstallDir.empty()) { + Path = VSIDEInstallDir.substr(0, VSIDEInstallDir.find("\\Common7\\IDE")); + return true; + } + + bool HasVCExpressDir = + getSystemRegistryString("SOFTWARE\\Microsoft\\VCExpress\\$VERSION", + "InstallDir", VSExpressIDEInstallDir, nullptr); + if (HasVCExpressDir && !VSExpressIDEInstallDir.empty()) { + Path = VSExpressIDEInstallDir.substr( + 0, VSIDEInstallDir.find("\\Common7\\IDE")); + return true; + } + + // Try the environment. + const char *VS120ComnTools = getenv("VS120COMNTOOLS"); + const char *VS100ComnTools = getenv("VS100COMNTOOLS"); + const char *VS90comnTools = getenv("VS90COMNTOOLS"); + const char *VS80comnTools = getenv("VS80COMNTOOLS"); + + const char *VSComnTools = nullptr; + + // Find any version we can + if (VS120ComnTools) + VSComnTools = VS120ComnTools; + else if (VS100ComnTools) + VSComnTools = VS100ComnTools; + else if (VS90comnTools) + VSComnTools = VS90comnTools; + else if (VS80comnTools) + VSComnTools = VS80comnTools; + + if (VSComnTools && *VSComnTools) { + const char *P = strstr(VSComnTools, "\\Common7\\Tools"); + Path = P ? std::string(VSComnTools, P) : VSComnTools; + return true; + } + return false; +} + +/// \brief Get Windows SDK installation directory. +bool getWindowsSDKDir(std::string &Path, int &Major, int &Minor) { + std::string SDKVersion; + // Try the Windows registry. + bool HasSDKDir = getSystemRegistryString( + "SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\$VERSION", + "InstallationFolder", Path, &SDKVersion); + if (!SDKVersion.empty()) + std::sscanf(SDKVersion.c_str(), "v%d.%d", &Major, &Minor); + return HasSDKDir && !Path.empty(); +} + +} // namespace llvm + +#else // LLVM_ON_WIN32 + +namespace llvm { +bool getVisualStudioInstallDir(std::string &Path) { return false; } +bool getWindowsSDKDir(std::string &Path, int &X, int &Y) { return false; } +} + +#endif // LLVM_ON_WIN32