1*81ad6265SDimitry Andric //===-- MSVCPaths.cpp - MSVC path-parsing helpers -------------------------===// 2*81ad6265SDimitry Andric // 3*81ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*81ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*81ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*81ad6265SDimitry Andric // 7*81ad6265SDimitry Andric //===----------------------------------------------------------------------===// 8*81ad6265SDimitry Andric 9*81ad6265SDimitry Andric #include "llvm/WindowsDriver/MSVCPaths.h" 10*81ad6265SDimitry Andric #include "llvm/ADT/Optional.h" 11*81ad6265SDimitry Andric #include "llvm/ADT/SmallString.h" 12*81ad6265SDimitry Andric #include "llvm/ADT/SmallVector.h" 13*81ad6265SDimitry Andric #include "llvm/ADT/StringRef.h" 14*81ad6265SDimitry Andric #include "llvm/ADT/Triple.h" 15*81ad6265SDimitry Andric #include "llvm/ADT/Twine.h" 16*81ad6265SDimitry Andric #include "llvm/Support/Host.h" 17*81ad6265SDimitry Andric #include "llvm/Support/Path.h" 18*81ad6265SDimitry Andric #include "llvm/Support/Process.h" 19*81ad6265SDimitry Andric #include "llvm/Support/Program.h" 20*81ad6265SDimitry Andric #include "llvm/Support/VersionTuple.h" 21*81ad6265SDimitry Andric #include "llvm/Support/VirtualFileSystem.h" 22*81ad6265SDimitry Andric #include <string> 23*81ad6265SDimitry Andric 24*81ad6265SDimitry Andric #ifdef _WIN32 25*81ad6265SDimitry Andric #include "llvm/Support/ConvertUTF.h" 26*81ad6265SDimitry Andric #endif 27*81ad6265SDimitry Andric 28*81ad6265SDimitry Andric #ifdef _WIN32 29*81ad6265SDimitry Andric #define WIN32_LEAN_AND_MEAN 30*81ad6265SDimitry Andric #define NOGDI 31*81ad6265SDimitry Andric #ifndef NOMINMAX 32*81ad6265SDimitry Andric #define NOMINMAX 33*81ad6265SDimitry Andric #endif 34*81ad6265SDimitry Andric #include <windows.h> 35*81ad6265SDimitry Andric #endif 36*81ad6265SDimitry Andric 37*81ad6265SDimitry Andric #ifdef _MSC_VER 38*81ad6265SDimitry Andric // Don't support SetupApi on MinGW. 39*81ad6265SDimitry Andric #define USE_MSVC_SETUP_API 40*81ad6265SDimitry Andric 41*81ad6265SDimitry Andric // Make sure this comes before MSVCSetupApi.h 42*81ad6265SDimitry Andric #include <comdef.h> 43*81ad6265SDimitry Andric 44*81ad6265SDimitry Andric #include "llvm/Support/COM.h" 45*81ad6265SDimitry Andric #ifdef __clang__ 46*81ad6265SDimitry Andric #pragma clang diagnostic push 47*81ad6265SDimitry Andric #pragma clang diagnostic ignored "-Wnon-virtual-dtor" 48*81ad6265SDimitry Andric #endif 49*81ad6265SDimitry Andric #include "llvm/WindowsDriver/MSVCSetupApi.h" 50*81ad6265SDimitry Andric #ifdef __clang__ 51*81ad6265SDimitry Andric #pragma clang diagnostic pop 52*81ad6265SDimitry Andric #endif 53*81ad6265SDimitry Andric _COM_SMARTPTR_TYPEDEF(ISetupConfiguration, __uuidof(ISetupConfiguration)); 54*81ad6265SDimitry Andric _COM_SMARTPTR_TYPEDEF(ISetupConfiguration2, __uuidof(ISetupConfiguration2)); 55*81ad6265SDimitry Andric _COM_SMARTPTR_TYPEDEF(ISetupHelper, __uuidof(ISetupHelper)); 56*81ad6265SDimitry Andric _COM_SMARTPTR_TYPEDEF(IEnumSetupInstances, __uuidof(IEnumSetupInstances)); 57*81ad6265SDimitry Andric _COM_SMARTPTR_TYPEDEF(ISetupInstance, __uuidof(ISetupInstance)); 58*81ad6265SDimitry Andric _COM_SMARTPTR_TYPEDEF(ISetupInstance2, __uuidof(ISetupInstance2)); 59*81ad6265SDimitry Andric #endif 60*81ad6265SDimitry Andric 61*81ad6265SDimitry Andric static std::string 62*81ad6265SDimitry Andric getHighestNumericTupleInDirectory(llvm::vfs::FileSystem &VFS, 63*81ad6265SDimitry Andric llvm::StringRef Directory) { 64*81ad6265SDimitry Andric std::string Highest; 65*81ad6265SDimitry Andric llvm::VersionTuple HighestTuple; 66*81ad6265SDimitry Andric 67*81ad6265SDimitry Andric std::error_code EC; 68*81ad6265SDimitry Andric for (llvm::vfs::directory_iterator DirIt = VFS.dir_begin(Directory, EC), 69*81ad6265SDimitry Andric DirEnd; 70*81ad6265SDimitry Andric !EC && DirIt != DirEnd; DirIt.increment(EC)) { 71*81ad6265SDimitry Andric auto Status = VFS.status(DirIt->path()); 72*81ad6265SDimitry Andric if (!Status || !Status->isDirectory()) 73*81ad6265SDimitry Andric continue; 74*81ad6265SDimitry Andric llvm::StringRef CandidateName = llvm::sys::path::filename(DirIt->path()); 75*81ad6265SDimitry Andric llvm::VersionTuple Tuple; 76*81ad6265SDimitry Andric if (Tuple.tryParse(CandidateName)) // tryParse() returns true on error. 77*81ad6265SDimitry Andric continue; 78*81ad6265SDimitry Andric if (Tuple > HighestTuple) { 79*81ad6265SDimitry Andric HighestTuple = Tuple; 80*81ad6265SDimitry Andric Highest = CandidateName.str(); 81*81ad6265SDimitry Andric } 82*81ad6265SDimitry Andric } 83*81ad6265SDimitry Andric 84*81ad6265SDimitry Andric return Highest; 85*81ad6265SDimitry Andric } 86*81ad6265SDimitry Andric 87*81ad6265SDimitry Andric static bool getWindows10SDKVersionFromPath(llvm::vfs::FileSystem &VFS, 88*81ad6265SDimitry Andric const std::string &SDKPath, 89*81ad6265SDimitry Andric std::string &SDKVersion) { 90*81ad6265SDimitry Andric llvm::SmallString<128> IncludePath(SDKPath); 91*81ad6265SDimitry Andric llvm::sys::path::append(IncludePath, "Include"); 92*81ad6265SDimitry Andric SDKVersion = getHighestNumericTupleInDirectory(VFS, IncludePath); 93*81ad6265SDimitry Andric return !SDKVersion.empty(); 94*81ad6265SDimitry Andric } 95*81ad6265SDimitry Andric 96*81ad6265SDimitry Andric static bool getWindowsSDKDirViaCommandLine( 97*81ad6265SDimitry Andric llvm::vfs::FileSystem &VFS, llvm::Optional<llvm::StringRef> WinSdkDir, 98*81ad6265SDimitry Andric llvm::Optional<llvm::StringRef> WinSdkVersion, 99*81ad6265SDimitry Andric llvm::Optional<llvm::StringRef> WinSysRoot, std::string &Path, int &Major, 100*81ad6265SDimitry Andric std::string &Version) { 101*81ad6265SDimitry Andric if (WinSdkDir || WinSysRoot) { 102*81ad6265SDimitry Andric // Don't validate the input; trust the value supplied by the user. 103*81ad6265SDimitry Andric // The motivation is to prevent unnecessary file and registry access. 104*81ad6265SDimitry Andric llvm::VersionTuple SDKVersion; 105*81ad6265SDimitry Andric if (WinSdkVersion) 106*81ad6265SDimitry Andric SDKVersion.tryParse(*WinSdkVersion); 107*81ad6265SDimitry Andric 108*81ad6265SDimitry Andric if (WinSysRoot) { 109*81ad6265SDimitry Andric llvm::SmallString<128> SDKPath(*WinSysRoot); 110*81ad6265SDimitry Andric llvm::sys::path::append(SDKPath, "Windows Kits"); 111*81ad6265SDimitry Andric if (!SDKVersion.empty()) 112*81ad6265SDimitry Andric llvm::sys::path::append(SDKPath, llvm::Twine(SDKVersion.getMajor())); 113*81ad6265SDimitry Andric else 114*81ad6265SDimitry Andric llvm::sys::path::append( 115*81ad6265SDimitry Andric SDKPath, getHighestNumericTupleInDirectory(VFS, SDKPath)); 116*81ad6265SDimitry Andric Path = std::string(SDKPath.str()); 117*81ad6265SDimitry Andric } else { 118*81ad6265SDimitry Andric Path = WinSdkDir->str(); 119*81ad6265SDimitry Andric } 120*81ad6265SDimitry Andric 121*81ad6265SDimitry Andric if (!SDKVersion.empty()) { 122*81ad6265SDimitry Andric Major = SDKVersion.getMajor(); 123*81ad6265SDimitry Andric Version = SDKVersion.getAsString(); 124*81ad6265SDimitry Andric } else if (getWindows10SDKVersionFromPath(VFS, Path, Version)) { 125*81ad6265SDimitry Andric Major = 10; 126*81ad6265SDimitry Andric } 127*81ad6265SDimitry Andric return true; 128*81ad6265SDimitry Andric } 129*81ad6265SDimitry Andric return false; 130*81ad6265SDimitry Andric } 131*81ad6265SDimitry Andric 132*81ad6265SDimitry Andric #ifdef _WIN32 133*81ad6265SDimitry Andric static bool readFullStringValue(HKEY hkey, const char *valueName, 134*81ad6265SDimitry Andric std::string &value) { 135*81ad6265SDimitry Andric std::wstring WideValueName; 136*81ad6265SDimitry Andric if (!llvm::ConvertUTF8toWide(valueName, WideValueName)) 137*81ad6265SDimitry Andric return false; 138*81ad6265SDimitry Andric 139*81ad6265SDimitry Andric DWORD result = 0; 140*81ad6265SDimitry Andric DWORD valueSize = 0; 141*81ad6265SDimitry Andric DWORD type = 0; 142*81ad6265SDimitry Andric // First just query for the required size. 143*81ad6265SDimitry Andric result = RegQueryValueExW(hkey, WideValueName.c_str(), NULL, &type, NULL, 144*81ad6265SDimitry Andric &valueSize); 145*81ad6265SDimitry Andric if (result != ERROR_SUCCESS || type != REG_SZ || !valueSize) 146*81ad6265SDimitry Andric return false; 147*81ad6265SDimitry Andric std::vector<BYTE> buffer(valueSize); 148*81ad6265SDimitry Andric result = RegQueryValueExW(hkey, WideValueName.c_str(), NULL, NULL, &buffer[0], 149*81ad6265SDimitry Andric &valueSize); 150*81ad6265SDimitry Andric if (result == ERROR_SUCCESS) { 151*81ad6265SDimitry Andric std::wstring WideValue(reinterpret_cast<const wchar_t *>(buffer.data()), 152*81ad6265SDimitry Andric valueSize / sizeof(wchar_t)); 153*81ad6265SDimitry Andric if (valueSize && WideValue.back() == L'\0') { 154*81ad6265SDimitry Andric WideValue.pop_back(); 155*81ad6265SDimitry Andric } 156*81ad6265SDimitry Andric // The destination buffer must be empty as an invariant of the conversion 157*81ad6265SDimitry Andric // function; but this function is sometimes called in a loop that passes in 158*81ad6265SDimitry Andric // the same buffer, however. Simply clear it out so we can overwrite it. 159*81ad6265SDimitry Andric value.clear(); 160*81ad6265SDimitry Andric return llvm::convertWideToUTF8(WideValue, value); 161*81ad6265SDimitry Andric } 162*81ad6265SDimitry Andric return false; 163*81ad6265SDimitry Andric } 164*81ad6265SDimitry Andric #endif 165*81ad6265SDimitry Andric 166*81ad6265SDimitry Andric /// Read registry string. 167*81ad6265SDimitry Andric /// This also supports a means to look for high-versioned keys by use 168*81ad6265SDimitry Andric /// of a $VERSION placeholder in the key path. 169*81ad6265SDimitry Andric /// $VERSION in the key path is a placeholder for the version number, 170*81ad6265SDimitry Andric /// causing the highest value path to be searched for and used. 171*81ad6265SDimitry Andric /// I.e. "SOFTWARE\\Microsoft\\VisualStudio\\$VERSION". 172*81ad6265SDimitry Andric /// There can be additional characters in the component. Only the numeric 173*81ad6265SDimitry Andric /// characters are compared. This function only searches HKLM. 174*81ad6265SDimitry Andric static bool getSystemRegistryString(const char *keyPath, const char *valueName, 175*81ad6265SDimitry Andric std::string &value, std::string *phValue) { 176*81ad6265SDimitry Andric #ifndef _WIN32 177*81ad6265SDimitry Andric return false; 178*81ad6265SDimitry Andric #else 179*81ad6265SDimitry Andric HKEY hRootKey = HKEY_LOCAL_MACHINE; 180*81ad6265SDimitry Andric HKEY hKey = NULL; 181*81ad6265SDimitry Andric long lResult; 182*81ad6265SDimitry Andric bool returnValue = false; 183*81ad6265SDimitry Andric 184*81ad6265SDimitry Andric const char *placeHolder = strstr(keyPath, "$VERSION"); 185*81ad6265SDimitry Andric std::string bestName; 186*81ad6265SDimitry Andric // If we have a $VERSION placeholder, do the highest-version search. 187*81ad6265SDimitry Andric if (placeHolder) { 188*81ad6265SDimitry Andric const char *keyEnd = placeHolder - 1; 189*81ad6265SDimitry Andric const char *nextKey = placeHolder; 190*81ad6265SDimitry Andric // Find end of previous key. 191*81ad6265SDimitry Andric while ((keyEnd > keyPath) && (*keyEnd != '\\')) 192*81ad6265SDimitry Andric keyEnd--; 193*81ad6265SDimitry Andric // Find end of key containing $VERSION. 194*81ad6265SDimitry Andric while (*nextKey && (*nextKey != '\\')) 195*81ad6265SDimitry Andric nextKey++; 196*81ad6265SDimitry Andric size_t partialKeyLength = keyEnd - keyPath; 197*81ad6265SDimitry Andric char partialKey[256]; 198*81ad6265SDimitry Andric if (partialKeyLength >= sizeof(partialKey)) 199*81ad6265SDimitry Andric partialKeyLength = sizeof(partialKey) - 1; 200*81ad6265SDimitry Andric strncpy(partialKey, keyPath, partialKeyLength); 201*81ad6265SDimitry Andric partialKey[partialKeyLength] = '\0'; 202*81ad6265SDimitry Andric HKEY hTopKey = NULL; 203*81ad6265SDimitry Andric lResult = RegOpenKeyExA(hRootKey, partialKey, 0, KEY_READ | KEY_WOW64_32KEY, 204*81ad6265SDimitry Andric &hTopKey); 205*81ad6265SDimitry Andric if (lResult == ERROR_SUCCESS) { 206*81ad6265SDimitry Andric char keyName[256]; 207*81ad6265SDimitry Andric double bestValue = 0.0; 208*81ad6265SDimitry Andric DWORD index, size = sizeof(keyName) - 1; 209*81ad6265SDimitry Andric for (index = 0; RegEnumKeyExA(hTopKey, index, keyName, &size, NULL, NULL, 210*81ad6265SDimitry Andric NULL, NULL) == ERROR_SUCCESS; 211*81ad6265SDimitry Andric index++) { 212*81ad6265SDimitry Andric const char *sp = keyName; 213*81ad6265SDimitry Andric while (*sp && !llvm::isDigit(*sp)) 214*81ad6265SDimitry Andric sp++; 215*81ad6265SDimitry Andric if (!*sp) 216*81ad6265SDimitry Andric continue; 217*81ad6265SDimitry Andric const char *ep = sp + 1; 218*81ad6265SDimitry Andric while (*ep && (llvm::isDigit(*ep) || (*ep == '.'))) 219*81ad6265SDimitry Andric ep++; 220*81ad6265SDimitry Andric char numBuf[32]; 221*81ad6265SDimitry Andric strncpy(numBuf, sp, sizeof(numBuf) - 1); 222*81ad6265SDimitry Andric numBuf[sizeof(numBuf) - 1] = '\0'; 223*81ad6265SDimitry Andric double dvalue = strtod(numBuf, NULL); 224*81ad6265SDimitry Andric if (dvalue > bestValue) { 225*81ad6265SDimitry Andric // Test that InstallDir is indeed there before keeping this index. 226*81ad6265SDimitry Andric // Open the chosen key path remainder. 227*81ad6265SDimitry Andric bestName = keyName; 228*81ad6265SDimitry Andric // Append rest of key. 229*81ad6265SDimitry Andric bestName.append(nextKey); 230*81ad6265SDimitry Andric lResult = RegOpenKeyExA(hTopKey, bestName.c_str(), 0, 231*81ad6265SDimitry Andric KEY_READ | KEY_WOW64_32KEY, &hKey); 232*81ad6265SDimitry Andric if (lResult == ERROR_SUCCESS) { 233*81ad6265SDimitry Andric if (readFullStringValue(hKey, valueName, value)) { 234*81ad6265SDimitry Andric bestValue = dvalue; 235*81ad6265SDimitry Andric if (phValue) 236*81ad6265SDimitry Andric *phValue = bestName; 237*81ad6265SDimitry Andric returnValue = true; 238*81ad6265SDimitry Andric } 239*81ad6265SDimitry Andric RegCloseKey(hKey); 240*81ad6265SDimitry Andric } 241*81ad6265SDimitry Andric } 242*81ad6265SDimitry Andric size = sizeof(keyName) - 1; 243*81ad6265SDimitry Andric } 244*81ad6265SDimitry Andric RegCloseKey(hTopKey); 245*81ad6265SDimitry Andric } 246*81ad6265SDimitry Andric } else { 247*81ad6265SDimitry Andric lResult = 248*81ad6265SDimitry Andric RegOpenKeyExA(hRootKey, keyPath, 0, KEY_READ | KEY_WOW64_32KEY, &hKey); 249*81ad6265SDimitry Andric if (lResult == ERROR_SUCCESS) { 250*81ad6265SDimitry Andric if (readFullStringValue(hKey, valueName, value)) 251*81ad6265SDimitry Andric returnValue = true; 252*81ad6265SDimitry Andric if (phValue) 253*81ad6265SDimitry Andric phValue->clear(); 254*81ad6265SDimitry Andric RegCloseKey(hKey); 255*81ad6265SDimitry Andric } 256*81ad6265SDimitry Andric } 257*81ad6265SDimitry Andric return returnValue; 258*81ad6265SDimitry Andric #endif // _WIN32 259*81ad6265SDimitry Andric } 260*81ad6265SDimitry Andric 261*81ad6265SDimitry Andric namespace llvm { 262*81ad6265SDimitry Andric 263*81ad6265SDimitry Andric const char *archToWindowsSDKArch(Triple::ArchType Arch) { 264*81ad6265SDimitry Andric switch (Arch) { 265*81ad6265SDimitry Andric case Triple::ArchType::x86: 266*81ad6265SDimitry Andric return "x86"; 267*81ad6265SDimitry Andric case Triple::ArchType::x86_64: 268*81ad6265SDimitry Andric return "x64"; 269*81ad6265SDimitry Andric case Triple::ArchType::arm: 270*81ad6265SDimitry Andric return "arm"; 271*81ad6265SDimitry Andric case Triple::ArchType::aarch64: 272*81ad6265SDimitry Andric return "arm64"; 273*81ad6265SDimitry Andric default: 274*81ad6265SDimitry Andric return ""; 275*81ad6265SDimitry Andric } 276*81ad6265SDimitry Andric } 277*81ad6265SDimitry Andric 278*81ad6265SDimitry Andric const char *archToLegacyVCArch(Triple::ArchType Arch) { 279*81ad6265SDimitry Andric switch (Arch) { 280*81ad6265SDimitry Andric case Triple::ArchType::x86: 281*81ad6265SDimitry Andric // x86 is default in legacy VC toolchains. 282*81ad6265SDimitry Andric // e.g. x86 libs are directly in /lib as opposed to /lib/x86. 283*81ad6265SDimitry Andric return ""; 284*81ad6265SDimitry Andric case Triple::ArchType::x86_64: 285*81ad6265SDimitry Andric return "amd64"; 286*81ad6265SDimitry Andric case Triple::ArchType::arm: 287*81ad6265SDimitry Andric return "arm"; 288*81ad6265SDimitry Andric case Triple::ArchType::aarch64: 289*81ad6265SDimitry Andric return "arm64"; 290*81ad6265SDimitry Andric default: 291*81ad6265SDimitry Andric return ""; 292*81ad6265SDimitry Andric } 293*81ad6265SDimitry Andric } 294*81ad6265SDimitry Andric 295*81ad6265SDimitry Andric const char *archToDevDivInternalArch(Triple::ArchType Arch) { 296*81ad6265SDimitry Andric switch (Arch) { 297*81ad6265SDimitry Andric case Triple::ArchType::x86: 298*81ad6265SDimitry Andric return "i386"; 299*81ad6265SDimitry Andric case Triple::ArchType::x86_64: 300*81ad6265SDimitry Andric return "amd64"; 301*81ad6265SDimitry Andric case Triple::ArchType::arm: 302*81ad6265SDimitry Andric return "arm"; 303*81ad6265SDimitry Andric case Triple::ArchType::aarch64: 304*81ad6265SDimitry Andric return "arm64"; 305*81ad6265SDimitry Andric default: 306*81ad6265SDimitry Andric return ""; 307*81ad6265SDimitry Andric } 308*81ad6265SDimitry Andric } 309*81ad6265SDimitry Andric 310*81ad6265SDimitry Andric bool appendArchToWindowsSDKLibPath(int SDKMajor, SmallString<128> LibPath, 311*81ad6265SDimitry Andric Triple::ArchType Arch, std::string &path) { 312*81ad6265SDimitry Andric if (SDKMajor >= 8) { 313*81ad6265SDimitry Andric sys::path::append(LibPath, archToWindowsSDKArch(Arch)); 314*81ad6265SDimitry Andric } else { 315*81ad6265SDimitry Andric switch (Arch) { 316*81ad6265SDimitry Andric // In Windows SDK 7.x, x86 libraries are directly in the Lib folder. 317*81ad6265SDimitry Andric case Triple::x86: 318*81ad6265SDimitry Andric break; 319*81ad6265SDimitry Andric case Triple::x86_64: 320*81ad6265SDimitry Andric sys::path::append(LibPath, "x64"); 321*81ad6265SDimitry Andric break; 322*81ad6265SDimitry Andric case Triple::arm: 323*81ad6265SDimitry Andric // It is not necessary to link against Windows SDK 7.x when targeting ARM. 324*81ad6265SDimitry Andric return false; 325*81ad6265SDimitry Andric default: 326*81ad6265SDimitry Andric return false; 327*81ad6265SDimitry Andric } 328*81ad6265SDimitry Andric } 329*81ad6265SDimitry Andric 330*81ad6265SDimitry Andric path = std::string(LibPath.str()); 331*81ad6265SDimitry Andric return true; 332*81ad6265SDimitry Andric } 333*81ad6265SDimitry Andric 334*81ad6265SDimitry Andric std::string getSubDirectoryPath(SubDirectoryType Type, ToolsetLayout VSLayout, 335*81ad6265SDimitry Andric const std::string &VCToolChainPath, 336*81ad6265SDimitry Andric Triple::ArchType TargetArch, 337*81ad6265SDimitry Andric StringRef SubdirParent) { 338*81ad6265SDimitry Andric const char *SubdirName; 339*81ad6265SDimitry Andric const char *IncludeName; 340*81ad6265SDimitry Andric switch (VSLayout) { 341*81ad6265SDimitry Andric case ToolsetLayout::OlderVS: 342*81ad6265SDimitry Andric SubdirName = archToLegacyVCArch(TargetArch); 343*81ad6265SDimitry Andric IncludeName = "include"; 344*81ad6265SDimitry Andric break; 345*81ad6265SDimitry Andric case ToolsetLayout::VS2017OrNewer: 346*81ad6265SDimitry Andric SubdirName = archToWindowsSDKArch(TargetArch); 347*81ad6265SDimitry Andric IncludeName = "include"; 348*81ad6265SDimitry Andric break; 349*81ad6265SDimitry Andric case ToolsetLayout::DevDivInternal: 350*81ad6265SDimitry Andric SubdirName = archToDevDivInternalArch(TargetArch); 351*81ad6265SDimitry Andric IncludeName = "inc"; 352*81ad6265SDimitry Andric break; 353*81ad6265SDimitry Andric } 354*81ad6265SDimitry Andric 355*81ad6265SDimitry Andric SmallString<256> Path(VCToolChainPath); 356*81ad6265SDimitry Andric if (!SubdirParent.empty()) 357*81ad6265SDimitry Andric sys::path::append(Path, SubdirParent); 358*81ad6265SDimitry Andric 359*81ad6265SDimitry Andric switch (Type) { 360*81ad6265SDimitry Andric case SubDirectoryType::Bin: 361*81ad6265SDimitry Andric if (VSLayout == ToolsetLayout::VS2017OrNewer) { 362*81ad6265SDimitry Andric // MSVC ships with two linkers: a 32-bit x86 and 64-bit x86 linker. 363*81ad6265SDimitry Andric // On x86, pick the linker that corresponds to the current process. 364*81ad6265SDimitry Andric // On ARM64, pick the 32-bit x86 linker; the 64-bit one doesn't run 365*81ad6265SDimitry Andric // on Windows 10. 366*81ad6265SDimitry Andric // 367*81ad6265SDimitry Andric // FIXME: Consider using IsWow64GuestMachineSupported to figure out 368*81ad6265SDimitry Andric // if we can invoke the 64-bit linker. It's generally preferable 369*81ad6265SDimitry Andric // because it won't run out of address-space. 370*81ad6265SDimitry Andric const bool HostIsX64 = 371*81ad6265SDimitry Andric Triple(sys::getProcessTriple()).getArch() == Triple::x86_64; 372*81ad6265SDimitry Andric const char *const HostName = HostIsX64 ? "Hostx64" : "Hostx86"; 373*81ad6265SDimitry Andric sys::path::append(Path, "bin", HostName, SubdirName); 374*81ad6265SDimitry Andric } else { // OlderVS or DevDivInternal 375*81ad6265SDimitry Andric sys::path::append(Path, "bin", SubdirName); 376*81ad6265SDimitry Andric } 377*81ad6265SDimitry Andric break; 378*81ad6265SDimitry Andric case SubDirectoryType::Include: 379*81ad6265SDimitry Andric sys::path::append(Path, IncludeName); 380*81ad6265SDimitry Andric break; 381*81ad6265SDimitry Andric case SubDirectoryType::Lib: 382*81ad6265SDimitry Andric sys::path::append(Path, "lib", SubdirName); 383*81ad6265SDimitry Andric break; 384*81ad6265SDimitry Andric } 385*81ad6265SDimitry Andric return std::string(Path.str()); 386*81ad6265SDimitry Andric } 387*81ad6265SDimitry Andric 388*81ad6265SDimitry Andric bool useUniversalCRT(ToolsetLayout VSLayout, const std::string &VCToolChainPath, 389*81ad6265SDimitry Andric Triple::ArchType TargetArch, vfs::FileSystem &VFS) { 390*81ad6265SDimitry Andric SmallString<128> TestPath(getSubDirectoryPath( 391*81ad6265SDimitry Andric SubDirectoryType::Include, VSLayout, VCToolChainPath, TargetArch)); 392*81ad6265SDimitry Andric sys::path::append(TestPath, "stdlib.h"); 393*81ad6265SDimitry Andric return !VFS.exists(TestPath); 394*81ad6265SDimitry Andric } 395*81ad6265SDimitry Andric 396*81ad6265SDimitry Andric bool getWindowsSDKDir(vfs::FileSystem &VFS, Optional<StringRef> WinSdkDir, 397*81ad6265SDimitry Andric Optional<StringRef> WinSdkVersion, 398*81ad6265SDimitry Andric Optional<StringRef> WinSysRoot, std::string &Path, 399*81ad6265SDimitry Andric int &Major, std::string &WindowsSDKIncludeVersion, 400*81ad6265SDimitry Andric std::string &WindowsSDKLibVersion) { 401*81ad6265SDimitry Andric // Trust /winsdkdir and /winsdkversion if present. 402*81ad6265SDimitry Andric if (getWindowsSDKDirViaCommandLine(VFS, WinSdkDir, WinSdkVersion, WinSysRoot, 403*81ad6265SDimitry Andric Path, Major, WindowsSDKIncludeVersion)) { 404*81ad6265SDimitry Andric WindowsSDKLibVersion = WindowsSDKIncludeVersion; 405*81ad6265SDimitry Andric return true; 406*81ad6265SDimitry Andric } 407*81ad6265SDimitry Andric 408*81ad6265SDimitry Andric // FIXME: Try env vars (%WindowsSdkDir%, %UCRTVersion%) before going to 409*81ad6265SDimitry Andric // registry. 410*81ad6265SDimitry Andric 411*81ad6265SDimitry Andric // Try the Windows registry. 412*81ad6265SDimitry Andric std::string RegistrySDKVersion; 413*81ad6265SDimitry Andric if (!getSystemRegistryString( 414*81ad6265SDimitry Andric "SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\$VERSION", 415*81ad6265SDimitry Andric "InstallationFolder", Path, &RegistrySDKVersion)) 416*81ad6265SDimitry Andric return false; 417*81ad6265SDimitry Andric if (Path.empty() || RegistrySDKVersion.empty()) 418*81ad6265SDimitry Andric return false; 419*81ad6265SDimitry Andric 420*81ad6265SDimitry Andric WindowsSDKIncludeVersion.clear(); 421*81ad6265SDimitry Andric WindowsSDKLibVersion.clear(); 422*81ad6265SDimitry Andric Major = 0; 423*81ad6265SDimitry Andric std::sscanf(RegistrySDKVersion.c_str(), "v%d.", &Major); 424*81ad6265SDimitry Andric if (Major <= 7) 425*81ad6265SDimitry Andric return true; 426*81ad6265SDimitry Andric if (Major == 8) { 427*81ad6265SDimitry Andric // Windows SDK 8.x installs libraries in a folder whose names depend on the 428*81ad6265SDimitry Andric // version of the OS you're targeting. By default choose the newest, which 429*81ad6265SDimitry Andric // usually corresponds to the version of the OS you've installed the SDK on. 430*81ad6265SDimitry Andric const char *Tests[] = {"winv6.3", "win8", "win7"}; 431*81ad6265SDimitry Andric for (const char *Test : Tests) { 432*81ad6265SDimitry Andric SmallString<128> TestPath(Path); 433*81ad6265SDimitry Andric sys::path::append(TestPath, "Lib", Test); 434*81ad6265SDimitry Andric if (VFS.exists(TestPath)) { 435*81ad6265SDimitry Andric WindowsSDKLibVersion = Test; 436*81ad6265SDimitry Andric break; 437*81ad6265SDimitry Andric } 438*81ad6265SDimitry Andric } 439*81ad6265SDimitry Andric return !WindowsSDKLibVersion.empty(); 440*81ad6265SDimitry Andric } 441*81ad6265SDimitry Andric if (Major == 10) { 442*81ad6265SDimitry Andric if (!getWindows10SDKVersionFromPath(VFS, Path, WindowsSDKIncludeVersion)) 443*81ad6265SDimitry Andric return false; 444*81ad6265SDimitry Andric WindowsSDKLibVersion = WindowsSDKIncludeVersion; 445*81ad6265SDimitry Andric return true; 446*81ad6265SDimitry Andric } 447*81ad6265SDimitry Andric // Unsupported SDK version 448*81ad6265SDimitry Andric return false; 449*81ad6265SDimitry Andric } 450*81ad6265SDimitry Andric 451*81ad6265SDimitry Andric bool getUniversalCRTSdkDir(vfs::FileSystem &VFS, Optional<StringRef> WinSdkDir, 452*81ad6265SDimitry Andric Optional<StringRef> WinSdkVersion, 453*81ad6265SDimitry Andric Optional<StringRef> WinSysRoot, std::string &Path, 454*81ad6265SDimitry Andric std::string &UCRTVersion) { 455*81ad6265SDimitry Andric // If /winsdkdir is passed, use it as location for the UCRT too. 456*81ad6265SDimitry Andric // FIXME: Should there be a dedicated /ucrtdir to override /winsdkdir? 457*81ad6265SDimitry Andric int Major; 458*81ad6265SDimitry Andric if (getWindowsSDKDirViaCommandLine(VFS, WinSdkDir, WinSdkVersion, WinSysRoot, 459*81ad6265SDimitry Andric Path, Major, UCRTVersion)) 460*81ad6265SDimitry Andric return true; 461*81ad6265SDimitry Andric 462*81ad6265SDimitry Andric // FIXME: Try env vars (%UniversalCRTSdkDir%, %UCRTVersion%) before going to 463*81ad6265SDimitry Andric // registry. 464*81ad6265SDimitry Andric 465*81ad6265SDimitry Andric // vcvarsqueryregistry.bat for Visual Studio 2015 queries the registry 466*81ad6265SDimitry Andric // for the specific key "KitsRoot10". So do we. 467*81ad6265SDimitry Andric if (!getSystemRegistryString( 468*81ad6265SDimitry Andric "SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots", "KitsRoot10", 469*81ad6265SDimitry Andric Path, nullptr)) 470*81ad6265SDimitry Andric return false; 471*81ad6265SDimitry Andric 472*81ad6265SDimitry Andric return getWindows10SDKVersionFromPath(VFS, Path, UCRTVersion); 473*81ad6265SDimitry Andric } 474*81ad6265SDimitry Andric 475*81ad6265SDimitry Andric bool findVCToolChainViaCommandLine(vfs::FileSystem &VFS, 476*81ad6265SDimitry Andric Optional<StringRef> VCToolsDir, 477*81ad6265SDimitry Andric Optional<StringRef> VCToolsVersion, 478*81ad6265SDimitry Andric Optional<StringRef> WinSysRoot, 479*81ad6265SDimitry Andric std::string &Path, ToolsetLayout &VSLayout) { 480*81ad6265SDimitry Andric // Don't validate the input; trust the value supplied by the user. 481*81ad6265SDimitry Andric // The primary motivation is to prevent unnecessary file and registry access. 482*81ad6265SDimitry Andric if (VCToolsDir || WinSysRoot) { 483*81ad6265SDimitry Andric if (WinSysRoot) { 484*81ad6265SDimitry Andric SmallString<128> ToolsPath(*WinSysRoot); 485*81ad6265SDimitry Andric sys::path::append(ToolsPath, "VC", "Tools", "MSVC"); 486*81ad6265SDimitry Andric std::string ToolsVersion; 487*81ad6265SDimitry Andric if (VCToolsVersion) 488*81ad6265SDimitry Andric ToolsVersion = VCToolsVersion->str(); 489*81ad6265SDimitry Andric else 490*81ad6265SDimitry Andric ToolsVersion = getHighestNumericTupleInDirectory(VFS, ToolsPath); 491*81ad6265SDimitry Andric sys::path::append(ToolsPath, ToolsVersion); 492*81ad6265SDimitry Andric Path = std::string(ToolsPath.str()); 493*81ad6265SDimitry Andric } else { 494*81ad6265SDimitry Andric Path = VCToolsDir->str(); 495*81ad6265SDimitry Andric } 496*81ad6265SDimitry Andric VSLayout = ToolsetLayout::VS2017OrNewer; 497*81ad6265SDimitry Andric return true; 498*81ad6265SDimitry Andric } 499*81ad6265SDimitry Andric return false; 500*81ad6265SDimitry Andric } 501*81ad6265SDimitry Andric 502*81ad6265SDimitry Andric bool findVCToolChainViaEnvironment(vfs::FileSystem &VFS, std::string &Path, 503*81ad6265SDimitry Andric ToolsetLayout &VSLayout) { 504*81ad6265SDimitry Andric // These variables are typically set by vcvarsall.bat 505*81ad6265SDimitry Andric // when launching a developer command prompt. 506*81ad6265SDimitry Andric if (Optional<std::string> VCToolsInstallDir = 507*81ad6265SDimitry Andric sys::Process::GetEnv("VCToolsInstallDir")) { 508*81ad6265SDimitry Andric // This is only set by newer Visual Studios, and it leads straight to 509*81ad6265SDimitry Andric // the toolchain directory. 510*81ad6265SDimitry Andric Path = std::move(*VCToolsInstallDir); 511*81ad6265SDimitry Andric VSLayout = ToolsetLayout::VS2017OrNewer; 512*81ad6265SDimitry Andric return true; 513*81ad6265SDimitry Andric } 514*81ad6265SDimitry Andric if (Optional<std::string> VCInstallDir = 515*81ad6265SDimitry Andric sys::Process::GetEnv("VCINSTALLDIR")) { 516*81ad6265SDimitry Andric // If the previous variable isn't set but this one is, then we've found 517*81ad6265SDimitry Andric // an older Visual Studio. This variable is set by newer Visual Studios too, 518*81ad6265SDimitry Andric // so this check has to appear second. 519*81ad6265SDimitry Andric // In older Visual Studios, the VC directory is the toolchain. 520*81ad6265SDimitry Andric Path = std::move(*VCInstallDir); 521*81ad6265SDimitry Andric VSLayout = ToolsetLayout::OlderVS; 522*81ad6265SDimitry Andric return true; 523*81ad6265SDimitry Andric } 524*81ad6265SDimitry Andric 525*81ad6265SDimitry Andric // We couldn't find any VC environment variables. Let's walk through PATH and 526*81ad6265SDimitry Andric // see if it leads us to a VC toolchain bin directory. If it does, pick the 527*81ad6265SDimitry Andric // first one that we find. 528*81ad6265SDimitry Andric if (Optional<std::string> PathEnv = sys::Process::GetEnv("PATH")) { 529*81ad6265SDimitry Andric SmallVector<StringRef, 8> PathEntries; 530*81ad6265SDimitry Andric StringRef(*PathEnv).split(PathEntries, sys::EnvPathSeparator); 531*81ad6265SDimitry Andric for (StringRef PathEntry : PathEntries) { 532*81ad6265SDimitry Andric if (PathEntry.empty()) 533*81ad6265SDimitry Andric continue; 534*81ad6265SDimitry Andric 535*81ad6265SDimitry Andric SmallString<256> ExeTestPath; 536*81ad6265SDimitry Andric 537*81ad6265SDimitry Andric // If cl.exe doesn't exist, then this definitely isn't a VC toolchain. 538*81ad6265SDimitry Andric ExeTestPath = PathEntry; 539*81ad6265SDimitry Andric sys::path::append(ExeTestPath, "cl.exe"); 540*81ad6265SDimitry Andric if (!VFS.exists(ExeTestPath)) 541*81ad6265SDimitry Andric continue; 542*81ad6265SDimitry Andric 543*81ad6265SDimitry Andric // cl.exe existing isn't a conclusive test for a VC toolchain; clang also 544*81ad6265SDimitry Andric // has a cl.exe. So let's check for link.exe too. 545*81ad6265SDimitry Andric ExeTestPath = PathEntry; 546*81ad6265SDimitry Andric sys::path::append(ExeTestPath, "link.exe"); 547*81ad6265SDimitry Andric if (!VFS.exists(ExeTestPath)) 548*81ad6265SDimitry Andric continue; 549*81ad6265SDimitry Andric 550*81ad6265SDimitry Andric // whatever/VC/bin --> old toolchain, VC dir is toolchain dir. 551*81ad6265SDimitry Andric StringRef TestPath = PathEntry; 552*81ad6265SDimitry Andric bool IsBin = sys::path::filename(TestPath).equals_insensitive("bin"); 553*81ad6265SDimitry Andric if (!IsBin) { 554*81ad6265SDimitry Andric // Strip any architecture subdir like "amd64". 555*81ad6265SDimitry Andric TestPath = sys::path::parent_path(TestPath); 556*81ad6265SDimitry Andric IsBin = sys::path::filename(TestPath).equals_insensitive("bin"); 557*81ad6265SDimitry Andric } 558*81ad6265SDimitry Andric if (IsBin) { 559*81ad6265SDimitry Andric StringRef ParentPath = sys::path::parent_path(TestPath); 560*81ad6265SDimitry Andric StringRef ParentFilename = sys::path::filename(ParentPath); 561*81ad6265SDimitry Andric if (ParentFilename.equals_insensitive("VC")) { 562*81ad6265SDimitry Andric Path = std::string(ParentPath); 563*81ad6265SDimitry Andric VSLayout = ToolsetLayout::OlderVS; 564*81ad6265SDimitry Andric return true; 565*81ad6265SDimitry Andric } 566*81ad6265SDimitry Andric if (ParentFilename.equals_insensitive("x86ret") || 567*81ad6265SDimitry Andric ParentFilename.equals_insensitive("x86chk") || 568*81ad6265SDimitry Andric ParentFilename.equals_insensitive("amd64ret") || 569*81ad6265SDimitry Andric ParentFilename.equals_insensitive("amd64chk")) { 570*81ad6265SDimitry Andric Path = std::string(ParentPath); 571*81ad6265SDimitry Andric VSLayout = ToolsetLayout::DevDivInternal; 572*81ad6265SDimitry Andric return true; 573*81ad6265SDimitry Andric } 574*81ad6265SDimitry Andric 575*81ad6265SDimitry Andric } else { 576*81ad6265SDimitry Andric // This could be a new (>=VS2017) toolchain. If it is, we should find 577*81ad6265SDimitry Andric // path components with these prefixes when walking backwards through 578*81ad6265SDimitry Andric // the path. 579*81ad6265SDimitry Andric // Note: empty strings match anything. 580*81ad6265SDimitry Andric StringRef ExpectedPrefixes[] = {"", "Host", "bin", "", 581*81ad6265SDimitry Andric "MSVC", "Tools", "VC"}; 582*81ad6265SDimitry Andric 583*81ad6265SDimitry Andric auto It = sys::path::rbegin(PathEntry); 584*81ad6265SDimitry Andric auto End = sys::path::rend(PathEntry); 585*81ad6265SDimitry Andric for (StringRef Prefix : ExpectedPrefixes) { 586*81ad6265SDimitry Andric if (It == End) 587*81ad6265SDimitry Andric goto NotAToolChain; 588*81ad6265SDimitry Andric if (!It->startswith_insensitive(Prefix)) 589*81ad6265SDimitry Andric goto NotAToolChain; 590*81ad6265SDimitry Andric ++It; 591*81ad6265SDimitry Andric } 592*81ad6265SDimitry Andric 593*81ad6265SDimitry Andric // We've found a new toolchain! 594*81ad6265SDimitry Andric // Back up 3 times (/bin/Host/arch) to get the root path. 595*81ad6265SDimitry Andric StringRef ToolChainPath(PathEntry); 596*81ad6265SDimitry Andric for (int i = 0; i < 3; ++i) 597*81ad6265SDimitry Andric ToolChainPath = sys::path::parent_path(ToolChainPath); 598*81ad6265SDimitry Andric 599*81ad6265SDimitry Andric Path = std::string(ToolChainPath); 600*81ad6265SDimitry Andric VSLayout = ToolsetLayout::VS2017OrNewer; 601*81ad6265SDimitry Andric return true; 602*81ad6265SDimitry Andric } 603*81ad6265SDimitry Andric 604*81ad6265SDimitry Andric NotAToolChain: 605*81ad6265SDimitry Andric continue; 606*81ad6265SDimitry Andric } 607*81ad6265SDimitry Andric } 608*81ad6265SDimitry Andric return false; 609*81ad6265SDimitry Andric } 610*81ad6265SDimitry Andric 611*81ad6265SDimitry Andric bool findVCToolChainViaSetupConfig(vfs::FileSystem &VFS, std::string &Path, 612*81ad6265SDimitry Andric ToolsetLayout &VSLayout) { 613*81ad6265SDimitry Andric #if !defined(USE_MSVC_SETUP_API) 614*81ad6265SDimitry Andric return false; 615*81ad6265SDimitry Andric #else 616*81ad6265SDimitry Andric // FIXME: This really should be done once in the top-level program's main 617*81ad6265SDimitry Andric // function, as it may have already been initialized with a different 618*81ad6265SDimitry Andric // threading model otherwise. 619*81ad6265SDimitry Andric sys::InitializeCOMRAII COM(sys::COMThreadingMode::SingleThreaded); 620*81ad6265SDimitry Andric HRESULT HR; 621*81ad6265SDimitry Andric 622*81ad6265SDimitry Andric // _com_ptr_t will throw a _com_error if a COM calls fail. 623*81ad6265SDimitry Andric // The LLVM coding standards forbid exception handling, so we'll have to 624*81ad6265SDimitry Andric // stop them from being thrown in the first place. 625*81ad6265SDimitry Andric // The destructor will put the regular error handler back when we leave 626*81ad6265SDimitry Andric // this scope. 627*81ad6265SDimitry Andric struct SuppressCOMErrorsRAII { 628*81ad6265SDimitry Andric static void __stdcall handler(HRESULT hr, IErrorInfo *perrinfo) {} 629*81ad6265SDimitry Andric 630*81ad6265SDimitry Andric SuppressCOMErrorsRAII() { _set_com_error_handler(handler); } 631*81ad6265SDimitry Andric 632*81ad6265SDimitry Andric ~SuppressCOMErrorsRAII() { _set_com_error_handler(_com_raise_error); } 633*81ad6265SDimitry Andric 634*81ad6265SDimitry Andric } COMErrorSuppressor; 635*81ad6265SDimitry Andric 636*81ad6265SDimitry Andric ISetupConfigurationPtr Query; 637*81ad6265SDimitry Andric HR = Query.CreateInstance(__uuidof(SetupConfiguration)); 638*81ad6265SDimitry Andric if (FAILED(HR)) 639*81ad6265SDimitry Andric return false; 640*81ad6265SDimitry Andric 641*81ad6265SDimitry Andric IEnumSetupInstancesPtr EnumInstances; 642*81ad6265SDimitry Andric HR = ISetupConfiguration2Ptr(Query)->EnumAllInstances(&EnumInstances); 643*81ad6265SDimitry Andric if (FAILED(HR)) 644*81ad6265SDimitry Andric return false; 645*81ad6265SDimitry Andric 646*81ad6265SDimitry Andric ISetupInstancePtr Instance; 647*81ad6265SDimitry Andric HR = EnumInstances->Next(1, &Instance, nullptr); 648*81ad6265SDimitry Andric if (HR != S_OK) 649*81ad6265SDimitry Andric return false; 650*81ad6265SDimitry Andric 651*81ad6265SDimitry Andric ISetupInstancePtr NewestInstance; 652*81ad6265SDimitry Andric Optional<uint64_t> NewestVersionNum; 653*81ad6265SDimitry Andric do { 654*81ad6265SDimitry Andric bstr_t VersionString; 655*81ad6265SDimitry Andric uint64_t VersionNum; 656*81ad6265SDimitry Andric HR = Instance->GetInstallationVersion(VersionString.GetAddress()); 657*81ad6265SDimitry Andric if (FAILED(HR)) 658*81ad6265SDimitry Andric continue; 659*81ad6265SDimitry Andric HR = ISetupHelperPtr(Query)->ParseVersion(VersionString, &VersionNum); 660*81ad6265SDimitry Andric if (FAILED(HR)) 661*81ad6265SDimitry Andric continue; 662*81ad6265SDimitry Andric if (!NewestVersionNum || (VersionNum > NewestVersionNum)) { 663*81ad6265SDimitry Andric NewestInstance = Instance; 664*81ad6265SDimitry Andric NewestVersionNum = VersionNum; 665*81ad6265SDimitry Andric } 666*81ad6265SDimitry Andric } while ((HR = EnumInstances->Next(1, &Instance, nullptr)) == S_OK); 667*81ad6265SDimitry Andric 668*81ad6265SDimitry Andric if (!NewestInstance) 669*81ad6265SDimitry Andric return false; 670*81ad6265SDimitry Andric 671*81ad6265SDimitry Andric bstr_t VCPathWide; 672*81ad6265SDimitry Andric HR = NewestInstance->ResolvePath(L"VC", VCPathWide.GetAddress()); 673*81ad6265SDimitry Andric if (FAILED(HR)) 674*81ad6265SDimitry Andric return false; 675*81ad6265SDimitry Andric 676*81ad6265SDimitry Andric std::string VCRootPath; 677*81ad6265SDimitry Andric convertWideToUTF8(std::wstring(VCPathWide), VCRootPath); 678*81ad6265SDimitry Andric 679*81ad6265SDimitry Andric SmallString<256> ToolsVersionFilePath(VCRootPath); 680*81ad6265SDimitry Andric sys::path::append(ToolsVersionFilePath, "Auxiliary", "Build", 681*81ad6265SDimitry Andric "Microsoft.VCToolsVersion.default.txt"); 682*81ad6265SDimitry Andric 683*81ad6265SDimitry Andric auto ToolsVersionFile = MemoryBuffer::getFile(ToolsVersionFilePath); 684*81ad6265SDimitry Andric if (!ToolsVersionFile) 685*81ad6265SDimitry Andric return false; 686*81ad6265SDimitry Andric 687*81ad6265SDimitry Andric SmallString<256> ToolchainPath(VCRootPath); 688*81ad6265SDimitry Andric sys::path::append(ToolchainPath, "Tools", "MSVC", 689*81ad6265SDimitry Andric ToolsVersionFile->get()->getBuffer().rtrim()); 690*81ad6265SDimitry Andric auto Status = VFS.status(ToolchainPath); 691*81ad6265SDimitry Andric if (!Status || !Status->isDirectory()) 692*81ad6265SDimitry Andric return false; 693*81ad6265SDimitry Andric 694*81ad6265SDimitry Andric Path = std::string(ToolchainPath.str()); 695*81ad6265SDimitry Andric VSLayout = ToolsetLayout::VS2017OrNewer; 696*81ad6265SDimitry Andric return true; 697*81ad6265SDimitry Andric #endif 698*81ad6265SDimitry Andric } 699*81ad6265SDimitry Andric 700*81ad6265SDimitry Andric bool findVCToolChainViaRegistry(std::string &Path, ToolsetLayout &VSLayout) { 701*81ad6265SDimitry Andric std::string VSInstallPath; 702*81ad6265SDimitry Andric if (getSystemRegistryString(R"(SOFTWARE\Microsoft\VisualStudio\$VERSION)", 703*81ad6265SDimitry Andric "InstallDir", VSInstallPath, nullptr) || 704*81ad6265SDimitry Andric getSystemRegistryString(R"(SOFTWARE\Microsoft\VCExpress\$VERSION)", 705*81ad6265SDimitry Andric "InstallDir", VSInstallPath, nullptr)) { 706*81ad6265SDimitry Andric if (!VSInstallPath.empty()) { 707*81ad6265SDimitry Andric SmallString<256> VCPath(StringRef(VSInstallPath.c_str(), 708*81ad6265SDimitry Andric VSInstallPath.find(R"(\Common7\IDE)"))); 709*81ad6265SDimitry Andric sys::path::append(VCPath, "VC"); 710*81ad6265SDimitry Andric 711*81ad6265SDimitry Andric Path = std::string(VCPath.str()); 712*81ad6265SDimitry Andric VSLayout = ToolsetLayout::OlderVS; 713*81ad6265SDimitry Andric return true; 714*81ad6265SDimitry Andric } 715*81ad6265SDimitry Andric } 716*81ad6265SDimitry Andric return false; 717*81ad6265SDimitry Andric } 718*81ad6265SDimitry Andric 719*81ad6265SDimitry Andric } // namespace llvm 720