1 //===-- MSVC.cpp - MSVC ToolChain Implementations -------------------------===//
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
7 //===----------------------------------------------------------------------===//
10 #include "CommonArgs.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"
34 #define WIN32_LEAN_AND_MEAN
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
;
48 static bool canExecute(llvm::vfs::FileSystem
&VFS
, StringRef Path
) {
49 auto Status
= VFS
.status(Path
);
52 return (Status
->getPermissions() & llvm::sys::fs::perms::all_exe
) != 0;
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
,
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
);
68 void visualstudio::Linker::ConstructJob(Compilation
&C
, const JobAction
&JA
,
69 const InputInfo
&Output
,
70 const InputInfoList
&Inputs
,
72 const char *LinkingOutput
) const {
73 ArgStringList CmdArgs
;
75 auto &TC
= static_cast<const toolchains::MSVCToolChain
&>(getToolChain());
77 assert((Output
.isFilename() || Output
.isNothing()) && "invalid output");
78 if (Output
.isFilename())
80 Args
.MakeArgString(std::string("-out:") + Output
.getFilename()));
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");
87 if (!Args
.hasArg(options::OPT_nostdlib
, options::OPT_nostartfiles
) &&
88 !C
.getDriver().IsCLMode() && !C
.getDriver().IsFlangMode()) {
89 CmdArgs
.push_back("-defaultlib:libcmt");
90 CmdArgs
.push_back("-defaultlib:oldnames");
93 // If the VC environment hasn't been configured (perhaps because the user
94 // did not run vcvarsall), try to build a consistent link environment. If
95 // the environment variable is set however, assume the user knows what
96 // they're doing. If the user passes /vctoolsdir or /winsdkdir, trust that
98 if (const Arg
*A
= Args
.getLastArg(options::OPT__SLASH_diasdkdir
,
99 options::OPT__SLASH_winsysroot
)) {
100 // cl.exe doesn't find the DIA SDK automatically, so this too requires
101 // explicit flags and doesn't automatically look in "DIA SDK" relative
102 // to the path we found for VCToolChainPath.
103 llvm::SmallString
<128> DIAPath(A
->getValue());
104 if (A
->getOption().getID() == options::OPT__SLASH_winsysroot
)
105 llvm::sys::path::append(DIAPath
, "DIA SDK");
107 // The DIA SDK always uses the legacy vc arch, even in new MSVC versions.
108 llvm::sys::path::append(DIAPath
, "lib",
109 llvm::archToLegacyVCArch(TC
.getArch()));
110 CmdArgs
.push_back(Args
.MakeArgString(Twine("-libpath:") + DIAPath
));
112 if (!llvm::sys::Process::GetEnv("LIB") ||
113 Args
.getLastArg(options::OPT__SLASH_vctoolsdir
,
114 options::OPT__SLASH_winsysroot
)) {
115 CmdArgs
.push_back(Args
.MakeArgString(
117 TC
.getSubDirectoryPath(llvm::SubDirectoryType::Lib
)));
118 CmdArgs
.push_back(Args
.MakeArgString(
120 TC
.getSubDirectoryPath(llvm::SubDirectoryType::Lib
, "atlmfc")));
122 if (!llvm::sys::Process::GetEnv("LIB") ||
123 Args
.getLastArg(options::OPT__SLASH_winsdkdir
,
124 options::OPT__SLASH_winsysroot
)) {
125 if (TC
.useUniversalCRT()) {
126 std::string UniversalCRTLibPath
;
127 if (TC
.getUniversalCRTLibraryPath(Args
, UniversalCRTLibPath
))
129 Args
.MakeArgString(Twine("-libpath:") + UniversalCRTLibPath
));
131 std::string WindowsSdkLibPath
;
132 if (TC
.getWindowsSDKLibraryPath(Args
, WindowsSdkLibPath
))
134 Args
.MakeArgString(std::string("-libpath:") + WindowsSdkLibPath
));
137 if (!C
.getDriver().IsCLMode() && Args
.hasArg(options::OPT_L
))
138 for (const auto &LibPath
: Args
.getAllArgValues(options::OPT_L
))
139 CmdArgs
.push_back(Args
.MakeArgString("-libpath:" + LibPath
));
141 if (C
.getDriver().IsFlangMode() &&
142 !Args
.hasArg(options::OPT_nostdlib
, options::OPT_nodefaultlibs
)) {
143 addFortranRuntimeLibraryPath(TC
, Args
, CmdArgs
);
144 addFortranRuntimeLibs(TC
, Args
, CmdArgs
);
146 // Inform the MSVC linker that we're generating a console application, i.e.
147 // one with `main` as the "user-defined" entry point. The `main` function is
148 // defined in flang's runtime libraries.
149 CmdArgs
.push_back("/subsystem:console");
152 // Add the compiler-rt library directories to libpath if they exist to help
153 // the linker find the various sanitizer, builtin, and profiling runtimes.
154 for (const auto &LibPath
: TC
.getLibraryPaths()) {
155 if (TC
.getVFS().exists(LibPath
))
156 CmdArgs
.push_back(Args
.MakeArgString("-libpath:" + LibPath
));
158 auto CRTPath
= TC
.getCompilerRTPath();
159 if (TC
.getVFS().exists(CRTPath
))
160 CmdArgs
.push_back(Args
.MakeArgString("-libpath:" + CRTPath
));
162 CmdArgs
.push_back("-nologo");
164 if (Args
.hasArg(options::OPT_g_Group
, options::OPT__SLASH_Z7
))
165 CmdArgs
.push_back("-debug");
167 // If we specify /hotpatch, let the linker add padding in front of each
168 // function, like MSVC does.
169 if (Args
.hasArg(options::OPT_fms_hotpatch
, options::OPT__SLASH_hotpatch
))
170 CmdArgs
.push_back("-functionpadmin");
172 // Pass on /Brepro if it was passed to the compiler.
173 // Note that /Brepro maps to -mno-incremental-linker-compatible.
174 bool DefaultIncrementalLinkerCompatible
=
175 C
.getDefaultToolChain().getTriple().isWindowsMSVCEnvironment();
176 if (!Args
.hasFlag(options::OPT_mincremental_linker_compatible
,
177 options::OPT_mno_incremental_linker_compatible
,
178 DefaultIncrementalLinkerCompatible
))
179 CmdArgs
.push_back("-Brepro");
181 bool DLL
= Args
.hasArg(options::OPT__SLASH_LD
, options::OPT__SLASH_LDd
,
182 options::OPT_shared
);
184 CmdArgs
.push_back(Args
.MakeArgString("-dll"));
186 SmallString
<128> ImplibName(Output
.getFilename());
187 llvm::sys::path::replace_extension(ImplibName
, "lib");
188 CmdArgs
.push_back(Args
.MakeArgString(std::string("-implib:") + ImplibName
));
191 if (TC
.getSanitizerArgs(Args
).needsFuzzer()) {
192 if (!Args
.hasArg(options::OPT_shared
))
194 Args
.MakeArgString(std::string("-wholearchive:") +
195 TC
.getCompilerRTArgString(Args
, "fuzzer")));
196 CmdArgs
.push_back(Args
.MakeArgString("-debug"));
197 // Prevent the linker from padding sections we use for instrumentation
199 CmdArgs
.push_back(Args
.MakeArgString("-incremental:no"));
202 if (TC
.getSanitizerArgs(Args
).needsAsanRt()) {
203 CmdArgs
.push_back(Args
.MakeArgString("-debug"));
204 CmdArgs
.push_back(Args
.MakeArgString("-incremental:no"));
205 CmdArgs
.push_back(TC
.getCompilerRTArgString(Args
, "asan_dynamic"));
206 auto defines
= Args
.getAllArgValues(options::OPT_D
);
207 if (Args
.hasArg(options::OPT__SLASH_MD
, options::OPT__SLASH_MDd
) ||
208 find(begin(defines
), end(defines
), "_DLL") != end(defines
)) {
209 // Make sure the dynamic runtime thunk is not optimized out at link time
210 // to ensure proper SEH handling.
211 CmdArgs
.push_back(Args
.MakeArgString(
212 TC
.getArch() == llvm::Triple::x86
213 ? "-include:___asan_seh_interceptor"
214 : "-include:__asan_seh_interceptor"));
215 // Make sure the linker consider all object files from the dynamic runtime
217 CmdArgs
.push_back(Args
.MakeArgString(
218 std::string("-wholearchive:") +
219 TC
.getCompilerRT(Args
, "asan_dynamic_runtime_thunk")));
221 // Make sure the linker consider all object files from the static runtime
223 CmdArgs
.push_back(Args
.MakeArgString(
224 std::string("-wholearchive:") +
225 TC
.getCompilerRT(Args
, "asan_static_runtime_thunk")));
229 Args
.AddAllArgValues(CmdArgs
, options::OPT__SLASH_link
);
231 // Control Flow Guard checks
232 for (const Arg
*A
: Args
.filtered(options::OPT__SLASH_guard
)) {
233 StringRef GuardArgs
= A
->getValue();
234 if (GuardArgs
.equals_insensitive("cf") ||
235 GuardArgs
.equals_insensitive("cf,nochecks")) {
236 // MSVC doesn't yet support the "nochecks" modifier.
237 CmdArgs
.push_back("-guard:cf");
238 } else if (GuardArgs
.equals_insensitive("cf-")) {
239 CmdArgs
.push_back("-guard:cf-");
240 } else if (GuardArgs
.equals_insensitive("ehcont")) {
241 CmdArgs
.push_back("-guard:ehcont");
242 } else if (GuardArgs
.equals_insensitive("ehcont-")) {
243 CmdArgs
.push_back("-guard:ehcont-");
247 if (Args
.hasFlag(options::OPT_fopenmp
, options::OPT_fopenmp_EQ
,
248 options::OPT_fno_openmp
, false)) {
249 CmdArgs
.push_back("-nodefaultlib:vcomp.lib");
250 CmdArgs
.push_back("-nodefaultlib:vcompd.lib");
251 CmdArgs
.push_back(Args
.MakeArgString(std::string("-libpath:") +
252 TC
.getDriver().Dir
+ "/../lib"));
253 switch (TC
.getDriver().getOpenMPRuntime(Args
)) {
254 case Driver::OMPRT_OMP
:
255 CmdArgs
.push_back("-defaultlib:libomp.lib");
257 case Driver::OMPRT_IOMP5
:
258 CmdArgs
.push_back("-defaultlib:libiomp5md.lib");
260 case Driver::OMPRT_GOMP
:
262 case Driver::OMPRT_Unknown
:
263 // Already diagnosed.
268 // Add compiler-rt lib in case if it was explicitly
269 // specified as an argument for --rtlib option.
270 if (!Args
.hasArg(options::OPT_nostdlib
)) {
271 AddRunTimeLibs(TC
, TC
.getDriver(), CmdArgs
, Args
);
275 Args
.getLastArgValue(options::OPT_fuse_ld_EQ
, CLANG_DEFAULT_LINKER
);
278 // We need to translate 'lld' into 'lld-link'.
279 else if (Linker
.equals_insensitive("lld"))
282 if (Linker
== "lld-link") {
283 for (Arg
*A
: Args
.filtered(options::OPT_vfsoverlay
))
285 Args
.MakeArgString(std::string("/vfsoverlay:") + A
->getValue()));
287 if (C
.getDriver().isUsingLTO() &&
288 Args
.hasFlag(options::OPT_gsplit_dwarf
, options::OPT_gno_split_dwarf
,
290 CmdArgs
.push_back(Args
.MakeArgString(Twine("/dwodir:") +
291 Output
.getFilename() + "_dwo"));
294 // Add filenames, libraries, and other linker inputs.
295 for (const auto &Input
: Inputs
) {
296 if (Input
.isFilename()) {
297 CmdArgs
.push_back(Input
.getFilename());
301 const Arg
&A
= Input
.getInputArg();
303 // Render -l options differently for the MSVC linker.
304 if (A
.getOption().matches(options::OPT_l
)) {
305 StringRef Lib
= A
.getValue();
306 const char *LinkLibArg
;
307 if (Lib
.ends_with(".lib"))
308 LinkLibArg
= Args
.MakeArgString(Lib
);
310 LinkLibArg
= Args
.MakeArgString(Lib
+ ".lib");
311 CmdArgs
.push_back(LinkLibArg
);
315 // Otherwise, this is some other kind of linker input option like -Wl, -z,
316 // or -L. Render it, even if MSVC doesn't understand it.
317 A
.renderAsInput(Args
, CmdArgs
);
320 addHIPRuntimeLibArgs(TC
, C
, Args
, CmdArgs
);
322 TC
.addProfileRTLibs(Args
, CmdArgs
);
324 std::vector
<const char *> Environment
;
326 // We need to special case some linker paths. In the case of the regular msvc
327 // linker, we need to use a special search algorithm.
328 llvm::SmallString
<128> linkPath
;
329 if (Linker
.equals_insensitive("link")) {
330 // If we're using the MSVC linker, it's not sufficient to just use link
331 // from the program PATH, because other environments like GnuWin32 install
332 // their own link.exe which may come first.
333 linkPath
= FindVisualStudioExecutable(TC
, "link.exe");
335 if (!TC
.FoundMSVCInstall() && !canExecute(TC
.getVFS(), linkPath
)) {
336 llvm::SmallString
<128> ClPath
;
337 ClPath
= TC
.GetProgramPath("cl.exe");
338 if (canExecute(TC
.getVFS(), ClPath
)) {
339 linkPath
= llvm::sys::path::parent_path(ClPath
);
340 llvm::sys::path::append(linkPath
, "link.exe");
341 if (!canExecute(TC
.getVFS(), linkPath
))
342 C
.getDriver().Diag(clang::diag::warn_drv_msvc_not_found
);
344 C
.getDriver().Diag(clang::diag::warn_drv_msvc_not_found
);
348 // Clang handles passing the proper asan libs to the linker, which goes
349 // against link.exe's /INFERASANLIBS which automatically finds asan libs.
350 if (TC
.getSanitizerArgs(Args
).needsAsanRt())
351 CmdArgs
.push_back("/INFERASANLIBS:NO");
354 // When cross-compiling with VS2017 or newer, link.exe expects to have
355 // its containing bin directory at the top of PATH, followed by the
356 // native target bin directory.
357 // e.g. when compiling for x86 on an x64 host, PATH should start with:
358 // /bin/Hostx64/x86;/bin/Hostx64/x64
359 // This doesn't attempt to handle llvm::ToolsetLayout::DevDivInternal.
360 if (TC
.getIsVS2017OrNewer() &&
361 llvm::Triple(llvm::sys::getProcessTriple()).getArch() != TC
.getArch()) {
362 auto HostArch
= llvm::Triple(llvm::sys::getProcessTriple()).getArch();
365 std::unique_ptr
<wchar_t[], decltype(&FreeEnvironmentStringsW
)>(
366 GetEnvironmentStringsW(), FreeEnvironmentStringsW
);
368 goto SkipSettingEnvironment
;
371 size_t EnvBlockLen
= 0;
372 while (EnvBlockWide
[EnvBlockLen
] != L
'\0') {
374 EnvBlockLen
+= std::wcslen(&EnvBlockWide
[EnvBlockLen
]) +
375 1 /*string null-terminator*/;
377 ++EnvBlockLen
; // add the block null-terminator
379 std::string EnvBlock
;
380 if (!llvm::convertUTF16ToUTF8String(
381 llvm::ArrayRef
<char>(reinterpret_cast<char *>(EnvBlockWide
.get()),
382 EnvBlockLen
* sizeof(EnvBlockWide
[0])),
384 goto SkipSettingEnvironment
;
386 Environment
.reserve(EnvCount
);
388 // Now loop over each string in the block and copy them into the
389 // environment vector, adjusting the PATH variable as needed when we
391 for (const char *Cursor
= EnvBlock
.data(); *Cursor
!= '\0';) {
392 llvm::StringRef
EnvVar(Cursor
);
393 if (EnvVar
.starts_with_insensitive("path=")) {
394 constexpr size_t PrefixLen
= 5; // strlen("path=")
395 Environment
.push_back(Args
.MakeArgString(
396 EnvVar
.substr(0, PrefixLen
) +
397 TC
.getSubDirectoryPath(llvm::SubDirectoryType::Bin
) +
398 llvm::Twine(llvm::sys::EnvPathSeparator
) +
399 TC
.getSubDirectoryPath(llvm::SubDirectoryType::Bin
, HostArch
) +
400 (EnvVar
.size() > PrefixLen
401 ? llvm::Twine(llvm::sys::EnvPathSeparator
) +
402 EnvVar
.substr(PrefixLen
)
405 Environment
.push_back(Args
.MakeArgString(EnvVar
));
407 Cursor
+= EnvVar
.size() + 1 /*null-terminator*/;
410 SkipSettingEnvironment
:;
413 linkPath
= TC
.GetProgramPath(Linker
.str().c_str());
416 auto LinkCmd
= std::make_unique
<Command
>(
417 JA
, *this, ResponseFileSupport::AtFileUTF16(),
418 Args
.MakeArgString(linkPath
), CmdArgs
, Inputs
, Output
);
419 if (!Environment
.empty())
420 LinkCmd
->setEnvironment(Environment
);
421 C
.addCommand(std::move(LinkCmd
));
424 MSVCToolChain::MSVCToolChain(const Driver
&D
, const llvm::Triple
&Triple
,
426 : ToolChain(D
, Triple
, Args
), CudaInstallation(D
, Triple
, Args
),
427 RocmInstallation(D
, Triple
, Args
) {
428 getProgramPaths().push_back(getDriver().Dir
);
430 std::optional
<llvm::StringRef
> VCToolsDir
, VCToolsVersion
;
431 if (Arg
*A
= Args
.getLastArg(options::OPT__SLASH_vctoolsdir
))
432 VCToolsDir
= A
->getValue();
433 if (Arg
*A
= Args
.getLastArg(options::OPT__SLASH_vctoolsversion
))
434 VCToolsVersion
= A
->getValue();
435 if (Arg
*A
= Args
.getLastArg(options::OPT__SLASH_winsdkdir
))
436 WinSdkDir
= A
->getValue();
437 if (Arg
*A
= Args
.getLastArg(options::OPT__SLASH_winsdkversion
))
438 WinSdkVersion
= A
->getValue();
439 if (Arg
*A
= Args
.getLastArg(options::OPT__SLASH_winsysroot
))
440 WinSysRoot
= A
->getValue();
442 // Check the command line first, that's the user explicitly telling us what to
443 // use. Check the environment next, in case we're being invoked from a VS
444 // command prompt. Failing that, just try to find the newest Visual Studio
445 // version we can and use its default VC toolchain.
446 llvm::findVCToolChainViaCommandLine(getVFS(), VCToolsDir
, VCToolsVersion
,
447 WinSysRoot
, VCToolChainPath
, VSLayout
) ||
448 llvm::findVCToolChainViaEnvironment(getVFS(), VCToolChainPath
,
450 llvm::findVCToolChainViaSetupConfig(getVFS(), VCToolsVersion
,
451 VCToolChainPath
, VSLayout
) ||
452 llvm::findVCToolChainViaRegistry(VCToolChainPath
, VSLayout
);
455 Tool
*MSVCToolChain::buildLinker() const {
456 return new tools::visualstudio::Linker(*this);
459 Tool
*MSVCToolChain::buildAssembler() const {
460 if (getTriple().isOSBinFormatMachO())
461 return new tools::darwin::Assembler(*this);
462 getDriver().Diag(clang::diag::err_no_external_assembler
);
466 ToolChain::UnwindTableLevel
467 MSVCToolChain::getDefaultUnwindTableLevel(const ArgList
&Args
) const {
468 // Don't emit unwind tables by default for MachO targets.
469 if (getTriple().isOSBinFormatMachO())
470 return UnwindTableLevel::None
;
472 // All non-x86_32 Windows targets require unwind tables. However, LLVM
473 // doesn't know how to generate them for all targets, so only enable
474 // the ones that are actually implemented.
475 if (getArch() == llvm::Triple::x86_64
|| getArch() == llvm::Triple::arm
||
476 getArch() == llvm::Triple::thumb
|| getArch() == llvm::Triple::aarch64
)
477 return UnwindTableLevel::Asynchronous
;
479 return UnwindTableLevel::None
;
482 bool MSVCToolChain::isPICDefault() const {
483 return getArch() == llvm::Triple::x86_64
||
484 getArch() == llvm::Triple::aarch64
;
487 bool MSVCToolChain::isPIEDefault(const llvm::opt::ArgList
&Args
) const {
491 bool MSVCToolChain::isPICDefaultForced() const {
492 return getArch() == llvm::Triple::x86_64
||
493 getArch() == llvm::Triple::aarch64
;
496 void MSVCToolChain::AddCudaIncludeArgs(const ArgList
&DriverArgs
,
497 ArgStringList
&CC1Args
) const {
498 CudaInstallation
->AddCudaIncludeArgs(DriverArgs
, CC1Args
);
501 void MSVCToolChain::AddHIPIncludeArgs(const ArgList
&DriverArgs
,
502 ArgStringList
&CC1Args
) const {
503 RocmInstallation
->AddHIPIncludeArgs(DriverArgs
, CC1Args
);
506 void MSVCToolChain::AddHIPRuntimeLibArgs(const ArgList
&Args
,
507 ArgStringList
&CmdArgs
) const {
508 CmdArgs
.append({Args
.MakeArgString(StringRef("-libpath:") +
509 RocmInstallation
->getLibPath()),
513 void MSVCToolChain::printVerboseInfo(raw_ostream
&OS
) const {
514 CudaInstallation
->print(OS
);
515 RocmInstallation
->print(OS
);
519 MSVCToolChain::getSubDirectoryPath(llvm::SubDirectoryType Type
,
520 llvm::StringRef SubdirParent
) const {
521 return llvm::getSubDirectoryPath(Type
, VSLayout
, VCToolChainPath
, getArch(),
526 MSVCToolChain::getSubDirectoryPath(llvm::SubDirectoryType Type
,
527 llvm::Triple::ArchType TargetArch
) const {
528 return llvm::getSubDirectoryPath(Type
, VSLayout
, VCToolChainPath
, TargetArch
,
532 // Find the most recent version of Universal CRT or Windows 10 SDK.
533 // vcvarsqueryregistry.bat from Visual Studio 2015 sorts entries in the include
534 // directory by name and uses the last one of the list.
535 // So we compare entry names lexicographically to find the greatest one.
536 // Gets the library path required to link against the Windows SDK.
537 bool MSVCToolChain::getWindowsSDKLibraryPath(const ArgList
&Args
,
538 std::string
&path
) const {
541 std::string windowsSDKIncludeVersion
;
542 std::string windowsSDKLibVersion
;
545 if (!llvm::getWindowsSDKDir(getVFS(), WinSdkDir
, WinSdkVersion
, WinSysRoot
,
546 sdkPath
, sdkMajor
, windowsSDKIncludeVersion
,
547 windowsSDKLibVersion
))
550 llvm::SmallString
<128> libPath(sdkPath
);
551 llvm::sys::path::append(libPath
, "Lib");
553 if (!(WinSdkDir
.has_value() || WinSysRoot
.has_value()) &&
554 WinSdkVersion
.has_value())
555 windowsSDKLibVersion
= *WinSdkVersion
;
557 llvm::sys::path::append(libPath
, windowsSDKLibVersion
, "um");
558 return llvm::appendArchToWindowsSDKLibPath(sdkMajor
, libPath
, getArch(),
562 bool MSVCToolChain::useUniversalCRT() const {
563 return llvm::useUniversalCRT(VSLayout
, VCToolChainPath
, getArch(), getVFS());
566 bool MSVCToolChain::getUniversalCRTLibraryPath(const ArgList
&Args
,
567 std::string
&Path
) const {
568 std::string UniversalCRTSdkPath
;
569 std::string UCRTVersion
;
572 if (!llvm::getUniversalCRTSdkDir(getVFS(), WinSdkDir
, WinSdkVersion
,
573 WinSysRoot
, UniversalCRTSdkPath
,
577 if (!(WinSdkDir
.has_value() || WinSysRoot
.has_value()) &&
578 WinSdkVersion
.has_value())
579 UCRTVersion
= *WinSdkVersion
;
581 StringRef ArchName
= llvm::archToWindowsSDKArch(getArch());
582 if (ArchName
.empty())
585 llvm::SmallString
<128> LibPath(UniversalCRTSdkPath
);
586 llvm::sys::path::append(LibPath
, "Lib", UCRTVersion
, "ucrt", ArchName
);
588 Path
= std::string(LibPath
);
592 static VersionTuple
getMSVCVersionFromExe(const std::string
&BinDir
) {
593 VersionTuple Version
;
595 SmallString
<128> ClExe(BinDir
);
596 llvm::sys::path::append(ClExe
, "cl.exe");
598 std::wstring ClExeWide
;
599 if (!llvm::ConvertUTF8toWide(ClExe
.c_str(), ClExeWide
))
602 const DWORD VersionSize
= ::GetFileVersionInfoSizeW(ClExeWide
.c_str(),
604 if (VersionSize
== 0)
607 SmallVector
<uint8_t, 4 * 1024> VersionBlock(VersionSize
);
608 if (!::GetFileVersionInfoW(ClExeWide
.c_str(), 0, VersionSize
,
609 VersionBlock
.data()))
612 VS_FIXEDFILEINFO
*FileInfo
= nullptr;
613 UINT FileInfoSize
= 0;
614 if (!::VerQueryValueW(VersionBlock
.data(), L
"\\",
615 reinterpret_cast<LPVOID
*>(&FileInfo
), &FileInfoSize
) ||
616 FileInfoSize
< sizeof(*FileInfo
))
619 const unsigned Major
= (FileInfo
->dwFileVersionMS
>> 16) & 0xFFFF;
620 const unsigned Minor
= (FileInfo
->dwFileVersionMS
) & 0xFFFF;
621 const unsigned Micro
= (FileInfo
->dwFileVersionLS
>> 16) & 0xFFFF;
623 Version
= VersionTuple(Major
, Minor
, Micro
);
628 void MSVCToolChain::AddSystemIncludeWithSubfolder(
629 const ArgList
&DriverArgs
, ArgStringList
&CC1Args
,
630 const std::string
&folder
, const Twine
&subfolder1
, const Twine
&subfolder2
,
631 const Twine
&subfolder3
) const {
632 llvm::SmallString
<128> path(folder
);
633 llvm::sys::path::append(path
, subfolder1
, subfolder2
, subfolder3
);
634 addSystemInclude(DriverArgs
, CC1Args
, path
);
637 void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList
&DriverArgs
,
638 ArgStringList
&CC1Args
) const {
639 if (DriverArgs
.hasArg(options::OPT_nostdinc
))
642 if (!DriverArgs
.hasArg(options::OPT_nobuiltininc
)) {
643 AddSystemIncludeWithSubfolder(DriverArgs
, CC1Args
, getDriver().ResourceDir
,
647 // Add %INCLUDE%-like directories from the -imsvc flag.
648 for (const auto &Path
: DriverArgs
.getAllArgValues(options::OPT__SLASH_imsvc
))
649 addSystemInclude(DriverArgs
, CC1Args
, Path
);
651 auto AddSystemIncludesFromEnv
= [&](StringRef Var
) -> bool {
652 if (auto Val
= llvm::sys::Process::GetEnv(Var
)) {
653 SmallVector
<StringRef
, 8> Dirs
;
654 StringRef(*Val
).split(Dirs
, ";", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
656 addSystemIncludes(DriverArgs
, CC1Args
, Dirs
);
663 // Add %INCLUDE%-like dirs via /external:env: flags.
664 for (const auto &Var
:
665 DriverArgs
.getAllArgValues(options::OPT__SLASH_external_env
)) {
666 AddSystemIncludesFromEnv(Var
);
669 // Add DIA SDK include if requested.
670 if (const Arg
*A
= DriverArgs
.getLastArg(options::OPT__SLASH_diasdkdir
,
671 options::OPT__SLASH_winsysroot
)) {
672 // cl.exe doesn't find the DIA SDK automatically, so this too requires
673 // explicit flags and doesn't automatically look in "DIA SDK" relative
674 // to the path we found for VCToolChainPath.
675 llvm::SmallString
<128> DIASDKPath(A
->getValue());
676 if (A
->getOption().getID() == options::OPT__SLASH_winsysroot
)
677 llvm::sys::path::append(DIASDKPath
, "DIA SDK");
678 AddSystemIncludeWithSubfolder(DriverArgs
, CC1Args
, std::string(DIASDKPath
),
682 if (DriverArgs
.hasArg(options::OPT_nostdlibinc
))
685 // Honor %INCLUDE% and %EXTERNAL_INCLUDE%. It should have essential search
686 // paths set by vcvarsall.bat. Skip if the user expressly set a vctoolsdir.
687 if (!DriverArgs
.getLastArg(options::OPT__SLASH_vctoolsdir
,
688 options::OPT__SLASH_winsysroot
)) {
689 bool Found
= AddSystemIncludesFromEnv("INCLUDE");
690 Found
|= AddSystemIncludesFromEnv("EXTERNAL_INCLUDE");
695 // When built with access to the proper Windows APIs, try to actually find
696 // the correct include paths first.
697 if (!VCToolChainPath
.empty()) {
698 addSystemInclude(DriverArgs
, CC1Args
,
699 getSubDirectoryPath(llvm::SubDirectoryType::Include
));
702 getSubDirectoryPath(llvm::SubDirectoryType::Include
, "atlmfc"));
704 if (useUniversalCRT()) {
705 std::string UniversalCRTSdkPath
;
706 std::string UCRTVersion
;
707 if (llvm::getUniversalCRTSdkDir(getVFS(), WinSdkDir
, WinSdkVersion
,
708 WinSysRoot
, UniversalCRTSdkPath
,
710 if (!(WinSdkDir
.has_value() || WinSysRoot
.has_value()) &&
711 WinSdkVersion
.has_value())
712 UCRTVersion
= *WinSdkVersion
;
713 AddSystemIncludeWithSubfolder(DriverArgs
, CC1Args
, UniversalCRTSdkPath
,
714 "Include", UCRTVersion
, "ucrt");
718 std::string WindowsSDKDir
;
720 std::string windowsSDKIncludeVersion
;
721 std::string windowsSDKLibVersion
;
722 if (llvm::getWindowsSDKDir(getVFS(), WinSdkDir
, WinSdkVersion
, WinSysRoot
,
723 WindowsSDKDir
, major
, windowsSDKIncludeVersion
,
724 windowsSDKLibVersion
)) {
726 if (!(WinSdkDir
.has_value() || WinSysRoot
.has_value()) &&
727 WinSdkVersion
.has_value())
728 windowsSDKIncludeVersion
= windowsSDKLibVersion
= *WinSdkVersion
;
730 // Note: windowsSDKIncludeVersion is empty for SDKs prior to v10.
731 // Anyway, llvm::sys::path::append is able to manage it.
732 AddSystemIncludeWithSubfolder(DriverArgs
, CC1Args
, WindowsSDKDir
,
733 "Include", windowsSDKIncludeVersion
,
735 AddSystemIncludeWithSubfolder(DriverArgs
, CC1Args
, WindowsSDKDir
,
736 "Include", windowsSDKIncludeVersion
,
738 AddSystemIncludeWithSubfolder(DriverArgs
, CC1Args
, WindowsSDKDir
,
739 "Include", windowsSDKIncludeVersion
,
742 llvm::VersionTuple Tuple
;
743 if (!Tuple
.tryParse(windowsSDKIncludeVersion
) &&
744 Tuple
.getSubminor().value_or(0) >= 17134) {
745 AddSystemIncludeWithSubfolder(DriverArgs
, CC1Args
, WindowsSDKDir
,
746 "Include", windowsSDKIncludeVersion
,
751 AddSystemIncludeWithSubfolder(DriverArgs
, CC1Args
, WindowsSDKDir
,
760 // As a fallback, select default install paths.
761 // FIXME: Don't guess drives and paths like this on Windows.
762 const StringRef Paths
[] = {
763 "C:/Program Files/Microsoft Visual Studio 10.0/VC/include",
764 "C:/Program Files/Microsoft Visual Studio 9.0/VC/include",
765 "C:/Program Files/Microsoft Visual Studio 9.0/VC/PlatformSDK/Include",
766 "C:/Program Files/Microsoft Visual Studio 8/VC/include",
767 "C:/Program Files/Microsoft Visual Studio 8/VC/PlatformSDK/Include"
769 addSystemIncludes(DriverArgs
, CC1Args
, Paths
);
773 void MSVCToolChain::AddClangCXXStdlibIncludeArgs(const ArgList
&DriverArgs
,
774 ArgStringList
&CC1Args
) const {
775 // FIXME: There should probably be logic here to find libc++ on Windows.
778 VersionTuple
MSVCToolChain::computeMSVCVersion(const Driver
*D
,
779 const ArgList
&Args
) const {
780 bool IsWindowsMSVC
= getTriple().isWindowsMSVCEnvironment();
781 VersionTuple MSVT
= ToolChain::computeMSVCVersion(D
, Args
);
783 MSVT
= getTriple().getEnvironmentVersion();
784 if (MSVT
.empty() && IsWindowsMSVC
)
786 getMSVCVersionFromExe(getSubDirectoryPath(llvm::SubDirectoryType::Bin
));
788 Args
.hasFlag(options::OPT_fms_extensions
, options::OPT_fno_ms_extensions
,
790 // -fms-compatibility-version=19.33 is default, aka 2022, 17.3
791 // NOTE: when changing this value, also update
792 // clang/docs/CommandGuide/clang.rst and clang/docs/UsersManual.rst
794 MSVT
= VersionTuple(19, 33);
800 MSVCToolChain::ComputeEffectiveClangTriple(const ArgList
&Args
,
801 types::ID InputType
) const {
802 // The MSVC version doesn't care about the architecture, even though it
803 // may look at the triple internally.
804 VersionTuple MSVT
= computeMSVCVersion(/*D=*/nullptr, Args
);
805 MSVT
= VersionTuple(MSVT
.getMajor(), MSVT
.getMinor().value_or(0),
806 MSVT
.getSubminor().value_or(0));
808 // For the rest of the triple, however, a computed architecture name may
810 llvm::Triple
Triple(ToolChain::ComputeEffectiveClangTriple(Args
, InputType
));
811 if (Triple
.getEnvironment() == llvm::Triple::MSVC
) {
812 StringRef ObjFmt
= Triple
.getEnvironmentName().split('-').second
;
814 Triple
.setEnvironmentName((Twine("msvc") + MSVT
.getAsString()).str());
816 Triple
.setEnvironmentName(
817 (Twine("msvc") + MSVT
.getAsString() + Twine('-') + ObjFmt
).str());
819 return Triple
.getTriple();
822 SanitizerMask
MSVCToolChain::getSupportedSanitizers() const {
823 SanitizerMask Res
= ToolChain::getSupportedSanitizers();
824 Res
|= SanitizerKind::Address
;
825 Res
|= SanitizerKind::PointerCompare
;
826 Res
|= SanitizerKind::PointerSubtract
;
827 Res
|= SanitizerKind::Fuzzer
;
828 Res
|= SanitizerKind::FuzzerNoLink
;
829 Res
&= ~SanitizerKind::CFIMFCall
;
833 static void TranslateOptArg(Arg
*A
, llvm::opt::DerivedArgList
&DAL
,
834 bool SupportsForcingFramePointer
,
835 const char *ExpandChar
, const OptTable
&Opts
) {
836 assert(A
->getOption().matches(options::OPT__SLASH_O
));
838 StringRef OptStr
= A
->getValue();
839 for (size_t I
= 0, E
= OptStr
.size(); I
!= E
; ++I
) {
840 const char &OptChar
= *(OptStr
.data() + I
);
848 // Ignore /O[12xd] flags that aren't the last one on the command line.
849 // Only the last one gets expanded.
850 if (&OptChar
!= ExpandChar
) {
854 if (OptChar
== 'd') {
855 DAL
.AddFlagArg(A
, Opts
.getOption(options::OPT_O0
));
857 if (OptChar
== '1') {
858 DAL
.AddJoinedArg(A
, Opts
.getOption(options::OPT_O
), "s");
859 } else if (OptChar
== '2' || OptChar
== 'x') {
860 DAL
.AddFlagArg(A
, Opts
.getOption(options::OPT_fbuiltin
));
861 DAL
.AddJoinedArg(A
, Opts
.getOption(options::OPT_O
), "3");
863 if (SupportsForcingFramePointer
&&
864 !DAL
.hasArgNoClaim(options::OPT_fno_omit_frame_pointer
))
865 DAL
.AddFlagArg(A
, Opts
.getOption(options::OPT_fomit_frame_pointer
));
866 if (OptChar
== '1' || OptChar
== '2')
867 DAL
.AddFlagArg(A
, Opts
.getOption(options::OPT_ffunction_sections
));
871 if (I
+ 1 != E
&& isdigit(OptStr
[I
+ 1])) {
872 switch (OptStr
[I
+ 1]) {
874 DAL
.AddFlagArg(A
, Opts
.getOption(options::OPT_fno_inline
));
877 DAL
.AddFlagArg(A
, Opts
.getOption(options::OPT_finline_hint_functions
));
881 DAL
.AddFlagArg(A
, Opts
.getOption(options::OPT_finline_functions
));
891 if (I
+ 1 != E
&& OptStr
[I
+ 1] == '-') {
893 DAL
.AddFlagArg(A
, Opts
.getOption(options::OPT_fno_builtin
));
895 DAL
.AddFlagArg(A
, Opts
.getOption(options::OPT_fbuiltin
));
899 DAL
.AddJoinedArg(A
, Opts
.getOption(options::OPT_O
), "s");
902 DAL
.AddJoinedArg(A
, Opts
.getOption(options::OPT_O
), "3");
905 bool OmitFramePointer
= true;
906 if (I
+ 1 != E
&& OptStr
[I
+ 1] == '-') {
907 OmitFramePointer
= false;
910 if (SupportsForcingFramePointer
) {
911 if (OmitFramePointer
)
913 Opts
.getOption(options::OPT_fomit_frame_pointer
));
916 A
, Opts
.getOption(options::OPT_fno_omit_frame_pointer
));
918 // Don't warn about /Oy- in x86-64 builds (where
919 // SupportsForcingFramePointer is false). The flag having no effect
920 // there is a compiler-internal optimization, and people shouldn't have
921 // to special-case their build files for x86-64 clang-cl.
930 static void TranslateDArg(Arg
*A
, llvm::opt::DerivedArgList
&DAL
,
931 const OptTable
&Opts
) {
932 assert(A
->getOption().matches(options::OPT_D
));
934 StringRef Val
= A
->getValue();
935 size_t Hash
= Val
.find('#');
936 if (Hash
== StringRef::npos
|| Hash
> Val
.find('=')) {
941 std::string NewVal
= std::string(Val
);
943 DAL
.AddJoinedArg(A
, Opts
.getOption(options::OPT_D
), NewVal
);
946 static void TranslatePermissive(Arg
*A
, llvm::opt::DerivedArgList
&DAL
,
947 const OptTable
&Opts
) {
948 DAL
.AddFlagArg(A
, Opts
.getOption(options::OPT__SLASH_Zc_twoPhase_
));
949 DAL
.AddFlagArg(A
, Opts
.getOption(options::OPT_fno_operator_names
));
952 static void TranslatePermissiveMinus(Arg
*A
, llvm::opt::DerivedArgList
&DAL
,
953 const OptTable
&Opts
) {
954 DAL
.AddFlagArg(A
, Opts
.getOption(options::OPT__SLASH_Zc_twoPhase
));
955 DAL
.AddFlagArg(A
, Opts
.getOption(options::OPT_foperator_names
));
958 llvm::opt::DerivedArgList
*
959 MSVCToolChain::TranslateArgs(const llvm::opt::DerivedArgList
&Args
,
961 Action::OffloadKind OFK
) const {
962 DerivedArgList
*DAL
= new DerivedArgList(Args
.getBaseArgs());
963 const OptTable
&Opts
= getDriver().getOpts();
965 // /Oy and /Oy- don't have an effect on X86-64
966 bool SupportsForcingFramePointer
= getArch() != llvm::Triple::x86_64
;
968 // The -O[12xd] flag actually expands to several flags. We must desugar the
969 // flags so that options embedded can be negated. For example, the '-O2' flag
970 // enables '-Oy'. Expanding '-O2' into its constituent flags allows us to
971 // correctly handle '-O2 -Oy-' where the trailing '-Oy-' disables a single
974 // Note that this expansion logic only applies to the *last* of '[12xd]'.
976 // First step is to search for the character we'd like to expand.
977 const char *ExpandChar
= nullptr;
978 for (Arg
*A
: Args
.filtered(options::OPT__SLASH_O
)) {
979 StringRef OptStr
= A
->getValue();
980 for (size_t I
= 0, E
= OptStr
.size(); I
!= E
; ++I
) {
981 char OptChar
= OptStr
[I
];
982 char PrevChar
= I
> 0 ? OptStr
[I
- 1] : '0';
983 if (PrevChar
== 'b') {
984 // OptChar does not expand; it's an argument to the previous char.
987 if (OptChar
== '1' || OptChar
== '2' || OptChar
== 'x' || OptChar
== 'd')
988 ExpandChar
= OptStr
.data() + I
;
992 for (Arg
*A
: Args
) {
993 if (A
->getOption().matches(options::OPT__SLASH_O
)) {
994 // The -O flag actually takes an amalgam of other options. For example,
995 // '/Ogyb2' is equivalent to '/Og' '/Oy' '/Ob2'.
996 TranslateOptArg(A
, *DAL
, SupportsForcingFramePointer
, ExpandChar
, Opts
);
997 } else if (A
->getOption().matches(options::OPT_D
)) {
998 // Translate -Dfoo#bar into -Dfoo=bar.
999 TranslateDArg(A
, *DAL
, Opts
);
1000 } else if (A
->getOption().matches(options::OPT__SLASH_permissive
)) {
1001 // Expand /permissive
1002 TranslatePermissive(A
, *DAL
, Opts
);
1003 } else if (A
->getOption().matches(options::OPT__SLASH_permissive_
)) {
1004 // Expand /permissive-
1005 TranslatePermissiveMinus(A
, *DAL
, Opts
);
1006 } else if (OFK
!= Action::OFK_HIP
) {
1007 // HIP Toolchain translates input args by itself.
1015 void MSVCToolChain::addClangTargetOptions(
1016 const ArgList
&DriverArgs
, ArgStringList
&CC1Args
,
1017 Action::OffloadKind DeviceOffloadKind
) const {
1018 // MSVC STL kindly allows removing all usages of typeid by defining
1019 // _HAS_STATIC_RTTI to 0. Do so, when compiling with -fno-rtti
1020 if (DriverArgs
.hasFlag(options::OPT_fno_rtti
, options::OPT_frtti
,
1022 CC1Args
.push_back("-D_HAS_STATIC_RTTI=0");
1024 if (Arg
*A
= DriverArgs
.getLastArgNoClaim(options::OPT_marm64x
))
1025 A
->ignoreTargetSpecific();