1 //===-- MSVC.cpp - MSVC ToolChain Implementations -------------------------===//
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
9 #include "MSVC.h"
10 #include "CommonArgs.h"
11 #include "Darwin.h"
12 #include "clang/Basic/CharInfo.h"
13 #include "clang/Basic/Version.h"
14 #include "clang/Config/config.h"
15 #include "clang/Driver/Compilation.h"
16 #include "clang/Driver/Driver.h"
17 #include "clang/Driver/DriverDiagnostic.h"
18 #include "clang/Driver/Options.h"
19 #include "clang/Driver/SanitizerArgs.h"
20 #include "llvm/ADT/StringExtras.h"
21 #include "llvm/ADT/StringSwitch.h"
22 #include "llvm/Option/Arg.h"
23 #include "llvm/Option/ArgList.h"
24 #include "llvm/Support/ConvertUTF.h"
25 #include "llvm/Support/ErrorHandling.h"
26 #include "llvm/Support/FileSystem.h"
27 #include "llvm/Support/Host.h"
28 #include "llvm/Support/MemoryBuffer.h"
29 #include "llvm/Support/Path.h"
30 #include "llvm/Support/Process.h"
31 #include "llvm/Support/VirtualFileSystem.h"
32 #include <cstdio>
33
34 #ifdef _WIN32
35 #define WIN32_LEAN_AND_MEAN
36 #define NOGDI
37 #ifndef NOMINMAX
38 #define NOMINMAX
39 #endif
40 #include <windows.h>
41 #endif
42
43 #ifdef _MSC_VER
44 // Don't support SetupApi on MinGW.
45 #define USE_MSVC_SETUP_API
46
47 // Make sure this comes before MSVCSetupApi.h
48 #include <comdef.h>
49
50 #include "MSVCSetupApi.h"
51 #include "llvm/Support/COM.h"
52 _COM_SMARTPTR_TYPEDEF(ISetupConfiguration, __uuidof(ISetupConfiguration));
53 _COM_SMARTPTR_TYPEDEF(ISetupConfiguration2, __uuidof(ISetupConfiguration2));
54 _COM_SMARTPTR_TYPEDEF(ISetupHelper, __uuidof(ISetupHelper));
55 _COM_SMARTPTR_TYPEDEF(IEnumSetupInstances, __uuidof(IEnumSetupInstances));
56 _COM_SMARTPTR_TYPEDEF(ISetupInstance, __uuidof(ISetupInstance));
57 _COM_SMARTPTR_TYPEDEF(ISetupInstance2, __uuidof(ISetupInstance2));
58 #endif
59
60 using namespace clang::driver;
61 using namespace clang::driver::toolchains;
62 using namespace clang::driver::tools;
63 using namespace clang;
64 using namespace llvm::opt;
65
66 // Windows SDKs and VC Toolchains group their contents into subdirectories based
67 // on the target architecture. This function converts an llvm::Triple::ArchType
68 // to the corresponding subdirectory name.
llvmArchToWindowsSDKArch(llvm::Triple::ArchType Arch)69 static const char *llvmArchToWindowsSDKArch(llvm::Triple::ArchType Arch) {
70 using ArchType = llvm::Triple::ArchType;
71 switch (Arch) {
72 case ArchType::x86:
73 return "x86";
74 case ArchType::x86_64:
75 return "x64";
76 case ArchType::arm:
77 return "arm";
78 case ArchType::aarch64:
79 return "arm64";
80 default:
81 return "";
82 }
83 }
84
85 // Similar to the above function, but for Visual Studios before VS2017.
llvmArchToLegacyVCArch(llvm::Triple::ArchType Arch)86 static const char *llvmArchToLegacyVCArch(llvm::Triple::ArchType Arch) {
87 using ArchType = llvm::Triple::ArchType;
88 switch (Arch) {
89 case ArchType::x86:
90 // x86 is default in legacy VC toolchains.
91 // e.g. x86 libs are directly in /lib as opposed to /lib/x86.
92 return "";
93 case ArchType::x86_64:
94 return "amd64";
95 case ArchType::arm:
96 return "arm";
97 case ArchType::aarch64:
98 return "arm64";
99 default:
100 return "";
101 }
102 }
103
104 // Similar to the above function, but for DevDiv internal builds.
llvmArchToDevDivInternalArch(llvm::Triple::ArchType Arch)105 static const char *llvmArchToDevDivInternalArch(llvm::Triple::ArchType Arch) {
106 using ArchType = llvm::Triple::ArchType;
107 switch (Arch) {
108 case ArchType::x86:
109 return "i386";
110 case ArchType::x86_64:
111 return "amd64";
112 case ArchType::arm:
113 return "arm";
114 case ArchType::aarch64:
115 return "arm64";
116 default:
117 return "";
118 }
119 }
120
canExecute(llvm::vfs::FileSystem & VFS,StringRef Path)121 static bool canExecute(llvm::vfs::FileSystem &VFS, StringRef Path) {
122 auto Status = VFS.status(Path);
123 if (!Status)
124 return false;
125 return (Status->getPermissions() & llvm::sys::fs::perms::all_exe) != 0;
126 }
127
128 // Defined below.
129 // Forward declare this so there aren't too many things above the constructor.
130 static bool getSystemRegistryString(const char *keyPath, const char *valueName,
131 std::string &value, std::string *phValue);
132
getHighestNumericTupleInDirectory(llvm::vfs::FileSystem & VFS,StringRef Directory)133 static std::string getHighestNumericTupleInDirectory(llvm::vfs::FileSystem &VFS,
134 StringRef Directory) {
135 std::string Highest;
136 llvm::VersionTuple HighestTuple;
137
138 std::error_code EC;
139 for (llvm::vfs::directory_iterator DirIt = VFS.dir_begin(Directory, EC),
140 DirEnd;
141 !EC && DirIt != DirEnd; DirIt.increment(EC)) {
142 auto Status = VFS.status(DirIt->path());
143 if (!Status || !Status->isDirectory())
144 continue;
145 StringRef CandidateName = llvm::sys::path::filename(DirIt->path());
146 llvm::VersionTuple Tuple;
147 if (Tuple.tryParse(CandidateName)) // tryParse() returns true on error.
148 continue;
149 if (Tuple > HighestTuple) {
150 HighestTuple = Tuple;
151 Highest = CandidateName.str();
152 }
153 }
154
155 return Highest;
156 }
157
158 // Check command line arguments to try and find a toolchain.
159 static bool
findVCToolChainViaCommandLine(llvm::vfs::FileSystem & VFS,const ArgList & Args,std::string & Path,MSVCToolChain::ToolsetLayout & VSLayout)160 findVCToolChainViaCommandLine(llvm::vfs::FileSystem &VFS, const ArgList &Args,
161 std::string &Path,
162 MSVCToolChain::ToolsetLayout &VSLayout) {
163 // Don't validate the input; trust the value supplied by the user.
164 // The primary motivation is to prevent unnecessary file and registry access.
165 if (Arg *A = Args.getLastArg(options::OPT__SLASH_vctoolsdir,
166 options::OPT__SLASH_winsysroot)) {
167 if (A->getOption().getID() == options::OPT__SLASH_winsysroot) {
168 llvm::SmallString<128> ToolsPath(A->getValue());
169 llvm::sys::path::append(ToolsPath, "VC", "Tools", "MSVC");
170 std::string VCToolsVersion;
171 if (Arg *A = Args.getLastArg(options::OPT__SLASH_vctoolsversion))
172 VCToolsVersion = A->getValue();
173 else
174 VCToolsVersion = getHighestNumericTupleInDirectory(VFS, ToolsPath);
175 llvm::sys::path::append(ToolsPath, VCToolsVersion);
176 Path = std::string(ToolsPath.str());
177 } else {
178 Path = A->getValue();
179 }
180 VSLayout = MSVCToolChain::ToolsetLayout::VS2017OrNewer;
181 return true;
182 }
183 return false;
184 }
185
186 // Check various environment variables to try and find a toolchain.
187 static bool
findVCToolChainViaEnvironment(llvm::vfs::FileSystem & VFS,std::string & Path,MSVCToolChain::ToolsetLayout & VSLayout)188 findVCToolChainViaEnvironment(llvm::vfs::FileSystem &VFS, std::string &Path,
189 MSVCToolChain::ToolsetLayout &VSLayout) {
190 // These variables are typically set by vcvarsall.bat
191 // when launching a developer command prompt.
192 if (llvm::Optional<std::string> VCToolsInstallDir =
193 llvm::sys::Process::GetEnv("VCToolsInstallDir")) {
194 // This is only set by newer Visual Studios, and it leads straight to
195 // the toolchain directory.
196 Path = std::move(*VCToolsInstallDir);
197 VSLayout = MSVCToolChain::ToolsetLayout::VS2017OrNewer;
198 return true;
199 }
200 if (llvm::Optional<std::string> VCInstallDir =
201 llvm::sys::Process::GetEnv("VCINSTALLDIR")) {
202 // If the previous variable isn't set but this one is, then we've found
203 // an older Visual Studio. This variable is set by newer Visual Studios too,
204 // so this check has to appear second.
205 // In older Visual Studios, the VC directory is the toolchain.
206 Path = std::move(*VCInstallDir);
207 VSLayout = MSVCToolChain::ToolsetLayout::OlderVS;
208 return true;
209 }
210
211 // We couldn't find any VC environment variables. Let's walk through PATH and
212 // see if it leads us to a VC toolchain bin directory. If it does, pick the
213 // first one that we find.
214 if (llvm::Optional<std::string> PathEnv =
215 llvm::sys::Process::GetEnv("PATH")) {
216 llvm::SmallVector<llvm::StringRef, 8> PathEntries;
217 llvm::StringRef(*PathEnv).split(PathEntries, llvm::sys::EnvPathSeparator);
218 for (llvm::StringRef PathEntry : PathEntries) {
219 if (PathEntry.empty())
220 continue;
221
222 llvm::SmallString<256> ExeTestPath;
223
224 // If cl.exe doesn't exist, then this definitely isn't a VC toolchain.
225 ExeTestPath = PathEntry;
226 llvm::sys::path::append(ExeTestPath, "cl.exe");
227 if (!VFS.exists(ExeTestPath))
228 continue;
229
230 // cl.exe existing isn't a conclusive test for a VC toolchain; clang also
231 // has a cl.exe. So let's check for link.exe too.
232 ExeTestPath = PathEntry;
233 llvm::sys::path::append(ExeTestPath, "link.exe");
234 if (!VFS.exists(ExeTestPath))
235 continue;
236
237 // whatever/VC/bin --> old toolchain, VC dir is toolchain dir.
238 llvm::StringRef TestPath = PathEntry;
239 bool IsBin =
240 llvm::sys::path::filename(TestPath).equals_insensitive("bin");
241 if (!IsBin) {
242 // Strip any architecture subdir like "amd64".
243 TestPath = llvm::sys::path::parent_path(TestPath);
244 IsBin = llvm::sys::path::filename(TestPath).equals_insensitive("bin");
245 }
246 if (IsBin) {
247 llvm::StringRef ParentPath = llvm::sys::path::parent_path(TestPath);
248 llvm::StringRef ParentFilename = llvm::sys::path::filename(ParentPath);
249 if (ParentFilename.equals_insensitive("VC")) {
250 Path = std::string(ParentPath);
251 VSLayout = MSVCToolChain::ToolsetLayout::OlderVS;
252 return true;
253 }
254 if (ParentFilename.equals_insensitive("x86ret") ||
255 ParentFilename.equals_insensitive("x86chk") ||
256 ParentFilename.equals_insensitive("amd64ret") ||
257 ParentFilename.equals_insensitive("amd64chk")) {
258 Path = std::string(ParentPath);
259 VSLayout = MSVCToolChain::ToolsetLayout::DevDivInternal;
260 return true;
261 }
262
263 } else {
264 // This could be a new (>=VS2017) toolchain. If it is, we should find
265 // path components with these prefixes when walking backwards through
266 // the path.
267 // Note: empty strings match anything.
268 llvm::StringRef ExpectedPrefixes[] = {"", "Host", "bin", "",
269 "MSVC", "Tools", "VC"};
270
271 auto It = llvm::sys::path::rbegin(PathEntry);
272 auto End = llvm::sys::path::rend(PathEntry);
273 for (llvm::StringRef Prefix : ExpectedPrefixes) {
274 if (It == End)
275 goto NotAToolChain;
276 if (!It->startswith_insensitive(Prefix))
277 goto NotAToolChain;
278 ++It;
279 }
280
281 // We've found a new toolchain!
282 // Back up 3 times (/bin/Host/arch) to get the root path.
283 llvm::StringRef ToolChainPath(PathEntry);
284 for (int i = 0; i < 3; ++i)
285 ToolChainPath = llvm::sys::path::parent_path(ToolChainPath);
286
287 Path = std::string(ToolChainPath);
288 VSLayout = MSVCToolChain::ToolsetLayout::VS2017OrNewer;
289 return true;
290 }
291
292 NotAToolChain:
293 continue;
294 }
295 }
296 return false;
297 }
298
299 // Query the Setup Config server for installs, then pick the newest version
300 // and find its default VC toolchain.
301 // This is the preferred way to discover new Visual Studios, as they're no
302 // longer listed in the registry.
303 static bool
findVCToolChainViaSetupConfig(llvm::vfs::FileSystem & VFS,std::string & Path,MSVCToolChain::ToolsetLayout & VSLayout)304 findVCToolChainViaSetupConfig(llvm::vfs::FileSystem &VFS, std::string &Path,
305 MSVCToolChain::ToolsetLayout &VSLayout) {
306 #if !defined(USE_MSVC_SETUP_API)
307 return false;
308 #else
309 // FIXME: This really should be done once in the top-level program's main
310 // function, as it may have already been initialized with a different
311 // threading model otherwise.
312 llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::SingleThreaded);
313 HRESULT HR;
314
315 // _com_ptr_t will throw a _com_error if a COM calls fail.
316 // The LLVM coding standards forbid exception handling, so we'll have to
317 // stop them from being thrown in the first place.
318 // The destructor will put the regular error handler back when we leave
319 // this scope.
320 struct SuppressCOMErrorsRAII {
321 static void __stdcall handler(HRESULT hr, IErrorInfo *perrinfo) {}
322
323 SuppressCOMErrorsRAII() { _set_com_error_handler(handler); }
324
325 ~SuppressCOMErrorsRAII() { _set_com_error_handler(_com_raise_error); }
326
327 } COMErrorSuppressor;
328
329 ISetupConfigurationPtr Query;
330 HR = Query.CreateInstance(__uuidof(SetupConfiguration));
331 if (FAILED(HR))
332 return false;
333
334 IEnumSetupInstancesPtr EnumInstances;
335 HR = ISetupConfiguration2Ptr(Query)->EnumAllInstances(&EnumInstances);
336 if (FAILED(HR))
337 return false;
338
339 ISetupInstancePtr Instance;
340 HR = EnumInstances->Next(1, &Instance, nullptr);
341 if (HR != S_OK)
342 return false;
343
344 ISetupInstancePtr NewestInstance;
345 Optional<uint64_t> NewestVersionNum;
346 do {
347 bstr_t VersionString;
348 uint64_t VersionNum;
349 HR = Instance->GetInstallationVersion(VersionString.GetAddress());
350 if (FAILED(HR))
351 continue;
352 HR = ISetupHelperPtr(Query)->ParseVersion(VersionString, &VersionNum);
353 if (FAILED(HR))
354 continue;
355 if (!NewestVersionNum || (VersionNum > NewestVersionNum)) {
356 NewestInstance = Instance;
357 NewestVersionNum = VersionNum;
358 }
359 } while ((HR = EnumInstances->Next(1, &Instance, nullptr)) == S_OK);
360
361 if (!NewestInstance)
362 return false;
363
364 bstr_t VCPathWide;
365 HR = NewestInstance->ResolvePath(L"VC", VCPathWide.GetAddress());
366 if (FAILED(HR))
367 return false;
368
369 std::string VCRootPath;
370 llvm::convertWideToUTF8(std::wstring(VCPathWide), VCRootPath);
371
372 llvm::SmallString<256> ToolsVersionFilePath(VCRootPath);
373 llvm::sys::path::append(ToolsVersionFilePath, "Auxiliary", "Build",
374 "Microsoft.VCToolsVersion.default.txt");
375
376 auto ToolsVersionFile = llvm::MemoryBuffer::getFile(ToolsVersionFilePath);
377 if (!ToolsVersionFile)
378 return false;
379
380 llvm::SmallString<256> ToolchainPath(VCRootPath);
381 llvm::sys::path::append(ToolchainPath, "Tools", "MSVC",
382 ToolsVersionFile->get()->getBuffer().rtrim());
383 auto Status = VFS.status(ToolchainPath);
384 if (!Status || !Status->isDirectory())
385 return false;
386
387 Path = std::string(ToolchainPath.str());
388 VSLayout = MSVCToolChain::ToolsetLayout::VS2017OrNewer;
389 return true;
390 #endif
391 }
392
393 // Look in the registry for Visual Studio installs, and use that to get
394 // a toolchain path. VS2017 and newer don't get added to the registry.
395 // So if we find something here, we know that it's an older version.
findVCToolChainViaRegistry(std::string & Path,MSVCToolChain::ToolsetLayout & VSLayout)396 static bool findVCToolChainViaRegistry(std::string &Path,
397 MSVCToolChain::ToolsetLayout &VSLayout) {
398 std::string VSInstallPath;
399 if (getSystemRegistryString(R"(SOFTWARE\Microsoft\VisualStudio\$VERSION)",
400 "InstallDir", VSInstallPath, nullptr) ||
401 getSystemRegistryString(R"(SOFTWARE\Microsoft\VCExpress\$VERSION)",
402 "InstallDir", VSInstallPath, nullptr)) {
403 if (!VSInstallPath.empty()) {
404 llvm::SmallString<256> VCPath(llvm::StringRef(
405 VSInstallPath.c_str(), VSInstallPath.find(R"(\Common7\IDE)")));
406 llvm::sys::path::append(VCPath, "VC");
407
408 Path = std::string(VCPath.str());
409 VSLayout = MSVCToolChain::ToolsetLayout::OlderVS;
410 return true;
411 }
412 }
413 return false;
414 }
415
416 // Try to find Exe from a Visual Studio distribution. This first tries to find
417 // an installed copy of Visual Studio and, failing that, looks in the PATH,
418 // making sure that whatever executable that's found is not a same-named exe
419 // from clang itself to prevent clang from falling back to itself.
FindVisualStudioExecutable(const ToolChain & TC,const char * Exe)420 static std::string FindVisualStudioExecutable(const ToolChain &TC,
421 const char *Exe) {
422 const auto &MSVC = static_cast<const toolchains::MSVCToolChain &>(TC);
423 SmallString<128> FilePath(MSVC.getSubDirectoryPath(
424 toolchains::MSVCToolChain::SubDirectoryType::Bin));
425 llvm::sys::path::append(FilePath, Exe);
426 return std::string(canExecute(TC.getVFS(), FilePath) ? FilePath.str() : Exe);
427 }
428
ConstructJob(Compilation & C,const JobAction & JA,const InputInfo & Output,const InputInfoList & Inputs,const ArgList & Args,const char * LinkingOutput) const429 void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
430 const InputInfo &Output,
431 const InputInfoList &Inputs,
432 const ArgList &Args,
433 const char *LinkingOutput) const {
434 ArgStringList CmdArgs;
435
436 auto &TC = static_cast<const toolchains::MSVCToolChain &>(getToolChain());
437
438 assert((Output.isFilename() || Output.isNothing()) && "invalid output");
439 if (Output.isFilename())
440 CmdArgs.push_back(
441 Args.MakeArgString(std::string("-out:") + Output.getFilename()));
442
443 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles) &&
444 !C.getDriver().IsCLMode()) {
445 CmdArgs.push_back("-defaultlib:libcmt");
446 CmdArgs.push_back("-defaultlib:oldnames");
447 }
448
449 // If the VC environment hasn't been configured (perhaps because the user
450 // did not run vcvarsall), try to build a consistent link environment. If
451 // the environment variable is set however, assume the user knows what
452 // they're doing. If the user passes /vctoolsdir or /winsdkdir, trust that
453 // over env vars.
454 if (const Arg *A = Args.getLastArg(options::OPT__SLASH_diasdkdir,
455 options::OPT__SLASH_winsysroot)) {
456 // cl.exe doesn't find the DIA SDK automatically, so this too requires
457 // explicit flags and doesn't automatically look in "DIA SDK" relative
458 // to the path we found for VCToolChainPath.
459 llvm::SmallString<128> DIAPath(A->getValue());
460 if (A->getOption().getID() == options::OPT__SLASH_winsysroot)
461 llvm::sys::path::append(DIAPath, "DIA SDK");
462
463 // The DIA SDK always uses the legacy vc arch, even in new MSVC versions.
464 llvm::sys::path::append(DIAPath, "lib",
465 llvmArchToLegacyVCArch(TC.getArch()));
466 CmdArgs.push_back(Args.MakeArgString(Twine("-libpath:") + DIAPath));
467 }
468 if (!llvm::sys::Process::GetEnv("LIB") ||
469 Args.getLastArg(options::OPT__SLASH_vctoolsdir,
470 options::OPT__SLASH_winsysroot)) {
471 CmdArgs.push_back(Args.MakeArgString(
472 Twine("-libpath:") +
473 TC.getSubDirectoryPath(
474 toolchains::MSVCToolChain::SubDirectoryType::Lib)));
475 CmdArgs.push_back(Args.MakeArgString(
476 Twine("-libpath:") +
477 TC.getSubDirectoryPath(toolchains::MSVCToolChain::SubDirectoryType::Lib,
478 "atlmfc")));
479 }
480 if (!llvm::sys::Process::GetEnv("LIB") ||
481 Args.getLastArg(options::OPT__SLASH_winsdkdir,
482 options::OPT__SLASH_winsysroot)) {
483 if (TC.useUniversalCRT()) {
484 std::string UniversalCRTLibPath;
485 if (TC.getUniversalCRTLibraryPath(Args, UniversalCRTLibPath))
486 CmdArgs.push_back(
487 Args.MakeArgString(Twine("-libpath:") + UniversalCRTLibPath));
488 }
489 std::string WindowsSdkLibPath;
490 if (TC.getWindowsSDKLibraryPath(Args, WindowsSdkLibPath))
491 CmdArgs.push_back(
492 Args.MakeArgString(std::string("-libpath:") + WindowsSdkLibPath));
493 }
494
495 // Add the compiler-rt library directories to libpath if they exist to help
496 // the linker find the various sanitizer, builtin, and profiling runtimes.
497 for (const auto &LibPath : TC.getLibraryPaths()) {
498 if (TC.getVFS().exists(LibPath))
499 CmdArgs.push_back(Args.MakeArgString("-libpath:" + LibPath));
500 }
501 auto CRTPath = TC.getCompilerRTPath();
502 if (TC.getVFS().exists(CRTPath))
503 CmdArgs.push_back(Args.MakeArgString("-libpath:" + CRTPath));
504
505 if (!C.getDriver().IsCLMode() && Args.hasArg(options::OPT_L))
506 for (const auto &LibPath : Args.getAllArgValues(options::OPT_L))
507 CmdArgs.push_back(Args.MakeArgString("-libpath:" + LibPath));
508
509 CmdArgs.push_back("-nologo");
510
511 if (Args.hasArg(options::OPT_g_Group, options::OPT__SLASH_Z7))
512 CmdArgs.push_back("-debug");
513
514 // Pass on /Brepro if it was passed to the compiler.
515 // Note that /Brepro maps to -mno-incremental-linker-compatible.
516 bool DefaultIncrementalLinkerCompatible =
517 C.getDefaultToolChain().getTriple().isWindowsMSVCEnvironment();
518 if (!Args.hasFlag(options::OPT_mincremental_linker_compatible,
519 options::OPT_mno_incremental_linker_compatible,
520 DefaultIncrementalLinkerCompatible))
521 CmdArgs.push_back("-Brepro");
522
523 bool DLL = Args.hasArg(options::OPT__SLASH_LD, options::OPT__SLASH_LDd,
524 options::OPT_shared);
525 if (DLL) {
526 CmdArgs.push_back(Args.MakeArgString("-dll"));
527
528 SmallString<128> ImplibName(Output.getFilename());
529 llvm::sys::path::replace_extension(ImplibName, "lib");
530 CmdArgs.push_back(Args.MakeArgString(std::string("-implib:") + ImplibName));
531 }
532
533 if (TC.getSanitizerArgs().needsFuzzer()) {
534 if (!Args.hasArg(options::OPT_shared))
535 CmdArgs.push_back(
536 Args.MakeArgString(std::string("-wholearchive:") +
537 TC.getCompilerRTArgString(Args, "fuzzer")));
538 CmdArgs.push_back(Args.MakeArgString("-debug"));
539 // Prevent the linker from padding sections we use for instrumentation
540 // arrays.
541 CmdArgs.push_back(Args.MakeArgString("-incremental:no"));
542 }
543
544 if (TC.getSanitizerArgs().needsAsanRt()) {
545 CmdArgs.push_back(Args.MakeArgString("-debug"));
546 CmdArgs.push_back(Args.MakeArgString("-incremental:no"));
547 if (TC.getSanitizerArgs().needsSharedRt() ||
548 Args.hasArg(options::OPT__SLASH_MD, options::OPT__SLASH_MDd)) {
549 for (const auto &Lib : {"asan_dynamic", "asan_dynamic_runtime_thunk"})
550 CmdArgs.push_back(TC.getCompilerRTArgString(Args, Lib));
551 // Make sure the dynamic runtime thunk is not optimized out at link time
552 // to ensure proper SEH handling.
553 CmdArgs.push_back(Args.MakeArgString(
554 TC.getArch() == llvm::Triple::x86
555 ? "-include:___asan_seh_interceptor"
556 : "-include:__asan_seh_interceptor"));
557 // Make sure the linker consider all object files from the dynamic runtime
558 // thunk.
559 CmdArgs.push_back(Args.MakeArgString(std::string("-wholearchive:") +
560 TC.getCompilerRT(Args, "asan_dynamic_runtime_thunk")));
561 } else if (DLL) {
562 CmdArgs.push_back(TC.getCompilerRTArgString(Args, "asan_dll_thunk"));
563 } else {
564 for (const auto &Lib : {"asan", "asan_cxx"}) {
565 CmdArgs.push_back(TC.getCompilerRTArgString(Args, Lib));
566 // Make sure the linker consider all object files from the static lib.
567 // This is necessary because instrumented dlls need access to all the
568 // interface exported by the static lib in the main executable.
569 CmdArgs.push_back(Args.MakeArgString(std::string("-wholearchive:") +
570 TC.getCompilerRT(Args, Lib)));
571 }
572 }
573 }
574
575 Args.AddAllArgValues(CmdArgs, options::OPT__SLASH_link);
576
577 // Control Flow Guard checks
578 if (Arg *A = Args.getLastArg(options::OPT__SLASH_guard)) {
579 StringRef GuardArgs = A->getValue();
580 if (GuardArgs.equals_insensitive("cf") ||
581 GuardArgs.equals_insensitive("cf,nochecks")) {
582 // MSVC doesn't yet support the "nochecks" modifier.
583 CmdArgs.push_back("-guard:cf");
584 } else if (GuardArgs.equals_insensitive("cf-")) {
585 CmdArgs.push_back("-guard:cf-");
586 } else if (GuardArgs.equals_insensitive("ehcont")) {
587 CmdArgs.push_back("-guard:ehcont");
588 } else if (GuardArgs.equals_insensitive("ehcont-")) {
589 CmdArgs.push_back("-guard:ehcont-");
590 }
591 }
592
593 if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ,
594 options::OPT_fno_openmp, false)) {
595 CmdArgs.push_back("-nodefaultlib:vcomp.lib");
596 CmdArgs.push_back("-nodefaultlib:vcompd.lib");
597 CmdArgs.push_back(Args.MakeArgString(std::string("-libpath:") +
598 TC.getDriver().Dir + "/../lib"));
599 switch (TC.getDriver().getOpenMPRuntime(Args)) {
600 case Driver::OMPRT_OMP:
601 CmdArgs.push_back("-defaultlib:libomp.lib");
602 break;
603 case Driver::OMPRT_IOMP5:
604 CmdArgs.push_back("-defaultlib:libiomp5md.lib");
605 break;
606 case Driver::OMPRT_GOMP:
607 break;
608 case Driver::OMPRT_Unknown:
609 // Already diagnosed.
610 break;
611 }
612 }
613
614 // Add compiler-rt lib in case if it was explicitly
615 // specified as an argument for --rtlib option.
616 if (!Args.hasArg(options::OPT_nostdlib)) {
617 AddRunTimeLibs(TC, TC.getDriver(), CmdArgs, Args);
618 }
619
620 // Add filenames, libraries, and other linker inputs.
621 for (const auto &Input : Inputs) {
622 if (Input.isFilename()) {
623 CmdArgs.push_back(Input.getFilename());
624 continue;
625 }
626
627 const Arg &A = Input.getInputArg();
628
629 // Render -l options differently for the MSVC linker.
630 if (A.getOption().matches(options::OPT_l)) {
631 StringRef Lib = A.getValue();
632 const char *LinkLibArg;
633 if (Lib.endswith(".lib"))
634 LinkLibArg = Args.MakeArgString(Lib);
635 else
636 LinkLibArg = Args.MakeArgString(Lib + ".lib");
637 CmdArgs.push_back(LinkLibArg);
638 continue;
639 }
640
641 // Otherwise, this is some other kind of linker input option like -Wl, -z,
642 // or -L. Render it, even if MSVC doesn't understand it.
643 A.renderAsInput(Args, CmdArgs);
644 }
645
646 TC.addProfileRTLibs(Args, CmdArgs);
647
648 std::vector<const char *> Environment;
649
650 // We need to special case some linker paths. In the case of lld, we need to
651 // translate 'lld' into 'lld-link', and in the case of the regular msvc
652 // linker, we need to use a special search algorithm.
653 llvm::SmallString<128> linkPath;
654 StringRef Linker
655 = Args.getLastArgValue(options::OPT_fuse_ld_EQ, CLANG_DEFAULT_LINKER);
656 if (Linker.empty())
657 Linker = "link";
658 if (Linker.equals_insensitive("lld"))
659 Linker = "lld-link";
660
661 if (Linker.equals_insensitive("link")) {
662 // If we're using the MSVC linker, it's not sufficient to just use link
663 // from the program PATH, because other environments like GnuWin32 install
664 // their own link.exe which may come first.
665 linkPath = FindVisualStudioExecutable(TC, "link.exe");
666
667 if (!TC.FoundMSVCInstall() && !canExecute(TC.getVFS(), linkPath)) {
668 llvm::SmallString<128> ClPath;
669 ClPath = TC.GetProgramPath("cl.exe");
670 if (canExecute(TC.getVFS(), ClPath)) {
671 linkPath = llvm::sys::path::parent_path(ClPath);
672 llvm::sys::path::append(linkPath, "link.exe");
673 if (!canExecute(TC.getVFS(), linkPath))
674 C.getDriver().Diag(clang::diag::warn_drv_msvc_not_found);
675 } else {
676 C.getDriver().Diag(clang::diag::warn_drv_msvc_not_found);
677 }
678 }
679
680 #ifdef _WIN32
681 // When cross-compiling with VS2017 or newer, link.exe expects to have
682 // its containing bin directory at the top of PATH, followed by the
683 // native target bin directory.
684 // e.g. when compiling for x86 on an x64 host, PATH should start with:
685 // /bin/Hostx64/x86;/bin/Hostx64/x64
686 // This doesn't attempt to handle ToolsetLayout::DevDivInternal.
687 if (TC.getIsVS2017OrNewer() &&
688 llvm::Triple(llvm::sys::getProcessTriple()).getArch() != TC.getArch()) {
689 auto HostArch = llvm::Triple(llvm::sys::getProcessTriple()).getArch();
690
691 auto EnvBlockWide =
692 std::unique_ptr<wchar_t[], decltype(&FreeEnvironmentStringsW)>(
693 GetEnvironmentStringsW(), FreeEnvironmentStringsW);
694 if (!EnvBlockWide)
695 goto SkipSettingEnvironment;
696
697 size_t EnvCount = 0;
698 size_t EnvBlockLen = 0;
699 while (EnvBlockWide[EnvBlockLen] != L'\0') {
700 ++EnvCount;
701 EnvBlockLen += std::wcslen(&EnvBlockWide[EnvBlockLen]) +
702 1 /*string null-terminator*/;
703 }
704 ++EnvBlockLen; // add the block null-terminator
705
706 std::string EnvBlock;
707 if (!llvm::convertUTF16ToUTF8String(
708 llvm::ArrayRef<char>(reinterpret_cast<char *>(EnvBlockWide.get()),
709 EnvBlockLen * sizeof(EnvBlockWide[0])),
710 EnvBlock))
711 goto SkipSettingEnvironment;
712
713 Environment.reserve(EnvCount);
714
715 // Now loop over each string in the block and copy them into the
716 // environment vector, adjusting the PATH variable as needed when we
717 // find it.
718 for (const char *Cursor = EnvBlock.data(); *Cursor != '\0';) {
719 llvm::StringRef EnvVar(Cursor);
720 if (EnvVar.startswith_insensitive("path=")) {
721 using SubDirectoryType = toolchains::MSVCToolChain::SubDirectoryType;
722 constexpr size_t PrefixLen = 5; // strlen("path=")
723 Environment.push_back(Args.MakeArgString(
724 EnvVar.substr(0, PrefixLen) +
725 TC.getSubDirectoryPath(SubDirectoryType::Bin) +
726 llvm::Twine(llvm::sys::EnvPathSeparator) +
727 TC.getSubDirectoryPath(SubDirectoryType::Bin, "", HostArch) +
728 (EnvVar.size() > PrefixLen
729 ? llvm::Twine(llvm::sys::EnvPathSeparator) +
730 EnvVar.substr(PrefixLen)
731 : "")));
732 } else {
733 Environment.push_back(Args.MakeArgString(EnvVar));
734 }
735 Cursor += EnvVar.size() + 1 /*null-terminator*/;
736 }
737 }
738 SkipSettingEnvironment:;
739 #endif
740 } else {
741 linkPath = TC.GetProgramPath(Linker.str().c_str());
742 }
743
744 auto LinkCmd = std::make_unique<Command>(
745 JA, *this, ResponseFileSupport::AtFileUTF16(),
746 Args.MakeArgString(linkPath), CmdArgs, Inputs, Output);
747 if (!Environment.empty())
748 LinkCmd->setEnvironment(Environment);
749 C.addCommand(std::move(LinkCmd));
750 }
751
MSVCToolChain(const Driver & D,const llvm::Triple & Triple,const ArgList & Args)752 MSVCToolChain::MSVCToolChain(const Driver &D, const llvm::Triple &Triple,
753 const ArgList &Args)
754 : ToolChain(D, Triple, Args), CudaInstallation(D, Triple, Args),
755 RocmInstallation(D, Triple, Args) {
756 getProgramPaths().push_back(getDriver().getInstalledDir());
757 if (getDriver().getInstalledDir() != getDriver().Dir)
758 getProgramPaths().push_back(getDriver().Dir);
759
760 // Check the command line first, that's the user explicitly telling us what to
761 // use. Check the environment next, in case we're being invoked from a VS
762 // command prompt. Failing that, just try to find the newest Visual Studio
763 // version we can and use its default VC toolchain.
764 findVCToolChainViaCommandLine(getVFS(), Args, VCToolChainPath, VSLayout) ||
765 findVCToolChainViaEnvironment(getVFS(), VCToolChainPath, VSLayout) ||
766 findVCToolChainViaSetupConfig(getVFS(), VCToolChainPath, VSLayout) ||
767 findVCToolChainViaRegistry(VCToolChainPath, VSLayout);
768 }
769
buildLinker() const770 Tool *MSVCToolChain::buildLinker() const {
771 return new tools::visualstudio::Linker(*this);
772 }
773
buildAssembler() const774 Tool *MSVCToolChain::buildAssembler() const {
775 if (getTriple().isOSBinFormatMachO())
776 return new tools::darwin::Assembler(*this);
777 getDriver().Diag(clang::diag::err_no_external_assembler);
778 return nullptr;
779 }
780
IsIntegratedAssemblerDefault() const781 bool MSVCToolChain::IsIntegratedAssemblerDefault() const {
782 return true;
783 }
784
IsUnwindTablesDefault(const ArgList & Args) const785 bool MSVCToolChain::IsUnwindTablesDefault(const ArgList &Args) const {
786 // Don't emit unwind tables by default for MachO targets.
787 if (getTriple().isOSBinFormatMachO())
788 return false;
789
790 // All non-x86_32 Windows targets require unwind tables. However, LLVM
791 // doesn't know how to generate them for all targets, so only enable
792 // the ones that are actually implemented.
793 return getArch() == llvm::Triple::x86_64 ||
794 getArch() == llvm::Triple::aarch64;
795 }
796
isPICDefault() const797 bool MSVCToolChain::isPICDefault() const {
798 return getArch() == llvm::Triple::x86_64;
799 }
800
isPIEDefault() const801 bool MSVCToolChain::isPIEDefault() const {
802 return false;
803 }
804
isPICDefaultForced() const805 bool MSVCToolChain::isPICDefaultForced() const {
806 return getArch() == llvm::Triple::x86_64;
807 }
808
AddCudaIncludeArgs(const ArgList & DriverArgs,ArgStringList & CC1Args) const809 void MSVCToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs,
810 ArgStringList &CC1Args) const {
811 CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args);
812 }
813
AddHIPIncludeArgs(const ArgList & DriverArgs,ArgStringList & CC1Args) const814 void MSVCToolChain::AddHIPIncludeArgs(const ArgList &DriverArgs,
815 ArgStringList &CC1Args) const {
816 RocmInstallation.AddHIPIncludeArgs(DriverArgs, CC1Args);
817 }
818
printVerboseInfo(raw_ostream & OS) const819 void MSVCToolChain::printVerboseInfo(raw_ostream &OS) const {
820 CudaInstallation.print(OS);
821 RocmInstallation.print(OS);
822 }
823
824 // Get the path to a specific subdirectory in the current toolchain for
825 // a given target architecture.
826 // VS2017 changed the VC toolchain layout, so this should be used instead
827 // of hardcoding paths.
828 std::string
getSubDirectoryPath(SubDirectoryType Type,llvm::StringRef SubdirParent,llvm::Triple::ArchType TargetArch) const829 MSVCToolChain::getSubDirectoryPath(SubDirectoryType Type,
830 llvm::StringRef SubdirParent,
831 llvm::Triple::ArchType TargetArch) const {
832 const char *SubdirName;
833 const char *IncludeName;
834 switch (VSLayout) {
835 case ToolsetLayout::OlderVS:
836 SubdirName = llvmArchToLegacyVCArch(TargetArch);
837 IncludeName = "include";
838 break;
839 case ToolsetLayout::VS2017OrNewer:
840 SubdirName = llvmArchToWindowsSDKArch(TargetArch);
841 IncludeName = "include";
842 break;
843 case ToolsetLayout::DevDivInternal:
844 SubdirName = llvmArchToDevDivInternalArch(TargetArch);
845 IncludeName = "inc";
846 break;
847 }
848
849 llvm::SmallString<256> Path(VCToolChainPath);
850 if (!SubdirParent.empty())
851 llvm::sys::path::append(Path, SubdirParent);
852
853 switch (Type) {
854 case SubDirectoryType::Bin:
855 if (VSLayout == ToolsetLayout::VS2017OrNewer) {
856 const bool HostIsX64 =
857 llvm::Triple(llvm::sys::getProcessTriple()).isArch64Bit();
858 const char *const HostName = HostIsX64 ? "Hostx64" : "Hostx86";
859 llvm::sys::path::append(Path, "bin", HostName, SubdirName);
860 } else { // OlderVS or DevDivInternal
861 llvm::sys::path::append(Path, "bin", SubdirName);
862 }
863 break;
864 case SubDirectoryType::Include:
865 llvm::sys::path::append(Path, IncludeName);
866 break;
867 case SubDirectoryType::Lib:
868 llvm::sys::path::append(Path, "lib", SubdirName);
869 break;
870 }
871 return std::string(Path.str());
872 }
873
874 #ifdef _WIN32
readFullStringValue(HKEY hkey,const char * valueName,std::string & value)875 static bool readFullStringValue(HKEY hkey, const char *valueName,
876 std::string &value) {
877 std::wstring WideValueName;
878 if (!llvm::ConvertUTF8toWide(valueName, WideValueName))
879 return false;
880
881 DWORD result = 0;
882 DWORD valueSize = 0;
883 DWORD type = 0;
884 // First just query for the required size.
885 result = RegQueryValueExW(hkey, WideValueName.c_str(), NULL, &type, NULL,
886 &valueSize);
887 if (result != ERROR_SUCCESS || type != REG_SZ || !valueSize)
888 return false;
889 std::vector<BYTE> buffer(valueSize);
890 result = RegQueryValueExW(hkey, WideValueName.c_str(), NULL, NULL, &buffer[0],
891 &valueSize);
892 if (result == ERROR_SUCCESS) {
893 std::wstring WideValue(reinterpret_cast<const wchar_t *>(buffer.data()),
894 valueSize / sizeof(wchar_t));
895 if (valueSize && WideValue.back() == L'\0') {
896 WideValue.pop_back();
897 }
898 // The destination buffer must be empty as an invariant of the conversion
899 // function; but this function is sometimes called in a loop that passes in
900 // the same buffer, however. Simply clear it out so we can overwrite it.
901 value.clear();
902 return llvm::convertWideToUTF8(WideValue, value);
903 }
904 return false;
905 }
906 #endif
907
908 /// Read registry string.
909 /// This also supports a means to look for high-versioned keys by use
910 /// of a $VERSION placeholder in the key path.
911 /// $VERSION in the key path is a placeholder for the version number,
912 /// causing the highest value path to be searched for and used.
913 /// I.e. "SOFTWARE\\Microsoft\\VisualStudio\\$VERSION".
914 /// There can be additional characters in the component. Only the numeric
915 /// characters are compared. This function only searches HKLM.
getSystemRegistryString(const char * keyPath,const char * valueName,std::string & value,std::string * phValue)916 static bool getSystemRegistryString(const char *keyPath, const char *valueName,
917 std::string &value, std::string *phValue) {
918 #ifndef _WIN32
919 return false;
920 #else
921 HKEY hRootKey = HKEY_LOCAL_MACHINE;
922 HKEY hKey = NULL;
923 long lResult;
924 bool returnValue = false;
925
926 const char *placeHolder = strstr(keyPath, "$VERSION");
927 std::string bestName;
928 // If we have a $VERSION placeholder, do the highest-version search.
929 if (placeHolder) {
930 const char *keyEnd = placeHolder - 1;
931 const char *nextKey = placeHolder;
932 // Find end of previous key.
933 while ((keyEnd > keyPath) && (*keyEnd != '\\'))
934 keyEnd--;
935 // Find end of key containing $VERSION.
936 while (*nextKey && (*nextKey != '\\'))
937 nextKey++;
938 size_t partialKeyLength = keyEnd - keyPath;
939 char partialKey[256];
940 if (partialKeyLength >= sizeof(partialKey))
941 partialKeyLength = sizeof(partialKey) - 1;
942 strncpy(partialKey, keyPath, partialKeyLength);
943 partialKey[partialKeyLength] = '\0';
944 HKEY hTopKey = NULL;
945 lResult = RegOpenKeyExA(hRootKey, partialKey, 0, KEY_READ | KEY_WOW64_32KEY,
946 &hTopKey);
947 if (lResult == ERROR_SUCCESS) {
948 char keyName[256];
949 double bestValue = 0.0;
950 DWORD index, size = sizeof(keyName) - 1;
951 for (index = 0; RegEnumKeyExA(hTopKey, index, keyName, &size, NULL, NULL,
952 NULL, NULL) == ERROR_SUCCESS;
953 index++) {
954 const char *sp = keyName;
955 while (*sp && !isDigit(*sp))
956 sp++;
957 if (!*sp)
958 continue;
959 const char *ep = sp + 1;
960 while (*ep && (isDigit(*ep) || (*ep == '.')))
961 ep++;
962 char numBuf[32];
963 strncpy(numBuf, sp, sizeof(numBuf) - 1);
964 numBuf[sizeof(numBuf) - 1] = '\0';
965 double dvalue = strtod(numBuf, NULL);
966 if (dvalue > bestValue) {
967 // Test that InstallDir is indeed there before keeping this index.
968 // Open the chosen key path remainder.
969 bestName = keyName;
970 // Append rest of key.
971 bestName.append(nextKey);
972 lResult = RegOpenKeyExA(hTopKey, bestName.c_str(), 0,
973 KEY_READ | KEY_WOW64_32KEY, &hKey);
974 if (lResult == ERROR_SUCCESS) {
975 if (readFullStringValue(hKey, valueName, value)) {
976 bestValue = dvalue;
977 if (phValue)
978 *phValue = bestName;
979 returnValue = true;
980 }
981 RegCloseKey(hKey);
982 }
983 }
984 size = sizeof(keyName) - 1;
985 }
986 RegCloseKey(hTopKey);
987 }
988 } else {
989 lResult =
990 RegOpenKeyExA(hRootKey, keyPath, 0, KEY_READ | KEY_WOW64_32KEY, &hKey);
991 if (lResult == ERROR_SUCCESS) {
992 if (readFullStringValue(hKey, valueName, value))
993 returnValue = true;
994 if (phValue)
995 phValue->clear();
996 RegCloseKey(hKey);
997 }
998 }
999 return returnValue;
1000 #endif // _WIN32
1001 }
1002
1003 // Find the most recent version of Universal CRT or Windows 10 SDK.
1004 // vcvarsqueryregistry.bat from Visual Studio 2015 sorts entries in the include
1005 // directory by name and uses the last one of the list.
1006 // So we compare entry names lexicographically to find the greatest one.
getWindows10SDKVersionFromPath(llvm::vfs::FileSystem & VFS,const std::string & SDKPath,std::string & SDKVersion)1007 static bool getWindows10SDKVersionFromPath(llvm::vfs::FileSystem &VFS,
1008 const std::string &SDKPath,
1009 std::string &SDKVersion) {
1010 llvm::SmallString<128> IncludePath(SDKPath);
1011 llvm::sys::path::append(IncludePath, "Include");
1012 SDKVersion = getHighestNumericTupleInDirectory(VFS, IncludePath);
1013 return !SDKVersion.empty();
1014 }
1015
getWindowsSDKDirViaCommandLine(llvm::vfs::FileSystem & VFS,const ArgList & Args,std::string & Path,int & Major,std::string & Version)1016 static bool getWindowsSDKDirViaCommandLine(llvm::vfs::FileSystem &VFS,
1017 const ArgList &Args,
1018 std::string &Path, int &Major,
1019 std::string &Version) {
1020 if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsdkdir,
1021 options::OPT__SLASH_winsysroot)) {
1022 // Don't validate the input; trust the value supplied by the user.
1023 // The motivation is to prevent unnecessary file and registry access.
1024 llvm::VersionTuple SDKVersion;
1025 if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsdkversion))
1026 SDKVersion.tryParse(A->getValue());
1027
1028 if (A->getOption().getID() == options::OPT__SLASH_winsysroot) {
1029 llvm::SmallString<128> SDKPath(A->getValue());
1030 llvm::sys::path::append(SDKPath, "Windows Kits");
1031 if (!SDKVersion.empty())
1032 llvm::sys::path::append(SDKPath, Twine(SDKVersion.getMajor()));
1033 else
1034 llvm::sys::path::append(
1035 SDKPath, getHighestNumericTupleInDirectory(VFS, SDKPath));
1036 Path = std::string(SDKPath.str());
1037 } else {
1038 Path = A->getValue();
1039 }
1040
1041 if (!SDKVersion.empty()) {
1042 Major = SDKVersion.getMajor();
1043 Version = SDKVersion.getAsString();
1044 } else if (getWindows10SDKVersionFromPath(VFS, Path, Version)) {
1045 Major = 10;
1046 }
1047 return true;
1048 }
1049 return false;
1050 }
1051
1052 /// Get Windows SDK installation directory.
getWindowsSDKDir(llvm::vfs::FileSystem & VFS,const ArgList & Args,std::string & Path,int & Major,std::string & WindowsSDKIncludeVersion,std::string & WindowsSDKLibVersion)1053 static bool getWindowsSDKDir(llvm::vfs::FileSystem &VFS, const ArgList &Args,
1054 std::string &Path, int &Major,
1055 std::string &WindowsSDKIncludeVersion,
1056 std::string &WindowsSDKLibVersion) {
1057 // Trust /winsdkdir and /winsdkversion if present.
1058 if (getWindowsSDKDirViaCommandLine(VFS, Args, Path, Major,
1059 WindowsSDKIncludeVersion)) {
1060 WindowsSDKLibVersion = WindowsSDKIncludeVersion;
1061 return true;
1062 }
1063
1064 // FIXME: Try env vars (%WindowsSdkDir%, %UCRTVersion%) before going to registry.
1065
1066 // Try the Windows registry.
1067 std::string RegistrySDKVersion;
1068 if (!getSystemRegistryString(
1069 "SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\$VERSION",
1070 "InstallationFolder", Path, &RegistrySDKVersion))
1071 return false;
1072 if (Path.empty() || RegistrySDKVersion.empty())
1073 return false;
1074
1075 WindowsSDKIncludeVersion.clear();
1076 WindowsSDKLibVersion.clear();
1077 Major = 0;
1078 std::sscanf(RegistrySDKVersion.c_str(), "v%d.", &Major);
1079 if (Major <= 7)
1080 return true;
1081 if (Major == 8) {
1082 // Windows SDK 8.x installs libraries in a folder whose names depend on the
1083 // version of the OS you're targeting. By default choose the newest, which
1084 // usually corresponds to the version of the OS you've installed the SDK on.
1085 const char *Tests[] = {"winv6.3", "win8", "win7"};
1086 for (const char *Test : Tests) {
1087 llvm::SmallString<128> TestPath(Path);
1088 llvm::sys::path::append(TestPath, "Lib", Test);
1089 if (VFS.exists(TestPath)) {
1090 WindowsSDKLibVersion = Test;
1091 break;
1092 }
1093 }
1094 return !WindowsSDKLibVersion.empty();
1095 }
1096 if (Major == 10) {
1097 if (!getWindows10SDKVersionFromPath(VFS, Path, WindowsSDKIncludeVersion))
1098 return false;
1099 WindowsSDKLibVersion = WindowsSDKIncludeVersion;
1100 return true;
1101 }
1102 // Unsupported SDK version
1103 return false;
1104 }
1105
1106 // Gets the library path required to link against the Windows SDK.
getWindowsSDKLibraryPath(const ArgList & Args,std::string & path) const1107 bool MSVCToolChain::getWindowsSDKLibraryPath(
1108 const ArgList &Args, std::string &path) const {
1109 std::string sdkPath;
1110 int sdkMajor = 0;
1111 std::string windowsSDKIncludeVersion;
1112 std::string windowsSDKLibVersion;
1113
1114 path.clear();
1115 if (!getWindowsSDKDir(getVFS(), Args, sdkPath, sdkMajor,
1116 windowsSDKIncludeVersion, windowsSDKLibVersion))
1117 return false;
1118
1119 llvm::SmallString<128> libPath(sdkPath);
1120 llvm::sys::path::append(libPath, "Lib");
1121 if (sdkMajor >= 8) {
1122 llvm::sys::path::append(libPath, windowsSDKLibVersion, "um",
1123 llvmArchToWindowsSDKArch(getArch()));
1124 } else {
1125 switch (getArch()) {
1126 // In Windows SDK 7.x, x86 libraries are directly in the Lib folder.
1127 case llvm::Triple::x86:
1128 break;
1129 case llvm::Triple::x86_64:
1130 llvm::sys::path::append(libPath, "x64");
1131 break;
1132 case llvm::Triple::arm:
1133 // It is not necessary to link against Windows SDK 7.x when targeting ARM.
1134 return false;
1135 default:
1136 return false;
1137 }
1138 }
1139
1140 path = std::string(libPath.str());
1141 return true;
1142 }
1143
1144 // Check if the Include path of a specified version of Visual Studio contains
1145 // specific header files. If not, they are probably shipped with Universal CRT.
useUniversalCRT() const1146 bool MSVCToolChain::useUniversalCRT() const {
1147 llvm::SmallString<128> TestPath(
1148 getSubDirectoryPath(SubDirectoryType::Include));
1149 llvm::sys::path::append(TestPath, "stdlib.h");
1150 return !getVFS().exists(TestPath);
1151 }
1152
getUniversalCRTSdkDir(llvm::vfs::FileSystem & VFS,const ArgList & Args,std::string & Path,std::string & UCRTVersion)1153 static bool getUniversalCRTSdkDir(llvm::vfs::FileSystem &VFS,
1154 const ArgList &Args, std::string &Path,
1155 std::string &UCRTVersion) {
1156 // If /winsdkdir is passed, use it as location for the UCRT too.
1157 // FIXME: Should there be a dedicated /ucrtdir to override /winsdkdir?
1158 int Major;
1159 if (getWindowsSDKDirViaCommandLine(VFS, Args, Path, Major, UCRTVersion))
1160 return true;
1161
1162 // FIXME: Try env vars (%UniversalCRTSdkDir%, %UCRTVersion%) before going to
1163 // registry.
1164
1165 // vcvarsqueryregistry.bat for Visual Studio 2015 queries the registry
1166 // for the specific key "KitsRoot10". So do we.
1167 if (!getSystemRegistryString(
1168 "SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots", "KitsRoot10",
1169 Path, nullptr))
1170 return false;
1171
1172 return getWindows10SDKVersionFromPath(VFS, Path, UCRTVersion);
1173 }
1174
getUniversalCRTLibraryPath(const ArgList & Args,std::string & Path) const1175 bool MSVCToolChain::getUniversalCRTLibraryPath(const ArgList &Args,
1176 std::string &Path) const {
1177 std::string UniversalCRTSdkPath;
1178 std::string UCRTVersion;
1179
1180 Path.clear();
1181 if (!getUniversalCRTSdkDir(getVFS(), Args, UniversalCRTSdkPath, UCRTVersion))
1182 return false;
1183
1184 StringRef ArchName = llvmArchToWindowsSDKArch(getArch());
1185 if (ArchName.empty())
1186 return false;
1187
1188 llvm::SmallString<128> LibPath(UniversalCRTSdkPath);
1189 llvm::sys::path::append(LibPath, "Lib", UCRTVersion, "ucrt", ArchName);
1190
1191 Path = std::string(LibPath.str());
1192 return true;
1193 }
1194
getMSVCVersionFromTriple(const llvm::Triple & Triple)1195 static VersionTuple getMSVCVersionFromTriple(const llvm::Triple &Triple) {
1196 unsigned Major, Minor, Micro;
1197 Triple.getEnvironmentVersion(Major, Minor, Micro);
1198 if (Major || Minor || Micro)
1199 return VersionTuple(Major, Minor, Micro);
1200 return VersionTuple();
1201 }
1202
getMSVCVersionFromExe(const std::string & BinDir)1203 static VersionTuple getMSVCVersionFromExe(const std::string &BinDir) {
1204 VersionTuple Version;
1205 #ifdef _WIN32
1206 SmallString<128> ClExe(BinDir);
1207 llvm::sys::path::append(ClExe, "cl.exe");
1208
1209 std::wstring ClExeWide;
1210 if (!llvm::ConvertUTF8toWide(ClExe.c_str(), ClExeWide))
1211 return Version;
1212
1213 const DWORD VersionSize = ::GetFileVersionInfoSizeW(ClExeWide.c_str(),
1214 nullptr);
1215 if (VersionSize == 0)
1216 return Version;
1217
1218 SmallVector<uint8_t, 4 * 1024> VersionBlock(VersionSize);
1219 if (!::GetFileVersionInfoW(ClExeWide.c_str(), 0, VersionSize,
1220 VersionBlock.data()))
1221 return Version;
1222
1223 VS_FIXEDFILEINFO *FileInfo = nullptr;
1224 UINT FileInfoSize = 0;
1225 if (!::VerQueryValueW(VersionBlock.data(), L"\\",
1226 reinterpret_cast<LPVOID *>(&FileInfo), &FileInfoSize) ||
1227 FileInfoSize < sizeof(*FileInfo))
1228 return Version;
1229
1230 const unsigned Major = (FileInfo->dwFileVersionMS >> 16) & 0xFFFF;
1231 const unsigned Minor = (FileInfo->dwFileVersionMS ) & 0xFFFF;
1232 const unsigned Micro = (FileInfo->dwFileVersionLS >> 16) & 0xFFFF;
1233
1234 Version = VersionTuple(Major, Minor, Micro);
1235 #endif
1236 return Version;
1237 }
1238
AddSystemIncludeWithSubfolder(const ArgList & DriverArgs,ArgStringList & CC1Args,const std::string & folder,const Twine & subfolder1,const Twine & subfolder2,const Twine & subfolder3) const1239 void MSVCToolChain::AddSystemIncludeWithSubfolder(
1240 const ArgList &DriverArgs, ArgStringList &CC1Args,
1241 const std::string &folder, const Twine &subfolder1, const Twine &subfolder2,
1242 const Twine &subfolder3) const {
1243 llvm::SmallString<128> path(folder);
1244 llvm::sys::path::append(path, subfolder1, subfolder2, subfolder3);
1245 addSystemInclude(DriverArgs, CC1Args, path);
1246 }
1247
AddClangSystemIncludeArgs(const ArgList & DriverArgs,ArgStringList & CC1Args) const1248 void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
1249 ArgStringList &CC1Args) const {
1250 if (DriverArgs.hasArg(options::OPT_nostdinc))
1251 return;
1252
1253 if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
1254 AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, getDriver().ResourceDir,
1255 "include");
1256 }
1257
1258 // Add %INCLUDE%-like directories from the -imsvc flag.
1259 for (const auto &Path : DriverArgs.getAllArgValues(options::OPT__SLASH_imsvc))
1260 addSystemInclude(DriverArgs, CC1Args, Path);
1261
1262 auto AddSystemIncludesFromEnv = [&](StringRef Var) -> bool {
1263 if (auto Val = llvm::sys::Process::GetEnv(Var)) {
1264 SmallVector<StringRef, 8> Dirs;
1265 StringRef(*Val).split(Dirs, ";", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
1266 if (!Dirs.empty()) {
1267 addSystemIncludes(DriverArgs, CC1Args, Dirs);
1268 return true;
1269 }
1270 }
1271 return false;
1272 };
1273
1274 // Add %INCLUDE%-like dirs via /external:env: flags.
1275 for (const auto &Var :
1276 DriverArgs.getAllArgValues(options::OPT__SLASH_external_env)) {
1277 AddSystemIncludesFromEnv(Var);
1278 }
1279
1280 // Add DIA SDK include if requested.
1281 if (const Arg *A = DriverArgs.getLastArg(options::OPT__SLASH_diasdkdir,
1282 options::OPT__SLASH_winsysroot)) {
1283 // cl.exe doesn't find the DIA SDK automatically, so this too requires
1284 // explicit flags and doesn't automatically look in "DIA SDK" relative
1285 // to the path we found for VCToolChainPath.
1286 llvm::SmallString<128> DIASDKPath(A->getValue());
1287 if (A->getOption().getID() == options::OPT__SLASH_winsysroot)
1288 llvm::sys::path::append(DIASDKPath, "DIA SDK");
1289 AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, std::string(DIASDKPath),
1290 "include");
1291 }
1292
1293 if (DriverArgs.hasArg(options::OPT_nostdlibinc))
1294 return;
1295
1296 // Honor %INCLUDE% and %EXTERNAL_INCLUDE%. It should have essential search
1297 // paths set by vcvarsall.bat. Skip if the user expressly set a vctoolsdir.
1298 if (!DriverArgs.getLastArg(options::OPT__SLASH_vctoolsdir,
1299 options::OPT__SLASH_winsysroot)) {
1300 bool Found = AddSystemIncludesFromEnv("INCLUDE");
1301 Found |= AddSystemIncludesFromEnv("EXTERNAL_INCLUDE");
1302 if (Found)
1303 return;
1304 }
1305
1306 // When built with access to the proper Windows APIs, try to actually find
1307 // the correct include paths first.
1308 if (!VCToolChainPath.empty()) {
1309 addSystemInclude(DriverArgs, CC1Args,
1310 getSubDirectoryPath(SubDirectoryType::Include));
1311 addSystemInclude(DriverArgs, CC1Args,
1312 getSubDirectoryPath(SubDirectoryType::Include, "atlmfc"));
1313
1314 if (useUniversalCRT()) {
1315 std::string UniversalCRTSdkPath;
1316 std::string UCRTVersion;
1317 if (getUniversalCRTSdkDir(getVFS(), DriverArgs, UniversalCRTSdkPath,
1318 UCRTVersion)) {
1319 AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, UniversalCRTSdkPath,
1320 "Include", UCRTVersion, "ucrt");
1321 }
1322 }
1323
1324 std::string WindowsSDKDir;
1325 int major = 0;
1326 std::string windowsSDKIncludeVersion;
1327 std::string windowsSDKLibVersion;
1328 if (getWindowsSDKDir(getVFS(), DriverArgs, WindowsSDKDir, major,
1329 windowsSDKIncludeVersion, windowsSDKLibVersion)) {
1330 if (major >= 8) {
1331 // Note: windowsSDKIncludeVersion is empty for SDKs prior to v10.
1332 // Anyway, llvm::sys::path::append is able to manage it.
1333 AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
1334 "Include", windowsSDKIncludeVersion,
1335 "shared");
1336 AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
1337 "Include", windowsSDKIncludeVersion,
1338 "um");
1339 AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
1340 "Include", windowsSDKIncludeVersion,
1341 "winrt");
1342 } else {
1343 AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
1344 "Include");
1345 }
1346 }
1347
1348 return;
1349 }
1350
1351 #if defined(_WIN32)
1352 // As a fallback, select default install paths.
1353 // FIXME: Don't guess drives and paths like this on Windows.
1354 const StringRef Paths[] = {
1355 "C:/Program Files/Microsoft Visual Studio 10.0/VC/include",
1356 "C:/Program Files/Microsoft Visual Studio 9.0/VC/include",
1357 "C:/Program Files/Microsoft Visual Studio 9.0/VC/PlatformSDK/Include",
1358 "C:/Program Files/Microsoft Visual Studio 8/VC/include",
1359 "C:/Program Files/Microsoft Visual Studio 8/VC/PlatformSDK/Include"
1360 };
1361 addSystemIncludes(DriverArgs, CC1Args, Paths);
1362 #endif
1363 }
1364
AddClangCXXStdlibIncludeArgs(const ArgList & DriverArgs,ArgStringList & CC1Args) const1365 void MSVCToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
1366 ArgStringList &CC1Args) const {
1367 // FIXME: There should probably be logic here to find libc++ on Windows.
1368 }
1369
computeMSVCVersion(const Driver * D,const ArgList & Args) const1370 VersionTuple MSVCToolChain::computeMSVCVersion(const Driver *D,
1371 const ArgList &Args) const {
1372 bool IsWindowsMSVC = getTriple().isWindowsMSVCEnvironment();
1373 VersionTuple MSVT = ToolChain::computeMSVCVersion(D, Args);
1374 if (MSVT.empty())
1375 MSVT = getMSVCVersionFromTriple(getTriple());
1376 if (MSVT.empty() && IsWindowsMSVC)
1377 MSVT = getMSVCVersionFromExe(getSubDirectoryPath(SubDirectoryType::Bin));
1378 if (MSVT.empty() &&
1379 Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions,
1380 IsWindowsMSVC)) {
1381 // -fms-compatibility-version=19.14 is default, aka 2017, 15.7
1382 MSVT = VersionTuple(19, 14);
1383 }
1384 return MSVT;
1385 }
1386
1387 std::string
ComputeEffectiveClangTriple(const ArgList & Args,types::ID InputType) const1388 MSVCToolChain::ComputeEffectiveClangTriple(const ArgList &Args,
1389 types::ID InputType) const {
1390 // The MSVC version doesn't care about the architecture, even though it
1391 // may look at the triple internally.
1392 VersionTuple MSVT = computeMSVCVersion(/*D=*/nullptr, Args);
1393 MSVT = VersionTuple(MSVT.getMajor(), MSVT.getMinor().getValueOr(0),
1394 MSVT.getSubminor().getValueOr(0));
1395
1396 // For the rest of the triple, however, a computed architecture name may
1397 // be needed.
1398 llvm::Triple Triple(ToolChain::ComputeEffectiveClangTriple(Args, InputType));
1399 if (Triple.getEnvironment() == llvm::Triple::MSVC) {
1400 StringRef ObjFmt = Triple.getEnvironmentName().split('-').second;
1401 if (ObjFmt.empty())
1402 Triple.setEnvironmentName((Twine("msvc") + MSVT.getAsString()).str());
1403 else
1404 Triple.setEnvironmentName(
1405 (Twine("msvc") + MSVT.getAsString() + Twine('-') + ObjFmt).str());
1406 }
1407 return Triple.getTriple();
1408 }
1409
getSupportedSanitizers() const1410 SanitizerMask MSVCToolChain::getSupportedSanitizers() const {
1411 SanitizerMask Res = ToolChain::getSupportedSanitizers();
1412 Res |= SanitizerKind::Address;
1413 Res |= SanitizerKind::PointerCompare;
1414 Res |= SanitizerKind::PointerSubtract;
1415 Res |= SanitizerKind::Fuzzer;
1416 Res |= SanitizerKind::FuzzerNoLink;
1417 Res &= ~SanitizerKind::CFIMFCall;
1418 return Res;
1419 }
1420
TranslateOptArg(Arg * A,llvm::opt::DerivedArgList & DAL,bool SupportsForcingFramePointer,const char * ExpandChar,const OptTable & Opts)1421 static void TranslateOptArg(Arg *A, llvm::opt::DerivedArgList &DAL,
1422 bool SupportsForcingFramePointer,
1423 const char *ExpandChar, const OptTable &Opts) {
1424 assert(A->getOption().matches(options::OPT__SLASH_O));
1425
1426 StringRef OptStr = A->getValue();
1427 for (size_t I = 0, E = OptStr.size(); I != E; ++I) {
1428 const char &OptChar = *(OptStr.data() + I);
1429 switch (OptChar) {
1430 default:
1431 break;
1432 case '1':
1433 case '2':
1434 case 'x':
1435 case 'd':
1436 // Ignore /O[12xd] flags that aren't the last one on the command line.
1437 // Only the last one gets expanded.
1438 if (&OptChar != ExpandChar) {
1439 A->claim();
1440 break;
1441 }
1442 if (OptChar == 'd') {
1443 DAL.AddFlagArg(A, Opts.getOption(options::OPT_O0));
1444 } else {
1445 if (OptChar == '1') {
1446 DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "s");
1447 } else if (OptChar == '2' || OptChar == 'x') {
1448 DAL.AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin));
1449 DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "2");
1450 }
1451 if (SupportsForcingFramePointer &&
1452 !DAL.hasArgNoClaim(options::OPT_fno_omit_frame_pointer))
1453 DAL.AddFlagArg(A, Opts.getOption(options::OPT_fomit_frame_pointer));
1454 if (OptChar == '1' || OptChar == '2')
1455 DAL.AddFlagArg(A, Opts.getOption(options::OPT_ffunction_sections));
1456 }
1457 break;
1458 case 'b':
1459 if (I + 1 != E && isdigit(OptStr[I + 1])) {
1460 switch (OptStr[I + 1]) {
1461 case '0':
1462 DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_inline));
1463 break;
1464 case '1':
1465 DAL.AddFlagArg(A, Opts.getOption(options::OPT_finline_hint_functions));
1466 break;
1467 case '2':
1468 DAL.AddFlagArg(A, Opts.getOption(options::OPT_finline_functions));
1469 break;
1470 }
1471 ++I;
1472 }
1473 break;
1474 case 'g':
1475 A->claim();
1476 break;
1477 case 'i':
1478 if (I + 1 != E && OptStr[I + 1] == '-') {
1479 ++I;
1480 DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_builtin));
1481 } else {
1482 DAL.AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin));
1483 }
1484 break;
1485 case 's':
1486 DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "s");
1487 break;
1488 case 't':
1489 DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "2");
1490 break;
1491 case 'y': {
1492 bool OmitFramePointer = true;
1493 if (I + 1 != E && OptStr[I + 1] == '-') {
1494 OmitFramePointer = false;
1495 ++I;
1496 }
1497 if (SupportsForcingFramePointer) {
1498 if (OmitFramePointer)
1499 DAL.AddFlagArg(A,
1500 Opts.getOption(options::OPT_fomit_frame_pointer));
1501 else
1502 DAL.AddFlagArg(
1503 A, Opts.getOption(options::OPT_fno_omit_frame_pointer));
1504 } else {
1505 // Don't warn about /Oy- in x86-64 builds (where
1506 // SupportsForcingFramePointer is false). The flag having no effect
1507 // there is a compiler-internal optimization, and people shouldn't have
1508 // to special-case their build files for x86-64 clang-cl.
1509 A->claim();
1510 }
1511 break;
1512 }
1513 }
1514 }
1515 }
1516
TranslateDArg(Arg * A,llvm::opt::DerivedArgList & DAL,const OptTable & Opts)1517 static void TranslateDArg(Arg *A, llvm::opt::DerivedArgList &DAL,
1518 const OptTable &Opts) {
1519 assert(A->getOption().matches(options::OPT_D));
1520
1521 StringRef Val = A->getValue();
1522 size_t Hash = Val.find('#');
1523 if (Hash == StringRef::npos || Hash > Val.find('=')) {
1524 DAL.append(A);
1525 return;
1526 }
1527
1528 std::string NewVal = std::string(Val);
1529 NewVal[Hash] = '=';
1530 DAL.AddJoinedArg(A, Opts.getOption(options::OPT_D), NewVal);
1531 }
1532
TranslatePermissive(Arg * A,llvm::opt::DerivedArgList & DAL,const OptTable & Opts)1533 static void TranslatePermissive(Arg *A, llvm::opt::DerivedArgList &DAL,
1534 const OptTable &Opts) {
1535 DAL.AddFlagArg(A, Opts.getOption(options::OPT__SLASH_Zc_twoPhase_));
1536 DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_operator_names));
1537 }
1538
TranslatePermissiveMinus(Arg * A,llvm::opt::DerivedArgList & DAL,const OptTable & Opts)1539 static void TranslatePermissiveMinus(Arg *A, llvm::opt::DerivedArgList &DAL,
1540 const OptTable &Opts) {
1541 DAL.AddFlagArg(A, Opts.getOption(options::OPT__SLASH_Zc_twoPhase));
1542 DAL.AddFlagArg(A, Opts.getOption(options::OPT_foperator_names));
1543 }
1544
1545 llvm::opt::DerivedArgList *
TranslateArgs(const llvm::opt::DerivedArgList & Args,StringRef BoundArch,Action::OffloadKind OFK) const1546 MSVCToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args,
1547 StringRef BoundArch,
1548 Action::OffloadKind OFK) const {
1549 DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs());
1550 const OptTable &Opts = getDriver().getOpts();
1551
1552 // /Oy and /Oy- don't have an effect on X86-64
1553 bool SupportsForcingFramePointer = getArch() != llvm::Triple::x86_64;
1554
1555 // The -O[12xd] flag actually expands to several flags. We must desugar the
1556 // flags so that options embedded can be negated. For example, the '-O2' flag
1557 // enables '-Oy'. Expanding '-O2' into its constituent flags allows us to
1558 // correctly handle '-O2 -Oy-' where the trailing '-Oy-' disables a single
1559 // aspect of '-O2'.
1560 //
1561 // Note that this expansion logic only applies to the *last* of '[12xd]'.
1562
1563 // First step is to search for the character we'd like to expand.
1564 const char *ExpandChar = nullptr;
1565 for (Arg *A : Args.filtered(options::OPT__SLASH_O)) {
1566 StringRef OptStr = A->getValue();
1567 for (size_t I = 0, E = OptStr.size(); I != E; ++I) {
1568 char OptChar = OptStr[I];
1569 char PrevChar = I > 0 ? OptStr[I - 1] : '0';
1570 if (PrevChar == 'b') {
1571 // OptChar does not expand; it's an argument to the previous char.
1572 continue;
1573 }
1574 if (OptChar == '1' || OptChar == '2' || OptChar == 'x' || OptChar == 'd')
1575 ExpandChar = OptStr.data() + I;
1576 }
1577 }
1578
1579 for (Arg *A : Args) {
1580 if (A->getOption().matches(options::OPT__SLASH_O)) {
1581 // The -O flag actually takes an amalgam of other options. For example,
1582 // '/Ogyb2' is equivalent to '/Og' '/Oy' '/Ob2'.
1583 TranslateOptArg(A, *DAL, SupportsForcingFramePointer, ExpandChar, Opts);
1584 } else if (A->getOption().matches(options::OPT_D)) {
1585 // Translate -Dfoo#bar into -Dfoo=bar.
1586 TranslateDArg(A, *DAL, Opts);
1587 } else if (A->getOption().matches(options::OPT__SLASH_permissive)) {
1588 // Expand /permissive
1589 TranslatePermissive(A, *DAL, Opts);
1590 } else if (A->getOption().matches(options::OPT__SLASH_permissive_)) {
1591 // Expand /permissive-
1592 TranslatePermissiveMinus(A, *DAL, Opts);
1593 } else if (OFK != Action::OFK_HIP) {
1594 // HIP Toolchain translates input args by itself.
1595 DAL->append(A);
1596 }
1597 }
1598
1599 return DAL;
1600 }
1601
addClangTargetOptions(const ArgList & DriverArgs,ArgStringList & CC1Args,Action::OffloadKind DeviceOffloadKind) const1602 void MSVCToolChain::addClangTargetOptions(
1603 const ArgList &DriverArgs, ArgStringList &CC1Args,
1604 Action::OffloadKind DeviceOffloadKind) const {
1605 // MSVC STL kindly allows removing all usages of typeid by defining
1606 // _HAS_STATIC_RTTI to 0. Do so, when compiling with -fno-rtti
1607 if (DriverArgs.hasArg(options::OPT_fno_rtti, options::OPT_frtti,
1608 /*Default=*/false))
1609 CC1Args.push_back("-D_HAS_STATIC_RTTI=0");
1610 }
1611