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