xref: /freebsd/contrib/llvm-project/clang/lib/Driver/ToolChains/MinGW.cpp (revision aa1a8ff2d6dbc51ef058f46f3db5a8bb77967145)
1 //===--- MinGW.cpp - MinGWToolChain Implementation ------------------------===//
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 "MinGW.h"
10 #include "CommonArgs.h"
11 #include "clang/Config/config.h"
12 #include "clang/Driver/Compilation.h"
13 #include "clang/Driver/Driver.h"
14 #include "clang/Driver/DriverDiagnostic.h"
15 #include "clang/Driver/InputInfo.h"
16 #include "clang/Driver/Options.h"
17 #include "clang/Driver/SanitizerArgs.h"
18 #include "llvm/Option/ArgList.h"
19 #include "llvm/Support/FileSystem.h"
20 #include "llvm/Support/Path.h"
21 #include "llvm/Support/VirtualFileSystem.h"
22 #include <system_error>
23 
24 using namespace clang::diag;
25 using namespace clang::driver;
26 using namespace clang;
27 using namespace llvm::opt;
28 
29 /// MinGW Tools
30 void tools::MinGW::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
31                                            const InputInfo &Output,
32                                            const InputInfoList &Inputs,
33                                            const ArgList &Args,
34                                            const char *LinkingOutput) const {
35   claimNoWarnArgs(Args);
36   ArgStringList CmdArgs;
37 
38   if (getToolChain().getArch() == llvm::Triple::x86) {
39     CmdArgs.push_back("--32");
40   } else if (getToolChain().getArch() == llvm::Triple::x86_64) {
41     CmdArgs.push_back("--64");
42   }
43 
44   Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
45 
46   CmdArgs.push_back("-o");
47   CmdArgs.push_back(Output.getFilename());
48 
49   for (const auto &II : Inputs)
50     CmdArgs.push_back(II.getFilename());
51 
52   const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
53   C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
54                                          Exec, CmdArgs, Inputs, Output));
55 
56   if (Args.hasArg(options::OPT_gsplit_dwarf))
57     SplitDebugInfo(getToolChain(), C, *this, JA, Args, Output,
58                    SplitDebugName(JA, Args, Inputs[0], Output));
59 }
60 
61 void tools::MinGW::Linker::AddLibGCC(const ArgList &Args,
62                                      ArgStringList &CmdArgs) const {
63   if (Args.hasArg(options::OPT_mthreads))
64     CmdArgs.push_back("-lmingwthrd");
65   CmdArgs.push_back("-lmingw32");
66 
67   // Make use of compiler-rt if --rtlib option is used
68   ToolChain::RuntimeLibType RLT = getToolChain().GetRuntimeLibType(Args);
69   if (RLT == ToolChain::RLT_Libgcc) {
70     bool Static = Args.hasArg(options::OPT_static_libgcc) ||
71                   Args.hasArg(options::OPT_static);
72     bool Shared = Args.hasArg(options::OPT_shared);
73     bool CXX = getToolChain().getDriver().CCCIsCXX();
74 
75     if (Static || (!CXX && !Shared)) {
76       CmdArgs.push_back("-lgcc");
77       CmdArgs.push_back("-lgcc_eh");
78     } else {
79       CmdArgs.push_back("-lgcc_s");
80       CmdArgs.push_back("-lgcc");
81     }
82   } else {
83     AddRunTimeLibs(getToolChain(), getToolChain().getDriver(), CmdArgs, Args);
84   }
85 
86   CmdArgs.push_back("-lmoldname");
87   CmdArgs.push_back("-lmingwex");
88   for (auto Lib : Args.getAllArgValues(options::OPT_l))
89     if (StringRef(Lib).starts_with("msvcr") ||
90         StringRef(Lib).starts_with("ucrt") ||
91         StringRef(Lib).starts_with("crtdll"))
92       return;
93   CmdArgs.push_back("-lmsvcrt");
94 }
95 
96 void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA,
97                                         const InputInfo &Output,
98                                         const InputInfoList &Inputs,
99                                         const ArgList &Args,
100                                         const char *LinkingOutput) const {
101   const ToolChain &TC = getToolChain();
102   const Driver &D = TC.getDriver();
103   const SanitizerArgs &Sanitize = TC.getSanitizerArgs(Args);
104 
105   ArgStringList CmdArgs;
106 
107   // Silence warning for "clang -g foo.o -o foo"
108   Args.ClaimAllArgs(options::OPT_g_Group);
109   // and "clang -emit-llvm foo.o -o foo"
110   Args.ClaimAllArgs(options::OPT_emit_llvm);
111   // and for "clang -w foo.o -o foo". Other warning options are already
112   // handled somewhere else.
113   Args.ClaimAllArgs(options::OPT_w);
114 
115   if (!D.SysRoot.empty())
116     CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
117 
118   if (Args.hasArg(options::OPT_s))
119     CmdArgs.push_back("-s");
120 
121   CmdArgs.push_back("-m");
122   switch (TC.getArch()) {
123   case llvm::Triple::x86:
124     CmdArgs.push_back("i386pe");
125     break;
126   case llvm::Triple::x86_64:
127     CmdArgs.push_back("i386pep");
128     break;
129   case llvm::Triple::arm:
130   case llvm::Triple::thumb:
131     // FIXME: this is incorrect for WinCE
132     CmdArgs.push_back("thumb2pe");
133     break;
134   case llvm::Triple::aarch64:
135     CmdArgs.push_back("arm64pe");
136     break;
137   default:
138     D.Diag(diag::err_target_unknown_triple) << TC.getEffectiveTriple().str();
139   }
140 
141   Arg *SubsysArg =
142       Args.getLastArg(options::OPT_mwindows, options::OPT_mconsole);
143   if (SubsysArg && SubsysArg->getOption().matches(options::OPT_mwindows)) {
144     CmdArgs.push_back("--subsystem");
145     CmdArgs.push_back("windows");
146   } else if (SubsysArg &&
147              SubsysArg->getOption().matches(options::OPT_mconsole)) {
148     CmdArgs.push_back("--subsystem");
149     CmdArgs.push_back("console");
150   }
151 
152   if (Args.hasArg(options::OPT_mdll))
153     CmdArgs.push_back("--dll");
154   else if (Args.hasArg(options::OPT_shared))
155     CmdArgs.push_back("--shared");
156   if (Args.hasArg(options::OPT_static))
157     CmdArgs.push_back("-Bstatic");
158   else
159     CmdArgs.push_back("-Bdynamic");
160   if (Args.hasArg(options::OPT_mdll) || Args.hasArg(options::OPT_shared)) {
161     CmdArgs.push_back("-e");
162     if (TC.getArch() == llvm::Triple::x86)
163       CmdArgs.push_back("_DllMainCRTStartup@12");
164     else
165       CmdArgs.push_back("DllMainCRTStartup");
166     CmdArgs.push_back("--enable-auto-image-base");
167   }
168 
169   if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle))
170     CmdArgs.push_back("--no-demangle");
171 
172   if (!Args.hasFlag(options::OPT_fauto_import, options::OPT_fno_auto_import,
173                     true))
174     CmdArgs.push_back("--disable-auto-import");
175 
176   if (Arg *A = Args.getLastArg(options::OPT_mguard_EQ)) {
177     StringRef GuardArgs = A->getValue();
178     if (GuardArgs == "none")
179       CmdArgs.push_back("--no-guard-cf");
180     else if (GuardArgs == "cf" || GuardArgs == "cf-nochecks")
181       CmdArgs.push_back("--guard-cf");
182     else
183       D.Diag(diag::err_drv_unsupported_option_argument)
184           << A->getSpelling() << GuardArgs;
185   }
186 
187   CmdArgs.push_back("-o");
188   const char *OutputFile = Output.getFilename();
189   // GCC implicitly adds an .exe extension if it is given an output file name
190   // that lacks an extension.
191   // GCC used to do this only when the compiler itself runs on windows, but
192   // since GCC 8 it does the same when cross compiling as well.
193   if (!llvm::sys::path::has_extension(OutputFile)) {
194     CmdArgs.push_back(Args.MakeArgString(Twine(OutputFile) + ".exe"));
195     OutputFile = CmdArgs.back();
196   } else
197     CmdArgs.push_back(OutputFile);
198 
199   // FIXME: add -N, -n flags
200   Args.AddLastArg(CmdArgs, options::OPT_r);
201   Args.AddLastArg(CmdArgs, options::OPT_s);
202   Args.AddLastArg(CmdArgs, options::OPT_t);
203   Args.AddAllArgs(CmdArgs, options::OPT_u_Group);
204 
205   // Add asan_dynamic as the first import lib before other libs. This allows
206   // asan to be initialized as early as possible to increase its instrumentation
207   // coverage to include other user DLLs which has not been built with asan.
208   if (Sanitize.needsAsanRt() && !Args.hasArg(options::OPT_nostdlib) &&
209       !Args.hasArg(options::OPT_nodefaultlibs)) {
210     // MinGW always links against a shared MSVCRT.
211     CmdArgs.push_back(
212         TC.getCompilerRTArgString(Args, "asan_dynamic", ToolChain::FT_Shared));
213   }
214 
215   if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
216     if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_mdll)) {
217       CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("dllcrt2.o")));
218     } else {
219       if (Args.hasArg(options::OPT_municode))
220         CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crt2u.o")));
221       else
222         CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crt2.o")));
223     }
224     if (Args.hasArg(options::OPT_pg))
225       CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("gcrt2.o")));
226     CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtbegin.o")));
227   }
228 
229   Args.AddAllArgs(CmdArgs, options::OPT_L);
230   TC.AddFilePathLibArgs(Args, CmdArgs);
231 
232   // Add the compiler-rt library directories if they exist to help
233   // the linker find the various sanitizer, builtin, and profiling runtimes.
234   for (const auto &LibPath : TC.getLibraryPaths()) {
235     if (TC.getVFS().exists(LibPath))
236       CmdArgs.push_back(Args.MakeArgString("-L" + LibPath));
237   }
238   auto CRTPath = TC.getCompilerRTPath();
239   if (TC.getVFS().exists(CRTPath))
240     CmdArgs.push_back(Args.MakeArgString("-L" + CRTPath));
241 
242   AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);
243 
244   if (D.isUsingLTO()) {
245     assert(!Inputs.empty() && "Must have at least one input.");
246     addLTOOptions(TC, Args, CmdArgs, Output, Inputs[0],
247                   D.getLTOMode() == LTOK_Thin);
248   }
249 
250   if (C.getDriver().IsFlangMode()) {
251     addFortranRuntimeLibraryPath(TC, Args, CmdArgs);
252     addFortranRuntimeLibs(TC, Args, CmdArgs);
253   }
254 
255   // TODO: Add profile stuff here
256 
257   if (TC.ShouldLinkCXXStdlib(Args)) {
258     bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) &&
259                                !Args.hasArg(options::OPT_static);
260     if (OnlyLibstdcxxStatic)
261       CmdArgs.push_back("-Bstatic");
262     TC.AddCXXStdlibLibArgs(Args, CmdArgs);
263     if (OnlyLibstdcxxStatic)
264       CmdArgs.push_back("-Bdynamic");
265   }
266 
267   bool HasWindowsApp = false;
268   for (auto Lib : Args.getAllArgValues(options::OPT_l)) {
269     if (Lib == "windowsapp") {
270       HasWindowsApp = true;
271       break;
272     }
273   }
274 
275   if (!Args.hasArg(options::OPT_nostdlib)) {
276     if (!Args.hasArg(options::OPT_nodefaultlibs)) {
277       if (Args.hasArg(options::OPT_static))
278         CmdArgs.push_back("--start-group");
279 
280       if (Args.hasArg(options::OPT_fstack_protector) ||
281           Args.hasArg(options::OPT_fstack_protector_strong) ||
282           Args.hasArg(options::OPT_fstack_protector_all)) {
283         CmdArgs.push_back("-lssp_nonshared");
284         CmdArgs.push_back("-lssp");
285       }
286 
287       if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ,
288                        options::OPT_fno_openmp, false)) {
289         switch (TC.getDriver().getOpenMPRuntime(Args)) {
290         case Driver::OMPRT_OMP:
291           CmdArgs.push_back("-lomp");
292           break;
293         case Driver::OMPRT_IOMP5:
294           CmdArgs.push_back("-liomp5md");
295           break;
296         case Driver::OMPRT_GOMP:
297           CmdArgs.push_back("-lgomp");
298           break;
299         case Driver::OMPRT_Unknown:
300           // Already diagnosed.
301           break;
302         }
303       }
304 
305       AddLibGCC(Args, CmdArgs);
306 
307       if (Args.hasArg(options::OPT_pg))
308         CmdArgs.push_back("-lgmon");
309 
310       if (Args.hasArg(options::OPT_pthread))
311         CmdArgs.push_back("-lpthread");
312 
313       if (Sanitize.needsAsanRt()) {
314         // MinGW always links against a shared MSVCRT.
315         CmdArgs.push_back(TC.getCompilerRTArgString(Args, "asan_dynamic",
316                                                     ToolChain::FT_Shared));
317         CmdArgs.push_back(
318             TC.getCompilerRTArgString(Args, "asan_dynamic_runtime_thunk"));
319         CmdArgs.push_back("--require-defined");
320         CmdArgs.push_back(TC.getArch() == llvm::Triple::x86
321                               ? "___asan_seh_interceptor"
322                               : "__asan_seh_interceptor");
323         // Make sure the linker consider all object files from the dynamic
324         // runtime thunk.
325         CmdArgs.push_back("--whole-archive");
326         CmdArgs.push_back(
327             TC.getCompilerRTArgString(Args, "asan_dynamic_runtime_thunk"));
328         CmdArgs.push_back("--no-whole-archive");
329       }
330 
331       TC.addProfileRTLibs(Args, CmdArgs);
332 
333       if (!HasWindowsApp) {
334         // Add system libraries. If linking to libwindowsapp.a, that import
335         // library replaces all these and we shouldn't accidentally try to
336         // link to the normal desktop mode dlls.
337         if (Args.hasArg(options::OPT_mwindows)) {
338           CmdArgs.push_back("-lgdi32");
339           CmdArgs.push_back("-lcomdlg32");
340         }
341         CmdArgs.push_back("-ladvapi32");
342         CmdArgs.push_back("-lshell32");
343         CmdArgs.push_back("-luser32");
344         CmdArgs.push_back("-lkernel32");
345       }
346 
347       if (Args.hasArg(options::OPT_static)) {
348         CmdArgs.push_back("--end-group");
349       } else {
350         AddLibGCC(Args, CmdArgs);
351         if (!HasWindowsApp)
352           CmdArgs.push_back("-lkernel32");
353       }
354     }
355 
356     if (!Args.hasArg(options::OPT_nostartfiles)) {
357       // Add crtfastmath.o if available and fast math is enabled.
358       TC.addFastMathRuntimeIfAvailable(Args, CmdArgs);
359 
360       CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtend.o")));
361     }
362   }
363   const char *Exec = Args.MakeArgString(TC.GetLinkerPath());
364   C.addCommand(std::make_unique<Command>(JA, *this,
365                                          ResponseFileSupport::AtFileUTF8(),
366                                          Exec, CmdArgs, Inputs, Output));
367 }
368 
369 static bool isCrossCompiling(const llvm::Triple &T, bool RequireArchMatch) {
370   llvm::Triple HostTriple(llvm::Triple::normalize(LLVM_HOST_TRIPLE));
371   if (HostTriple.getOS() != llvm::Triple::Win32)
372     return true;
373   if (RequireArchMatch && HostTriple.getArch() != T.getArch())
374     return true;
375   return false;
376 }
377 
378 // Simplified from Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple.
379 static bool findGccVersion(StringRef LibDir, std::string &GccLibDir,
380                            std::string &Ver,
381                            toolchains::Generic_GCC::GCCVersion &Version) {
382   Version = toolchains::Generic_GCC::GCCVersion::Parse("0.0.0");
383   std::error_code EC;
384   for (llvm::sys::fs::directory_iterator LI(LibDir, EC), LE; !EC && LI != LE;
385        LI = LI.increment(EC)) {
386     StringRef VersionText = llvm::sys::path::filename(LI->path());
387     auto CandidateVersion =
388         toolchains::Generic_GCC::GCCVersion::Parse(VersionText);
389     if (CandidateVersion.Major == -1)
390       continue;
391     if (CandidateVersion <= Version)
392       continue;
393     Version = CandidateVersion;
394     Ver = std::string(VersionText);
395     GccLibDir = LI->path();
396   }
397   return Ver.size();
398 }
399 
400 static llvm::Triple getLiteralTriple(const Driver &D, const llvm::Triple &T) {
401   llvm::Triple LiteralTriple(D.getTargetTriple());
402   // The arch portion of the triple may be overridden by -m32/-m64.
403   LiteralTriple.setArchName(T.getArchName());
404   return LiteralTriple;
405 }
406 
407 void toolchains::MinGW::findGccLibDir(const llvm::Triple &LiteralTriple) {
408   llvm::SmallVector<llvm::SmallString<32>, 5> SubdirNames;
409   SubdirNames.emplace_back(LiteralTriple.str());
410   SubdirNames.emplace_back(getTriple().str());
411   SubdirNames.emplace_back(getTriple().getArchName());
412   SubdirNames.back() += "-w64-mingw32";
413   SubdirNames.emplace_back(getTriple().getArchName());
414   SubdirNames.back() += "-w64-mingw32ucrt";
415   SubdirNames.emplace_back("mingw32");
416   if (SubdirName.empty()) {
417     SubdirName = getTriple().getArchName();
418     SubdirName += "-w64-mingw32";
419   }
420   // lib: Arch Linux, Ubuntu, Windows
421   // lib64: openSUSE Linux
422   for (StringRef CandidateLib : {"lib", "lib64"}) {
423     for (StringRef CandidateSysroot : SubdirNames) {
424       llvm::SmallString<1024> LibDir(Base);
425       llvm::sys::path::append(LibDir, CandidateLib, "gcc", CandidateSysroot);
426       if (findGccVersion(LibDir, GccLibDir, Ver, GccVer)) {
427         SubdirName = std::string(CandidateSysroot);
428         return;
429       }
430     }
431   }
432 }
433 
434 static llvm::ErrorOr<std::string> findGcc(const llvm::Triple &LiteralTriple,
435                                           const llvm::Triple &T) {
436   llvm::SmallVector<llvm::SmallString<32>, 5> Gccs;
437   Gccs.emplace_back(LiteralTriple.str());
438   Gccs.back() += "-gcc";
439   Gccs.emplace_back(T.str());
440   Gccs.back() += "-gcc";
441   Gccs.emplace_back(T.getArchName());
442   Gccs.back() += "-w64-mingw32-gcc";
443   Gccs.emplace_back(T.getArchName());
444   Gccs.back() += "-w64-mingw32ucrt-gcc";
445   Gccs.emplace_back("mingw32-gcc");
446   // Please do not add "gcc" here
447   for (StringRef CandidateGcc : Gccs)
448     if (llvm::ErrorOr<std::string> GPPName = llvm::sys::findProgramByName(CandidateGcc))
449       return GPPName;
450   return make_error_code(std::errc::no_such_file_or_directory);
451 }
452 
453 static llvm::ErrorOr<std::string>
454 findClangRelativeSysroot(const Driver &D, const llvm::Triple &LiteralTriple,
455                          const llvm::Triple &T, std::string &SubdirName) {
456   llvm::SmallVector<llvm::SmallString<32>, 4> Subdirs;
457   Subdirs.emplace_back(LiteralTriple.str());
458   Subdirs.emplace_back(T.str());
459   Subdirs.emplace_back(T.getArchName());
460   Subdirs.back() += "-w64-mingw32";
461   Subdirs.emplace_back(T.getArchName());
462   Subdirs.back() += "-w64-mingw32ucrt";
463   StringRef ClangRoot = llvm::sys::path::parent_path(D.getInstalledDir());
464   StringRef Sep = llvm::sys::path::get_separator();
465   for (StringRef CandidateSubdir : Subdirs) {
466     if (llvm::sys::fs::is_directory(ClangRoot + Sep + CandidateSubdir)) {
467       SubdirName = std::string(CandidateSubdir);
468       return (ClangRoot + Sep + CandidateSubdir).str();
469     }
470   }
471   return make_error_code(std::errc::no_such_file_or_directory);
472 }
473 
474 static bool looksLikeMinGWSysroot(const std::string &Directory) {
475   StringRef Sep = llvm::sys::path::get_separator();
476   if (!llvm::sys::fs::exists(Directory + Sep + "include" + Sep + "_mingw.h"))
477     return false;
478   if (!llvm::sys::fs::exists(Directory + Sep + "lib" + Sep + "libkernel32.a"))
479     return false;
480   return true;
481 }
482 
483 toolchains::MinGW::MinGW(const Driver &D, const llvm::Triple &Triple,
484                          const ArgList &Args)
485     : ToolChain(D, Triple, Args), CudaInstallation(D, Triple, Args),
486       RocmInstallation(D, Triple, Args) {
487   getProgramPaths().push_back(getDriver().getInstalledDir());
488 
489   std::string InstallBase =
490       std::string(llvm::sys::path::parent_path(getDriver().getInstalledDir()));
491   // The sequence for detecting a sysroot here should be kept in sync with
492   // the testTriple function below.
493   llvm::Triple LiteralTriple = getLiteralTriple(D, getTriple());
494   if (getDriver().SysRoot.size())
495     Base = getDriver().SysRoot;
496   // Look for <clang-bin>/../<triplet>; if found, use <clang-bin>/.. as the
497   // base as it could still be a base for a gcc setup with libgcc.
498   else if (llvm::ErrorOr<std::string> TargetSubdir = findClangRelativeSysroot(
499                getDriver(), LiteralTriple, getTriple(), SubdirName))
500     Base = std::string(llvm::sys::path::parent_path(TargetSubdir.get()));
501   // If the install base of Clang seems to have mingw sysroot files directly
502   // in the toplevel include and lib directories, use this as base instead of
503   // looking for a triple prefixed GCC in the path.
504   else if (looksLikeMinGWSysroot(InstallBase))
505     Base = InstallBase;
506   else if (llvm::ErrorOr<std::string> GPPName =
507                findGcc(LiteralTriple, getTriple()))
508     Base = std::string(llvm::sys::path::parent_path(
509         llvm::sys::path::parent_path(GPPName.get())));
510   else
511     Base = InstallBase;
512 
513   Base += llvm::sys::path::get_separator();
514   findGccLibDir(LiteralTriple);
515   TripleDirName = SubdirName;
516   // GccLibDir must precede Base/lib so that the
517   // correct crtbegin.o ,cetend.o would be found.
518   getFilePaths().push_back(GccLibDir);
519 
520   // openSUSE/Fedora
521   std::string CandidateSubdir = SubdirName + "/sys-root/mingw";
522   if (getDriver().getVFS().exists(Base + CandidateSubdir))
523     SubdirName = CandidateSubdir;
524 
525   getFilePaths().push_back(
526       (Base + SubdirName + llvm::sys::path::get_separator() + "lib").str());
527 
528   // Gentoo
529   getFilePaths().push_back(
530       (Base + SubdirName + llvm::sys::path::get_separator() + "mingw/lib").str());
531 
532   // Only include <base>/lib if we're not cross compiling (not even for
533   // windows->windows to a different arch), or if the sysroot has been set
534   // (where we presume the user has pointed it at an arch specific
535   // subdirectory).
536   if (!::isCrossCompiling(getTriple(), /*RequireArchMatch=*/true) ||
537       getDriver().SysRoot.size())
538     getFilePaths().push_back(Base + "lib");
539 
540   NativeLLVMSupport =
541       Args.getLastArgValue(options::OPT_fuse_ld_EQ, CLANG_DEFAULT_LINKER)
542           .equals_insensitive("lld");
543 }
544 
545 Tool *toolchains::MinGW::getTool(Action::ActionClass AC) const {
546   switch (AC) {
547   case Action::PreprocessJobClass:
548     if (!Preprocessor)
549       Preprocessor.reset(new tools::gcc::Preprocessor(*this));
550     return Preprocessor.get();
551   case Action::CompileJobClass:
552     if (!Compiler)
553       Compiler.reset(new tools::gcc::Compiler(*this));
554     return Compiler.get();
555   default:
556     return ToolChain::getTool(AC);
557   }
558 }
559 
560 Tool *toolchains::MinGW::buildAssembler() const {
561   return new tools::MinGW::Assembler(*this);
562 }
563 
564 Tool *toolchains::MinGW::buildLinker() const {
565   return new tools::MinGW::Linker(*this);
566 }
567 
568 bool toolchains::MinGW::HasNativeLLVMSupport() const {
569   return NativeLLVMSupport;
570 }
571 
572 ToolChain::UnwindTableLevel
573 toolchains::MinGW::getDefaultUnwindTableLevel(const ArgList &Args) const {
574   Arg *ExceptionArg = Args.getLastArg(options::OPT_fsjlj_exceptions,
575                                       options::OPT_fseh_exceptions,
576                                       options::OPT_fdwarf_exceptions);
577   if (ExceptionArg &&
578       ExceptionArg->getOption().matches(options::OPT_fseh_exceptions))
579     return UnwindTableLevel::Asynchronous;
580 
581   if (getArch() == llvm::Triple::x86_64 || getArch() == llvm::Triple::arm ||
582       getArch() == llvm::Triple::thumb || getArch() == llvm::Triple::aarch64)
583     return UnwindTableLevel::Asynchronous;
584   return UnwindTableLevel::None;
585 }
586 
587 bool toolchains::MinGW::isPICDefault() const {
588   return getArch() == llvm::Triple::x86_64 ||
589          getArch() == llvm::Triple::aarch64;
590 }
591 
592 bool toolchains::MinGW::isPIEDefault(const llvm::opt::ArgList &Args) const {
593   return false;
594 }
595 
596 bool toolchains::MinGW::isPICDefaultForced() const { return true; }
597 
598 llvm::ExceptionHandling
599 toolchains::MinGW::GetExceptionModel(const ArgList &Args) const {
600   if (getArch() == llvm::Triple::x86_64 || getArch() == llvm::Triple::aarch64 ||
601       getArch() == llvm::Triple::arm || getArch() == llvm::Triple::thumb)
602     return llvm::ExceptionHandling::WinEH;
603   return llvm::ExceptionHandling::DwarfCFI;
604 }
605 
606 SanitizerMask toolchains::MinGW::getSupportedSanitizers() const {
607   SanitizerMask Res = ToolChain::getSupportedSanitizers();
608   Res |= SanitizerKind::Address;
609   Res |= SanitizerKind::PointerCompare;
610   Res |= SanitizerKind::PointerSubtract;
611   Res |= SanitizerKind::Vptr;
612   return Res;
613 }
614 
615 void toolchains::MinGW::AddCudaIncludeArgs(const ArgList &DriverArgs,
616                                            ArgStringList &CC1Args) const {
617   CudaInstallation->AddCudaIncludeArgs(DriverArgs, CC1Args);
618 }
619 
620 void toolchains::MinGW::AddHIPIncludeArgs(const ArgList &DriverArgs,
621                                           ArgStringList &CC1Args) const {
622   RocmInstallation->AddHIPIncludeArgs(DriverArgs, CC1Args);
623 }
624 
625 void toolchains::MinGW::printVerboseInfo(raw_ostream &OS) const {
626   CudaInstallation->print(OS);
627   RocmInstallation->print(OS);
628 }
629 
630 // Include directories for various hosts:
631 
632 // Windows, mingw.org
633 // c:\mingw\lib\gcc\mingw32\4.8.1\include\c++
634 // c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\mingw32
635 // c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\backward
636 // c:\mingw\include
637 // c:\mingw\mingw32\include
638 
639 // Windows, mingw-w64 mingw-builds
640 // c:\mingw32\i686-w64-mingw32\include
641 // c:\mingw32\i686-w64-mingw32\include\c++
642 // c:\mingw32\i686-w64-mingw32\include\c++\i686-w64-mingw32
643 // c:\mingw32\i686-w64-mingw32\include\c++\backward
644 
645 // Windows, mingw-w64 msys2
646 // c:\msys64\mingw32\include
647 // c:\msys64\mingw32\i686-w64-mingw32\include
648 // c:\msys64\mingw32\include\c++\4.9.2
649 // c:\msys64\mingw32\include\c++\4.9.2\i686-w64-mingw32
650 // c:\msys64\mingw32\include\c++\4.9.2\backward
651 
652 // openSUSE
653 // /usr/lib64/gcc/x86_64-w64-mingw32/5.1.0/include/c++
654 // /usr/lib64/gcc/x86_64-w64-mingw32/5.1.0/include/c++/x86_64-w64-mingw32
655 // /usr/lib64/gcc/x86_64-w64-mingw32/5.1.0/include/c++/backward
656 // /usr/x86_64-w64-mingw32/sys-root/mingw/include
657 
658 // Arch Linux
659 // /usr/i686-w64-mingw32/include/c++/5.1.0
660 // /usr/i686-w64-mingw32/include/c++/5.1.0/i686-w64-mingw32
661 // /usr/i686-w64-mingw32/include/c++/5.1.0/backward
662 // /usr/i686-w64-mingw32/include
663 
664 // Ubuntu
665 // /usr/include/c++/4.8
666 // /usr/include/c++/4.8/x86_64-w64-mingw32
667 // /usr/include/c++/4.8/backward
668 // /usr/x86_64-w64-mingw32/include
669 
670 // Fedora
671 // /usr/x86_64-w64-mingw32ucrt/sys-root/mingw/include/c++/x86_64-w64-mingw32ucrt
672 // /usr/x86_64-w64-mingw32ucrt/sys-root/mingw/include/c++/backward
673 // /usr/x86_64-w64-mingw32ucrt/sys-root/mingw/include
674 // /usr/lib/gcc/x86_64-w64-mingw32ucrt/12.2.1/include-fixed
675 
676 void toolchains::MinGW::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
677                                                   ArgStringList &CC1Args) const {
678   if (DriverArgs.hasArg(options::OPT_nostdinc))
679     return;
680 
681   if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
682     SmallString<1024> P(getDriver().ResourceDir);
683     llvm::sys::path::append(P, "include");
684     addSystemInclude(DriverArgs, CC1Args, P.str());
685   }
686 
687   if (DriverArgs.hasArg(options::OPT_nostdlibinc))
688     return;
689 
690   addSystemInclude(DriverArgs, CC1Args,
691                    Base + SubdirName + llvm::sys::path::get_separator() +
692                        "include");
693 
694   // Gentoo
695   addSystemInclude(DriverArgs, CC1Args,
696                    Base + SubdirName + llvm::sys::path::get_separator() + "usr/include");
697 
698   // Only include <base>/include if we're not cross compiling (but do allow it
699   // if we're on Windows and building for Windows on another architecture),
700   // or if the sysroot has been set (where we presume the user has pointed it
701   // at an arch specific subdirectory).
702   if (!::isCrossCompiling(getTriple(), /*RequireArchMatch=*/false) ||
703       getDriver().SysRoot.size())
704     addSystemInclude(DriverArgs, CC1Args, Base + "include");
705 }
706 
707 void toolchains::MinGW::addClangTargetOptions(
708     const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args,
709     Action::OffloadKind DeviceOffloadKind) const {
710   if (Arg *A = DriverArgs.getLastArg(options::OPT_mguard_EQ)) {
711     StringRef GuardArgs = A->getValue();
712     if (GuardArgs == "none") {
713       // Do nothing.
714     } else if (GuardArgs == "cf") {
715       // Emit CFG instrumentation and the table of address-taken functions.
716       CC1Args.push_back("-cfguard");
717     } else if (GuardArgs == "cf-nochecks") {
718       // Emit only the table of address-taken functions.
719       CC1Args.push_back("-cfguard-no-checks");
720     } else {
721       getDriver().Diag(diag::err_drv_unsupported_option_argument)
722           << A->getSpelling() << GuardArgs;
723     }
724   }
725 
726   CC1Args.push_back("-fno-use-init-array");
727 
728   for (auto Opt : {options::OPT_mthreads, options::OPT_mwindows,
729                    options::OPT_mconsole, options::OPT_mdll}) {
730     if (Arg *A = DriverArgs.getLastArgNoClaim(Opt))
731       A->ignoreTargetSpecific();
732   }
733 }
734 
735 void toolchains::MinGW::AddClangCXXStdlibIncludeArgs(
736     const ArgList &DriverArgs, ArgStringList &CC1Args) const {
737   if (DriverArgs.hasArg(options::OPT_nostdinc, options::OPT_nostdlibinc,
738                         options::OPT_nostdincxx))
739     return;
740 
741   StringRef Slash = llvm::sys::path::get_separator();
742 
743   switch (GetCXXStdlibType(DriverArgs)) {
744   case ToolChain::CST_Libcxx: {
745     std::string TargetDir = (Base + "include" + Slash + getTripleString() +
746                              Slash + "c++" + Slash + "v1")
747                                 .str();
748     if (getDriver().getVFS().exists(TargetDir))
749       addSystemInclude(DriverArgs, CC1Args, TargetDir);
750     addSystemInclude(DriverArgs, CC1Args,
751                      Base + SubdirName + Slash + "include" + Slash + "c++" +
752                          Slash + "v1");
753     addSystemInclude(DriverArgs, CC1Args,
754                      Base + "include" + Slash + "c++" + Slash + "v1");
755     break;
756   }
757 
758   case ToolChain::CST_Libstdcxx:
759     llvm::SmallVector<llvm::SmallString<1024>, 7> CppIncludeBases;
760     CppIncludeBases.emplace_back(Base);
761     llvm::sys::path::append(CppIncludeBases[0], SubdirName, "include", "c++");
762     CppIncludeBases.emplace_back(Base);
763     llvm::sys::path::append(CppIncludeBases[1], SubdirName, "include", "c++",
764                             Ver);
765     CppIncludeBases.emplace_back(Base);
766     llvm::sys::path::append(CppIncludeBases[2], "include", "c++", Ver);
767     CppIncludeBases.emplace_back(GccLibDir);
768     llvm::sys::path::append(CppIncludeBases[3], "include", "c++");
769     CppIncludeBases.emplace_back(GccLibDir);
770     llvm::sys::path::append(CppIncludeBases[4], "include",
771                             "g++-v" + GccVer.Text);
772     CppIncludeBases.emplace_back(GccLibDir);
773     llvm::sys::path::append(CppIncludeBases[5], "include",
774                             "g++-v" + GccVer.MajorStr + "." + GccVer.MinorStr);
775     CppIncludeBases.emplace_back(GccLibDir);
776     llvm::sys::path::append(CppIncludeBases[6], "include",
777                             "g++-v" + GccVer.MajorStr);
778     for (auto &CppIncludeBase : CppIncludeBases) {
779       addSystemInclude(DriverArgs, CC1Args, CppIncludeBase);
780       CppIncludeBase += Slash;
781       addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + TripleDirName);
782       addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + "backward");
783     }
784     break;
785   }
786 }
787 
788 static bool testTriple(const Driver &D, const llvm::Triple &Triple,
789                        const ArgList &Args) {
790   // If an explicit sysroot is set, that will be used and we shouldn't try to
791   // detect anything else.
792   std::string SubdirName;
793   if (D.SysRoot.size())
794     return true;
795   llvm::Triple LiteralTriple = getLiteralTriple(D, Triple);
796   std::string InstallBase =
797       std::string(llvm::sys::path::parent_path(D.getInstalledDir()));
798   if (llvm::ErrorOr<std::string> TargetSubdir =
799           findClangRelativeSysroot(D, LiteralTriple, Triple, SubdirName))
800     return true;
801   // If the install base itself looks like a mingw sysroot, we'll use that
802   // - don't use any potentially unrelated gcc to influence what triple to use.
803   if (looksLikeMinGWSysroot(InstallBase))
804     return false;
805   if (llvm::ErrorOr<std::string> GPPName = findGcc(LiteralTriple, Triple))
806     return true;
807   // If we neither found a colocated sysroot or a matching gcc executable,
808   // conclude that we can't know if this is the correct spelling of the triple.
809   return false;
810 }
811 
812 static llvm::Triple adjustTriple(const Driver &D, const llvm::Triple &Triple,
813                                  const ArgList &Args) {
814   // First test if the original triple can find a sysroot with the triple
815   // name.
816   if (testTriple(D, Triple, Args))
817     return Triple;
818   llvm::SmallVector<llvm::StringRef, 3> Archs;
819   // If not, test a couple other possible arch names that might be what was
820   // intended.
821   if (Triple.getArch() == llvm::Triple::x86) {
822     Archs.emplace_back("i386");
823     Archs.emplace_back("i586");
824     Archs.emplace_back("i686");
825   } else if (Triple.getArch() == llvm::Triple::arm ||
826              Triple.getArch() == llvm::Triple::thumb) {
827     Archs.emplace_back("armv7");
828   }
829   for (auto A : Archs) {
830     llvm::Triple TestTriple(Triple);
831     TestTriple.setArchName(A);
832     if (testTriple(D, TestTriple, Args))
833       return TestTriple;
834   }
835   // If none was found, just proceed with the original value.
836   return Triple;
837 }
838 
839 void toolchains::MinGW::fixTripleArch(const Driver &D, llvm::Triple &Triple,
840                                       const ArgList &Args) {
841   if (Triple.getArch() == llvm::Triple::x86 ||
842       Triple.getArch() == llvm::Triple::arm ||
843       Triple.getArch() == llvm::Triple::thumb)
844     Triple = adjustTriple(D, Triple, Args);
845 }
846