181ad6265SDimitry Andric //===-- MSVCPaths.cpp - MSVC path-parsing helpers -------------------------===// 281ad6265SDimitry Andric // 381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 681ad6265SDimitry Andric // 781ad6265SDimitry Andric //===----------------------------------------------------------------------===// 881ad6265SDimitry Andric 981ad6265SDimitry Andric #include "llvm/WindowsDriver/MSVCPaths.h" 1081ad6265SDimitry Andric #include "llvm/ADT/SmallString.h" 1181ad6265SDimitry Andric #include "llvm/ADT/SmallVector.h" 1206c3fb27SDimitry Andric #include "llvm/ADT/StringExtras.h" 1381ad6265SDimitry Andric #include "llvm/ADT/StringRef.h" 1481ad6265SDimitry Andric #include "llvm/ADT/Twine.h" 1581ad6265SDimitry Andric #include "llvm/Support/Path.h" 1681ad6265SDimitry Andric #include "llvm/Support/Process.h" 1781ad6265SDimitry Andric #include "llvm/Support/Program.h" 1881ad6265SDimitry Andric #include "llvm/Support/VersionTuple.h" 1981ad6265SDimitry Andric #include "llvm/Support/VirtualFileSystem.h" 2006c3fb27SDimitry Andric #include "llvm/TargetParser/Host.h" 2106c3fb27SDimitry Andric #include "llvm/TargetParser/Triple.h" 22bdd1243dSDimitry Andric #include <optional> 2381ad6265SDimitry Andric #include <string> 2481ad6265SDimitry Andric 2581ad6265SDimitry Andric #ifdef _WIN32 2681ad6265SDimitry Andric #include "llvm/Support/ConvertUTF.h" 2781ad6265SDimitry Andric #endif 2881ad6265SDimitry Andric 2981ad6265SDimitry Andric #ifdef _WIN32 3081ad6265SDimitry Andric #define WIN32_LEAN_AND_MEAN 3181ad6265SDimitry Andric #define NOGDI 3281ad6265SDimitry Andric #ifndef NOMINMAX 3381ad6265SDimitry Andric #define NOMINMAX 3481ad6265SDimitry Andric #endif 3581ad6265SDimitry Andric #include <windows.h> 3681ad6265SDimitry Andric #endif 3781ad6265SDimitry Andric 3881ad6265SDimitry Andric #ifdef _MSC_VER 3981ad6265SDimitry Andric // Don't support SetupApi on MinGW. 4081ad6265SDimitry Andric #define USE_MSVC_SETUP_API 4181ad6265SDimitry Andric 4281ad6265SDimitry Andric // Make sure this comes before MSVCSetupApi.h 4381ad6265SDimitry Andric #include <comdef.h> 4481ad6265SDimitry Andric 4581ad6265SDimitry Andric #include "llvm/Support/COM.h" 4681ad6265SDimitry Andric #ifdef __clang__ 4781ad6265SDimitry Andric #pragma clang diagnostic push 4881ad6265SDimitry Andric #pragma clang diagnostic ignored "-Wnon-virtual-dtor" 4981ad6265SDimitry Andric #endif 5081ad6265SDimitry Andric #include "llvm/WindowsDriver/MSVCSetupApi.h" 5181ad6265SDimitry Andric #ifdef __clang__ 5281ad6265SDimitry Andric #pragma clang diagnostic pop 5381ad6265SDimitry Andric #endif 5481ad6265SDimitry Andric _COM_SMARTPTR_TYPEDEF(ISetupConfiguration, __uuidof(ISetupConfiguration)); 5581ad6265SDimitry Andric _COM_SMARTPTR_TYPEDEF(ISetupConfiguration2, __uuidof(ISetupConfiguration2)); 5681ad6265SDimitry Andric _COM_SMARTPTR_TYPEDEF(ISetupHelper, __uuidof(ISetupHelper)); 5781ad6265SDimitry Andric _COM_SMARTPTR_TYPEDEF(IEnumSetupInstances, __uuidof(IEnumSetupInstances)); 5881ad6265SDimitry Andric _COM_SMARTPTR_TYPEDEF(ISetupInstance, __uuidof(ISetupInstance)); 5981ad6265SDimitry Andric _COM_SMARTPTR_TYPEDEF(ISetupInstance2, __uuidof(ISetupInstance2)); 6081ad6265SDimitry Andric #endif 6181ad6265SDimitry Andric 6281ad6265SDimitry Andric static std::string 6381ad6265SDimitry Andric getHighestNumericTupleInDirectory(llvm::vfs::FileSystem &VFS, 6481ad6265SDimitry Andric llvm::StringRef Directory) { 6581ad6265SDimitry Andric std::string Highest; 6681ad6265SDimitry Andric llvm::VersionTuple HighestTuple; 6781ad6265SDimitry Andric 6881ad6265SDimitry Andric std::error_code EC; 6981ad6265SDimitry Andric for (llvm::vfs::directory_iterator DirIt = VFS.dir_begin(Directory, EC), 7081ad6265SDimitry Andric DirEnd; 7181ad6265SDimitry Andric !EC && DirIt != DirEnd; DirIt.increment(EC)) { 7281ad6265SDimitry Andric auto Status = VFS.status(DirIt->path()); 7381ad6265SDimitry Andric if (!Status || !Status->isDirectory()) 7481ad6265SDimitry Andric continue; 7581ad6265SDimitry Andric llvm::StringRef CandidateName = llvm::sys::path::filename(DirIt->path()); 7681ad6265SDimitry Andric llvm::VersionTuple Tuple; 7781ad6265SDimitry Andric if (Tuple.tryParse(CandidateName)) // tryParse() returns true on error. 7881ad6265SDimitry Andric continue; 7981ad6265SDimitry Andric if (Tuple > HighestTuple) { 8081ad6265SDimitry Andric HighestTuple = Tuple; 8181ad6265SDimitry Andric Highest = CandidateName.str(); 8281ad6265SDimitry Andric } 8381ad6265SDimitry Andric } 8481ad6265SDimitry Andric 8581ad6265SDimitry Andric return Highest; 8681ad6265SDimitry Andric } 8781ad6265SDimitry Andric 8881ad6265SDimitry Andric static bool getWindows10SDKVersionFromPath(llvm::vfs::FileSystem &VFS, 8981ad6265SDimitry Andric const std::string &SDKPath, 9081ad6265SDimitry Andric std::string &SDKVersion) { 9181ad6265SDimitry Andric llvm::SmallString<128> IncludePath(SDKPath); 9281ad6265SDimitry Andric llvm::sys::path::append(IncludePath, "Include"); 9381ad6265SDimitry Andric SDKVersion = getHighestNumericTupleInDirectory(VFS, IncludePath); 9481ad6265SDimitry Andric return !SDKVersion.empty(); 9581ad6265SDimitry Andric } 9681ad6265SDimitry Andric 9781ad6265SDimitry Andric static bool getWindowsSDKDirViaCommandLine( 98bdd1243dSDimitry Andric llvm::vfs::FileSystem &VFS, std::optional<llvm::StringRef> WinSdkDir, 99bdd1243dSDimitry Andric std::optional<llvm::StringRef> WinSdkVersion, 100bdd1243dSDimitry Andric std::optional<llvm::StringRef> WinSysRoot, std::string &Path, int &Major, 10181ad6265SDimitry Andric std::string &Version) { 10281ad6265SDimitry Andric if (WinSdkDir || WinSysRoot) { 10381ad6265SDimitry Andric // Don't validate the input; trust the value supplied by the user. 10481ad6265SDimitry Andric // The motivation is to prevent unnecessary file and registry access. 10581ad6265SDimitry Andric llvm::VersionTuple SDKVersion; 10681ad6265SDimitry Andric if (WinSdkVersion) 10781ad6265SDimitry Andric SDKVersion.tryParse(*WinSdkVersion); 10881ad6265SDimitry Andric 10981ad6265SDimitry Andric if (WinSysRoot) { 11081ad6265SDimitry Andric llvm::SmallString<128> SDKPath(*WinSysRoot); 11181ad6265SDimitry Andric llvm::sys::path::append(SDKPath, "Windows Kits"); 11281ad6265SDimitry Andric if (!SDKVersion.empty()) 11381ad6265SDimitry Andric llvm::sys::path::append(SDKPath, llvm::Twine(SDKVersion.getMajor())); 11481ad6265SDimitry Andric else 11581ad6265SDimitry Andric llvm::sys::path::append( 11681ad6265SDimitry Andric SDKPath, getHighestNumericTupleInDirectory(VFS, SDKPath)); 1177a6dacacSDimitry Andric Path = std::string(SDKPath); 11881ad6265SDimitry Andric } else { 11981ad6265SDimitry Andric Path = WinSdkDir->str(); 12081ad6265SDimitry Andric } 12181ad6265SDimitry Andric 12281ad6265SDimitry Andric if (!SDKVersion.empty()) { 12381ad6265SDimitry Andric Major = SDKVersion.getMajor(); 12481ad6265SDimitry Andric Version = SDKVersion.getAsString(); 12581ad6265SDimitry Andric } else if (getWindows10SDKVersionFromPath(VFS, Path, Version)) { 12681ad6265SDimitry Andric Major = 10; 12781ad6265SDimitry Andric } 12881ad6265SDimitry Andric return true; 12981ad6265SDimitry Andric } 13081ad6265SDimitry Andric return false; 13181ad6265SDimitry Andric } 13281ad6265SDimitry Andric 13381ad6265SDimitry Andric #ifdef _WIN32 13481ad6265SDimitry Andric static bool readFullStringValue(HKEY hkey, const char *valueName, 13581ad6265SDimitry Andric std::string &value) { 13681ad6265SDimitry Andric std::wstring WideValueName; 13781ad6265SDimitry Andric if (!llvm::ConvertUTF8toWide(valueName, WideValueName)) 13881ad6265SDimitry Andric return false; 13981ad6265SDimitry Andric 14081ad6265SDimitry Andric DWORD result = 0; 14181ad6265SDimitry Andric DWORD valueSize = 0; 14281ad6265SDimitry Andric DWORD type = 0; 14381ad6265SDimitry Andric // First just query for the required size. 14481ad6265SDimitry Andric result = RegQueryValueExW(hkey, WideValueName.c_str(), NULL, &type, NULL, 14581ad6265SDimitry Andric &valueSize); 14681ad6265SDimitry Andric if (result != ERROR_SUCCESS || type != REG_SZ || !valueSize) 14781ad6265SDimitry Andric return false; 14881ad6265SDimitry Andric std::vector<BYTE> buffer(valueSize); 14981ad6265SDimitry Andric result = RegQueryValueExW(hkey, WideValueName.c_str(), NULL, NULL, &buffer[0], 15081ad6265SDimitry Andric &valueSize); 15181ad6265SDimitry Andric if (result == ERROR_SUCCESS) { 15281ad6265SDimitry Andric std::wstring WideValue(reinterpret_cast<const wchar_t *>(buffer.data()), 15381ad6265SDimitry Andric valueSize / sizeof(wchar_t)); 15481ad6265SDimitry Andric if (valueSize && WideValue.back() == L'\0') { 15581ad6265SDimitry Andric WideValue.pop_back(); 15681ad6265SDimitry Andric } 15781ad6265SDimitry Andric // The destination buffer must be empty as an invariant of the conversion 15881ad6265SDimitry Andric // function; but this function is sometimes called in a loop that passes in 15981ad6265SDimitry Andric // the same buffer, however. Simply clear it out so we can overwrite it. 16081ad6265SDimitry Andric value.clear(); 16181ad6265SDimitry Andric return llvm::convertWideToUTF8(WideValue, value); 16281ad6265SDimitry Andric } 16381ad6265SDimitry Andric return false; 16481ad6265SDimitry Andric } 16581ad6265SDimitry Andric #endif 16681ad6265SDimitry Andric 16781ad6265SDimitry Andric /// Read registry string. 16881ad6265SDimitry Andric /// This also supports a means to look for high-versioned keys by use 16981ad6265SDimitry Andric /// of a $VERSION placeholder in the key path. 17081ad6265SDimitry Andric /// $VERSION in the key path is a placeholder for the version number, 17181ad6265SDimitry Andric /// causing the highest value path to be searched for and used. 17281ad6265SDimitry Andric /// I.e. "SOFTWARE\\Microsoft\\VisualStudio\\$VERSION". 17381ad6265SDimitry Andric /// There can be additional characters in the component. Only the numeric 17481ad6265SDimitry Andric /// characters are compared. This function only searches HKLM. 17581ad6265SDimitry Andric static bool getSystemRegistryString(const char *keyPath, const char *valueName, 17681ad6265SDimitry Andric std::string &value, std::string *phValue) { 17781ad6265SDimitry Andric #ifndef _WIN32 17881ad6265SDimitry Andric return false; 17981ad6265SDimitry Andric #else 18081ad6265SDimitry Andric HKEY hRootKey = HKEY_LOCAL_MACHINE; 18181ad6265SDimitry Andric HKEY hKey = NULL; 18281ad6265SDimitry Andric long lResult; 18381ad6265SDimitry Andric bool returnValue = false; 18481ad6265SDimitry Andric 18581ad6265SDimitry Andric const char *placeHolder = strstr(keyPath, "$VERSION"); 18681ad6265SDimitry Andric std::string bestName; 18781ad6265SDimitry Andric // If we have a $VERSION placeholder, do the highest-version search. 18881ad6265SDimitry Andric if (placeHolder) { 18981ad6265SDimitry Andric const char *keyEnd = placeHolder - 1; 19081ad6265SDimitry Andric const char *nextKey = placeHolder; 19181ad6265SDimitry Andric // Find end of previous key. 19281ad6265SDimitry Andric while ((keyEnd > keyPath) && (*keyEnd != '\\')) 19381ad6265SDimitry Andric keyEnd--; 19481ad6265SDimitry Andric // Find end of key containing $VERSION. 19581ad6265SDimitry Andric while (*nextKey && (*nextKey != '\\')) 19681ad6265SDimitry Andric nextKey++; 19781ad6265SDimitry Andric size_t partialKeyLength = keyEnd - keyPath; 19881ad6265SDimitry Andric char partialKey[256]; 19981ad6265SDimitry Andric if (partialKeyLength >= sizeof(partialKey)) 20081ad6265SDimitry Andric partialKeyLength = sizeof(partialKey) - 1; 20181ad6265SDimitry Andric strncpy(partialKey, keyPath, partialKeyLength); 20281ad6265SDimitry Andric partialKey[partialKeyLength] = '\0'; 20381ad6265SDimitry Andric HKEY hTopKey = NULL; 20481ad6265SDimitry Andric lResult = RegOpenKeyExA(hRootKey, partialKey, 0, KEY_READ | KEY_WOW64_32KEY, 20581ad6265SDimitry Andric &hTopKey); 20681ad6265SDimitry Andric if (lResult == ERROR_SUCCESS) { 20781ad6265SDimitry Andric char keyName[256]; 20881ad6265SDimitry Andric double bestValue = 0.0; 20981ad6265SDimitry Andric DWORD index, size = sizeof(keyName) - 1; 21081ad6265SDimitry Andric for (index = 0; RegEnumKeyExA(hTopKey, index, keyName, &size, NULL, NULL, 21181ad6265SDimitry Andric NULL, NULL) == ERROR_SUCCESS; 21281ad6265SDimitry Andric index++) { 21381ad6265SDimitry Andric const char *sp = keyName; 21481ad6265SDimitry Andric while (*sp && !llvm::isDigit(*sp)) 21581ad6265SDimitry Andric sp++; 21681ad6265SDimitry Andric if (!*sp) 21781ad6265SDimitry Andric continue; 21881ad6265SDimitry Andric const char *ep = sp + 1; 21981ad6265SDimitry Andric while (*ep && (llvm::isDigit(*ep) || (*ep == '.'))) 22081ad6265SDimitry Andric ep++; 22181ad6265SDimitry Andric char numBuf[32]; 22281ad6265SDimitry Andric strncpy(numBuf, sp, sizeof(numBuf) - 1); 22381ad6265SDimitry Andric numBuf[sizeof(numBuf) - 1] = '\0'; 22481ad6265SDimitry Andric double dvalue = strtod(numBuf, NULL); 22581ad6265SDimitry Andric if (dvalue > bestValue) { 22681ad6265SDimitry Andric // Test that InstallDir is indeed there before keeping this index. 22781ad6265SDimitry Andric // Open the chosen key path remainder. 22881ad6265SDimitry Andric bestName = keyName; 22981ad6265SDimitry Andric // Append rest of key. 23081ad6265SDimitry Andric bestName.append(nextKey); 23181ad6265SDimitry Andric lResult = RegOpenKeyExA(hTopKey, bestName.c_str(), 0, 23281ad6265SDimitry Andric KEY_READ | KEY_WOW64_32KEY, &hKey); 23381ad6265SDimitry Andric if (lResult == ERROR_SUCCESS) { 23481ad6265SDimitry Andric if (readFullStringValue(hKey, valueName, value)) { 23581ad6265SDimitry Andric bestValue = dvalue; 23681ad6265SDimitry Andric if (phValue) 23781ad6265SDimitry Andric *phValue = bestName; 23881ad6265SDimitry Andric returnValue = true; 23981ad6265SDimitry Andric } 24081ad6265SDimitry Andric RegCloseKey(hKey); 24181ad6265SDimitry Andric } 24281ad6265SDimitry Andric } 24381ad6265SDimitry Andric size = sizeof(keyName) - 1; 24481ad6265SDimitry Andric } 24581ad6265SDimitry Andric RegCloseKey(hTopKey); 24681ad6265SDimitry Andric } 24781ad6265SDimitry Andric } else { 24881ad6265SDimitry Andric lResult = 24981ad6265SDimitry Andric RegOpenKeyExA(hRootKey, keyPath, 0, KEY_READ | KEY_WOW64_32KEY, &hKey); 25081ad6265SDimitry Andric if (lResult == ERROR_SUCCESS) { 25181ad6265SDimitry Andric if (readFullStringValue(hKey, valueName, value)) 25281ad6265SDimitry Andric returnValue = true; 25381ad6265SDimitry Andric if (phValue) 25481ad6265SDimitry Andric phValue->clear(); 25581ad6265SDimitry Andric RegCloseKey(hKey); 25681ad6265SDimitry Andric } 25781ad6265SDimitry Andric } 25881ad6265SDimitry Andric return returnValue; 25981ad6265SDimitry Andric #endif // _WIN32 26081ad6265SDimitry Andric } 26181ad6265SDimitry Andric 26281ad6265SDimitry Andric namespace llvm { 26381ad6265SDimitry Andric 26481ad6265SDimitry Andric const char *archToWindowsSDKArch(Triple::ArchType Arch) { 26581ad6265SDimitry Andric switch (Arch) { 26681ad6265SDimitry Andric case Triple::ArchType::x86: 26781ad6265SDimitry Andric return "x86"; 26881ad6265SDimitry Andric case Triple::ArchType::x86_64: 26981ad6265SDimitry Andric return "x64"; 27081ad6265SDimitry Andric case Triple::ArchType::arm: 271*0fca6ea1SDimitry Andric case Triple::ArchType::thumb: 27281ad6265SDimitry Andric return "arm"; 27381ad6265SDimitry Andric case Triple::ArchType::aarch64: 27481ad6265SDimitry Andric return "arm64"; 27581ad6265SDimitry Andric default: 27681ad6265SDimitry Andric return ""; 27781ad6265SDimitry Andric } 27881ad6265SDimitry Andric } 27981ad6265SDimitry Andric 28081ad6265SDimitry Andric const char *archToLegacyVCArch(Triple::ArchType Arch) { 28181ad6265SDimitry Andric switch (Arch) { 28281ad6265SDimitry Andric case Triple::ArchType::x86: 28381ad6265SDimitry Andric // x86 is default in legacy VC toolchains. 28481ad6265SDimitry Andric // e.g. x86 libs are directly in /lib as opposed to /lib/x86. 28581ad6265SDimitry Andric return ""; 28681ad6265SDimitry Andric case Triple::ArchType::x86_64: 28781ad6265SDimitry Andric return "amd64"; 28881ad6265SDimitry Andric case Triple::ArchType::arm: 289*0fca6ea1SDimitry Andric case Triple::ArchType::thumb: 29081ad6265SDimitry Andric return "arm"; 29181ad6265SDimitry Andric case Triple::ArchType::aarch64: 29281ad6265SDimitry Andric return "arm64"; 29381ad6265SDimitry Andric default: 29481ad6265SDimitry Andric return ""; 29581ad6265SDimitry Andric } 29681ad6265SDimitry Andric } 29781ad6265SDimitry Andric 29881ad6265SDimitry Andric const char *archToDevDivInternalArch(Triple::ArchType Arch) { 29981ad6265SDimitry Andric switch (Arch) { 30081ad6265SDimitry Andric case Triple::ArchType::x86: 30181ad6265SDimitry Andric return "i386"; 30281ad6265SDimitry Andric case Triple::ArchType::x86_64: 30381ad6265SDimitry Andric return "amd64"; 30481ad6265SDimitry Andric case Triple::ArchType::arm: 305*0fca6ea1SDimitry Andric case Triple::ArchType::thumb: 30681ad6265SDimitry Andric return "arm"; 30781ad6265SDimitry Andric case Triple::ArchType::aarch64: 30881ad6265SDimitry Andric return "arm64"; 30981ad6265SDimitry Andric default: 31081ad6265SDimitry Andric return ""; 31181ad6265SDimitry Andric } 31281ad6265SDimitry Andric } 31381ad6265SDimitry Andric 31481ad6265SDimitry Andric bool appendArchToWindowsSDKLibPath(int SDKMajor, SmallString<128> LibPath, 31581ad6265SDimitry Andric Triple::ArchType Arch, std::string &path) { 31681ad6265SDimitry Andric if (SDKMajor >= 8) { 31781ad6265SDimitry Andric sys::path::append(LibPath, archToWindowsSDKArch(Arch)); 31881ad6265SDimitry Andric } else { 31981ad6265SDimitry Andric switch (Arch) { 32081ad6265SDimitry Andric // In Windows SDK 7.x, x86 libraries are directly in the Lib folder. 32181ad6265SDimitry Andric case Triple::x86: 32281ad6265SDimitry Andric break; 32381ad6265SDimitry Andric case Triple::x86_64: 32481ad6265SDimitry Andric sys::path::append(LibPath, "x64"); 32581ad6265SDimitry Andric break; 32681ad6265SDimitry Andric case Triple::arm: 327*0fca6ea1SDimitry Andric case Triple::thumb: 32881ad6265SDimitry Andric // It is not necessary to link against Windows SDK 7.x when targeting ARM. 32981ad6265SDimitry Andric return false; 33081ad6265SDimitry Andric default: 33181ad6265SDimitry Andric return false; 33281ad6265SDimitry Andric } 33381ad6265SDimitry Andric } 33481ad6265SDimitry Andric 3357a6dacacSDimitry Andric path = std::string(LibPath); 33681ad6265SDimitry Andric return true; 33781ad6265SDimitry Andric } 33881ad6265SDimitry Andric 33981ad6265SDimitry Andric std::string getSubDirectoryPath(SubDirectoryType Type, ToolsetLayout VSLayout, 34081ad6265SDimitry Andric const std::string &VCToolChainPath, 34181ad6265SDimitry Andric Triple::ArchType TargetArch, 34281ad6265SDimitry Andric StringRef SubdirParent) { 34381ad6265SDimitry Andric const char *SubdirName; 34481ad6265SDimitry Andric const char *IncludeName; 34581ad6265SDimitry Andric switch (VSLayout) { 34681ad6265SDimitry Andric case ToolsetLayout::OlderVS: 34781ad6265SDimitry Andric SubdirName = archToLegacyVCArch(TargetArch); 34881ad6265SDimitry Andric IncludeName = "include"; 34981ad6265SDimitry Andric break; 35081ad6265SDimitry Andric case ToolsetLayout::VS2017OrNewer: 35181ad6265SDimitry Andric SubdirName = archToWindowsSDKArch(TargetArch); 35281ad6265SDimitry Andric IncludeName = "include"; 35381ad6265SDimitry Andric break; 35481ad6265SDimitry Andric case ToolsetLayout::DevDivInternal: 35581ad6265SDimitry Andric SubdirName = archToDevDivInternalArch(TargetArch); 35681ad6265SDimitry Andric IncludeName = "inc"; 35781ad6265SDimitry Andric break; 35881ad6265SDimitry Andric } 35981ad6265SDimitry Andric 36081ad6265SDimitry Andric SmallString<256> Path(VCToolChainPath); 36181ad6265SDimitry Andric if (!SubdirParent.empty()) 36281ad6265SDimitry Andric sys::path::append(Path, SubdirParent); 36381ad6265SDimitry Andric 36481ad6265SDimitry Andric switch (Type) { 36581ad6265SDimitry Andric case SubDirectoryType::Bin: 36681ad6265SDimitry Andric if (VSLayout == ToolsetLayout::VS2017OrNewer) { 36781ad6265SDimitry Andric // MSVC ships with two linkers: a 32-bit x86 and 64-bit x86 linker. 36881ad6265SDimitry Andric // On x86, pick the linker that corresponds to the current process. 36981ad6265SDimitry Andric // On ARM64, pick the 32-bit x86 linker; the 64-bit one doesn't run 37081ad6265SDimitry Andric // on Windows 10. 37181ad6265SDimitry Andric // 37281ad6265SDimitry Andric // FIXME: Consider using IsWow64GuestMachineSupported to figure out 37381ad6265SDimitry Andric // if we can invoke the 64-bit linker. It's generally preferable 37481ad6265SDimitry Andric // because it won't run out of address-space. 37581ad6265SDimitry Andric const bool HostIsX64 = 37681ad6265SDimitry Andric Triple(sys::getProcessTriple()).getArch() == Triple::x86_64; 37781ad6265SDimitry Andric const char *const HostName = HostIsX64 ? "Hostx64" : "Hostx86"; 37881ad6265SDimitry Andric sys::path::append(Path, "bin", HostName, SubdirName); 37981ad6265SDimitry Andric } else { // OlderVS or DevDivInternal 38081ad6265SDimitry Andric sys::path::append(Path, "bin", SubdirName); 38181ad6265SDimitry Andric } 38281ad6265SDimitry Andric break; 38381ad6265SDimitry Andric case SubDirectoryType::Include: 38481ad6265SDimitry Andric sys::path::append(Path, IncludeName); 38581ad6265SDimitry Andric break; 38681ad6265SDimitry Andric case SubDirectoryType::Lib: 38781ad6265SDimitry Andric sys::path::append(Path, "lib", SubdirName); 38881ad6265SDimitry Andric break; 38981ad6265SDimitry Andric } 3907a6dacacSDimitry Andric return std::string(Path); 39181ad6265SDimitry Andric } 39281ad6265SDimitry Andric 39381ad6265SDimitry Andric bool useUniversalCRT(ToolsetLayout VSLayout, const std::string &VCToolChainPath, 39481ad6265SDimitry Andric Triple::ArchType TargetArch, vfs::FileSystem &VFS) { 39581ad6265SDimitry Andric SmallString<128> TestPath(getSubDirectoryPath( 39681ad6265SDimitry Andric SubDirectoryType::Include, VSLayout, VCToolChainPath, TargetArch)); 39781ad6265SDimitry Andric sys::path::append(TestPath, "stdlib.h"); 39881ad6265SDimitry Andric return !VFS.exists(TestPath); 39981ad6265SDimitry Andric } 40081ad6265SDimitry Andric 401bdd1243dSDimitry Andric bool getWindowsSDKDir(vfs::FileSystem &VFS, std::optional<StringRef> WinSdkDir, 402bdd1243dSDimitry Andric std::optional<StringRef> WinSdkVersion, 403bdd1243dSDimitry Andric std::optional<StringRef> WinSysRoot, std::string &Path, 40481ad6265SDimitry Andric int &Major, std::string &WindowsSDKIncludeVersion, 40581ad6265SDimitry Andric std::string &WindowsSDKLibVersion) { 40681ad6265SDimitry Andric // Trust /winsdkdir and /winsdkversion if present. 40781ad6265SDimitry Andric if (getWindowsSDKDirViaCommandLine(VFS, WinSdkDir, WinSdkVersion, WinSysRoot, 40881ad6265SDimitry Andric Path, Major, WindowsSDKIncludeVersion)) { 40981ad6265SDimitry Andric WindowsSDKLibVersion = WindowsSDKIncludeVersion; 41081ad6265SDimitry Andric return true; 41181ad6265SDimitry Andric } 41281ad6265SDimitry Andric 41381ad6265SDimitry Andric // FIXME: Try env vars (%WindowsSdkDir%, %UCRTVersion%) before going to 41481ad6265SDimitry Andric // registry. 41581ad6265SDimitry Andric 41681ad6265SDimitry Andric // Try the Windows registry. 41781ad6265SDimitry Andric std::string RegistrySDKVersion; 41881ad6265SDimitry Andric if (!getSystemRegistryString( 41981ad6265SDimitry Andric "SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\$VERSION", 42081ad6265SDimitry Andric "InstallationFolder", Path, &RegistrySDKVersion)) 42181ad6265SDimitry Andric return false; 42281ad6265SDimitry Andric if (Path.empty() || RegistrySDKVersion.empty()) 42381ad6265SDimitry Andric return false; 42481ad6265SDimitry Andric 42581ad6265SDimitry Andric WindowsSDKIncludeVersion.clear(); 42681ad6265SDimitry Andric WindowsSDKLibVersion.clear(); 42781ad6265SDimitry Andric Major = 0; 42881ad6265SDimitry Andric std::sscanf(RegistrySDKVersion.c_str(), "v%d.", &Major); 42981ad6265SDimitry Andric if (Major <= 7) 43081ad6265SDimitry Andric return true; 43181ad6265SDimitry Andric if (Major == 8) { 43281ad6265SDimitry Andric // Windows SDK 8.x installs libraries in a folder whose names depend on the 43381ad6265SDimitry Andric // version of the OS you're targeting. By default choose the newest, which 43481ad6265SDimitry Andric // usually corresponds to the version of the OS you've installed the SDK on. 43581ad6265SDimitry Andric const char *Tests[] = {"winv6.3", "win8", "win7"}; 43681ad6265SDimitry Andric for (const char *Test : Tests) { 43781ad6265SDimitry Andric SmallString<128> TestPath(Path); 43881ad6265SDimitry Andric sys::path::append(TestPath, "Lib", Test); 43981ad6265SDimitry Andric if (VFS.exists(TestPath)) { 44081ad6265SDimitry Andric WindowsSDKLibVersion = Test; 44181ad6265SDimitry Andric break; 44281ad6265SDimitry Andric } 44381ad6265SDimitry Andric } 44481ad6265SDimitry Andric return !WindowsSDKLibVersion.empty(); 44581ad6265SDimitry Andric } 44681ad6265SDimitry Andric if (Major == 10) { 44781ad6265SDimitry Andric if (!getWindows10SDKVersionFromPath(VFS, Path, WindowsSDKIncludeVersion)) 44881ad6265SDimitry Andric return false; 44981ad6265SDimitry Andric WindowsSDKLibVersion = WindowsSDKIncludeVersion; 45081ad6265SDimitry Andric return true; 45181ad6265SDimitry Andric } 45281ad6265SDimitry Andric // Unsupported SDK version 45381ad6265SDimitry Andric return false; 45481ad6265SDimitry Andric } 45581ad6265SDimitry Andric 456bdd1243dSDimitry Andric bool getUniversalCRTSdkDir(vfs::FileSystem &VFS, 457bdd1243dSDimitry Andric std::optional<StringRef> WinSdkDir, 458bdd1243dSDimitry Andric std::optional<StringRef> WinSdkVersion, 459bdd1243dSDimitry Andric std::optional<StringRef> WinSysRoot, 460bdd1243dSDimitry Andric std::string &Path, std::string &UCRTVersion) { 46181ad6265SDimitry Andric // If /winsdkdir is passed, use it as location for the UCRT too. 46281ad6265SDimitry Andric // FIXME: Should there be a dedicated /ucrtdir to override /winsdkdir? 46381ad6265SDimitry Andric int Major; 46481ad6265SDimitry Andric if (getWindowsSDKDirViaCommandLine(VFS, WinSdkDir, WinSdkVersion, WinSysRoot, 46581ad6265SDimitry Andric Path, Major, UCRTVersion)) 46681ad6265SDimitry Andric return true; 46781ad6265SDimitry Andric 46881ad6265SDimitry Andric // FIXME: Try env vars (%UniversalCRTSdkDir%, %UCRTVersion%) before going to 46981ad6265SDimitry Andric // registry. 47081ad6265SDimitry Andric 47181ad6265SDimitry Andric // vcvarsqueryregistry.bat for Visual Studio 2015 queries the registry 47281ad6265SDimitry Andric // for the specific key "KitsRoot10". So do we. 47381ad6265SDimitry Andric if (!getSystemRegistryString( 47481ad6265SDimitry Andric "SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots", "KitsRoot10", 47581ad6265SDimitry Andric Path, nullptr)) 47681ad6265SDimitry Andric return false; 47781ad6265SDimitry Andric 47881ad6265SDimitry Andric return getWindows10SDKVersionFromPath(VFS, Path, UCRTVersion); 47981ad6265SDimitry Andric } 48081ad6265SDimitry Andric 48181ad6265SDimitry Andric bool findVCToolChainViaCommandLine(vfs::FileSystem &VFS, 482bdd1243dSDimitry Andric std::optional<StringRef> VCToolsDir, 483bdd1243dSDimitry Andric std::optional<StringRef> VCToolsVersion, 484bdd1243dSDimitry Andric std::optional<StringRef> WinSysRoot, 48581ad6265SDimitry Andric std::string &Path, ToolsetLayout &VSLayout) { 48681ad6265SDimitry Andric // Don't validate the input; trust the value supplied by the user. 48781ad6265SDimitry Andric // The primary motivation is to prevent unnecessary file and registry access. 48881ad6265SDimitry Andric if (VCToolsDir || WinSysRoot) { 48981ad6265SDimitry Andric if (WinSysRoot) { 49081ad6265SDimitry Andric SmallString<128> ToolsPath(*WinSysRoot); 49181ad6265SDimitry Andric sys::path::append(ToolsPath, "VC", "Tools", "MSVC"); 49281ad6265SDimitry Andric std::string ToolsVersion; 49381ad6265SDimitry Andric if (VCToolsVersion) 49481ad6265SDimitry Andric ToolsVersion = VCToolsVersion->str(); 49581ad6265SDimitry Andric else 49681ad6265SDimitry Andric ToolsVersion = getHighestNumericTupleInDirectory(VFS, ToolsPath); 49781ad6265SDimitry Andric sys::path::append(ToolsPath, ToolsVersion); 4987a6dacacSDimitry Andric Path = std::string(ToolsPath); 49981ad6265SDimitry Andric } else { 50081ad6265SDimitry Andric Path = VCToolsDir->str(); 50181ad6265SDimitry Andric } 50281ad6265SDimitry Andric VSLayout = ToolsetLayout::VS2017OrNewer; 50381ad6265SDimitry Andric return true; 50481ad6265SDimitry Andric } 50581ad6265SDimitry Andric return false; 50681ad6265SDimitry Andric } 50781ad6265SDimitry Andric 50881ad6265SDimitry Andric bool findVCToolChainViaEnvironment(vfs::FileSystem &VFS, std::string &Path, 50981ad6265SDimitry Andric ToolsetLayout &VSLayout) { 51081ad6265SDimitry Andric // These variables are typically set by vcvarsall.bat 51181ad6265SDimitry Andric // when launching a developer command prompt. 512bdd1243dSDimitry Andric if (std::optional<std::string> VCToolsInstallDir = 51381ad6265SDimitry Andric sys::Process::GetEnv("VCToolsInstallDir")) { 51481ad6265SDimitry Andric // This is only set by newer Visual Studios, and it leads straight to 51581ad6265SDimitry Andric // the toolchain directory. 51681ad6265SDimitry Andric Path = std::move(*VCToolsInstallDir); 51781ad6265SDimitry Andric VSLayout = ToolsetLayout::VS2017OrNewer; 51881ad6265SDimitry Andric return true; 51981ad6265SDimitry Andric } 520bdd1243dSDimitry Andric if (std::optional<std::string> VCInstallDir = 52181ad6265SDimitry Andric sys::Process::GetEnv("VCINSTALLDIR")) { 52281ad6265SDimitry Andric // If the previous variable isn't set but this one is, then we've found 52381ad6265SDimitry Andric // an older Visual Studio. This variable is set by newer Visual Studios too, 52481ad6265SDimitry Andric // so this check has to appear second. 52581ad6265SDimitry Andric // In older Visual Studios, the VC directory is the toolchain. 52681ad6265SDimitry Andric Path = std::move(*VCInstallDir); 52781ad6265SDimitry Andric VSLayout = ToolsetLayout::OlderVS; 52881ad6265SDimitry Andric return true; 52981ad6265SDimitry Andric } 53081ad6265SDimitry Andric 53181ad6265SDimitry Andric // We couldn't find any VC environment variables. Let's walk through PATH and 53281ad6265SDimitry Andric // see if it leads us to a VC toolchain bin directory. If it does, pick the 53381ad6265SDimitry Andric // first one that we find. 534bdd1243dSDimitry Andric if (std::optional<std::string> PathEnv = sys::Process::GetEnv("PATH")) { 53581ad6265SDimitry Andric SmallVector<StringRef, 8> PathEntries; 53681ad6265SDimitry Andric StringRef(*PathEnv).split(PathEntries, sys::EnvPathSeparator); 53781ad6265SDimitry Andric for (StringRef PathEntry : PathEntries) { 53881ad6265SDimitry Andric if (PathEntry.empty()) 53981ad6265SDimitry Andric continue; 54081ad6265SDimitry Andric 54181ad6265SDimitry Andric SmallString<256> ExeTestPath; 54281ad6265SDimitry Andric 54381ad6265SDimitry Andric // If cl.exe doesn't exist, then this definitely isn't a VC toolchain. 54481ad6265SDimitry Andric ExeTestPath = PathEntry; 54581ad6265SDimitry Andric sys::path::append(ExeTestPath, "cl.exe"); 54681ad6265SDimitry Andric if (!VFS.exists(ExeTestPath)) 54781ad6265SDimitry Andric continue; 54881ad6265SDimitry Andric 54981ad6265SDimitry Andric // cl.exe existing isn't a conclusive test for a VC toolchain; clang also 55081ad6265SDimitry Andric // has a cl.exe. So let's check for link.exe too. 55181ad6265SDimitry Andric ExeTestPath = PathEntry; 55281ad6265SDimitry Andric sys::path::append(ExeTestPath, "link.exe"); 55381ad6265SDimitry Andric if (!VFS.exists(ExeTestPath)) 55481ad6265SDimitry Andric continue; 55581ad6265SDimitry Andric 55681ad6265SDimitry Andric // whatever/VC/bin --> old toolchain, VC dir is toolchain dir. 55781ad6265SDimitry Andric StringRef TestPath = PathEntry; 55881ad6265SDimitry Andric bool IsBin = sys::path::filename(TestPath).equals_insensitive("bin"); 55981ad6265SDimitry Andric if (!IsBin) { 56081ad6265SDimitry Andric // Strip any architecture subdir like "amd64". 56181ad6265SDimitry Andric TestPath = sys::path::parent_path(TestPath); 56281ad6265SDimitry Andric IsBin = sys::path::filename(TestPath).equals_insensitive("bin"); 56381ad6265SDimitry Andric } 56481ad6265SDimitry Andric if (IsBin) { 56581ad6265SDimitry Andric StringRef ParentPath = sys::path::parent_path(TestPath); 56681ad6265SDimitry Andric StringRef ParentFilename = sys::path::filename(ParentPath); 56781ad6265SDimitry Andric if (ParentFilename.equals_insensitive("VC")) { 56881ad6265SDimitry Andric Path = std::string(ParentPath); 56981ad6265SDimitry Andric VSLayout = ToolsetLayout::OlderVS; 57081ad6265SDimitry Andric return true; 57181ad6265SDimitry Andric } 57281ad6265SDimitry Andric if (ParentFilename.equals_insensitive("x86ret") || 57381ad6265SDimitry Andric ParentFilename.equals_insensitive("x86chk") || 57481ad6265SDimitry Andric ParentFilename.equals_insensitive("amd64ret") || 57581ad6265SDimitry Andric ParentFilename.equals_insensitive("amd64chk")) { 57681ad6265SDimitry Andric Path = std::string(ParentPath); 57781ad6265SDimitry Andric VSLayout = ToolsetLayout::DevDivInternal; 57881ad6265SDimitry Andric return true; 57981ad6265SDimitry Andric } 58081ad6265SDimitry Andric 58181ad6265SDimitry Andric } else { 58281ad6265SDimitry Andric // This could be a new (>=VS2017) toolchain. If it is, we should find 58381ad6265SDimitry Andric // path components with these prefixes when walking backwards through 58481ad6265SDimitry Andric // the path. 58581ad6265SDimitry Andric // Note: empty strings match anything. 58681ad6265SDimitry Andric StringRef ExpectedPrefixes[] = {"", "Host", "bin", "", 58781ad6265SDimitry Andric "MSVC", "Tools", "VC"}; 58881ad6265SDimitry Andric 58981ad6265SDimitry Andric auto It = sys::path::rbegin(PathEntry); 59081ad6265SDimitry Andric auto End = sys::path::rend(PathEntry); 59181ad6265SDimitry Andric for (StringRef Prefix : ExpectedPrefixes) { 59281ad6265SDimitry Andric if (It == End) 59381ad6265SDimitry Andric goto NotAToolChain; 59406c3fb27SDimitry Andric if (!It->starts_with_insensitive(Prefix)) 59581ad6265SDimitry Andric goto NotAToolChain; 59681ad6265SDimitry Andric ++It; 59781ad6265SDimitry Andric } 59881ad6265SDimitry Andric 59981ad6265SDimitry Andric // We've found a new toolchain! 60081ad6265SDimitry Andric // Back up 3 times (/bin/Host/arch) to get the root path. 60181ad6265SDimitry Andric StringRef ToolChainPath(PathEntry); 60281ad6265SDimitry Andric for (int i = 0; i < 3; ++i) 60381ad6265SDimitry Andric ToolChainPath = sys::path::parent_path(ToolChainPath); 60481ad6265SDimitry Andric 60581ad6265SDimitry Andric Path = std::string(ToolChainPath); 60681ad6265SDimitry Andric VSLayout = ToolsetLayout::VS2017OrNewer; 60781ad6265SDimitry Andric return true; 60881ad6265SDimitry Andric } 60981ad6265SDimitry Andric 61081ad6265SDimitry Andric NotAToolChain: 61181ad6265SDimitry Andric continue; 61281ad6265SDimitry Andric } 61381ad6265SDimitry Andric } 61481ad6265SDimitry Andric return false; 61581ad6265SDimitry Andric } 61681ad6265SDimitry Andric 61706c3fb27SDimitry Andric bool findVCToolChainViaSetupConfig(vfs::FileSystem &VFS, 61806c3fb27SDimitry Andric std::optional<StringRef> VCToolsVersion, 61906c3fb27SDimitry Andric std::string &Path, ToolsetLayout &VSLayout) { 62081ad6265SDimitry Andric #if !defined(USE_MSVC_SETUP_API) 62181ad6265SDimitry Andric return false; 62281ad6265SDimitry Andric #else 62381ad6265SDimitry Andric // FIXME: This really should be done once in the top-level program's main 62481ad6265SDimitry Andric // function, as it may have already been initialized with a different 62581ad6265SDimitry Andric // threading model otherwise. 62681ad6265SDimitry Andric sys::InitializeCOMRAII COM(sys::COMThreadingMode::SingleThreaded); 62781ad6265SDimitry Andric HRESULT HR; 62881ad6265SDimitry Andric 62981ad6265SDimitry Andric // _com_ptr_t will throw a _com_error if a COM calls fail. 63081ad6265SDimitry Andric // The LLVM coding standards forbid exception handling, so we'll have to 63181ad6265SDimitry Andric // stop them from being thrown in the first place. 63281ad6265SDimitry Andric // The destructor will put the regular error handler back when we leave 63381ad6265SDimitry Andric // this scope. 63481ad6265SDimitry Andric struct SuppressCOMErrorsRAII { 63581ad6265SDimitry Andric static void __stdcall handler(HRESULT hr, IErrorInfo *perrinfo) {} 63681ad6265SDimitry Andric 63781ad6265SDimitry Andric SuppressCOMErrorsRAII() { _set_com_error_handler(handler); } 63881ad6265SDimitry Andric 63981ad6265SDimitry Andric ~SuppressCOMErrorsRAII() { _set_com_error_handler(_com_raise_error); } 64081ad6265SDimitry Andric 64181ad6265SDimitry Andric } COMErrorSuppressor; 64281ad6265SDimitry Andric 64381ad6265SDimitry Andric ISetupConfigurationPtr Query; 64481ad6265SDimitry Andric HR = Query.CreateInstance(__uuidof(SetupConfiguration)); 64581ad6265SDimitry Andric if (FAILED(HR)) 64681ad6265SDimitry Andric return false; 64781ad6265SDimitry Andric 64881ad6265SDimitry Andric IEnumSetupInstancesPtr EnumInstances; 64981ad6265SDimitry Andric HR = ISetupConfiguration2Ptr(Query)->EnumAllInstances(&EnumInstances); 65081ad6265SDimitry Andric if (FAILED(HR)) 65181ad6265SDimitry Andric return false; 65281ad6265SDimitry Andric 65381ad6265SDimitry Andric ISetupInstancePtr Instance; 65481ad6265SDimitry Andric HR = EnumInstances->Next(1, &Instance, nullptr); 65581ad6265SDimitry Andric if (HR != S_OK) 65681ad6265SDimitry Andric return false; 65781ad6265SDimitry Andric 65881ad6265SDimitry Andric ISetupInstancePtr NewestInstance; 659bdd1243dSDimitry Andric std::optional<uint64_t> NewestVersionNum; 66081ad6265SDimitry Andric do { 66181ad6265SDimitry Andric bstr_t VersionString; 66281ad6265SDimitry Andric uint64_t VersionNum; 66381ad6265SDimitry Andric HR = Instance->GetInstallationVersion(VersionString.GetAddress()); 66481ad6265SDimitry Andric if (FAILED(HR)) 66581ad6265SDimitry Andric continue; 66681ad6265SDimitry Andric HR = ISetupHelperPtr(Query)->ParseVersion(VersionString, &VersionNum); 66781ad6265SDimitry Andric if (FAILED(HR)) 66881ad6265SDimitry Andric continue; 66981ad6265SDimitry Andric if (!NewestVersionNum || (VersionNum > NewestVersionNum)) { 67081ad6265SDimitry Andric NewestInstance = Instance; 67181ad6265SDimitry Andric NewestVersionNum = VersionNum; 67281ad6265SDimitry Andric } 67381ad6265SDimitry Andric } while ((HR = EnumInstances->Next(1, &Instance, nullptr)) == S_OK); 67481ad6265SDimitry Andric 67581ad6265SDimitry Andric if (!NewestInstance) 67681ad6265SDimitry Andric return false; 67781ad6265SDimitry Andric 67881ad6265SDimitry Andric bstr_t VCPathWide; 67981ad6265SDimitry Andric HR = NewestInstance->ResolvePath(L"VC", VCPathWide.GetAddress()); 68081ad6265SDimitry Andric if (FAILED(HR)) 68181ad6265SDimitry Andric return false; 68281ad6265SDimitry Andric 68381ad6265SDimitry Andric std::string VCRootPath; 68481ad6265SDimitry Andric convertWideToUTF8(std::wstring(VCPathWide), VCRootPath); 68581ad6265SDimitry Andric 68606c3fb27SDimitry Andric std::string ToolsVersion; 68706c3fb27SDimitry Andric if (VCToolsVersion.has_value()) { 68806c3fb27SDimitry Andric ToolsVersion = *VCToolsVersion; 68906c3fb27SDimitry Andric } else { 69081ad6265SDimitry Andric SmallString<256> ToolsVersionFilePath(VCRootPath); 69181ad6265SDimitry Andric sys::path::append(ToolsVersionFilePath, "Auxiliary", "Build", 69281ad6265SDimitry Andric "Microsoft.VCToolsVersion.default.txt"); 69381ad6265SDimitry Andric 69481ad6265SDimitry Andric auto ToolsVersionFile = MemoryBuffer::getFile(ToolsVersionFilePath); 69581ad6265SDimitry Andric if (!ToolsVersionFile) 69681ad6265SDimitry Andric return false; 69781ad6265SDimitry Andric 69806c3fb27SDimitry Andric ToolsVersion = ToolsVersionFile->get()->getBuffer().rtrim(); 69906c3fb27SDimitry Andric } 70006c3fb27SDimitry Andric 70106c3fb27SDimitry Andric 70281ad6265SDimitry Andric SmallString<256> ToolchainPath(VCRootPath); 70306c3fb27SDimitry Andric sys::path::append(ToolchainPath, "Tools", "MSVC", ToolsVersion); 70481ad6265SDimitry Andric auto Status = VFS.status(ToolchainPath); 70581ad6265SDimitry Andric if (!Status || !Status->isDirectory()) 70681ad6265SDimitry Andric return false; 70781ad6265SDimitry Andric 70881ad6265SDimitry Andric Path = std::string(ToolchainPath.str()); 70981ad6265SDimitry Andric VSLayout = ToolsetLayout::VS2017OrNewer; 71081ad6265SDimitry Andric return true; 71181ad6265SDimitry Andric #endif 71281ad6265SDimitry Andric } 71381ad6265SDimitry Andric 71481ad6265SDimitry Andric bool findVCToolChainViaRegistry(std::string &Path, ToolsetLayout &VSLayout) { 71581ad6265SDimitry Andric std::string VSInstallPath; 71681ad6265SDimitry Andric if (getSystemRegistryString(R"(SOFTWARE\Microsoft\VisualStudio\$VERSION)", 71781ad6265SDimitry Andric "InstallDir", VSInstallPath, nullptr) || 71881ad6265SDimitry Andric getSystemRegistryString(R"(SOFTWARE\Microsoft\VCExpress\$VERSION)", 71981ad6265SDimitry Andric "InstallDir", VSInstallPath, nullptr)) { 72081ad6265SDimitry Andric if (!VSInstallPath.empty()) { 721bdd1243dSDimitry Andric auto pos = VSInstallPath.find(R"(\Common7\IDE)"); 722bdd1243dSDimitry Andric if (pos == std::string::npos) 723bdd1243dSDimitry Andric return false; 724bdd1243dSDimitry Andric SmallString<256> VCPath(StringRef(VSInstallPath.c_str(), pos)); 72581ad6265SDimitry Andric sys::path::append(VCPath, "VC"); 72681ad6265SDimitry Andric 7277a6dacacSDimitry Andric Path = std::string(VCPath); 72881ad6265SDimitry Andric VSLayout = ToolsetLayout::OlderVS; 72981ad6265SDimitry Andric return true; 73081ad6265SDimitry Andric } 73181ad6265SDimitry Andric } 73281ad6265SDimitry Andric return false; 73381ad6265SDimitry Andric } 73481ad6265SDimitry Andric 73581ad6265SDimitry Andric } // namespace llvm 736