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