LLVM 24.0.0git
MSVCPaths.cpp
Go to the documentation of this file.
1//===-- MSVCPaths.cpp - MSVC path-parsing helpers -------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
13#include "llvm/ADT/StringRef.h"
14#include "llvm/ADT/Twine.h"
15#include "llvm/Support/Path.h"
22#include <optional>
23#include <string>
24
25#ifdef _WIN32
27#endif
28
29#ifdef _WIN32
30#ifndef WIN32_LEAN_AND_MEAN
31#define WIN32_LEAN_AND_MEAN
32#endif
33#define NOGDI
34#ifndef NOMINMAX
35#define NOMINMAX
36#endif
37#include <windows.h>
38
39// Make sure this comes before MSVCSetupApi.h
40#include <comdef.h>
41
42#include "llvm/Support/COM.h"
43#ifdef __clang__
44#pragma clang diagnostic push
45#pragma clang diagnostic ignored "-Wnon-virtual-dtor"
46#endif
48#ifdef __clang__
49#pragma clang diagnostic pop
50#endif
51#ifdef __MINGW32__
52// mingw-w64 emulates __uuidof, which takes the IIDs from __CRT_UUID_DECL
53// rather than from the DECLSPEC_UUID in MSVCSetupApi.h.
54__CRT_UUID_DECL(ISetupInstance, 0xB41463C3, 0x8866, 0x43B5, 0xBC, 0x33, 0x2B,
55 0x06, 0x76, 0xF7, 0xF4, 0x2E)
56__CRT_UUID_DECL(ISetupInstance2, 0x89143C9A, 0x05AF, 0x49B0, 0xB7, 0x17, 0x72,
57 0xE2, 0x18, 0xA2, 0x18, 0x5C)
58__CRT_UUID_DECL(IEnumSetupInstances, 0x6380BCFF, 0x41D3, 0x4B2E, 0x8B, 0x2E,
59 0xBF, 0x8A, 0x68, 0x10, 0xC8, 0x48)
60__CRT_UUID_DECL(ISetupConfiguration, 0x42843719, 0xDB4C, 0x46C2, 0x8E, 0x7C,
61 0x64, 0xF1, 0x81, 0x6E, 0xFD, 0x5B)
62__CRT_UUID_DECL(ISetupConfiguration2, 0x26AAB78C, 0x4A60, 0x49D6, 0xAF, 0x3B,
63 0x3C, 0x35, 0xBC, 0x93, 0x36, 0x5D)
64__CRT_UUID_DECL(ISetupHelper, 0x42B21B78, 0x6192, 0x463E, 0x87, 0xBF, 0xD5,
65 0x77, 0x83, 0x8F, 0x1D, 0x5C)
66__CRT_UUID_DECL(SetupConfiguration, 0x177F0C4A, 0x1CD3, 0x4DE7, 0xA3, 0x2C,
67 0x71, 0xDB, 0xBB, 0x9F, 0xA3, 0x6D)
68#endif
69_COM_SMARTPTR_TYPEDEF(ISetupConfiguration, __uuidof(ISetupConfiguration));
70_COM_SMARTPTR_TYPEDEF(ISetupConfiguration2, __uuidof(ISetupConfiguration2));
71_COM_SMARTPTR_TYPEDEF(ISetupHelper, __uuidof(ISetupHelper));
72_COM_SMARTPTR_TYPEDEF(IEnumSetupInstances, __uuidof(IEnumSetupInstances));
73_COM_SMARTPTR_TYPEDEF(ISetupInstance, __uuidof(ISetupInstance));
74_COM_SMARTPTR_TYPEDEF(ISetupInstance2, __uuidof(ISetupInstance2));
75#endif
76
77static std::string
79 llvm::StringRef Directory) {
80 std::string Highest;
81 llvm::VersionTuple HighestTuple;
82
83 std::error_code EC;
84 for (llvm::vfs::directory_iterator DirIt = VFS.dir_begin(Directory, EC),
85 DirEnd;
86 !EC && DirIt != DirEnd; DirIt.increment(EC)) {
87 auto Status = VFS.status(DirIt->path());
88 if (!Status || !Status->isDirectory())
89 continue;
90 llvm::StringRef CandidateName = llvm::sys::path::filename(DirIt->path());
92 if (Tuple.tryParse(CandidateName)) // tryParse() returns true on error.
93 continue;
94 if (Tuple > HighestTuple) {
95 HighestTuple = Tuple;
96 Highest = CandidateName.str();
97 }
98 }
99
100 return Highest;
101}
102
104 const std::string &SDKPath,
105 std::string &SDKVersion) {
106 llvm::SmallString<128> IncludePath(SDKPath);
107 llvm::sys::path::append(IncludePath, "Include");
108 SDKVersion = getHighestNumericTupleInDirectory(VFS, IncludePath);
109 return !SDKVersion.empty();
110}
111
113 llvm::vfs::FileSystem &VFS, std::optional<llvm::StringRef> WinSdkDir,
114 std::optional<llvm::StringRef> WinSdkVersion,
115 std::optional<llvm::StringRef> WinSysRoot, std::string &Path, int &Major,
116 std::string &Version) {
117 if (WinSdkDir || WinSysRoot) {
118 // Don't validate the input; trust the value supplied by the user.
119 // The motivation is to prevent unnecessary file and registry access.
120 llvm::VersionTuple SDKVersion;
121 if (WinSdkVersion)
122 SDKVersion.tryParse(*WinSdkVersion);
123
124 if (WinSysRoot) {
125 llvm::SmallString<128> SDKPath(*WinSysRoot);
126 llvm::sys::path::append(SDKPath, "Windows Kits");
127 if (!SDKVersion.empty())
128 llvm::sys::path::append(SDKPath, llvm::Twine(SDKVersion.getMajor()));
129 else
131 SDKPath, getHighestNumericTupleInDirectory(VFS, SDKPath));
132 Path = std::string(SDKPath);
133 } else {
134 Path = WinSdkDir->str();
135 }
136
137 if (!SDKVersion.empty()) {
138 Major = SDKVersion.getMajor();
139 Version = SDKVersion.getAsString();
140 } else if (getWindows10SDKVersionFromPath(VFS, Path, Version)) {
141 Major = 10;
142 }
143 return true;
144 }
145 return false;
146}
147
148#ifdef _WIN32
149static bool readFullStringValue(HKEY hkey, const char *valueName,
150 std::string &value) {
151 std::wstring WideValueName;
152 if (!llvm::ConvertUTF8toWide(valueName, WideValueName))
153 return false;
154
155 DWORD result = 0;
156 DWORD valueSize = 0;
157 DWORD type = 0;
158 // First just query for the required size.
159 result = RegQueryValueExW(hkey, WideValueName.c_str(), NULL, &type, NULL,
160 &valueSize);
161 if (result != ERROR_SUCCESS || type != REG_SZ || !valueSize)
162 return false;
163 std::vector<BYTE> buffer(valueSize);
164 result = RegQueryValueExW(hkey, WideValueName.c_str(), NULL, NULL, &buffer[0],
165 &valueSize);
166 if (result == ERROR_SUCCESS) {
167 std::wstring WideValue(reinterpret_cast<const wchar_t *>(buffer.data()),
168 valueSize / sizeof(wchar_t));
169 if (valueSize && WideValue.back() == L'\0') {
170 WideValue.pop_back();
171 }
172 // The destination buffer must be empty as an invariant of the conversion
173 // function; but this function is sometimes called in a loop that passes in
174 // the same buffer, however. Simply clear it out so we can overwrite it.
175 value.clear();
176 return llvm::convertWideToUTF8(WideValue, value);
177 }
178 return false;
179}
180#endif
181
182/// Read registry string.
183/// This also supports a means to look for high-versioned keys by use
184/// of a $VERSION placeholder in the key path.
185/// $VERSION in the key path is a placeholder for the version number,
186/// causing the highest value path to be searched for and used.
187/// I.e. "SOFTWARE\\Microsoft\\VisualStudio\\$VERSION".
188/// There can be additional characters in the component. Only the numeric
189/// characters are compared. This function only searches HKLM.
190static bool getSystemRegistryString(const char *keyPath, const char *valueName,
191 std::string &value, std::string *phValue) {
192#ifndef _WIN32
193 return false;
194#else
195 HKEY hRootKey = HKEY_LOCAL_MACHINE;
196 HKEY hKey = NULL;
197 long lResult;
198 bool returnValue = false;
199
200 const char *placeHolder = strstr(keyPath, "$VERSION");
201 std::string bestName;
202 // If we have a $VERSION placeholder, do the highest-version search.
203 if (placeHolder) {
204 const char *keyEnd = placeHolder - 1;
205 const char *nextKey = placeHolder;
206 // Find end of previous key.
207 while ((keyEnd > keyPath) && (*keyEnd != '\\'))
208 keyEnd--;
209 // Find end of key containing $VERSION.
210 while (*nextKey && (*nextKey != '\\'))
211 nextKey++;
212 size_t partialKeyLength = keyEnd - keyPath;
213 char partialKey[256];
214 if (partialKeyLength >= sizeof(partialKey))
215 partialKeyLength = sizeof(partialKey) - 1;
216 strncpy(partialKey, keyPath, partialKeyLength);
217 partialKey[partialKeyLength] = '\0';
218 HKEY hTopKey = NULL;
219 lResult = RegOpenKeyExA(hRootKey, partialKey, 0, KEY_READ | KEY_WOW64_32KEY,
220 &hTopKey);
221 if (lResult == ERROR_SUCCESS) {
222 char keyName[256];
223 double bestValue = 0.0;
224 DWORD index, size = sizeof(keyName) - 1;
225 for (index = 0; RegEnumKeyExA(hTopKey, index, keyName, &size, NULL, NULL,
226 NULL, NULL) == ERROR_SUCCESS;
227 index++) {
228 const char *sp = keyName;
229 while (*sp && !llvm::isDigit(*sp))
230 sp++;
231 if (!*sp)
232 continue;
233 const char *ep = sp + 1;
234 while (*ep && (llvm::isDigit(*ep) || (*ep == '.')))
235 ep++;
236 char numBuf[32];
237 strncpy(numBuf, sp, sizeof(numBuf) - 1);
238 numBuf[sizeof(numBuf) - 1] = '\0';
239 double dvalue = strtod(numBuf, NULL);
240 if (dvalue > bestValue) {
241 // Test that InstallDir is indeed there before keeping this index.
242 // Open the chosen key path remainder.
243 bestName = keyName;
244 // Append rest of key.
245 bestName.append(nextKey);
246 lResult = RegOpenKeyExA(hTopKey, bestName.c_str(), 0,
247 KEY_READ | KEY_WOW64_32KEY, &hKey);
248 if (lResult == ERROR_SUCCESS) {
249 if (readFullStringValue(hKey, valueName, value)) {
250 bestValue = dvalue;
251 if (phValue)
252 *phValue = bestName;
253 returnValue = true;
254 }
255 RegCloseKey(hKey);
256 }
257 }
258 size = sizeof(keyName) - 1;
259 }
260 RegCloseKey(hTopKey);
261 }
262 } else {
263 lResult =
264 RegOpenKeyExA(hRootKey, keyPath, 0, KEY_READ | KEY_WOW64_32KEY, &hKey);
265 if (lResult == ERROR_SUCCESS) {
266 if (readFullStringValue(hKey, valueName, value))
267 returnValue = true;
268 if (phValue)
269 phValue->clear();
270 RegCloseKey(hKey);
271 }
272 }
273 return returnValue;
274#endif // _WIN32
275}
276
278 switch (Arch) {
280 return "x86";
282 return "x64";
285 return "arm";
287 return "arm64";
288 default:
289 return "";
290 }
291}
292
294 switch (Arch) {
296 // x86 is default in legacy VC toolchains.
297 // e.g. x86 libs are directly in /lib as opposed to /lib/x86.
298 return "";
300 return "amd64";
303 return "arm";
305 return "arm64";
306 default:
307 return "";
308 }
309}
310
312 switch (Arch) {
314 return "i386";
316 return "amd64";
319 return "arm";
321 return "arm64";
322 default:
323 return "";
324 }
325}
326
328 Triple::ArchType Arch,
329 std::string &path) {
330 if (SDKMajor >= 8) {
332 } else {
333 switch (Arch) {
334 // In Windows SDK 7.x, x86 libraries are directly in the Lib folder.
335 case Triple::x86:
336 break;
337 case Triple::x86_64:
338 sys::path::append(LibPath, "x64");
339 break;
340 case Triple::arm:
341 case Triple::thumb:
342 // It is not necessary to link against Windows SDK 7.x when targeting ARM.
343 return false;
344 default:
345 return false;
346 }
347 }
348
349 path = std::string(LibPath);
350 return true;
351}
352
354 ToolsetLayout VSLayout,
355 const std::string &VCToolChainPath,
356 Triple::ArchType TargetArch,
357 StringRef SubdirParent) {
358 const char *SubdirName;
359 const char *IncludeName;
360 switch (VSLayout) {
362 SubdirName = archToLegacyVCArch(TargetArch);
363 IncludeName = "include";
364 break;
366 SubdirName = archToWindowsSDKArch(TargetArch);
367 IncludeName = "include";
368 break;
370 SubdirName = archToDevDivInternalArch(TargetArch);
371 IncludeName = "inc";
372 break;
373 }
374
375 SmallString<256> Path(VCToolChainPath);
376 if (!SubdirParent.empty())
377 sys::path::append(Path, SubdirParent);
378
379 switch (Type) {
381 if (VSLayout == ToolsetLayout::VS2017OrNewer) {
382 // MSVC ships with two linkers: a 32-bit x86 and 64-bit x86 linker.
383 // On x86, pick the linker that corresponds to the current process.
384 // On ARM64, pick the 32-bit x86 linker; the 64-bit one doesn't run
385 // on Windows 10.
386 //
387 // FIXME: Consider using IsWow64GuestMachineSupported to figure out
388 // if we can invoke the 64-bit linker. It's generally preferable
389 // because it won't run out of address-space.
390 const bool HostIsX64 =
392 const char *const HostName = HostIsX64 ? "Hostx64" : "Hostx86";
393 sys::path::append(Path, "bin", HostName, SubdirName);
394 } else { // OlderVS or DevDivInternal
395 sys::path::append(Path, "bin", SubdirName);
396 }
397 break;
399 sys::path::append(Path, IncludeName);
400 break;
402 sys::path::append(Path, "lib", SubdirName);
403 break;
404 }
405 return std::string(Path);
406}
407
409 const std::string &VCToolChainPath,
410 Triple::ArchType TargetArch, vfs::FileSystem &VFS) {
412 SubDirectoryType::Include, VSLayout, VCToolChainPath, TargetArch));
413 sys::path::append(TestPath, "stdlib.h");
414 return !VFS.exists(TestPath);
415}
416
418 std::optional<StringRef> WinSdkDir,
419 std::optional<StringRef> WinSdkVersion,
420 std::optional<StringRef> WinSysRoot,
421 std::string &Path, int &Major,
422 std::string &WindowsSDKIncludeVersion,
423 std::string &WindowsSDKLibVersion) {
424 // Trust /winsdkdir and /winsdkversion if present.
425 if (getWindowsSDKDirViaCommandLine(VFS, WinSdkDir, WinSdkVersion, WinSysRoot,
426 Path, Major, WindowsSDKIncludeVersion)) {
427 WindowsSDKLibVersion = WindowsSDKIncludeVersion;
428 return true;
429 }
430
431 // FIXME: Try env vars (%WindowsSdkDir%, %UCRTVersion%) before going to
432 // registry.
433
434 // Try the Windows registry.
435 std::string RegistrySDKVersion;
437 "SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\$VERSION",
438 "InstallationFolder", Path, &RegistrySDKVersion))
439 return false;
440 if (Path.empty() || RegistrySDKVersion.empty())
441 return false;
442
443 WindowsSDKIncludeVersion.clear();
444 WindowsSDKLibVersion.clear();
445 Major = 0;
446 std::sscanf(RegistrySDKVersion.c_str(), "v%d.", &Major);
447 if (Major <= 7)
448 return true;
449 if (Major == 8) {
450 // Windows SDK 8.x installs libraries in a folder whose names depend on the
451 // version of the OS you're targeting. By default choose the newest, which
452 // usually corresponds to the version of the OS you've installed the SDK on.
453 const char *Tests[] = {"winv6.3", "win8", "win7"};
454 for (const char *Test : Tests) {
455 SmallString<128> TestPath(Path);
456 sys::path::append(TestPath, "Lib", Test);
457 if (VFS.exists(TestPath)) {
458 WindowsSDKLibVersion = Test;
459 break;
460 }
461 }
462 return !WindowsSDKLibVersion.empty();
463 }
464 if (Major == 10) {
465 if (WinSdkVersion) {
466 // Use the user-provided version as-is.
467 WindowsSDKIncludeVersion = WinSdkVersion->str();
468 WindowsSDKLibVersion = WindowsSDKIncludeVersion;
469 return true;
470 }
471
472 if (!getWindows10SDKVersionFromPath(VFS, Path, WindowsSDKIncludeVersion))
473 return false;
474 WindowsSDKLibVersion = WindowsSDKIncludeVersion;
475 return true;
476 }
477 // Unsupported SDK version
478 return false;
479}
480
482 std::optional<StringRef> WinSdkDir,
483 std::optional<StringRef> WinSdkVersion,
484 std::optional<StringRef> WinSysRoot,
485 std::string &Path, std::string &UCRTVersion) {
486 // If /winsdkdir is passed, use it as location for the UCRT too.
487 // FIXME: Should there be a dedicated /ucrtdir to override /winsdkdir?
488 int Major;
489 if (getWindowsSDKDirViaCommandLine(VFS, WinSdkDir, WinSdkVersion, WinSysRoot,
490 Path, Major, UCRTVersion))
491 return true;
492
493 // FIXME: Try env vars (%UniversalCRTSdkDir%, %UCRTVersion%) before going to
494 // registry.
495
496 // vcvarsqueryregistry.bat for Visual Studio 2015 queries the registry
497 // for the specific key "KitsRoot10". So do we.
499 "SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots", "KitsRoot10",
500 Path, nullptr))
501 return false;
502
503 if (WinSdkVersion) {
504 // Use the user-provided version as-is.
505 UCRTVersion = WinSdkVersion->str();
506 return true;
507 }
508
509 return getWindows10SDKVersionFromPath(VFS, Path, UCRTVersion);
510}
511
513 vfs::FileSystem &VFS, std::optional<StringRef> VCToolsDir,
514 std::optional<StringRef> VCToolsVersion,
515 std::optional<StringRef> WinSysRoot, std::string &Path,
516 ToolsetLayout &VSLayout) {
517 // Don't validate the input; trust the value supplied by the user.
518 // The primary motivation is to prevent unnecessary file and registry access.
519 if (VCToolsDir || WinSysRoot) {
520 if (WinSysRoot) {
521 SmallString<128> ToolsPath(*WinSysRoot);
522 sys::path::append(ToolsPath, "VC", "Tools", "MSVC");
523 std::string ToolsVersion;
524 if (VCToolsVersion)
525 ToolsVersion = VCToolsVersion->str();
526 else
527 ToolsVersion = getHighestNumericTupleInDirectory(VFS, ToolsPath);
528 sys::path::append(ToolsPath, ToolsVersion);
529 Path = std::string(ToolsPath);
530 } else {
531 Path = VCToolsDir->str();
532 }
534 return true;
535 }
536 return false;
537}
538
540 std::string &Path,
541 ToolsetLayout &VSLayout) {
542 // These variables are typically set by vcvarsall.bat
543 // when launching a developer command prompt.
544 if (std::optional<std::string> VCToolsInstallDir =
545 sys::Process::GetEnv("VCToolsInstallDir")) {
546 // This is only set by newer Visual Studios, and it leads straight to
547 // the toolchain directory.
548 Path = std::move(*VCToolsInstallDir);
550 return true;
551 }
552 if (std::optional<std::string> VCInstallDir =
553 sys::Process::GetEnv("VCINSTALLDIR")) {
554 // If the previous variable isn't set but this one is, then we've found
555 // an older Visual Studio. This variable is set by newer Visual Studios too,
556 // so this check has to appear second.
557 // In older Visual Studios, the VC directory is the toolchain.
558 Path = std::move(*VCInstallDir);
559 VSLayout = ToolsetLayout::OlderVS;
560 return true;
561 }
562
563 // We couldn't find any VC environment variables. Let's walk through PATH and
564 // see if it leads us to a VC toolchain bin directory. If it does, pick the
565 // first one that we find.
566 if (std::optional<std::string> PathEnv = sys::Process::GetEnv("PATH")) {
567 SmallVector<StringRef, 8> PathEntries;
568 StringRef(*PathEnv).split(PathEntries, sys::EnvPathSeparator);
569 for (StringRef PathEntry : PathEntries) {
570 if (PathEntry.empty())
571 continue;
572
573 SmallString<256> ExeTestPath;
574
575 // If cl.exe doesn't exist, then this definitely isn't a VC toolchain.
576 ExeTestPath = PathEntry;
577 sys::path::append(ExeTestPath, "cl.exe");
578 if (!VFS.exists(ExeTestPath))
579 continue;
580
581 // cl.exe existing isn't a conclusive test for a VC toolchain; clang also
582 // has a cl.exe. So let's check for link.exe too.
583 ExeTestPath = PathEntry;
584 sys::path::append(ExeTestPath, "link.exe");
585 if (!VFS.exists(ExeTestPath))
586 continue;
587
588 // whatever/VC/bin --> old toolchain, VC dir is toolchain dir.
589 StringRef TestPath = PathEntry;
590 bool IsBin = sys::path::filename(TestPath).equals_insensitive("bin");
591 if (!IsBin) {
592 // Strip any architecture subdir like "amd64".
593 TestPath = sys::path::parent_path(TestPath);
594 IsBin = sys::path::filename(TestPath).equals_insensitive("bin");
595 }
596 if (IsBin) {
597 StringRef ParentPath = sys::path::parent_path(TestPath);
598 StringRef ParentFilename = sys::path::filename(ParentPath);
599 if (ParentFilename.equals_insensitive("VC")) {
600 Path = std::string(ParentPath);
601 VSLayout = ToolsetLayout::OlderVS;
602 return true;
603 }
604 if (ParentFilename.equals_insensitive("x86ret") ||
605 ParentFilename.equals_insensitive("x86chk") ||
606 ParentFilename.equals_insensitive("amd64ret") ||
607 ParentFilename.equals_insensitive("amd64chk")) {
608 Path = std::string(ParentPath);
610 return true;
611 }
612
613 } else {
614 // This could be a new (>=VS2017) toolchain. If it is, we should find
615 // path components with these prefixes when walking backwards through
616 // the path.
617 // Note: empty strings match anything.
618 StringRef ExpectedPrefixes[] = {"", "Host", "bin", "",
619 "MSVC", "Tools", "VC"};
620
621 auto It = sys::path::rbegin(PathEntry);
622 auto End = sys::path::rend(PathEntry);
623 for (StringRef Prefix : ExpectedPrefixes) {
624 if (It == End)
625 goto NotAToolChain;
626 if (!It->starts_with_insensitive(Prefix))
627 goto NotAToolChain;
628 ++It;
629 }
630
631 // We've found a new toolchain!
632 // Back up 3 times (/bin/Host/arch) to get the root path.
633 StringRef ToolChainPath(PathEntry);
634 for (int i = 0; i < 3; ++i)
635 ToolChainPath = sys::path::parent_path(ToolChainPath);
636
637 Path = std::string(ToolChainPath);
639 return true;
640 }
641
642 NotAToolChain:
643 continue;
644 }
645 }
646 return false;
647}
648
650 vfs::FileSystem &VFS, std::optional<StringRef> VCToolsVersion,
651 std::string &Path, ToolsetLayout &VSLayout) {
652#ifndef _WIN32
653 return false;
654#else
655 // FIXME: This really should be done once in the top-level program's main
656 // function, as it may have already been initialized with a different
657 // threading model otherwise.
659 HRESULT HR;
660
661 // _com_ptr_t will throw a _com_error if a COM calls fail.
662 // The LLVM coding standards forbid exception handling, so we'll have to
663 // stop them from being thrown in the first place.
664 // The destructor will put the regular error handler back when we leave
665 // this scope.
666 struct SuppressCOMErrorsRAII {
667 static void __stdcall handler(HRESULT hr, IErrorInfo *perrinfo) {}
668
669 SuppressCOMErrorsRAII() { _set_com_error_handler(handler); }
670
671 ~SuppressCOMErrorsRAII() { _set_com_error_handler(_com_raise_error); }
672
673 } COMErrorSuppressor;
674
675 ISetupConfigurationPtr Query;
676 HR = Query.CreateInstance(__uuidof(SetupConfiguration));
677 if (FAILED(HR))
678 return false;
679
680 IEnumSetupInstancesPtr EnumInstances;
681 HR = ISetupConfiguration2Ptr(Query)->EnumAllInstances(&EnumInstances);
682 if (FAILED(HR))
683 return false;
684
685 ISetupInstancePtr Instance;
686 HR = EnumInstances->Next(1, &Instance, nullptr);
687 if (HR != S_OK)
688 return false;
689
690 ISetupInstancePtr NewestInstance;
691 std::optional<uint64_t> NewestVersionNum;
692 do {
693 bstr_t VersionString;
694 uint64_t VersionNum;
695 HR = Instance->GetInstallationVersion(VersionString.GetAddress());
696 if (FAILED(HR))
697 continue;
698 HR = ISetupHelperPtr(Query)->ParseVersion(VersionString, &VersionNum);
699 if (FAILED(HR))
700 continue;
701 if (!NewestVersionNum || (VersionNum > NewestVersionNum)) {
702 NewestInstance = Instance;
703 NewestVersionNum = VersionNum;
704 }
705 } while ((HR = EnumInstances->Next(1, &Instance, nullptr)) == S_OK);
706
707 if (!NewestInstance)
708 return false;
709
710 bstr_t VCPathWide;
711 HR = NewestInstance->ResolvePath(L"VC", VCPathWide.GetAddress());
712 if (FAILED(HR))
713 return false;
714
715 std::string VCRootPath;
716 convertWideToUTF8(std::wstring(VCPathWide), VCRootPath);
717
718 std::string ToolsVersion;
719 if (VCToolsVersion.has_value()) {
720 ToolsVersion = *VCToolsVersion;
721 } else {
722 SmallString<256> ToolsVersionFilePath(VCRootPath);
723 sys::path::append(ToolsVersionFilePath, "Auxiliary", "Build",
724 "Microsoft.VCToolsVersion.default.txt");
725
726 auto ToolsVersionFile = MemoryBuffer::getFile(ToolsVersionFilePath);
727 if (!ToolsVersionFile)
728 return false;
729
730 ToolsVersion = ToolsVersionFile->get()->getBuffer().rtrim();
731 }
732
733
734 SmallString<256> ToolchainPath(VCRootPath);
735 sys::path::append(ToolchainPath, "Tools", "MSVC", ToolsVersion);
736 auto Status = VFS.status(ToolchainPath);
737 if (!Status || !Status->isDirectory())
738 return false;
739
740 Path = std::string(ToolchainPath.str());
742 return true;
743#endif
744}
745
746bool llvm::findVCToolChainViaRegistry(std::string &Path,
747 ToolsetLayout &VSLayout) {
748 std::string VSInstallPath;
749 if (getSystemRegistryString(R"(SOFTWARE\Microsoft\VisualStudio\$VERSION)",
750 "InstallDir", VSInstallPath, nullptr) ||
751 getSystemRegistryString(R"(SOFTWARE\Microsoft\VCExpress\$VERSION)",
752 "InstallDir", VSInstallPath, nullptr)) {
753 if (!VSInstallPath.empty()) {
754 auto pos = VSInstallPath.find(R"(\Common7\IDE)");
755 if (pos == std::string::npos)
756 return false;
757 SmallString<256> VCPath(StringRef(VSInstallPath.c_str(), pos));
758 sys::path::append(VCPath, "VC");
759
760 Path = std::string(VCPath);
761 VSLayout = ToolsetLayout::OlderVS;
762 return true;
763 }
764 }
765 return false;
766}
uint64_t uint64_t
Provides a library for accessing COM functionality of the Host OS.
static bool getSystemRegistryString(const char *keyPath, const char *valueName, std::string &value, std::string *phValue)
Read registry string.
static bool getWindowsSDKDirViaCommandLine(llvm::vfs::FileSystem &VFS, std::optional< llvm::StringRef > WinSdkDir, std::optional< llvm::StringRef > WinSdkVersion, std::optional< llvm::StringRef > WinSysRoot, std::string &Path, int &Major, std::string &Version)
static bool getWindows10SDKVersionFromPath(llvm::vfs::FileSystem &VFS, const std::string &SDKPath, std::string &SDKVersion)
static std::string getHighestNumericTupleInDirectory(llvm::vfs::FileSystem &VFS, llvm::StringRef Directory)
Definition MSVCPaths.cpp:78
struct ISetupInstance2 ISetupInstance2
struct ISetupInstance ISetupInstance
struct ISetupConfiguration ISetupConfiguration
struct ISetupHelper ISetupHelper
struct ISetupConfiguration2 ISetupConfiguration2
struct IEnumSetupInstances IEnumSetupInstances
Provides a library for accessing information about this process and other processes on the operating ...
This file defines the SmallString class.
This file defines the SmallVector class.
This file contains some functions that are useful when dealing with strings.
Defines the llvm::VersionTuple class, which represents a version in the form major[....
Defines the virtual file system interface vfs::FileSystem.
static ErrorOr< std::unique_ptr< MemoryBuffer > > getFile(const Twine &Filename, bool IsText=false, bool RequiresNullTerminator=true, bool IsVolatile=false, std::optional< Align > Alignment=std::nullopt)
Open the specified file as a MemoryBuffer, returning a new MemoryBuffer if successful,...
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Definition SmallString.h:26
StringRef str() const
Explicit conversion to StringRef.
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
std::pair< StringRef, StringRef > split(char Separator) const
Split into two substrings around the first occurrence of a separator character.
Definition StringRef.h:736
std::string str() const
Get the contents as an std::string.
Definition StringRef.h:222
constexpr bool empty() const
Check if the string is empty.
Definition StringRef.h:141
bool equals_insensitive(StringRef RHS) const
Check for string equality, ignoring case.
Definition StringRef.h:170
Triple - Helper class for working with autoconf configuration names.
Definition Triple.h:48
ArchType getArch() const
Get the parsed architecture type of this triple.
Definition Triple.h:515
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
Represents a version number in the form major[.minor[.subminor[.build]]].
unsigned getMajor() const
Retrieve the major version number.
LLVM_ABI bool tryParse(StringRef string)
Try to parse the given string as a version number.
LLVM_ABI std::string getAsString() const
Retrieve a string representation of the version number.
bool empty() const
Determine whether this version information is empty (e.g., all version components are zero).
static LLVM_ABI std::optional< std::string > GetEnv(StringRef name)
The virtual file system interface.
virtual bool exists(const Twine &Path)
Check whether Path exists.
virtual directory_iterator dir_begin(const Twine &Dir, std::error_code &EC)=0
Get a directory_iterator for Dir.
virtual llvm::ErrorOr< Status > status(const Twine &Path)=0
Get the status of the entry at Path, if one exists.
An input iterator over the entries in a virtual path, similar to llvm::sys::fs::directory_iterator.
LLVM_ABI StringRef parent_path(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Get parent path.
Definition Path.cpp:478
LLVM_ABI StringRef filename(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Get filename.
Definition Path.cpp:594
LLVM_ABI void append(SmallVectorImpl< char > &path, const Twine &a, const Twine &b="", const Twine &c="", const Twine &d="")
Append to path.
Definition Path.cpp:467
LLVM_ABI reverse_iterator rend(StringRef path LLVM_LIFETIME_BOUND)
Get reverse end iterator over path.
LLVM_ABI reverse_iterator rbegin(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Get reverse begin iterator over path.
const char EnvPathSeparator
This is the OS-specific separator for PATH like environment variables:
Definition Program.h:33
LLVM_ABI std::string getProcessTriple()
getProcessTriple() - Return an appropriate target triple for generating code to be loaded into the cu...
Definition Host.cpp:2675
LLVM_ABI const char * archToWindowsSDKArch(llvm::Triple::ArchType Arch)
LLVM_ABI bool findVCToolChainViaCommandLine(vfs::FileSystem &VFS, std::optional< llvm::StringRef > VCToolsDir, std::optional< llvm::StringRef > VCToolsVersion, std::optional< llvm::StringRef > WinSysRoot, std::string &Path, ToolsetLayout &VSLayout)
SubDirectoryType
Definition MSVCPaths.h:22
LLVM_ABI bool getWindowsSDKDir(vfs::FileSystem &VFS, std::optional< llvm::StringRef > WinSdkDir, std::optional< llvm::StringRef > WinSdkVersion, std::optional< llvm::StringRef > WinSysRoot, std::string &Path, int &Major, std::string &WindowsSDKIncludeVersion, std::string &WindowsSDKLibVersion)
Get Windows SDK installation directory.
LLVM_ABI bool useUniversalCRT(ToolsetLayout VSLayout, const std::string &VCToolChainPath, llvm::Triple::ArchType TargetArch, llvm::vfs::FileSystem &VFS)
LLVM_ABI bool convertWideToUTF8(std::wstring_view Source, std::string &Result)
Converts a wide string view to a UTF-8 encoded std::string.
LLVM_ABI bool findVCToolChainViaEnvironment(vfs::FileSystem &VFS, std::string &Path, ToolsetLayout &VSLayout)
LLVM_ABI bool findVCToolChainViaSetupConfig(vfs::FileSystem &VFS, std::optional< llvm::StringRef > VCToolsVersion, std::string &Path, ToolsetLayout &VSLayout)
LLVM_ABI const char * archToLegacyVCArch(llvm::Triple::ArchType Arch)
bool isDigit(char C)
Checks if character C is one of the 10 decimal digits.
ToolsetLayout
Definition MSVCPaths.h:28
LLVM_ABI bool ConvertUTF8toWide(unsigned WideCharWidth, llvm::StringRef Source, char *&ResultPtr, const UTF8 *&ErrorPtr)
Convert an UTF8 StringRef to UTF8, UTF16, or UTF32 depending on WideCharWidth.
LLVM_ABI const char * archToDevDivInternalArch(llvm::Triple::ArchType Arch)
LLVM_ABI std::string getSubDirectoryPath(SubDirectoryType Type, ToolsetLayout VSLayout, const std::string &VCToolChainPath, llvm::Triple::ArchType TargetArch, llvm::StringRef SubdirParent="")
@ End
Run the machine verifier once, at the end of the pipeline.
Definition CodeGen.h:320
LLVM_ABI bool appendArchToWindowsSDKLibPath(int SDKMajor, llvm::SmallString< 128 > LibPath, llvm::Triple::ArchType Arch, std::string &path)
LLVM_ABI bool findVCToolChainViaRegistry(std::string &Path, ToolsetLayout &VSLayout)
LLVM_ABI bool getUniversalCRTSdkDir(vfs::FileSystem &VFS, std::optional< llvm::StringRef > WinSdkDir, std::optional< llvm::StringRef > WinSdkVersion, std::optional< llvm::StringRef > WinSysRoot, std::string &Path, std::string &UCRTVersion)