xref: /llvm-project/clang/lib/Driver/ToolChains/MSVC.cpp (revision d00f65c6acd9f0e1ddae83391f55eb9d232d2f9e)
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/Option/Arg.h"
22 #include "llvm/Option/ArgList.h"
23 #include "llvm/Support/ConvertUTF.h"
24 #include "llvm/Support/ErrorHandling.h"
25 #include "llvm/Support/FileSystem.h"
26 #include "llvm/Support/MemoryBuffer.h"
27 #include "llvm/Support/Path.h"
28 #include "llvm/Support/Process.h"
29 #include "llvm/Support/VirtualFileSystem.h"
30 #include "llvm/TargetParser/Host.h"
31 #include <cstdio>
32 
33 #ifdef _WIN32
34   #define WIN32_LEAN_AND_MEAN
35   #define NOGDI
36   #ifndef NOMINMAX
37     #define NOMINMAX
38   #endif
39   #include <windows.h>
40 #endif
41 
42 using namespace clang::driver;
43 using namespace clang::driver::toolchains;
44 using namespace clang::driver::tools;
45 using namespace clang;
46 using namespace llvm::opt;
47 
48 static bool canExecute(llvm::vfs::FileSystem &VFS, StringRef Path) {
49   auto Status = VFS.status(Path);
50   if (!Status)
51     return false;
52   return (Status->getPermissions() & llvm::sys::fs::perms::all_exe) != 0;
53 }
54 
55 // Try to find Exe from a Visual Studio distribution.  This first tries to find
56 // an installed copy of Visual Studio and, failing that, looks in the PATH,
57 // making sure that whatever executable that's found is not a same-named exe
58 // from clang itself to prevent clang from falling back to itself.
59 static std::string FindVisualStudioExecutable(const ToolChain &TC,
60                                               const char *Exe) {
61   const auto &MSVC = static_cast<const toolchains::MSVCToolChain &>(TC);
62   SmallString<128> FilePath(
63       MSVC.getSubDirectoryPath(llvm::SubDirectoryType::Bin));
64   llvm::sys::path::append(FilePath, Exe);
65   return std::string(canExecute(TC.getVFS(), FilePath) ? FilePath.str() : Exe);
66 }
67 
68 void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
69                                         const InputInfo &Output,
70                                         const InputInfoList &Inputs,
71                                         const ArgList &Args,
72                                         const char *LinkingOutput) const {
73   ArgStringList CmdArgs;
74 
75   auto &TC = static_cast<const toolchains::MSVCToolChain &>(getToolChain());
76 
77   assert((Output.isFilename() || Output.isNothing()) && "invalid output");
78   if (Output.isFilename())
79     CmdArgs.push_back(
80         Args.MakeArgString(std::string("-out:") + Output.getFilename()));
81 
82   if (Args.hasArg(options::OPT_marm64x))
83     CmdArgs.push_back("-machine:arm64x");
84   else if (TC.getTriple().isWindowsArm64EC())
85     CmdArgs.push_back("-machine:arm64ec");
86 
87   if (const Arg *A = Args.getLastArg(options::OPT_fveclib)) {
88     StringRef V = A->getValue();
89     if (V == "ArmPL")
90       CmdArgs.push_back(Args.MakeArgString("--dependent-lib=amath"));
91   }
92 
93   if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles) &&
94       !C.getDriver().IsCLMode() && !C.getDriver().IsFlangMode()) {
95     CmdArgs.push_back("-defaultlib:libcmt");
96     CmdArgs.push_back("-defaultlib:oldnames");
97   }
98 
99   // If the VC environment hasn't been configured (perhaps because the user
100   // did not run vcvarsall), try to build a consistent link environment.  If
101   // the environment variable is set however, assume the user knows what
102   // they're doing. If the user passes /vctoolsdir or /winsdkdir, trust that
103   // over env vars.
104   if (const Arg *A = Args.getLastArg(options::OPT__SLASH_diasdkdir,
105                                      options::OPT__SLASH_winsysroot)) {
106     // cl.exe doesn't find the DIA SDK automatically, so this too requires
107     // explicit flags and doesn't automatically look in "DIA SDK" relative
108     // to the path we found for VCToolChainPath.
109     llvm::SmallString<128> DIAPath(A->getValue());
110     if (A->getOption().getID() == options::OPT__SLASH_winsysroot)
111       llvm::sys::path::append(DIAPath, "DIA SDK");
112 
113     // The DIA SDK always uses the legacy vc arch, even in new MSVC versions.
114     llvm::sys::path::append(DIAPath, "lib",
115                             llvm::archToLegacyVCArch(TC.getArch()));
116     CmdArgs.push_back(Args.MakeArgString(Twine("-libpath:") + DIAPath));
117   }
118   if (!llvm::sys::Process::GetEnv("LIB") ||
119       Args.getLastArg(options::OPT__SLASH_vctoolsdir,
120                       options::OPT__SLASH_winsysroot)) {
121     CmdArgs.push_back(Args.MakeArgString(
122         Twine("-libpath:") +
123         TC.getSubDirectoryPath(llvm::SubDirectoryType::Lib)));
124     CmdArgs.push_back(Args.MakeArgString(
125         Twine("-libpath:") +
126         TC.getSubDirectoryPath(llvm::SubDirectoryType::Lib, "atlmfc")));
127   }
128   if (!llvm::sys::Process::GetEnv("LIB") ||
129       Args.getLastArg(options::OPT__SLASH_winsdkdir,
130                       options::OPT__SLASH_winsysroot)) {
131     if (TC.useUniversalCRT()) {
132       std::string UniversalCRTLibPath;
133       if (TC.getUniversalCRTLibraryPath(Args, UniversalCRTLibPath))
134         CmdArgs.push_back(
135             Args.MakeArgString(Twine("-libpath:") + UniversalCRTLibPath));
136     }
137     std::string WindowsSdkLibPath;
138     if (TC.getWindowsSDKLibraryPath(Args, WindowsSdkLibPath))
139       CmdArgs.push_back(
140           Args.MakeArgString(std::string("-libpath:") + WindowsSdkLibPath));
141   }
142 
143   if (!C.getDriver().IsCLMode() && Args.hasArg(options::OPT_L))
144     for (const auto &LibPath : Args.getAllArgValues(options::OPT_L))
145       CmdArgs.push_back(Args.MakeArgString("-libpath:" + LibPath));
146 
147   if (C.getDriver().IsFlangMode() &&
148       !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
149     addFortranRuntimeLibraryPath(TC, Args, CmdArgs);
150     addFortranRuntimeLibs(TC, Args, CmdArgs);
151 
152     // Inform the MSVC linker that we're generating a console application, i.e.
153     // one with `main` as the "user-defined" entry point. The `main` function is
154     // defined in flang's runtime libraries.
155     CmdArgs.push_back("/subsystem:console");
156   }
157 
158   // Add the compiler-rt library directories to libpath if they exist to help
159   // the linker find the various sanitizer, builtin, and profiling runtimes.
160   for (const auto &LibPath : TC.getLibraryPaths()) {
161     if (TC.getVFS().exists(LibPath))
162       CmdArgs.push_back(Args.MakeArgString("-libpath:" + LibPath));
163   }
164   auto CRTPath = TC.getCompilerRTPath();
165   if (TC.getVFS().exists(CRTPath))
166     CmdArgs.push_back(Args.MakeArgString("-libpath:" + CRTPath));
167 
168   CmdArgs.push_back("-nologo");
169 
170   if (Args.hasArg(options::OPT_g_Group, options::OPT__SLASH_Z7))
171     CmdArgs.push_back("-debug");
172 
173   // If we specify /hotpatch, let the linker add padding in front of each
174   // function, like MSVC does.
175   if (Args.hasArg(options::OPT_fms_hotpatch, options::OPT__SLASH_hotpatch))
176     CmdArgs.push_back("-functionpadmin");
177 
178   // Pass on /Brepro if it was passed to the compiler.
179   // Note that /Brepro maps to -mno-incremental-linker-compatible.
180   bool DefaultIncrementalLinkerCompatible =
181       C.getDefaultToolChain().getTriple().isWindowsMSVCEnvironment();
182   if (!Args.hasFlag(options::OPT_mincremental_linker_compatible,
183                     options::OPT_mno_incremental_linker_compatible,
184                     DefaultIncrementalLinkerCompatible))
185     CmdArgs.push_back("-Brepro");
186 
187   bool DLL = Args.hasArg(options::OPT__SLASH_LD, options::OPT__SLASH_LDd,
188                          options::OPT_shared);
189   if (DLL) {
190     CmdArgs.push_back(Args.MakeArgString("-dll"));
191 
192     SmallString<128> ImplibName(Output.getFilename());
193     llvm::sys::path::replace_extension(ImplibName, "lib");
194     CmdArgs.push_back(Args.MakeArgString(std::string("-implib:") + ImplibName));
195   }
196 
197   if (TC.getSanitizerArgs(Args).needsFuzzer()) {
198     if (!Args.hasArg(options::OPT_shared))
199       CmdArgs.push_back(
200           Args.MakeArgString(std::string("-wholearchive:") +
201                              TC.getCompilerRTArgString(Args, "fuzzer")));
202     CmdArgs.push_back(Args.MakeArgString("-debug"));
203     // Prevent the linker from padding sections we use for instrumentation
204     // arrays.
205     CmdArgs.push_back(Args.MakeArgString("-incremental:no"));
206   }
207 
208   if (TC.getSanitizerArgs(Args).needsAsanRt()) {
209     CmdArgs.push_back(Args.MakeArgString("-debug"));
210     CmdArgs.push_back(Args.MakeArgString("-incremental:no"));
211     CmdArgs.push_back(TC.getCompilerRTArgString(Args, "asan_dynamic"));
212     auto defines = Args.getAllArgValues(options::OPT_D);
213     if (Args.hasArg(options::OPT__SLASH_MD, options::OPT__SLASH_MDd) ||
214         find(begin(defines), end(defines), "_DLL") != end(defines)) {
215       // Make sure the dynamic runtime thunk is not optimized out at link time
216       // to ensure proper SEH handling.
217       CmdArgs.push_back(Args.MakeArgString(
218           TC.getArch() == llvm::Triple::x86
219               ? "-include:___asan_seh_interceptor"
220               : "-include:__asan_seh_interceptor"));
221       // Make sure the linker consider all object files from the dynamic runtime
222       // thunk.
223       CmdArgs.push_back(Args.MakeArgString(
224           std::string("-wholearchive:") +
225           TC.getCompilerRT(Args, "asan_dynamic_runtime_thunk")));
226     } else {
227       // Make sure the linker consider all object files from the static runtime
228       // thunk.
229       CmdArgs.push_back(Args.MakeArgString(
230           std::string("-wholearchive:") +
231           TC.getCompilerRT(Args, "asan_static_runtime_thunk")));
232     }
233   }
234 
235   Args.AddAllArgValues(CmdArgs, options::OPT__SLASH_link);
236 
237   // Control Flow Guard checks
238   for (const Arg *A : Args.filtered(options::OPT__SLASH_guard)) {
239     StringRef GuardArgs = A->getValue();
240     if (GuardArgs.equals_insensitive("cf") ||
241         GuardArgs.equals_insensitive("cf,nochecks")) {
242       // MSVC doesn't yet support the "nochecks" modifier.
243       CmdArgs.push_back("-guard:cf");
244     } else if (GuardArgs.equals_insensitive("cf-")) {
245       CmdArgs.push_back("-guard:cf-");
246     } else if (GuardArgs.equals_insensitive("ehcont")) {
247       CmdArgs.push_back("-guard:ehcont");
248     } else if (GuardArgs.equals_insensitive("ehcont-")) {
249       CmdArgs.push_back("-guard:ehcont-");
250     }
251   }
252 
253   if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ,
254                    options::OPT_fno_openmp, false)) {
255     CmdArgs.push_back("-nodefaultlib:vcomp.lib");
256     CmdArgs.push_back("-nodefaultlib:vcompd.lib");
257     CmdArgs.push_back(Args.MakeArgString(std::string("-libpath:") +
258                                          TC.getDriver().Dir + "/../lib"));
259     switch (TC.getDriver().getOpenMPRuntime(Args)) {
260     case Driver::OMPRT_OMP:
261       CmdArgs.push_back("-defaultlib:libomp.lib");
262       break;
263     case Driver::OMPRT_IOMP5:
264       CmdArgs.push_back("-defaultlib:libiomp5md.lib");
265       break;
266     case Driver::OMPRT_GOMP:
267       break;
268     case Driver::OMPRT_Unknown:
269       // Already diagnosed.
270       break;
271     }
272   }
273 
274   // Add compiler-rt lib in case if it was explicitly
275   // specified as an argument for --rtlib option.
276   if (!Args.hasArg(options::OPT_nostdlib)) {
277     AddRunTimeLibs(TC, TC.getDriver(), CmdArgs, Args);
278   }
279 
280   StringRef Linker =
281       Args.getLastArgValue(options::OPT_fuse_ld_EQ, CLANG_DEFAULT_LINKER);
282   if (Linker.empty())
283     Linker = "link";
284   // We need to translate 'lld' into 'lld-link'.
285   else if (Linker.equals_insensitive("lld"))
286     Linker = "lld-link";
287 
288   if (Linker == "lld-link") {
289     for (Arg *A : Args.filtered(options::OPT_vfsoverlay))
290       CmdArgs.push_back(
291           Args.MakeArgString(std::string("/vfsoverlay:") + A->getValue()));
292 
293     if (C.getDriver().isUsingLTO() &&
294         Args.hasFlag(options::OPT_gsplit_dwarf, options::OPT_gno_split_dwarf,
295                      false))
296       CmdArgs.push_back(Args.MakeArgString(Twine("/dwodir:") +
297                                            Output.getFilename() + "_dwo"));
298   }
299 
300   // Add filenames, libraries, and other linker inputs.
301   for (const auto &Input : Inputs) {
302     if (Input.isFilename()) {
303       CmdArgs.push_back(Input.getFilename());
304       continue;
305     }
306 
307     const Arg &A = Input.getInputArg();
308 
309     // Render -l options differently for the MSVC linker.
310     if (A.getOption().matches(options::OPT_l)) {
311       StringRef Lib = A.getValue();
312       const char *LinkLibArg;
313       if (Lib.ends_with(".lib"))
314         LinkLibArg = Args.MakeArgString(Lib);
315       else
316         LinkLibArg = Args.MakeArgString(Lib + ".lib");
317       CmdArgs.push_back(LinkLibArg);
318       continue;
319     }
320 
321     // Otherwise, this is some other kind of linker input option like -Wl, -z,
322     // or -L. Render it, even if MSVC doesn't understand it.
323     A.renderAsInput(Args, CmdArgs);
324   }
325 
326   addHIPRuntimeLibArgs(TC, C, Args, CmdArgs);
327 
328   TC.addProfileRTLibs(Args, CmdArgs);
329 
330   std::vector<const char *> Environment;
331 
332   // We need to special case some linker paths. In the case of the regular msvc
333   // linker, we need to use a special search algorithm.
334   llvm::SmallString<128> linkPath;
335   if (Linker.equals_insensitive("link")) {
336     // If we're using the MSVC linker, it's not sufficient to just use link
337     // from the program PATH, because other environments like GnuWin32 install
338     // their own link.exe which may come first.
339     linkPath = FindVisualStudioExecutable(TC, "link.exe");
340 
341     if (!TC.FoundMSVCInstall() && !canExecute(TC.getVFS(), linkPath)) {
342       llvm::SmallString<128> ClPath;
343       ClPath = TC.GetProgramPath("cl.exe");
344       if (canExecute(TC.getVFS(), ClPath)) {
345         linkPath = llvm::sys::path::parent_path(ClPath);
346         llvm::sys::path::append(linkPath, "link.exe");
347         if (!canExecute(TC.getVFS(), linkPath))
348           C.getDriver().Diag(clang::diag::warn_drv_msvc_not_found);
349       } else {
350         C.getDriver().Diag(clang::diag::warn_drv_msvc_not_found);
351       }
352     }
353 
354     // Clang handles passing the proper asan libs to the linker, which goes
355     // against link.exe's /INFERASANLIBS which automatically finds asan libs.
356     if (TC.getSanitizerArgs(Args).needsAsanRt())
357       CmdArgs.push_back("/INFERASANLIBS:NO");
358 
359 #ifdef _WIN32
360     // When cross-compiling with VS2017 or newer, link.exe expects to have
361     // its containing bin directory at the top of PATH, followed by the
362     // native target bin directory.
363     // e.g. when compiling for x86 on an x64 host, PATH should start with:
364     // /bin/Hostx64/x86;/bin/Hostx64/x64
365     // This doesn't attempt to handle llvm::ToolsetLayout::DevDivInternal.
366     if (TC.getIsVS2017OrNewer() &&
367         llvm::Triple(llvm::sys::getProcessTriple()).getArch() != TC.getArch()) {
368       auto HostArch = llvm::Triple(llvm::sys::getProcessTriple()).getArch();
369 
370       auto EnvBlockWide =
371           std::unique_ptr<wchar_t[], decltype(&FreeEnvironmentStringsW)>(
372               GetEnvironmentStringsW(), FreeEnvironmentStringsW);
373       if (!EnvBlockWide)
374         goto SkipSettingEnvironment;
375 
376       size_t EnvCount = 0;
377       size_t EnvBlockLen = 0;
378       while (EnvBlockWide[EnvBlockLen] != L'\0') {
379         ++EnvCount;
380         EnvBlockLen += std::wcslen(&EnvBlockWide[EnvBlockLen]) +
381                        1 /*string null-terminator*/;
382       }
383       ++EnvBlockLen; // add the block null-terminator
384 
385       std::string EnvBlock;
386       if (!llvm::convertUTF16ToUTF8String(
387               llvm::ArrayRef<char>(reinterpret_cast<char *>(EnvBlockWide.get()),
388                                    EnvBlockLen * sizeof(EnvBlockWide[0])),
389               EnvBlock))
390         goto SkipSettingEnvironment;
391 
392       Environment.reserve(EnvCount);
393 
394       // Now loop over each string in the block and copy them into the
395       // environment vector, adjusting the PATH variable as needed when we
396       // find it.
397       for (const char *Cursor = EnvBlock.data(); *Cursor != '\0';) {
398         llvm::StringRef EnvVar(Cursor);
399         if (EnvVar.starts_with_insensitive("path=")) {
400           constexpr size_t PrefixLen = 5; // strlen("path=")
401           Environment.push_back(Args.MakeArgString(
402               EnvVar.substr(0, PrefixLen) +
403               TC.getSubDirectoryPath(llvm::SubDirectoryType::Bin) +
404               llvm::Twine(llvm::sys::EnvPathSeparator) +
405               TC.getSubDirectoryPath(llvm::SubDirectoryType::Bin, HostArch) +
406               (EnvVar.size() > PrefixLen
407                    ? llvm::Twine(llvm::sys::EnvPathSeparator) +
408                          EnvVar.substr(PrefixLen)
409                    : "")));
410         } else {
411           Environment.push_back(Args.MakeArgString(EnvVar));
412         }
413         Cursor += EnvVar.size() + 1 /*null-terminator*/;
414       }
415     }
416   SkipSettingEnvironment:;
417 #endif
418   } else {
419     linkPath = TC.GetProgramPath(Linker.str().c_str());
420   }
421 
422   auto LinkCmd = std::make_unique<Command>(
423       JA, *this, ResponseFileSupport::AtFileUTF16(),
424       Args.MakeArgString(linkPath), CmdArgs, Inputs, Output);
425   if (!Environment.empty())
426     LinkCmd->setEnvironment(Environment);
427   C.addCommand(std::move(LinkCmd));
428 }
429 
430 MSVCToolChain::MSVCToolChain(const Driver &D, const llvm::Triple &Triple,
431                              const ArgList &Args)
432     : ToolChain(D, Triple, Args), CudaInstallation(D, Triple, Args),
433       RocmInstallation(D, Triple, Args), SYCLInstallation(D, Triple, Args) {
434   getProgramPaths().push_back(getDriver().Dir);
435 
436   std::optional<llvm::StringRef> VCToolsDir, VCToolsVersion;
437   if (Arg *A = Args.getLastArg(options::OPT__SLASH_vctoolsdir))
438     VCToolsDir = A->getValue();
439   if (Arg *A = Args.getLastArg(options::OPT__SLASH_vctoolsversion))
440     VCToolsVersion = A->getValue();
441   if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsdkdir))
442     WinSdkDir = A->getValue();
443   if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsdkversion))
444     WinSdkVersion = A->getValue();
445   if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsysroot))
446     WinSysRoot = A->getValue();
447 
448   // Check the command line first, that's the user explicitly telling us what to
449   // use. Check the environment next, in case we're being invoked from a VS
450   // command prompt. Failing that, just try to find the newest Visual Studio
451   // version we can and use its default VC toolchain.
452   llvm::findVCToolChainViaCommandLine(getVFS(), VCToolsDir, VCToolsVersion,
453                                       WinSysRoot, VCToolChainPath, VSLayout) ||
454       llvm::findVCToolChainViaEnvironment(getVFS(), VCToolChainPath,
455                                           VSLayout) ||
456       llvm::findVCToolChainViaSetupConfig(getVFS(), VCToolsVersion,
457                                           VCToolChainPath, VSLayout) ||
458       llvm::findVCToolChainViaRegistry(VCToolChainPath, VSLayout);
459 }
460 
461 Tool *MSVCToolChain::buildLinker() const {
462   return new tools::visualstudio::Linker(*this);
463 }
464 
465 Tool *MSVCToolChain::buildAssembler() const {
466   if (getTriple().isOSBinFormatMachO())
467     return new tools::darwin::Assembler(*this);
468   getDriver().Diag(clang::diag::err_no_external_assembler);
469   return nullptr;
470 }
471 
472 ToolChain::UnwindTableLevel
473 MSVCToolChain::getDefaultUnwindTableLevel(const ArgList &Args) const {
474   // Don't emit unwind tables by default for MachO targets.
475   if (getTriple().isOSBinFormatMachO())
476     return UnwindTableLevel::None;
477 
478   // All non-x86_32 Windows targets require unwind tables. However, LLVM
479   // doesn't know how to generate them for all targets, so only enable
480   // the ones that are actually implemented.
481   if (getArch() == llvm::Triple::x86_64 || getArch() == llvm::Triple::arm ||
482       getArch() == llvm::Triple::thumb || getArch() == llvm::Triple::aarch64)
483     return UnwindTableLevel::Asynchronous;
484 
485   return UnwindTableLevel::None;
486 }
487 
488 bool MSVCToolChain::isPICDefault() const {
489   return getArch() == llvm::Triple::x86_64 ||
490          getArch() == llvm::Triple::aarch64;
491 }
492 
493 bool MSVCToolChain::isPIEDefault(const llvm::opt::ArgList &Args) const {
494   return false;
495 }
496 
497 bool MSVCToolChain::isPICDefaultForced() const {
498   return getArch() == llvm::Triple::x86_64 ||
499          getArch() == llvm::Triple::aarch64;
500 }
501 
502 void MSVCToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs,
503                                        ArgStringList &CC1Args) const {
504   CudaInstallation->AddCudaIncludeArgs(DriverArgs, CC1Args);
505 }
506 
507 void MSVCToolChain::AddHIPIncludeArgs(const ArgList &DriverArgs,
508                                       ArgStringList &CC1Args) const {
509   RocmInstallation->AddHIPIncludeArgs(DriverArgs, CC1Args);
510 }
511 
512 void MSVCToolChain::addSYCLIncludeArgs(const ArgList &DriverArgs,
513                                        ArgStringList &CC1Args) const {
514   SYCLInstallation->addSYCLIncludeArgs(DriverArgs, CC1Args);
515 }
516 
517 void MSVCToolChain::AddHIPRuntimeLibArgs(const ArgList &Args,
518                                          ArgStringList &CmdArgs) const {
519   CmdArgs.append({Args.MakeArgString(StringRef("-libpath:") +
520                                      RocmInstallation->getLibPath()),
521                   "amdhip64.lib"});
522 }
523 
524 void MSVCToolChain::printVerboseInfo(raw_ostream &OS) const {
525   CudaInstallation->print(OS);
526   RocmInstallation->print(OS);
527 }
528 
529 std::string
530 MSVCToolChain::getSubDirectoryPath(llvm::SubDirectoryType Type,
531                                    llvm::StringRef SubdirParent) const {
532   return llvm::getSubDirectoryPath(Type, VSLayout, VCToolChainPath, getArch(),
533                                    SubdirParent);
534 }
535 
536 std::string
537 MSVCToolChain::getSubDirectoryPath(llvm::SubDirectoryType Type,
538                                    llvm::Triple::ArchType TargetArch) const {
539   return llvm::getSubDirectoryPath(Type, VSLayout, VCToolChainPath, TargetArch,
540                                    "");
541 }
542 
543 // Find the most recent version of Universal CRT or Windows 10 SDK.
544 // vcvarsqueryregistry.bat from Visual Studio 2015 sorts entries in the include
545 // directory by name and uses the last one of the list.
546 // So we compare entry names lexicographically to find the greatest one.
547 // Gets the library path required to link against the Windows SDK.
548 bool MSVCToolChain::getWindowsSDKLibraryPath(const ArgList &Args,
549                                              std::string &path) const {
550   std::string sdkPath;
551   int sdkMajor = 0;
552   std::string windowsSDKIncludeVersion;
553   std::string windowsSDKLibVersion;
554 
555   path.clear();
556   if (!llvm::getWindowsSDKDir(getVFS(), WinSdkDir, WinSdkVersion, WinSysRoot,
557                               sdkPath, sdkMajor, windowsSDKIncludeVersion,
558                               windowsSDKLibVersion))
559     return false;
560 
561   llvm::SmallString<128> libPath(sdkPath);
562   llvm::sys::path::append(libPath, "Lib");
563   if (sdkMajor >= 10)
564     if (!(WinSdkDir.has_value() || WinSysRoot.has_value()) &&
565         WinSdkVersion.has_value())
566       windowsSDKLibVersion = *WinSdkVersion;
567   if (sdkMajor >= 8)
568     llvm::sys::path::append(libPath, windowsSDKLibVersion, "um");
569   return llvm::appendArchToWindowsSDKLibPath(sdkMajor, libPath, getArch(),
570                                              path);
571 }
572 
573 bool MSVCToolChain::useUniversalCRT() const {
574   return llvm::useUniversalCRT(VSLayout, VCToolChainPath, getArch(), getVFS());
575 }
576 
577 bool MSVCToolChain::getUniversalCRTLibraryPath(const ArgList &Args,
578                                                std::string &Path) const {
579   std::string UniversalCRTSdkPath;
580   std::string UCRTVersion;
581 
582   Path.clear();
583   if (!llvm::getUniversalCRTSdkDir(getVFS(), WinSdkDir, WinSdkVersion,
584                                    WinSysRoot, UniversalCRTSdkPath,
585                                    UCRTVersion))
586     return false;
587 
588   if (!(WinSdkDir.has_value() || WinSysRoot.has_value()) &&
589       WinSdkVersion.has_value())
590     UCRTVersion = *WinSdkVersion;
591 
592   StringRef ArchName = llvm::archToWindowsSDKArch(getArch());
593   if (ArchName.empty())
594     return false;
595 
596   llvm::SmallString<128> LibPath(UniversalCRTSdkPath);
597   llvm::sys::path::append(LibPath, "Lib", UCRTVersion, "ucrt", ArchName);
598 
599   Path = std::string(LibPath);
600   return true;
601 }
602 
603 static VersionTuple getMSVCVersionFromExe(const std::string &BinDir) {
604   VersionTuple Version;
605 #ifdef _WIN32
606   SmallString<128> ClExe(BinDir);
607   llvm::sys::path::append(ClExe, "cl.exe");
608 
609   std::wstring ClExeWide;
610   if (!llvm::ConvertUTF8toWide(ClExe.c_str(), ClExeWide))
611     return Version;
612 
613   const DWORD VersionSize = ::GetFileVersionInfoSizeW(ClExeWide.c_str(),
614                                                       nullptr);
615   if (VersionSize == 0)
616     return Version;
617 
618   SmallVector<uint8_t, 4 * 1024> VersionBlock(VersionSize);
619   if (!::GetFileVersionInfoW(ClExeWide.c_str(), 0, VersionSize,
620                              VersionBlock.data()))
621     return Version;
622 
623   VS_FIXEDFILEINFO *FileInfo = nullptr;
624   UINT FileInfoSize = 0;
625   if (!::VerQueryValueW(VersionBlock.data(), L"\\",
626                         reinterpret_cast<LPVOID *>(&FileInfo), &FileInfoSize) ||
627       FileInfoSize < sizeof(*FileInfo))
628     return Version;
629 
630   const unsigned Major = (FileInfo->dwFileVersionMS >> 16) & 0xFFFF;
631   const unsigned Minor = (FileInfo->dwFileVersionMS      ) & 0xFFFF;
632   const unsigned Micro = (FileInfo->dwFileVersionLS >> 16) & 0xFFFF;
633 
634   Version = VersionTuple(Major, Minor, Micro);
635 #endif
636   return Version;
637 }
638 
639 void MSVCToolChain::AddSystemIncludeWithSubfolder(
640     const ArgList &DriverArgs, ArgStringList &CC1Args,
641     const std::string &folder, const Twine &subfolder1, const Twine &subfolder2,
642     const Twine &subfolder3) const {
643   llvm::SmallString<128> path(folder);
644   llvm::sys::path::append(path, subfolder1, subfolder2, subfolder3);
645   addSystemInclude(DriverArgs, CC1Args, path);
646 }
647 
648 void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
649                                               ArgStringList &CC1Args) const {
650   if (DriverArgs.hasArg(options::OPT_nostdinc))
651     return;
652 
653   if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
654     AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, getDriver().ResourceDir,
655                                   "include");
656   }
657 
658   // Add %INCLUDE%-like directories from the -imsvc flag.
659   for (const auto &Path : DriverArgs.getAllArgValues(options::OPT__SLASH_imsvc))
660     addSystemInclude(DriverArgs, CC1Args, Path);
661 
662   auto AddSystemIncludesFromEnv = [&](StringRef Var) -> bool {
663     if (auto Val = llvm::sys::Process::GetEnv(Var)) {
664       SmallVector<StringRef, 8> Dirs;
665       StringRef(*Val).split(Dirs, ";", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
666       if (!Dirs.empty()) {
667         addSystemIncludes(DriverArgs, CC1Args, Dirs);
668         return true;
669       }
670     }
671     return false;
672   };
673 
674   // Add %INCLUDE%-like dirs via /external:env: flags.
675   for (const auto &Var :
676        DriverArgs.getAllArgValues(options::OPT__SLASH_external_env)) {
677     AddSystemIncludesFromEnv(Var);
678   }
679 
680   // Add DIA SDK include if requested.
681   if (const Arg *A = DriverArgs.getLastArg(options::OPT__SLASH_diasdkdir,
682                                            options::OPT__SLASH_winsysroot)) {
683     // cl.exe doesn't find the DIA SDK automatically, so this too requires
684     // explicit flags and doesn't automatically look in "DIA SDK" relative
685     // to the path we found for VCToolChainPath.
686     llvm::SmallString<128> DIASDKPath(A->getValue());
687     if (A->getOption().getID() == options::OPT__SLASH_winsysroot)
688       llvm::sys::path::append(DIASDKPath, "DIA SDK");
689     AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, std::string(DIASDKPath),
690                                   "include");
691   }
692 
693   if (DriverArgs.hasArg(options::OPT_nostdlibinc))
694     return;
695 
696   // Honor %INCLUDE% and %EXTERNAL_INCLUDE%. It should have essential search
697   // paths set by vcvarsall.bat. Skip if the user expressly set a vctoolsdir.
698   if (!DriverArgs.getLastArg(options::OPT__SLASH_vctoolsdir,
699                              options::OPT__SLASH_winsysroot)) {
700     bool Found = AddSystemIncludesFromEnv("INCLUDE");
701     Found |= AddSystemIncludesFromEnv("EXTERNAL_INCLUDE");
702     if (Found)
703       return;
704   }
705 
706   // When built with access to the proper Windows APIs, try to actually find
707   // the correct include paths first.
708   if (!VCToolChainPath.empty()) {
709     addSystemInclude(DriverArgs, CC1Args,
710                      getSubDirectoryPath(llvm::SubDirectoryType::Include));
711     addSystemInclude(
712         DriverArgs, CC1Args,
713         getSubDirectoryPath(llvm::SubDirectoryType::Include, "atlmfc"));
714 
715     if (useUniversalCRT()) {
716       std::string UniversalCRTSdkPath;
717       std::string UCRTVersion;
718       if (llvm::getUniversalCRTSdkDir(getVFS(), WinSdkDir, WinSdkVersion,
719                                       WinSysRoot, UniversalCRTSdkPath,
720                                       UCRTVersion)) {
721         if (!(WinSdkDir.has_value() || WinSysRoot.has_value()) &&
722             WinSdkVersion.has_value())
723           UCRTVersion = *WinSdkVersion;
724         AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, UniversalCRTSdkPath,
725                                       "Include", UCRTVersion, "ucrt");
726       }
727     }
728 
729     std::string WindowsSDKDir;
730     int major = 0;
731     std::string windowsSDKIncludeVersion;
732     std::string windowsSDKLibVersion;
733     if (llvm::getWindowsSDKDir(getVFS(), WinSdkDir, WinSdkVersion, WinSysRoot,
734                                WindowsSDKDir, major, windowsSDKIncludeVersion,
735                                windowsSDKLibVersion)) {
736       if (major >= 10)
737         if (!(WinSdkDir.has_value() || WinSysRoot.has_value()) &&
738             WinSdkVersion.has_value())
739           windowsSDKIncludeVersion = windowsSDKLibVersion = *WinSdkVersion;
740       if (major >= 8) {
741         // Note: windowsSDKIncludeVersion is empty for SDKs prior to v10.
742         // Anyway, llvm::sys::path::append is able to manage it.
743         AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
744                                       "Include", windowsSDKIncludeVersion,
745                                       "shared");
746         AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
747                                       "Include", windowsSDKIncludeVersion,
748                                       "um");
749         AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
750                                       "Include", windowsSDKIncludeVersion,
751                                       "winrt");
752         if (major >= 10) {
753           llvm::VersionTuple Tuple;
754           if (!Tuple.tryParse(windowsSDKIncludeVersion) &&
755               Tuple.getSubminor().value_or(0) >= 17134) {
756             AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
757                                           "Include", windowsSDKIncludeVersion,
758                                           "cppwinrt");
759           }
760         }
761       } else {
762         AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
763                                       "Include");
764       }
765     }
766 
767     return;
768   }
769 
770 #if defined(_WIN32)
771   // As a fallback, select default install paths.
772   // FIXME: Don't guess drives and paths like this on Windows.
773   const StringRef Paths[] = {
774     "C:/Program Files/Microsoft Visual Studio 10.0/VC/include",
775     "C:/Program Files/Microsoft Visual Studio 9.0/VC/include",
776     "C:/Program Files/Microsoft Visual Studio 9.0/VC/PlatformSDK/Include",
777     "C:/Program Files/Microsoft Visual Studio 8/VC/include",
778     "C:/Program Files/Microsoft Visual Studio 8/VC/PlatformSDK/Include"
779   };
780   addSystemIncludes(DriverArgs, CC1Args, Paths);
781 #endif
782 }
783 
784 void MSVCToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
785                                                  ArgStringList &CC1Args) const {
786   // FIXME: There should probably be logic here to find libc++ on Windows.
787 }
788 
789 VersionTuple MSVCToolChain::computeMSVCVersion(const Driver *D,
790                                                const ArgList &Args) const {
791   bool IsWindowsMSVC = getTriple().isWindowsMSVCEnvironment();
792   VersionTuple MSVT = ToolChain::computeMSVCVersion(D, Args);
793   if (MSVT.empty())
794     MSVT = getTriple().getEnvironmentVersion();
795   if (MSVT.empty() && IsWindowsMSVC)
796     MSVT =
797         getMSVCVersionFromExe(getSubDirectoryPath(llvm::SubDirectoryType::Bin));
798   if (MSVT.empty() &&
799       Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions,
800                    IsWindowsMSVC)) {
801     // -fms-compatibility-version=19.33 is default, aka 2022, 17.3
802     // NOTE: when changing this value, also update
803     // clang/docs/CommandGuide/clang.rst and clang/docs/UsersManual.rst
804     // accordingly.
805     MSVT = VersionTuple(19, 33);
806   }
807   return MSVT;
808 }
809 
810 std::string
811 MSVCToolChain::ComputeEffectiveClangTriple(const ArgList &Args,
812                                            types::ID InputType) const {
813   // The MSVC version doesn't care about the architecture, even though it
814   // may look at the triple internally.
815   VersionTuple MSVT = computeMSVCVersion(/*D=*/nullptr, Args);
816   MSVT = VersionTuple(MSVT.getMajor(), MSVT.getMinor().value_or(0),
817                       MSVT.getSubminor().value_or(0));
818 
819   // For the rest of the triple, however, a computed architecture name may
820   // be needed.
821   llvm::Triple Triple(ToolChain::ComputeEffectiveClangTriple(Args, InputType));
822   if (Triple.getEnvironment() == llvm::Triple::MSVC) {
823     StringRef ObjFmt = Triple.getEnvironmentName().split('-').second;
824     if (ObjFmt.empty())
825       Triple.setEnvironmentName((Twine("msvc") + MSVT.getAsString()).str());
826     else
827       Triple.setEnvironmentName(
828           (Twine("msvc") + MSVT.getAsString() + Twine('-') + ObjFmt).str());
829   }
830   return Triple.getTriple();
831 }
832 
833 SanitizerMask MSVCToolChain::getSupportedSanitizers() const {
834   SanitizerMask Res = ToolChain::getSupportedSanitizers();
835   Res |= SanitizerKind::Address;
836   Res |= SanitizerKind::PointerCompare;
837   Res |= SanitizerKind::PointerSubtract;
838   Res |= SanitizerKind::Fuzzer;
839   Res |= SanitizerKind::FuzzerNoLink;
840   Res &= ~SanitizerKind::CFIMFCall;
841   return Res;
842 }
843 
844 static void TranslateOptArg(Arg *A, llvm::opt::DerivedArgList &DAL,
845                             bool SupportsForcingFramePointer,
846                             const char *ExpandChar, const OptTable &Opts) {
847   assert(A->getOption().matches(options::OPT__SLASH_O));
848 
849   StringRef OptStr = A->getValue();
850   for (size_t I = 0, E = OptStr.size(); I != E; ++I) {
851     const char &OptChar = *(OptStr.data() + I);
852     switch (OptChar) {
853     default:
854       break;
855     case '1':
856     case '2':
857     case 'x':
858     case 'd':
859       // Ignore /O[12xd] flags that aren't the last one on the command line.
860       // Only the last one gets expanded.
861       if (&OptChar != ExpandChar) {
862         A->claim();
863         break;
864       }
865       if (OptChar == 'd') {
866         DAL.AddFlagArg(A, Opts.getOption(options::OPT_O0));
867       } else {
868         if (OptChar == '1') {
869           DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "s");
870         } else if (OptChar == '2' || OptChar == 'x') {
871           DAL.AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin));
872           DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "3");
873         }
874         if (SupportsForcingFramePointer &&
875             !DAL.hasArgNoClaim(options::OPT_fno_omit_frame_pointer))
876           DAL.AddFlagArg(A, Opts.getOption(options::OPT_fomit_frame_pointer));
877         if (OptChar == '1' || OptChar == '2')
878           DAL.AddFlagArg(A, Opts.getOption(options::OPT_ffunction_sections));
879       }
880       break;
881     case 'b':
882       if (I + 1 != E && isdigit(OptStr[I + 1])) {
883         switch (OptStr[I + 1]) {
884         case '0':
885           DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_inline));
886           break;
887         case '1':
888           DAL.AddFlagArg(A, Opts.getOption(options::OPT_finline_hint_functions));
889           break;
890         case '2':
891         case '3':
892           DAL.AddFlagArg(A, Opts.getOption(options::OPT_finline_functions));
893           break;
894         }
895         ++I;
896       }
897       break;
898     case 'g':
899       A->claim();
900       break;
901     case 'i':
902       if (I + 1 != E && OptStr[I + 1] == '-') {
903         ++I;
904         DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_builtin));
905       } else {
906         DAL.AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin));
907       }
908       break;
909     case 's':
910       DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "s");
911       break;
912     case 't':
913       DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "3");
914       break;
915     case 'y': {
916       bool OmitFramePointer = true;
917       if (I + 1 != E && OptStr[I + 1] == '-') {
918         OmitFramePointer = false;
919         ++I;
920       }
921       if (SupportsForcingFramePointer) {
922         if (OmitFramePointer)
923           DAL.AddFlagArg(A,
924                          Opts.getOption(options::OPT_fomit_frame_pointer));
925         else
926           DAL.AddFlagArg(
927               A, Opts.getOption(options::OPT_fno_omit_frame_pointer));
928       } else {
929         // Don't warn about /Oy- in x86-64 builds (where
930         // SupportsForcingFramePointer is false).  The flag having no effect
931         // there is a compiler-internal optimization, and people shouldn't have
932         // to special-case their build files for x86-64 clang-cl.
933         A->claim();
934       }
935       break;
936     }
937     }
938   }
939 }
940 
941 static void TranslateDArg(Arg *A, llvm::opt::DerivedArgList &DAL,
942                           const OptTable &Opts) {
943   assert(A->getOption().matches(options::OPT_D));
944 
945   StringRef Val = A->getValue();
946   size_t Hash = Val.find('#');
947   if (Hash == StringRef::npos || Hash > Val.find('=')) {
948     DAL.append(A);
949     return;
950   }
951 
952   std::string NewVal = std::string(Val);
953   NewVal[Hash] = '=';
954   DAL.AddJoinedArg(A, Opts.getOption(options::OPT_D), NewVal);
955 }
956 
957 static void TranslatePermissive(Arg *A, llvm::opt::DerivedArgList &DAL,
958                                 const OptTable &Opts) {
959   DAL.AddFlagArg(A, Opts.getOption(options::OPT__SLASH_Zc_twoPhase_));
960   DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_operator_names));
961 }
962 
963 static void TranslatePermissiveMinus(Arg *A, llvm::opt::DerivedArgList &DAL,
964                                      const OptTable &Opts) {
965   DAL.AddFlagArg(A, Opts.getOption(options::OPT__SLASH_Zc_twoPhase));
966   DAL.AddFlagArg(A, Opts.getOption(options::OPT_foperator_names));
967 }
968 
969 llvm::opt::DerivedArgList *
970 MSVCToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args,
971                              StringRef BoundArch,
972                              Action::OffloadKind OFK) const {
973   DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs());
974   const OptTable &Opts = getDriver().getOpts();
975 
976   // /Oy and /Oy- don't have an effect on X86-64
977   bool SupportsForcingFramePointer = getArch() != llvm::Triple::x86_64;
978 
979   // The -O[12xd] flag actually expands to several flags.  We must desugar the
980   // flags so that options embedded can be negated.  For example, the '-O2' flag
981   // enables '-Oy'.  Expanding '-O2' into its constituent flags allows us to
982   // correctly handle '-O2 -Oy-' where the trailing '-Oy-' disables a single
983   // aspect of '-O2'.
984   //
985   // Note that this expansion logic only applies to the *last* of '[12xd]'.
986 
987   // First step is to search for the character we'd like to expand.
988   const char *ExpandChar = nullptr;
989   for (Arg *A : Args.filtered(options::OPT__SLASH_O)) {
990     StringRef OptStr = A->getValue();
991     for (size_t I = 0, E = OptStr.size(); I != E; ++I) {
992       char OptChar = OptStr[I];
993       char PrevChar = I > 0 ? OptStr[I - 1] : '0';
994       if (PrevChar == 'b') {
995         // OptChar does not expand; it's an argument to the previous char.
996         continue;
997       }
998       if (OptChar == '1' || OptChar == '2' || OptChar == 'x' || OptChar == 'd')
999         ExpandChar = OptStr.data() + I;
1000     }
1001   }
1002 
1003   for (Arg *A : Args) {
1004     if (A->getOption().matches(options::OPT__SLASH_O)) {
1005       // The -O flag actually takes an amalgam of other options.  For example,
1006       // '/Ogyb2' is equivalent to '/Og' '/Oy' '/Ob2'.
1007       TranslateOptArg(A, *DAL, SupportsForcingFramePointer, ExpandChar, Opts);
1008     } else if (A->getOption().matches(options::OPT_D)) {
1009       // Translate -Dfoo#bar into -Dfoo=bar.
1010       TranslateDArg(A, *DAL, Opts);
1011     } else if (A->getOption().matches(options::OPT__SLASH_permissive)) {
1012       // Expand /permissive
1013       TranslatePermissive(A, *DAL, Opts);
1014     } else if (A->getOption().matches(options::OPT__SLASH_permissive_)) {
1015       // Expand /permissive-
1016       TranslatePermissiveMinus(A, *DAL, Opts);
1017     } else if (OFK != Action::OFK_HIP) {
1018       // HIP Toolchain translates input args by itself.
1019       DAL->append(A);
1020     }
1021   }
1022 
1023   return DAL;
1024 }
1025 
1026 void MSVCToolChain::addClangTargetOptions(
1027     const ArgList &DriverArgs, ArgStringList &CC1Args,
1028     Action::OffloadKind DeviceOffloadKind) const {
1029   // MSVC STL kindly allows removing all usages of typeid by defining
1030   // _HAS_STATIC_RTTI to 0. Do so, when compiling with -fno-rtti
1031   if (DriverArgs.hasFlag(options::OPT_fno_rtti, options::OPT_frtti,
1032                          /*Default=*/false))
1033     CC1Args.push_back("-D_HAS_STATIC_RTTI=0");
1034 
1035   if (Arg *A = DriverArgs.getLastArgNoClaim(options::OPT_marm64x))
1036     A->ignoreTargetSpecific();
1037 }
1038