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