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