xref: /llvm-project-15.0.7/lld/MinGW/Driver.cpp (revision ccbe567f)
1 //===- MinGW/Driver.cpp ---------------------------------------------------===//
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 // MinGW is a GNU development environment for Windows. It consists of GNU
10 // tools such as GCC and GNU ld. Unlike Cygwin, there's no POSIX-compatible
11 // layer, as it aims to be a native development toolchain.
12 //
13 // lld/MinGW is a drop-in replacement for GNU ld/MinGW.
14 //
15 // Being a native development tool, a MinGW linker is not very different from
16 // Microsoft link.exe, so a MinGW linker can be implemented as a thin wrapper
17 // for lld/COFF. This driver takes Unix-ish command line options, translates
18 // them to Windows-ish ones, and then passes them to lld/COFF.
19 //
20 // When this driver calls the lld/COFF driver, it passes a hidden option
21 // "-lldmingw" along with other user-supplied options, to run the lld/COFF
22 // linker in "MinGW mode".
23 //
24 // There are subtle differences between MS link.exe and GNU ld/MinGW, and GNU
25 // ld/MinGW implements a few GNU-specific features. Such features are directly
26 // implemented in lld/COFF and enabled only when the linker is running in MinGW
27 // mode.
28 //
29 //===----------------------------------------------------------------------===//
30 
31 #include "lld/Common/Driver.h"
32 #include "lld/Common/ErrorHandler.h"
33 #include "llvm/ADT/ArrayRef.h"
34 #include "llvm/ADT/Optional.h"
35 #include "llvm/ADT/StringExtras.h"
36 #include "llvm/ADT/StringRef.h"
37 #include "llvm/Option/Arg.h"
38 #include "llvm/Option/ArgList.h"
39 #include "llvm/Option/Option.h"
40 #include "llvm/Support/CommandLine.h"
41 #include "llvm/Support/FileSystem.h"
42 #include "llvm/Support/Path.h"
43 
44 #if !defined(_MSC_VER) && !defined(__MINGW32__)
45 #include <unistd.h>
46 #endif
47 
48 using namespace lld;
49 using namespace llvm;
50 
51 // Create OptTable
52 enum {
53   OPT_INVALID = 0,
54 #define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11, _12) OPT_##ID,
55 #include "Options.inc"
56 #undef OPTION
57 };
58 
59 // Create prefix string literals used in Options.td
60 #define PREFIX(NAME, VALUE) static const char *const NAME[] = VALUE;
61 #include "Options.inc"
62 #undef PREFIX
63 
64 // Create table mapping all options defined in Options.td
65 static const opt::OptTable::Info InfoTable[] = {
66 #define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12)      \
67   {X1, X2, X10,         X11,         OPT_##ID, opt::Option::KIND##Class,       \
68    X9, X8, OPT_##GROUP, OPT_##ALIAS, X7,       X12},
69 #include "Options.inc"
70 #undef OPTION
71 };
72 
73 namespace {
74 class MinGWOptTable : public opt::OptTable {
75 public:
76   MinGWOptTable() : OptTable(InfoTable, false) {}
77   opt::InputArgList parse(ArrayRef<const char *> Argv);
78 };
79 } // namespace
80 
81 opt::InputArgList MinGWOptTable::parse(ArrayRef<const char *> Argv) {
82   unsigned MissingIndex;
83   unsigned MissingCount;
84 
85   SmallVector<const char *, 256> Vec(Argv.data(), Argv.data() + Argv.size());
86   opt::InputArgList Args = this->ParseArgs(Vec, MissingIndex, MissingCount);
87 
88   if (MissingCount)
89     fatal(StringRef(Args.getArgString(MissingIndex)) + ": missing argument");
90   for (auto *Arg : Args.filtered(OPT_UNKNOWN))
91     fatal("unknown argument: " + Arg->getSpelling());
92   if (!Args.hasArg(OPT_INPUT) && !Args.hasArg(OPT_l))
93     fatal("no input files");
94   return Args;
95 }
96 
97 // Find a file by concatenating given paths.
98 static Optional<std::string> findFile(StringRef Path1, const Twine &Path2) {
99   SmallString<128> S;
100   sys::path::append(S, Path1, Path2);
101   if (sys::fs::exists(S))
102     return S.str().str();
103   return None;
104 }
105 
106 // This is for -lfoo. We'll look for libfoo.dll.a or libfoo.a from search paths.
107 static std::string
108 searchLibrary(StringRef Name, ArrayRef<StringRef> SearchPaths, bool BStatic) {
109   if (Name.startswith(":")) {
110     for (StringRef Dir : SearchPaths)
111       if (Optional<std::string> S = findFile(Dir, Name.substr(1)))
112         return *S;
113     fatal("unable to find library -l" + Name);
114   }
115 
116   for (StringRef Dir : SearchPaths) {
117     if (!BStatic)
118       if (Optional<std::string> S = findFile(Dir, "lib" + Name + ".dll.a"))
119         return *S;
120     if (Optional<std::string> S = findFile(Dir, "lib" + Name + ".a"))
121       return *S;
122   }
123   fatal("unable to find library -l" + Name);
124 }
125 
126 // Convert Unix-ish command line arguments to Windows-ish ones and
127 // then call coff::link.
128 bool mingw::link(ArrayRef<const char *> ArgsArr, raw_ostream &Diag) {
129   MinGWOptTable Parser;
130   opt::InputArgList Args = Parser.parse(ArgsArr.slice(1));
131 
132   std::vector<std::string> LinkArgs;
133   auto Add = [&](const Twine &S) { LinkArgs.push_back(S.str()); };
134 
135   Add("lld-link");
136   Add("-lldmingw");
137 
138   if (auto *A = Args.getLastArg(OPT_entry)) {
139     StringRef S = A->getValue();
140     if (Args.getLastArgValue(OPT_m) == "i386pe" && S.startswith("_"))
141       Add("-entry:" + S.substr(1));
142     else
143       Add("-entry:" + S);
144   }
145 
146   if (auto *A = Args.getLastArg(OPT_subs))
147     Add("-subsystem:" + StringRef(A->getValue()));
148   if (auto *A = Args.getLastArg(OPT_out_implib))
149     Add("-implib:" + StringRef(A->getValue()));
150   if (auto *A = Args.getLastArg(OPT_stack))
151     Add("-stack:" + StringRef(A->getValue()));
152   if (auto *A = Args.getLastArg(OPT_output_def))
153     Add("-output-def:" + StringRef(A->getValue()));
154   if (auto *A = Args.getLastArg(OPT_image_base))
155     Add("-base:" + StringRef(A->getValue()));
156   if (auto *A = Args.getLastArg(OPT_map))
157     Add("-lldmap:" + StringRef(A->getValue()));
158 
159   if (auto *A = Args.getLastArg(OPT_o))
160     Add("-out:" + StringRef(A->getValue()));
161   else if (Args.hasArg(OPT_shared))
162     Add("-out:a.dll");
163   else
164     Add("-out:a.exe");
165 
166   if (auto *A = Args.getLastArg(OPT_pdb)) {
167     Add("-debug");
168     Add("-pdb:" + StringRef(A->getValue()));
169   } else if (Args.hasArg(OPT_strip_debug)) {
170     Add("-debug:symtab");
171   } else if (!Args.hasArg(OPT_strip_all)) {
172     Add("-debug:dwarf");
173   }
174 
175   if (Args.hasArg(OPT_shared))
176     Add("-dll");
177   if (Args.hasArg(OPT_verbose))
178     Add("-verbose");
179   if (Args.hasArg(OPT_exclude_all_symbols))
180     Add("-exclude-all-symbols");
181   if (Args.hasArg(OPT_export_all_symbols))
182     Add("-export-all-symbols");
183   if (Args.hasArg(OPT_large_address_aware))
184     Add("-largeaddressaware");
185   if (Args.hasArg(OPT_kill_at))
186     Add("-kill-at");
187   if (Args.hasArg(OPT_appcontainer))
188     Add("-appcontainer");
189 
190   if (Args.getLastArgValue(OPT_m) != "thumb2pe" &&
191       Args.getLastArgValue(OPT_m) != "arm64pe" && !Args.hasArg(OPT_dynamicbase))
192     Add("-dynamicbase:no");
193 
194   if (Args.hasFlag(OPT_no_insert_timestamp, OPT_insert_timestamp, false))
195     Add("-timestamp:0");
196 
197   if (Args.hasFlag(OPT_gc_sections, OPT_no_gc_sections, false))
198     Add("-opt:ref");
199   else
200     Add("-opt:noref");
201 
202   if (auto *A = Args.getLastArg(OPT_icf)) {
203     StringRef S = A->getValue();
204     if (S == "all")
205       Add("-opt:icf");
206     else if (S == "safe" || S == "none")
207       Add("-opt:noicf");
208     else
209       fatal("unknown parameter: --icf=" + S);
210   } else {
211     Add("-opt:noicf");
212   }
213 
214   if (auto *A = Args.getLastArg(OPT_m)) {
215     StringRef S = A->getValue();
216     if (S == "i386pe")
217       Add("-machine:x86");
218     else if (S == "i386pep")
219       Add("-machine:x64");
220     else if (S == "thumb2pe")
221       Add("-machine:arm");
222     else if (S == "arm64pe")
223       Add("-machine:arm64");
224     else
225       fatal("unknown parameter: -m" + S);
226   }
227 
228   for (auto *A : Args.filtered(OPT_mllvm))
229     Add("-mllvm:" + StringRef(A->getValue()));
230 
231   for (auto *A : Args.filtered(OPT_Xlink))
232     Add(A->getValue());
233 
234   if (Args.getLastArgValue(OPT_m) == "i386pe")
235     Add("-alternatename:__image_base__=___ImageBase");
236   else
237     Add("-alternatename:__image_base__=__ImageBase");
238 
239   for (auto *A : Args.filtered(OPT_require_defined))
240     Add("-include:" + StringRef(A->getValue()));
241 
242   std::vector<StringRef> SearchPaths;
243   for (auto *A : Args.filtered(OPT_L)) {
244     SearchPaths.push_back(A->getValue());
245     Add("-libpath:" + StringRef(A->getValue()));
246   }
247 
248   StringRef Prefix = "";
249   bool Static = false;
250   for (auto *A : Args) {
251     switch (A->getOption().getUnaliasedOption().getID()) {
252     case OPT_INPUT:
253       if (StringRef(A->getValue()).endswith_lower(".def"))
254         Add("-def:" + StringRef(A->getValue()));
255       else
256         Add(Prefix + StringRef(A->getValue()));
257       break;
258     case OPT_l:
259       Add(Prefix + searchLibrary(A->getValue(), SearchPaths, Static));
260       break;
261     case OPT_whole_archive:
262       Prefix = "-wholearchive:";
263       break;
264     case OPT_no_whole_archive:
265       Prefix = "";
266       break;
267     case OPT_Bstatic:
268       Static = true;
269       break;
270     case OPT_Bdynamic:
271       Static = false;
272       break;
273     }
274   }
275 
276   if (Args.hasArg(OPT_verbose) || Args.hasArg(OPT__HASH_HASH_HASH))
277     outs() << llvm::join(LinkArgs, " ") << "\n";
278 
279   if (Args.hasArg(OPT__HASH_HASH_HASH))
280     return true;
281 
282   // Repack vector of strings to vector of const char pointers for coff::link.
283   std::vector<const char *> Vec;
284   for (const std::string &S : LinkArgs)
285     Vec.push_back(S.c_str());
286   return coff::link(Vec, true);
287 }
288