1//===-- MSVCPaths.cpp - MSVC path-parsing helpers -------------------------===//
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
7//===----------------------------------------------------------------------===//
30#define WIN32_LEAN_AND_MEAN
39// Don't support SetupApi on MinGW.
40#define USE_MSVC_SETUP_API
42// Make sure this comes before MSVCSetupApi.h
47#pragma clang diagnostic push
48#pragma clang diagnostic ignored "-Wnon-virtual-dtor"
52#pragma clang diagnostic pop
71 !EC && DirIt != DirEnd; DirIt.increment(EC)) {
77 if (Tuple.tryParse(CandidateName))
// tryParse() returns true on error.
79 if (Tuple > HighestTuple) {
81 Highest = CandidateName.
str();
89 const std::string &SDKPath,
90 std::string &SDKVersion) {
94 return !SDKVersion.empty();
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.
107 SDKVersion.
tryParse(*WinSdkVersion);
112 if (!SDKVersion.
empty())
117 Path = std::string(SDKPath);
119 Path = WinSdkDir->str();
122 if (!SDKVersion.
empty()) {
134static bool readFullStringValue(HKEY hkey,
const char *valueName,
135 std::string &value) {
136 std::wstring WideValueName;
143 // First just query for the required size.
144 result = RegQueryValueExW(hkey, WideValueName.c_str(), NULL, &type, NULL,
146 if (result != ERROR_SUCCESS || type != REG_SZ || !valueSize)
148 std::vector<BYTE> buffer(valueSize);
149 result = RegQueryValueExW(hkey, WideValueName.c_str(), NULL, NULL, &buffer[0],
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();
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.
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.
176 std::string &value, std::string *phValue) {
180 HKEY hRootKey = HKEY_LOCAL_MACHINE;
183 bool returnValue =
false;
185 const char *placeHolder = strstr(keyPath,
"$VERSION");
186 std::string bestName;
187 // If we have a $VERSION placeholder, do the highest-version search.
189 const char *keyEnd = placeHolder - 1;
190 const char *nextKey = placeHolder;
191 // Find end of previous key.
192 while ((keyEnd > keyPath) && (*keyEnd !=
'\\'))
194 // Find end of key containing $VERSION.
195 while (*nextKey && (*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円';
204 lResult = RegOpenKeyExA(hRootKey, partialKey, 0, KEY_READ | KEY_WOW64_32KEY,
206 if (lResult == ERROR_SUCCESS) {
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;
213 const char *sp = keyName;
218 const char *ep = sp + 1;
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.
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)) {
243 size =
sizeof(keyName) - 1;
245 RegCloseKey(hTopKey);
249 RegOpenKeyExA(hRootKey, keyPath, 0, KEY_READ | KEY_WOW64_32KEY, &hKey);
250 if (lResult == ERROR_SUCCESS) {
251 if (readFullStringValue(hKey, valueName, value))
281 // x86 is default in legacy VC toolchains.
282 // e.g. x86 libs are directly in /lib as opposed to /lib/x86.
319 // In Windows SDK 7.x, x86 libraries are directly in the Lib folder.
327 // It is not necessary to link against Windows SDK 7.x when targeting ARM.
334 path = std::string(LibPath);
340 const std::string &VCToolChainPath,
343 const char *SubdirName;
344 const char *IncludeName;
348 IncludeName =
"include";
352 IncludeName =
"include";
361 if (!SubdirParent.
empty())
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
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";
379 }
else {
// OlderVS or DevDivInternal
390 return std::string(Path);
394 const std::string &VCToolChainPath,
399 return !VFS.
exists(TestPath);
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.
411 Path, Major, WindowsSDKIncludeVersion)) {
412 WindowsSDKLibVersion = WindowsSDKIncludeVersion;
416 // FIXME: Try env vars (%WindowsSdkDir%, %UCRTVersion%) before going to
419 // Try the Windows registry.
420 std::string RegistrySDKVersion;
422 "SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\$VERSION",
423 "InstallationFolder", Path, &RegistrySDKVersion))
425 if (Path.empty() || RegistrySDKVersion.empty())
428 WindowsSDKIncludeVersion.clear();
429 WindowsSDKLibVersion.clear();
431 std::sscanf(RegistrySDKVersion.c_str(),
"v%d.", &Major);
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) {
442 if (VFS.
exists(TestPath)) {
443 WindowsSDKLibVersion =
Test;
447 return !WindowsSDKLibVersion.empty();
451 // Use the user-provided version as-is.
452 WindowsSDKIncludeVersion = WinSdkVersion->str();
453 WindowsSDKLibVersion = WindowsSDKIncludeVersion;
459 WindowsSDKLibVersion = WindowsSDKIncludeVersion;
462 // Unsupported SDK version
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?
475 Path, Major, UCRTVersion))
478 // FIXME: Try env vars (%UniversalCRTSdkDir%, %UCRTVersion%) before going to
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",
489 // Use the user-provided version as-is.
490 UCRTVersion = WinSdkVersion->str();
499 std::optional<StringRef> VCToolsVersion,
500 std::optional<StringRef> WinSysRoot, std::string &Path,
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) {
508 std::string ToolsVersion;
510 ToolsVersion = VCToolsVersion->str();
514 Path = std::string(ToolsPath);
516 Path = VCToolsDir->str();
527 // These variables are typically set by vcvarsall.bat
528 // when launching a developer command prompt.
529 if (std::optional<std::string> VCToolsInstallDir =
531 // This is only set by newer Visual Studios, and it leads straight to
532 // the toolchain directory.
533 Path = std::move(*VCToolsInstallDir);
537 if (std::optional<std::string> 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);
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.
554 for (
StringRef PathEntry : PathEntries) {
555 if (PathEntry.empty())
560 // If cl.exe doesn't exist, then this definitely isn't a VC toolchain.
561 ExeTestPath = PathEntry;
563 if (!VFS.
exists(ExeTestPath))
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;
570 if (!VFS.
exists(ExeTestPath))
573 // whatever/VC/bin --> old toolchain, VC dir is toolchain dir.
577 // Strip any architecture subdir like "amd64".
585 Path = std::string(ParentPath);
593 Path = std::string(ParentPath);
599 // This could be a new (>=VS2017) toolchain. If it is, we should find
600 // path components with these prefixes when walking backwards through
602 // Note: empty strings match anything.
603 StringRef ExpectedPrefixes[] = {
"",
"Host",
"bin",
"",
604 "MSVC",
"Tools",
"VC"};
608 for (
StringRef Prefix : ExpectedPrefixes) {
611 if (!It->starts_with_insensitive(Prefix))
616 // We've found a new toolchain!
617 // Back up 3 times (/bin/Host/arch) to get the root path.
619 for (
int i = 0; i < 3; ++i)
622 Path = std::string(ToolChainPath);
637#if !defined(USE_MSVC_SETUP_API)
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.
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
651 struct SuppressCOMErrorsRAII {
652 static void __stdcall handler(HRESULT hr, IErrorInfo *perrinfo) {}
654 SuppressCOMErrorsRAII() { _set_com_error_handler(handler); }
656 ~SuppressCOMErrorsRAII() { _set_com_error_handler(_com_raise_error); }
658 } COMErrorSuppressor;
660 ISetupConfigurationPtr Query;
661 HR = Query.CreateInstance(__uuidof(SetupConfiguration));
665 IEnumSetupInstancesPtr EnumInstances;
666 HR = ISetupConfiguration2Ptr(Query)->EnumAllInstances(&EnumInstances);
670 ISetupInstancePtr Instance;
671 HR = EnumInstances->Next(1, &Instance,
nullptr);
675 ISetupInstancePtr NewestInstance;
676 std::optional<uint64_t> NewestVersionNum;
678 bstr_t VersionString;
680 HR = Instance->GetInstallationVersion(VersionString.GetAddress());
683 HR = ISetupHelperPtr(Query)->ParseVersion(VersionString, &VersionNum);
686 if (!NewestVersionNum || (VersionNum > NewestVersionNum)) {
687 NewestInstance = Instance;
688 NewestVersionNum = VersionNum;
690 }
while ((HR = EnumInstances->Next(1, &Instance,
nullptr)) == S_OK);
696 HR = NewestInstance->ResolvePath(L
"VC", VCPathWide.GetAddress());
700 std::string VCRootPath;
703 std::string ToolsVersion;
704 if (VCToolsVersion.has_value()) {
705 ToolsVersion = *VCToolsVersion;
709 "Microsoft.VCToolsVersion.default.txt");
712 if (!ToolsVersionFile)
715 ToolsVersion = ToolsVersionFile->get()->getBuffer().rtrim();
725 Path = std::string(ToolchainPath.
str());
733 std::string VSInstallPath;
735"InstallDir", VSInstallPath,
nullptr) ||
737"InstallDir", VSInstallPath,
nullptr)) {
738 if (!VSInstallPath.empty()) {
739 auto pos = VSInstallPath.find(R
"(\Common7\IDE)");
740if (pos == std::string::npos)
745 Path = std::string(VCPath);
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)
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.
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...
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.
std::pair< StringRef, StringRef > split(char Separator) const
Split into two substrings around the first occurrence of a separator character.
std::string str() const
str - Get the contents as an std::string.
constexpr bool empty() const
empty - Check if the string is empty.
bool equals_insensitive(StringRef RHS) const
Check for string equality, ignoring case.
Triple - Helper class for working with autoconf configuration names.
ArchType getArch() const
Get the parsed architecture type of this triple.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
The instances of the Type class are immutable: once they are created, they are never changed.
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.
LLVM_ABI StringRef filename(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Get filename.
LLVM_ABI void append(SmallVectorImpl< char > &path, const Twine &a, const Twine &b="", const Twine &c="", const Twine &d="")
Append to path.
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:
LLVM_ABI std::string getProcessTriple()
getProcessTriple() - Return an appropriate target triple for generating code to be loaded into the cu...
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)
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.
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)