Index: include/llvm/Support/MSVC.h =================================================================== --- /dev/null +++ include/llvm/Support/MSVC.h @@ -0,0 +1,30 @@ +//===-- 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 { +class Triple; + +// 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); + +// Gets the library path required to link against the Windows SDK. +bool getWindowsSDKLibraryPath(std::string &Path, const llvm::Triple Triple); + +} + +#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,283 @@ +//===- 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/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MSVC.h" +#include "llvm/Support/Path.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 && '0' <= *SP && *SP <= '9') + SP++; + if (!*SP) + continue; + const char *EP = SP + 1; + while (*EP && (('0' <= *EP && *EP <= '9') || (*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(); +} + +// Gets the library path required to link against the Windows SDK. +bool getWindowsSDKLibraryPath(std::string &Path, const llvm::Triple Triple) { + std::string SDKPath; + int SDKMajor = 0; + int SDKMinor = 0; + + Path.clear(); + if (!llvm::getWindowsSDKDir(SDKPath, SDKMajor, SDKMinor)) + return false; + + llvm::SmallString<128> LibPath(SDKPath); + llvm::sys::path::append(LibPath, "Lib"); + if (SDKMajor <= 7) { + switch (Triple.getArch()) { + // In Windows SDK 7.x, x86 libraries are directly in the Lib folder. + case llvm::Triple::x86: + break; + case llvm::Triple::x86_64: + llvm::sys::path::append(LibPath, "x64"); + break; + case llvm::Triple::arm: + // It is not necessary to link against Windows SDK 7.x when targeting ARM. + return false; + default: + return false; + } + } else { + // Windows SDK 8.x installs libraries in a folder whose names depend on the + // version of the OS you're targeting. By default choose the newest, which + // usually corresponds to the version of the OS you've installed the SDK on. + const char *tests[] = {"winv6.3", "win8", "win7"}; + bool found = false; + for (const char *test : tests) { + llvm::SmallString<128> testPath(LibPath); + llvm::sys::path::append(testPath, test); + if (llvm::sys::fs::exists(testPath.c_str())) { + LibPath = testPath; + found = true; + break; + } + } + + if (!found) + return false; + + llvm::sys::path::append(LibPath, "um"); + switch (Triple.getArch()) { + case llvm::Triple::x86: + llvm::sys::path::append(LibPath, "x86"); + break; + case llvm::Triple::x86_64: + llvm::sys::path::append(LibPath, "x64"); + break; + case llvm::Triple::arm: + llvm::sys::path::append(LibPath, "arm"); + break; + default: + return false; + } + } + + Path = LibPath.str(); + return true; +} + +} // 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