[flang][cuda] Do not register global constants (#118582)
[llvm-project.git] / clang / lib / Driver / ToolChains / MSVC.cpp
blob80799d1e715f0755b87ebdf8b729a5f9610e3e72
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 //===----------------------------------------------------------------------===//
9 #include "MSVC.h"
10 #include "CommonArgs.h"
11 #include "Darwin.h"
12 #include "clang/Basic/CharInfo.h"
13 #include "clang/Basic/Version.h"
14 #include "clang/Config/config.h"
15 #include "clang/Driver/Compilation.h"
16 #include "clang/Driver/Driver.h"
17 #include "clang/Driver/DriverDiagnostic.h"
18 #include "clang/Driver/Options.h"
19 #include "clang/Driver/SanitizerArgs.h"
20 #include "llvm/ADT/StringExtras.h"
21 #include "llvm/Option/Arg.h"
22 #include "llvm/Option/ArgList.h"
23 #include "llvm/Support/ConvertUTF.h"
24 #include "llvm/Support/ErrorHandling.h"
25 #include "llvm/Support/FileSystem.h"
26 #include "llvm/Support/MemoryBuffer.h"
27 #include "llvm/Support/Path.h"
28 #include "llvm/Support/Process.h"
29 #include "llvm/Support/VirtualFileSystem.h"
30 #include "llvm/TargetParser/Host.h"
31 #include <cstdio>
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
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);
50 if (!Status)
51 return false;
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,
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);
68 void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
69 const InputInfo &Output,
70 const InputInfoList &Inputs,
71 const ArgList &Args,
72 const char *LinkingOutput) const {
73 ArgStringList CmdArgs;
75 auto &TC = static_cast<const toolchains::MSVCToolChain &>(getToolChain());
77 assert((Output.isFilename() || Output.isNothing()) && "invalid output");
78 if (Output.isFilename())
79 CmdArgs.push_back(
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
97 // over env vars.
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(
116 Twine("-libpath:") +
117 TC.getSubDirectoryPath(llvm::SubDirectoryType::Lib)));
118 CmdArgs.push_back(Args.MakeArgString(
119 Twine("-libpath:") +
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))
128 CmdArgs.push_back(
129 Args.MakeArgString(Twine("-libpath:") + UniversalCRTLibPath));
131 std::string WindowsSdkLibPath;
132 if (TC.getWindowsSDKLibraryPath(Args, WindowsSdkLibPath))
133 CmdArgs.push_back(
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);
183 if (DLL) {
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))
193 CmdArgs.push_back(
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
198 // arrays.
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
216 // thunk.
217 CmdArgs.push_back(Args.MakeArgString(
218 std::string("-wholearchive:") +
219 TC.getCompilerRT(Args, "asan_dynamic_runtime_thunk")));
220 } else {
221 // Make sure the linker consider all object files from the static runtime
222 // thunk.
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");
256 break;
257 case Driver::OMPRT_IOMP5:
258 CmdArgs.push_back("-defaultlib:libiomp5md.lib");
259 break;
260 case Driver::OMPRT_GOMP:
261 break;
262 case Driver::OMPRT_Unknown:
263 // Already diagnosed.
264 break;
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);
274 StringRef Linker =
275 Args.getLastArgValue(options::OPT_fuse_ld_EQ, CLANG_DEFAULT_LINKER);
276 if (Linker.empty())
277 Linker = "link";
278 // We need to translate 'lld' into 'lld-link'.
279 else if (Linker.equals_insensitive("lld"))
280 Linker = "lld-link";
282 if (Linker == "lld-link") {
283 for (Arg *A : Args.filtered(options::OPT_vfsoverlay))
284 CmdArgs.push_back(
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,
289 false))
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());
298 continue;
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);
309 else
310 LinkLibArg = Args.MakeArgString(Lib + ".lib");
311 CmdArgs.push_back(LinkLibArg);
312 continue;
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);
343 } else {
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");
353 #ifdef _WIN32
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();
364 auto EnvBlockWide =
365 std::unique_ptr<wchar_t[], decltype(&FreeEnvironmentStringsW)>(
366 GetEnvironmentStringsW(), FreeEnvironmentStringsW);
367 if (!EnvBlockWide)
368 goto SkipSettingEnvironment;
370 size_t EnvCount = 0;
371 size_t EnvBlockLen = 0;
372 while (EnvBlockWide[EnvBlockLen] != L'\0') {
373 ++EnvCount;
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])),
383 EnvBlock))
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
390 // find it.
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)
403 : "")));
404 } else {
405 Environment.push_back(Args.MakeArgString(EnvVar));
407 Cursor += EnvVar.size() + 1 /*null-terminator*/;
410 SkipSettingEnvironment:;
411 #endif
412 } else {
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,
425 const ArgList &Args)
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,
449 VSLayout) ||
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);
463 return nullptr;
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 {
488 return false;
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()),
510 "amdhip64.lib"});
513 void MSVCToolChain::printVerboseInfo(raw_ostream &OS) const {
514 CudaInstallation->print(OS);
515 RocmInstallation->print(OS);
518 std::string
519 MSVCToolChain::getSubDirectoryPath(llvm::SubDirectoryType Type,
520 llvm::StringRef SubdirParent) const {
521 return llvm::getSubDirectoryPath(Type, VSLayout, VCToolChainPath, getArch(),
522 SubdirParent);
525 std::string
526 MSVCToolChain::getSubDirectoryPath(llvm::SubDirectoryType Type,
527 llvm::Triple::ArchType TargetArch) const {
528 return llvm::getSubDirectoryPath(Type, VSLayout, VCToolChainPath, TargetArch,
529 "");
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 {
539 std::string sdkPath;
540 int sdkMajor = 0;
541 std::string windowsSDKIncludeVersion;
542 std::string windowsSDKLibVersion;
544 path.clear();
545 if (!llvm::getWindowsSDKDir(getVFS(), WinSdkDir, WinSdkVersion, WinSysRoot,
546 sdkPath, sdkMajor, windowsSDKIncludeVersion,
547 windowsSDKLibVersion))
548 return false;
550 llvm::SmallString<128> libPath(sdkPath);
551 llvm::sys::path::append(libPath, "Lib");
552 if (sdkMajor >= 10)
553 if (!(WinSdkDir.has_value() || WinSysRoot.has_value()) &&
554 WinSdkVersion.has_value())
555 windowsSDKLibVersion = *WinSdkVersion;
556 if (sdkMajor >= 8)
557 llvm::sys::path::append(libPath, windowsSDKLibVersion, "um");
558 return llvm::appendArchToWindowsSDKLibPath(sdkMajor, libPath, getArch(),
559 path);
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;
571 Path.clear();
572 if (!llvm::getUniversalCRTSdkDir(getVFS(), WinSdkDir, WinSdkVersion,
573 WinSysRoot, UniversalCRTSdkPath,
574 UCRTVersion))
575 return false;
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())
583 return false;
585 llvm::SmallString<128> LibPath(UniversalCRTSdkPath);
586 llvm::sys::path::append(LibPath, "Lib", UCRTVersion, "ucrt", ArchName);
588 Path = std::string(LibPath);
589 return true;
592 static VersionTuple getMSVCVersionFromExe(const std::string &BinDir) {
593 VersionTuple Version;
594 #ifdef _WIN32
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))
600 return Version;
602 const DWORD VersionSize = ::GetFileVersionInfoSizeW(ClExeWide.c_str(),
603 nullptr);
604 if (VersionSize == 0)
605 return Version;
607 SmallVector<uint8_t, 4 * 1024> VersionBlock(VersionSize);
608 if (!::GetFileVersionInfoW(ClExeWide.c_str(), 0, VersionSize,
609 VersionBlock.data()))
610 return Version;
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))
617 return Version;
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);
624 #endif
625 return Version;
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))
640 return;
642 if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
643 AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, getDriver().ResourceDir,
644 "include");
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);
655 if (!Dirs.empty()) {
656 addSystemIncludes(DriverArgs, CC1Args, Dirs);
657 return true;
660 return false;
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),
679 "include");
682 if (DriverArgs.hasArg(options::OPT_nostdlibinc))
683 return;
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");
691 if (Found)
692 return;
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));
700 addSystemInclude(
701 DriverArgs, CC1Args,
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,
709 UCRTVersion)) {
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;
719 int major = 0;
720 std::string windowsSDKIncludeVersion;
721 std::string windowsSDKLibVersion;
722 if (llvm::getWindowsSDKDir(getVFS(), WinSdkDir, WinSdkVersion, WinSysRoot,
723 WindowsSDKDir, major, windowsSDKIncludeVersion,
724 windowsSDKLibVersion)) {
725 if (major >= 10)
726 if (!(WinSdkDir.has_value() || WinSysRoot.has_value()) &&
727 WinSdkVersion.has_value())
728 windowsSDKIncludeVersion = windowsSDKLibVersion = *WinSdkVersion;
729 if (major >= 8) {
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,
734 "shared");
735 AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
736 "Include", windowsSDKIncludeVersion,
737 "um");
738 AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
739 "Include", windowsSDKIncludeVersion,
740 "winrt");
741 if (major >= 10) {
742 llvm::VersionTuple Tuple;
743 if (!Tuple.tryParse(windowsSDKIncludeVersion) &&
744 Tuple.getSubminor().value_or(0) >= 17134) {
745 AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
746 "Include", windowsSDKIncludeVersion,
747 "cppwinrt");
750 } else {
751 AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
752 "Include");
756 return;
759 #if defined(_WIN32)
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);
770 #endif
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);
782 if (MSVT.empty())
783 MSVT = getTriple().getEnvironmentVersion();
784 if (MSVT.empty() && IsWindowsMSVC)
785 MSVT =
786 getMSVCVersionFromExe(getSubDirectoryPath(llvm::SubDirectoryType::Bin));
787 if (MSVT.empty() &&
788 Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions,
789 IsWindowsMSVC)) {
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
793 // accordingly.
794 MSVT = VersionTuple(19, 33);
796 return MSVT;
799 std::string
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
809 // be needed.
810 llvm::Triple Triple(ToolChain::ComputeEffectiveClangTriple(Args, InputType));
811 if (Triple.getEnvironment() == llvm::Triple::MSVC) {
812 StringRef ObjFmt = Triple.getEnvironmentName().split('-').second;
813 if (ObjFmt.empty())
814 Triple.setEnvironmentName((Twine("msvc") + MSVT.getAsString()).str());
815 else
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;
830 return Res;
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);
841 switch (OptChar) {
842 default:
843 break;
844 case '1':
845 case '2':
846 case 'x':
847 case 'd':
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) {
851 A->claim();
852 break;
854 if (OptChar == 'd') {
855 DAL.AddFlagArg(A, Opts.getOption(options::OPT_O0));
856 } else {
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));
869 break;
870 case 'b':
871 if (I + 1 != E && isdigit(OptStr[I + 1])) {
872 switch (OptStr[I + 1]) {
873 case '0':
874 DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_inline));
875 break;
876 case '1':
877 DAL.AddFlagArg(A, Opts.getOption(options::OPT_finline_hint_functions));
878 break;
879 case '2':
880 case '3':
881 DAL.AddFlagArg(A, Opts.getOption(options::OPT_finline_functions));
882 break;
884 ++I;
886 break;
887 case 'g':
888 A->claim();
889 break;
890 case 'i':
891 if (I + 1 != E && OptStr[I + 1] == '-') {
892 ++I;
893 DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_builtin));
894 } else {
895 DAL.AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin));
897 break;
898 case 's':
899 DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "s");
900 break;
901 case 't':
902 DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "3");
903 break;
904 case 'y': {
905 bool OmitFramePointer = true;
906 if (I + 1 != E && OptStr[I + 1] == '-') {
907 OmitFramePointer = false;
908 ++I;
910 if (SupportsForcingFramePointer) {
911 if (OmitFramePointer)
912 DAL.AddFlagArg(A,
913 Opts.getOption(options::OPT_fomit_frame_pointer));
914 else
915 DAL.AddFlagArg(
916 A, Opts.getOption(options::OPT_fno_omit_frame_pointer));
917 } else {
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.
922 A->claim();
924 break;
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('=')) {
937 DAL.append(A);
938 return;
941 std::string NewVal = std::string(Val);
942 NewVal[Hash] = '=';
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,
960 StringRef BoundArch,
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
972 // aspect of '-O2'.
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.
985 continue;
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.
1008 DAL->append(A);
1012 return DAL;
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,
1021 /*Default=*/false))
1022 CC1Args.push_back("-D_HAS_STATIC_RTTI=0");
1024 if (Arg *A = DriverArgs.getLastArgNoClaim(options::OPT_marm64x))
1025 A->ignoreTargetSpecific();