LLVM: lib/WindowsDriver/MSVCPaths.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

22#include

23#include

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

40#define USE_MSVC_SETUP_API

41

42

43#include <comdef.h>

44

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

60#endif

61

62static std::string

65 std::string Highest;

67

68 std::error_code EC;

70 DirEnd;

71 !EC && DirIt != DirEnd; DirIt.increment(EC)) {

74 continue;

77 if (Tuple.tryParse(CandidateName))

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) {

94 return !SDKVersion.empty();

95}

96

99 std::optionalllvm::StringRef WinSdkVersion,

100 std::optionalllvm::StringRef WinSysRoot, std::string &Path, int &Major,

101 std::string &Version) {

102 if (WinSdkDir || WinSysRoot) {

103

104

106 if (WinSdkVersion)

107 SDKVersion.tryParse(*WinSdkVersion);

108

109 if (WinSysRoot) {

112 if (!SDKVersion.empty())

114 else

117 Path = std::string(SDKPath);

118 } else {

119 Path = WinSdkDir->str();

120 }

121

122 if (!SDKVersion.empty()) {

123 Major = SDKVersion.getMajor();

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;

138 return false;

139

140 DWORD result = 0;

141 DWORD valueSize = 0;

142 DWORD type = 0;

143

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 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

158

159

160 value.clear();

162 }

163 return false;

164}

165#endif

166

167

168

169

170

171

172

173

174

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

188 if (placeHolder) {

189 const char *keyEnd = placeHolder - 1;

190 const char *nextKey = placeHolder;

191

192 while ((keyEnd > keyPath) && (*keyEnd != '\\'))

193 keyEnd--;

194

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;

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

227

228 bestName = keyName;

229

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

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

282

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

314 std::string &path) {

315 if (SDKMajor >= 8) {

317 } else {

318 switch (Arch) {

319

321 break;

324 break;

327

328 return false;

329 default:

330 return false;

331 }

332 }

333

334 path = std::string(LibPath);

335 return true;

336}

337

340 const std::string &VCToolChainPath,

343 const char *SubdirName;

344 const char *IncludeName;

345 switch (VSLayout) {

348 IncludeName = "include";

349 break;

352 IncludeName = "include";

353 break;

356 IncludeName = "inc";

357 break;

358 }

359

361 if (!SubdirParent.empty())

363

364 switch (Type) {

367

368

369

370

371

372

373

374

375 const bool HostIsX64 =

377 const char *const HostName = HostIsX64 ? "Hostx64" : "Hostx86";

379 } else {

381 }

382 break;

385 break;

388 break;

389 }

390 return std::string(Path);

391}

392

394 const std::string &VCToolChainPath,

399 return !VFS.exists(TestPath);

400}

401

403 std::optional WinSdkDir,

404 std::optional WinSdkVersion,

405 std::optional WinSysRoot,

406 std::string &Path, int &Major,

407 std::string &WindowsSDKIncludeVersion,

408 std::string &WindowsSDKLibVersion) {

409

411 Path, Major, WindowsSDKIncludeVersion)) {

412 WindowsSDKLibVersion = WindowsSDKIncludeVersion;

413 return true;

414 }

415

416

417

418

419

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

436

437

438 const char *Tests[] = {"winv6.3", "win8", "win7"};

439 for (const char *Test : Tests) {

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

452 WindowsSDKIncludeVersion = WinSdkVersion->str();

453 WindowsSDKLibVersion = WindowsSDKIncludeVersion;

454 return true;

455 }

456

458 return false;

459 WindowsSDKLibVersion = WindowsSDKIncludeVersion;

460 return true;

461 }

462

463 return false;

464}

465

467 std::optional WinSdkDir,

468 std::optional WinSdkVersion,

469 std::optional WinSysRoot,

470 std::string &Path, std::string &UCRTVersion) {

471

472

473 int Major;

475 Path, Major, UCRTVersion))

476 return true;

477

478

479

480

481

482

484 "SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots", "KitsRoot10",

485 Path, nullptr))

486 return false;

487

488 if (WinSdkVersion) {

489

490 UCRTVersion = WinSdkVersion->str();

491 return true;

492 }

493

495}

496

498 vfs::FileSystem &VFS, std::optional VCToolsDir,

499 std::optional VCToolsVersion,

500 std::optional WinSysRoot, std::string &Path,

502

503

504 if (VCToolsDir || WinSysRoot) {

505 if (WinSysRoot) {

508 std::string ToolsVersion;

509 if (VCToolsVersion)

510 ToolsVersion = VCToolsVersion->str();

511 else

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,

527

528

529 if (std::optionalstd::string VCToolsInstallDir =

531

532

533 Path = std::move(*VCToolsInstallDir);

535 return true;

536 }

537 if (std::optionalstd::string VCInstallDir =

539

540

541

542

543 Path = std::move(*VCInstallDir);

545 return true;

546 }

547

548

549

550

554 for (StringRef PathEntry : PathEntries) {

555 if (PathEntry.empty())

556 continue;

557

559

560

561 ExeTestPath = PathEntry;

563 if (!VFS.exists(ExeTestPath))

564 continue;

565

566

567

568 ExeTestPath = PathEntry;

570 if (!VFS.exists(ExeTestPath))

571 continue;

572

573

576 if (!IsBin) {

577

580 }

581 if (IsBin) {

585 Path = std::string(ParentPath);

587 return true;

588 }

593 Path = std::string(ParentPath);

595 return true;

596 }

597

598 } else {

599

600

601

602

603 StringRef ExpectedPrefixes[] = {"", "Host", "bin", "",

604 "MSVC", "Tools", "VC"};

605

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

617

618 StringRef ToolChainPath(PathEntry);

619 for (int i = 0; i < 3; ++i)

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 VCToolsVersion,

637#if !defined(USE_MSVC_SETUP_API)

638 return false;

639#else

640

641

642

644 HRESULT HR;

645

646

647

648

649

650

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;

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;

702

703 std::string ToolsVersion;

704 if (VCToolsVersion.has_value()) {

705 ToolsVersion = *VCToolsVersion;

706 } else {

709 "Microsoft.VCToolsVersion.default.txt");

710

712 if (!ToolsVersionFile)

713 return false;

714

715 ToolsVersion = ToolsVersionFile->get()->getBuffer().rtrim();

716 }

717

718

723 return false;

724

725 Path = std::string(ToolchainPath.str());

727 return true;

728#endif

729}

730

733 std::string VSInstallPath;

735 "InstallDir", VSInstallPath, nullptr) ||

737 "InstallDir", VSInstallPath, nullptr)) {

738 if (!VSInstallPath.empty()) {

739 auto pos = VSInstallPath.find(R"(\Common7\IDE)");

740 if (pos == std:🧵:npos)

741 return false;

744

745 Path = std::string(VCPath);

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.

Definition MSVCPaths.cpp:175

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.

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)

Definition MSVCPaths.cpp:262

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)

Definition MSVCPaths.cpp:497

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.

Definition MSVCPaths.cpp:402

LLVM_ABI bool useUniversalCRT(ToolsetLayout VSLayout, const std::string &VCToolChainPath, llvm::Triple::ArchType TargetArch, llvm::vfs::FileSystem &VFS)

Definition MSVCPaths.cpp:393

LLVM_ABI bool findVCToolChainViaEnvironment(vfs::FileSystem &VFS, std::string &Path, ToolsetLayout &VSLayout)

Definition MSVCPaths.cpp:524

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)

Definition MSVCPaths.cpp:634

LLVM_ABI const char * archToLegacyVCArch(llvm::Triple::ArchType Arch)

Definition MSVCPaths.cpp:278

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)

Definition MSVCPaths.cpp:296

LLVM_ABI std::string getSubDirectoryPath(SubDirectoryType Type, ToolsetLayout VSLayout, const std::string &VCToolChainPath, llvm::Triple::ArchType TargetArch, llvm::StringRef SubdirParent="")

Definition MSVCPaths.cpp:338

LLVM_ABI bool appendArchToWindowsSDKLibPath(int SDKMajor, llvm::SmallString< 128 > LibPath, llvm::Triple::ArchType Arch, std::string &path)

Definition MSVCPaths.cpp:312

LLVM_ABI bool findVCToolChainViaRegistry(std::string &Path, ToolsetLayout &VSLayout)

Definition MSVCPaths.cpp:731

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)

Definition MSVCPaths.cpp:466