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;

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

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;

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

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

262namespace llvm {

263

265 switch (Arch) {

267 return "x86";

269 return "x64";

272 return "arm";

274 return "arm64";

275 default:

276 return "";

277 }

278}

279

281 switch (Arch) {

283

284

285 return "";

287 return "amd64";

290 return "arm";

292 return "arm64";

293 default:

294 return "";

295 }

296}

297

299 switch (Arch) {

301 return "i386";

303 return "amd64";

306 return "arm";

308 return "arm64";

309 default:

310 return "";

311 }

312}

313

316 if (SDKMajor >= 8) {

318 } else {

319 switch (Arch) {

320

322 break;

325 break;

328

329 return false;

330 default:

331 return false;

332 }

333 }

334

335 path = std::string(LibPath);

336 return true;

337}

338

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

398 return !VFS.exists(TestPath);

399}

400

402 std::optional WinSdkVersion,

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

404 int &Major, std::string &WindowsSDKIncludeVersion,

405 std::string &WindowsSDKLibVersion) {

406

408 Path, Major, WindowsSDKIncludeVersion)) {

409 WindowsSDKLibVersion = WindowsSDKIncludeVersion;

410 return true;

411 }

412

413

414

415

416

417 std::string RegistrySDKVersion;

419 "SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\$VERSION",

420 "InstallationFolder", Path, &RegistrySDKVersion))

421 return false;

422 if (Path.empty() || RegistrySDKVersion.empty())

423 return false;

424

425 WindowsSDKIncludeVersion.clear();

426 WindowsSDKLibVersion.clear();

427 Major = 0;

428 std::sscanf(RegistrySDKVersion.c_str(), "v%d.", &Major);

429 if (Major <= 7)

430 return true;

431 if (Major == 8) {

432

433

434

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

436 for (const char *Test : Tests) {

439 if (VFS.exists(TestPath)) {

440 WindowsSDKLibVersion = Test;

441 break;

442 }

443 }

444 return !WindowsSDKLibVersion.empty();

445 }

446 if (Major == 10) {

448 return false;

449 WindowsSDKLibVersion = WindowsSDKIncludeVersion;

450 return true;

451 }

452

453 return false;

454}

455

457 std::optional WinSdkDir,

458 std::optional WinSdkVersion,

459 std::optional WinSysRoot,

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

461

462

463 int Major;

465 Path, Major, UCRTVersion))

466 return true;

467

468

469

470

471

472

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

475 Path, nullptr))

476 return false;

477

479}

480

482 std::optional VCToolsDir,

483 std::optional VCToolsVersion,

484 std::optional WinSysRoot,

486

487

488 if (VCToolsDir || WinSysRoot) {

489 if (WinSysRoot) {

492 std::string ToolsVersion;

493 if (VCToolsVersion)

494 ToolsVersion = VCToolsVersion->str();

495 else

498 Path = std::string(ToolsPath);

499 } else {

500 Path = VCToolsDir->str();

501 }

503 return true;

504 }

505 return false;

506}

507

510

511

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

514

515

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

518 return true;

519 }

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

522

523

524

525

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

528 return true;

529 }

530

531

532

533

537 for (StringRef PathEntry : PathEntries) {

538 if (PathEntry.empty())

539 continue;

540

542

543

544 ExeTestPath = PathEntry;

546 if (!VFS.exists(ExeTestPath))

547 continue;

548

549

550

551 ExeTestPath = PathEntry;

553 if (!VFS.exists(ExeTestPath))

554 continue;

555

556

559 if (!IsBin) {

560

563 }

564 if (IsBin) {

568 Path = std::string(ParentPath);

570 return true;

571 }

576 Path = std::string(ParentPath);

578 return true;

579 }

580

581 } else {

582

583

584

585

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

587 "MSVC", "Tools", "VC"};

588

591 for (StringRef Prefix : ExpectedPrefixes) {

592 if (It == End)

593 goto NotAToolChain;

594 if (!It->starts_with_insensitive(Prefix))

595 goto NotAToolChain;

596 ++It;

597 }

598

599

600

601 StringRef ToolChainPath(PathEntry);

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

604

605 Path = std::string(ToolChainPath);

607 return true;

608 }

609

610 NotAToolChain:

611 continue;

612 }

613 }

614 return false;

615}

616

618 std::optional VCToolsVersion,

620#if !defined(USE_MSVC_SETUP_API)

621 return false;

622#else

623

624

625

627 HRESULT HR;

628

629

630

631

632

633

634 struct SuppressCOMErrorsRAII {

635 static void __stdcall handler(HRESULT hr, IErrorInfo *perrinfo) {}

636

637 SuppressCOMErrorsRAII() { _set_com_error_handler(handler); }

638

639 ~SuppressCOMErrorsRAII() { _set_com_error_handler(_com_raise_error); }

640

641 } COMErrorSuppressor;

642

643 ISetupConfigurationPtr Query;

644 HR = Query.CreateInstance(__uuidof(SetupConfiguration));

645 if (FAILED(HR))

646 return false;

647

648 IEnumSetupInstancesPtr EnumInstances;

649 HR = ISetupConfiguration2Ptr(Query)->EnumAllInstances(&EnumInstances);

650 if (FAILED(HR))

651 return false;

652

653 ISetupInstancePtr Instance;

654 HR = EnumInstances->Next(1, &Instance, nullptr);

655 if (HR != S_OK)

656 return false;

657

658 ISetupInstancePtr NewestInstance;

659 std::optional<uint64_t> NewestVersionNum;

660 do {

661 bstr_t VersionString;

663 HR = Instance->GetInstallationVersion(VersionString.GetAddress());

664 if (FAILED(HR))

665 continue;

666 HR = ISetupHelperPtr(Query)->ParseVersion(VersionString, &VersionNum);

667 if (FAILED(HR))

668 continue;

669 if (!NewestVersionNum || (VersionNum > NewestVersionNum)) {

670 NewestInstance = Instance;

671 NewestVersionNum = VersionNum;

672 }

673 } while ((HR = EnumInstances->Next(1, &Instance, nullptr)) == S_OK);

674

675 if (!NewestInstance)

676 return false;

677

678 bstr_t VCPathWide;

679 HR = NewestInstance->ResolvePath(L"VC", VCPathWide.GetAddress());

680 if (FAILED(HR))

681 return false;

682

683 std::string VCRootPath;

685

686 std::string ToolsVersion;

687 if (VCToolsVersion.has_value()) {

688 ToolsVersion = *VCToolsVersion;

689 } else {

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

693

695 if (!ToolsVersionFile)

696 return false;

697

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

699 }

700

701

706 return false;

707

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

710 return true;

711#endif

712}

713

715 std::string VSInstallPath;

717 "InstallDir", VSInstallPath, nullptr) ||

719 "InstallDir", VSInstallPath, nullptr)) {

720 if (!VSInstallPath.empty()) {

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

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

723 return false;

726

727 Path = std::string(VCPath);

729 return true;

730 }

731 }

732 return false;

733}

734

735}

Provides a library for accessing COM functionality of the Host OS.

Given that RA is a live value

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.

bool tryParse(StringRef string)

Try to parse the given string as a version number.

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

reverse_iterator rend(StringRef path LLVM_LIFETIME_BOUND)

Get reverse end iterator over path.

StringRef parent_path(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)

Get parent path.

StringRef filename(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)

Get filename.

void append(SmallVectorImpl< char > &path, const Twine &a, const Twine &b="", const Twine &c="", const Twine &d="")

Append to path.

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:

std::string getProcessTriple()

getProcessTriple() - Return an appropriate target triple for generating code to be loaded into the cu...

This is an optimization pass for GlobalISel generic memory operations.

const char * archToWindowsSDKArch(llvm::Triple::ArchType Arch)

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)

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.

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

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

bool convertWideToUTF8(const std::wstring &Source, std::string &Result)

Converts a std::wstring to a UTF-8 encoded std::string.

bool findVCToolChainViaSetupConfig(vfs::FileSystem &VFS, std::optional< llvm::StringRef > VCToolsVersion, std::string &Path, ToolsetLayout &VSLayout)

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

bool ConvertUTF8toWide(unsigned WideCharWidth, llvm::StringRef Source, char *&ResultPtr, const UTF8 *&ErrorPtr)

Convert an UTF8 StringRef to UTF8, UTF16, or UTF32 depending on WideCharWidth.

const char * archToDevDivInternalArch(llvm::Triple::ArchType Arch)

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

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

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

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)