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/CommonLinkerContext.h"
33#include "lld/Common/ErrorHandler.h"
34#include "lld/Common/Version.h"
35#include "llvm/ADT/ArrayRef.h"
36#include "llvm/ADT/StringExtras.h"
37#include "llvm/ADT/StringRef.h"
38#include "llvm/Option/Arg.h"
39#include "llvm/Option/ArgList.h"
40#include "llvm/Option/Option.h"
41#include "llvm/Support/CommandLine.h"
42#include "llvm/Support/FileSystem.h"
43#include "llvm/Support/Path.h"
44#include "llvm/TargetParser/Host.h"
45#include "llvm/TargetParser/Triple.h"
46#include <optional>
47
48using namespace lld;
49using namespace llvm::opt;
50using namespace llvm;
51
52// Create OptTable
53enum {
54 OPT_INVALID = 0,
55#define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),
56#include "Options.inc"
57#undef OPTION
58};
59
60#define OPTTABLE_STR_TABLE_CODE
61#include "Options.inc"
62#undef OPTTABLE_STR_TABLE_CODE
63
64#define OPTTABLE_PREFIXES_TABLE_CODE
65#include "Options.inc"
66#undef OPTTABLE_PREFIXES_TABLE_CODE
67
68// Create table mapping all options defined in Options.td
69static constexpr opt::OptTable::Info infoTable[] = {
70#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, \
71 VISIBILITY, PARAM, HELPTEXT, HELPTEXTSFORVARIANTS, METAVAR, \
72 VALUES) \
73 {PREFIX, \
74 NAME, \
75 HELPTEXT, \
76 HELPTEXTSFORVARIANTS, \
77 METAVAR, \
78 OPT_##ID, \
79 opt::Option::KIND##Class, \
80 PARAM, \
81 FLAGS, \
82 VISIBILITY, \
83 OPT_##GROUP, \
84 OPT_##ALIAS, \
85 ALIASARGS, \
86 VALUES},
87#include "Options.inc"
88#undef OPTION
89};
90
91namespace {
92class MinGWOptTable : public opt::GenericOptTable {
93public:
94 MinGWOptTable()
95 : opt::GenericOptTable(OptionStrTable, OptionPrefixesTable, infoTable,
96 false) {}
97 opt::InputArgList parse(ArrayRef<const char *> argv);
98};
99} // namespace
100
101static void printHelp(CommonLinkerContext &ctx, const char *argv0) {
102 auto &outs = ctx.e.outs();
103 MinGWOptTable().printHelp(
104 OS&: outs, Usage: (std::string(argv0) + " [options] file...").c_str(), Title: "lld",
105 /*ShowHidden=*/false, /*ShowAllAliases=*/true);
106 outs << '\n';
107}
108
109static cl::TokenizerCallback getQuotingStyle() {
110 if (Triple(sys::getProcessTriple()).getOS() == Triple::Win32)
111 return cl::TokenizeWindowsCommandLine;
112 return cl::TokenizeGNUCommandLine;
113}
114
115opt::InputArgList MinGWOptTable::parse(ArrayRef<const char *> argv) {
116 unsigned missingIndex;
117 unsigned missingCount;
118
119 SmallVector<const char *, 256> vec(argv.data(), argv.data() + argv.size());
120 cl::ExpandResponseFiles(Saver&: saver(), Tokenizer: getQuotingStyle(), Argv&: vec);
121 opt::InputArgList args = this->ParseArgs(Args: vec, MissingArgIndex&: missingIndex, MissingArgCount&: missingCount);
122
123 if (missingCount)
124 error(msg: StringRef(args.getArgString(Index: missingIndex)) + ": missing argument");
125 for (auto *arg : args.filtered(Ids: OPT_UNKNOWN))
126 error(msg: "unknown argument: " + arg->getAsString(Args: args));
127 return args;
128}
129
130// Find a file by concatenating given paths.
131static std::optional<std::string> findFile(StringRef path1,
132 const Twine &path2) {
133 SmallString<128> s;
134 sys::path::append(path&: s, a: path1, b: path2);
135 if (sys::fs::exists(Path: s))
136 return std::string(s);
137 return std::nullopt;
138}
139
140// This is for -lfoo. We'll look for libfoo.dll.a or libfoo.a from search paths.
141static std::string searchLibrary(StringRef name,
142 ArrayRef<StringRef> searchPaths, bool bStatic,
143 StringRef prefix) {
144 if (name.starts_with(Prefix: ":")) {
145 for (StringRef dir : searchPaths)
146 if (std::optional<std::string> s = findFile(path1: dir, path2: name.substr(Start: 1)))
147 return *s;
148 error(msg: "unable to find library -l" + name);
149 return "";
150 }
151
152 for (StringRef dir : searchPaths) {
153 if (!bStatic) {
154 if (std::optional<std::string> s = findFile(path1: dir, path2: "lib" + name + ".dll.a"))
155 return *s;
156 if (std::optional<std::string> s = findFile(path1: dir, path2: name + ".dll.a"))
157 return *s;
158 }
159 if (std::optional<std::string> s = findFile(path1: dir, path2: "lib" + name + ".a"))
160 return *s;
161 if (std::optional<std::string> s = findFile(path1: dir, path2: name + ".lib"))
162 return *s;
163 if (!bStatic) {
164 if (std::optional<std::string> s = findFile(path1: dir, path2: prefix + name + ".dll"))
165 return *s;
166 if (std::optional<std::string> s = findFile(path1: dir, path2: name + ".dll"))
167 return *s;
168 }
169 }
170 error(msg: "unable to find library -l" + name);
171 return "";
172}
173
174static bool isI386Target(const opt::InputArgList &args,
175 const Triple &defaultTarget) {
176 auto *a = args.getLastArg(Ids: OPT_m);
177 if (a)
178 return StringRef(a->getValue()) == "i386pe";
179 return defaultTarget.getArch() == Triple::x86;
180}
181
182namespace lld {
183namespace coff {
184bool link(ArrayRef<const char *> argsArr, llvm::raw_ostream &stdoutOS,
185 llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput);
186}
187
188namespace mingw {
189// Convert Unix-ish command line arguments to Windows-ish ones and
190// then call coff::link.
191bool link(ArrayRef<const char *> argsArr, llvm::raw_ostream &stdoutOS,
192 llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput) {
193 auto *ctx = new CommonLinkerContext;
194 ctx->e.initialize(stdoutOS, stderrOS, exitEarly, disableOutput);
195
196 MinGWOptTable parser;
197 opt::InputArgList args = parser.parse(argv: argsArr.slice(N: 1));
198
199 if (errorCount())
200 return false;
201
202 if (args.hasArg(Ids: OPT_help)) {
203 printHelp(ctx&: *ctx, argv0: argsArr[0]);
204 return true;
205 }
206
207 // A note about "compatible with GNU linkers" message: this is a hack for
208 // scripts generated by GNU Libtool 2.4.6 (released in February 2014 and
209 // still the newest version in March 2017) or earlier to recognize LLD as
210 // a GNU compatible linker. As long as an output for the -v option
211 // contains "GNU" or "with BFD", they recognize us as GNU-compatible.
212 if (args.hasArg(Ids: OPT_v) || args.hasArg(Ids: OPT_version))
213 message(msg: getLLDVersion() + " (compatible with GNU linkers)");
214
215 // The behavior of -v or --version is a bit strange, but this is
216 // needed for compatibility with GNU linkers.
217 if (args.hasArg(Ids: OPT_v) && !args.hasArg(Ids: OPT_INPUT) && !args.hasArg(Ids: OPT_l))
218 return true;
219 if (args.hasArg(Ids: OPT_version))
220 return true;
221
222 if (!args.hasArg(Ids: OPT_INPUT) && !args.hasArg(Ids: OPT_l)) {
223 error(msg: "no input files");
224 return false;
225 }
226
227 Triple defaultTarget(Triple::normalize(Str: sys::getDefaultTargetTriple()));
228
229 std::vector<std::string> linkArgs;
230 auto add = [&](const Twine &s) { linkArgs.push_back(x: s.str()); };
231
232 add("lld-link");
233 add("-lldmingw");
234
235 if (auto *a = args.getLastArg(Ids: OPT_entry)) {
236 StringRef s = a->getValue();
237 if (isI386Target(args, defaultTarget) && s.starts_with(Prefix: "_"))
238 add("-entry:" + s.substr(Start: 1));
239 else if (!s.empty())
240 add("-entry:" + s);
241 else
242 add("-noentry");
243 }
244
245 if (args.hasArg(Ids: OPT_major_os_version, Ids: OPT_minor_os_version,
246 Ids: OPT_major_subsystem_version, Ids: OPT_minor_subsystem_version)) {
247 StringRef majOSVer = args.getLastArgValue(Id: OPT_major_os_version, Default: "6");
248 StringRef minOSVer = args.getLastArgValue(Id: OPT_minor_os_version, Default: "0");
249 StringRef majSubSysVer = "6";
250 StringRef minSubSysVer = "0";
251 StringRef subSysName = "default";
252 StringRef subSysVer;
253 // Iterate over --{major,minor}-subsystem-version and --subsystem, and pick
254 // the version number components from the last one of them that specifies
255 // a version.
256 for (auto *a : args.filtered(Ids: OPT_major_subsystem_version,
257 Ids: OPT_minor_subsystem_version, Ids: OPT_subs)) {
258 switch (a->getOption().getID()) {
259 case OPT_major_subsystem_version:
260 majSubSysVer = a->getValue();
261 break;
262 case OPT_minor_subsystem_version:
263 minSubSysVer = a->getValue();
264 break;
265 case OPT_subs:
266 std::tie(args&: subSysName, args&: subSysVer) = StringRef(a->getValue()).split(Separator: ':');
267 if (!subSysVer.empty()) {
268 if (subSysVer.contains(C: '.'))
269 std::tie(args&: majSubSysVer, args&: minSubSysVer) = subSysVer.split(Separator: '.');
270 else
271 majSubSysVer = subSysVer;
272 }
273 break;
274 }
275 }
276 add("-osversion:" + majOSVer + "." + minOSVer);
277 add("-subsystem:" + subSysName + "," + majSubSysVer + "." + minSubSysVer);
278 } else if (args.hasArg(Ids: OPT_subs)) {
279 StringRef subSys = args.getLastArgValue(Id: OPT_subs, Default: "default");
280 StringRef subSysName, subSysVer;
281 std::tie(args&: subSysName, args&: subSysVer) = subSys.split(Separator: ':');
282 StringRef sep = subSysVer.empty() ? "" : ",";
283 add("-subsystem:" + subSysName + sep + subSysVer);
284 }
285
286 if (auto *a = args.getLastArg(Ids: OPT_out_implib))
287 add("-implib:" + StringRef(a->getValue()));
288 if (auto *a = args.getLastArg(Ids: OPT_stack))
289 add("-stack:" + StringRef(a->getValue()));
290 if (auto *a = args.getLastArg(Ids: OPT_output_def))
291 add("-output-def:" + StringRef(a->getValue()));
292 if (auto *a = args.getLastArg(Ids: OPT_image_base))
293 add("-base:" + StringRef(a->getValue()));
294 if (auto *a = args.getLastArg(Ids: OPT_map))
295 add("-lldmap:" + StringRef(a->getValue()));
296 if (auto *a = args.getLastArg(Ids: OPT_reproduce))
297 add("-reproduce:" + StringRef(a->getValue()));
298 if (auto *a = args.getLastArg(Ids: OPT_file_alignment))
299 add("-filealign:" + StringRef(a->getValue()));
300 if (auto *a = args.getLastArg(Ids: OPT_section_alignment))
301 add("-align:" + StringRef(a->getValue()));
302 if (auto *a = args.getLastArg(Ids: OPT_heap))
303 add("-heap:" + StringRef(a->getValue()));
304 if (auto *a = args.getLastArg(Ids: OPT_threads))
305 add("-threads:" + StringRef(a->getValue()));
306
307 if (auto *a = args.getLastArg(Ids: OPT_o))
308 add("-out:" + StringRef(a->getValue()));
309 else if (args.hasArg(Ids: OPT_shared))
310 add("-out:a.dll");
311 else
312 add("-out:a.exe");
313
314 if (auto *a = args.getLastArg(Ids: OPT_pdb)) {
315 add("-debug");
316 StringRef v = a->getValue();
317 if (!v.empty())
318 add("-pdb:" + v);
319 if (args.hasArg(Ids: OPT_strip_all)) {
320 add("-debug:nodwarf,nosymtab");
321 } else if (args.hasArg(Ids: OPT_strip_debug)) {
322 add("-debug:nodwarf,symtab");
323 }
324 } else if (args.hasArg(Ids: OPT_strip_debug)) {
325 add("-debug:symtab");
326 } else if (!args.hasArg(Ids: OPT_strip_all)) {
327 add("-debug:dwarf");
328 }
329 if (auto *a = args.getLastArg(Ids: OPT_build_id)) {
330 StringRef v = a->getValue();
331 if (v == "none")
332 add("-build-id:no");
333 else {
334 if (!v.empty())
335 warn(msg: "unsupported build id hashing: " + v + ", using default hashing.");
336 add("-build-id");
337 }
338 } else {
339 if (args.hasArg(Ids: OPT_strip_debug) || args.hasArg(Ids: OPT_strip_all))
340 add("-build-id:no");
341 else
342 add("-build-id");
343 }
344
345 if (auto *a = args.getLastArg(Ids: OPT_functionpadmin)) {
346 StringRef v = a->getValue();
347 if (v.empty())
348 add("-functionpadmin");
349 else
350 add("-functionpadmin:" + v);
351 }
352
353 if (args.hasFlag(Pos: OPT_fatal_warnings, Neg: OPT_no_fatal_warnings, Default: false))
354 add("-WX");
355 else
356 add("-WX:no");
357
358 if (args.hasFlag(Pos: OPT_enable_stdcall_fixup, Neg: OPT_disable_stdcall_fixup, Default: false))
359 add("-stdcall-fixup");
360 else if (args.hasArg(Ids: OPT_disable_stdcall_fixup))
361 add("-stdcall-fixup:no");
362
363 if (args.hasArg(Ids: OPT_shared))
364 add("-dll");
365 if (args.hasArg(Ids: OPT_verbose))
366 add("-verbose");
367 if (args.hasArg(Ids: OPT_exclude_all_symbols))
368 add("-exclude-all-symbols");
369 if (args.hasArg(Ids: OPT_export_all_symbols))
370 add("-export-all-symbols");
371 if (args.hasArg(Ids: OPT_large_address_aware))
372 add("-largeaddressaware");
373 if (args.hasArg(Ids: OPT_kill_at))
374 add("-kill-at");
375 if (args.hasArg(Ids: OPT_appcontainer))
376 add("-appcontainer");
377 if (args.hasFlag(Pos: OPT_no_seh, Neg: OPT_disable_no_seh, Default: false))
378 add("-noseh");
379
380 if (args.getLastArgValue(Id: OPT_m) != "thumb2pe" &&
381 args.getLastArgValue(Id: OPT_m) != "arm64pe" &&
382 args.getLastArgValue(Id: OPT_m) != "arm64ecpe" &&
383 args.hasFlag(Pos: OPT_disable_dynamicbase, Neg: OPT_dynamicbase, Default: false))
384 add("-dynamicbase:no");
385 if (args.hasFlag(Pos: OPT_disable_high_entropy_va, Neg: OPT_high_entropy_va, Default: false))
386 add("-highentropyva:no");
387 if (args.hasFlag(Pos: OPT_disable_nxcompat, Neg: OPT_nxcompat, Default: false))
388 add("-nxcompat:no");
389 if (args.hasFlag(Pos: OPT_disable_tsaware, Neg: OPT_tsaware, Default: false))
390 add("-tsaware:no");
391
392 if (args.hasFlag(Pos: OPT_disable_reloc_section, Neg: OPT_enable_reloc_section, Default: false))
393 add("-fixed");
394
395 if (args.hasFlag(Pos: OPT_no_insert_timestamp, Neg: OPT_insert_timestamp, Default: false))
396 add("-timestamp:0");
397
398 if (args.hasFlag(Pos: OPT_gc_sections, Neg: OPT_no_gc_sections, Default: false))
399 add("-opt:ref");
400 else
401 add("-opt:noref");
402
403 if (args.hasFlag(Pos: OPT_demangle, Neg: OPT_no_demangle, Default: true))
404 add("-demangle");
405 else
406 add("-demangle:no");
407
408 if (args.hasFlag(Pos: OPT_enable_auto_import, Neg: OPT_disable_auto_import, Default: true))
409 add("-auto-import");
410 else
411 add("-auto-import:no");
412 if (args.hasFlag(Pos: OPT_enable_runtime_pseudo_reloc,
413 Neg: OPT_disable_runtime_pseudo_reloc, Default: true))
414 add("-runtime-pseudo-reloc");
415 else
416 add("-runtime-pseudo-reloc:no");
417
418 if (args.hasFlag(Pos: OPT_allow_multiple_definition,
419 Neg: OPT_no_allow_multiple_definition, Default: false))
420 add("-force:multiple");
421
422 if (auto *a = args.getLastArg(Ids: OPT_dependent_load_flag))
423 add("-dependentloadflag:" + StringRef(a->getValue()));
424
425 if (auto *a = args.getLastArg(Ids: OPT_icf)) {
426 StringRef s = a->getValue();
427 if (s == "all")
428 add("-opt:icf");
429 else if (s == "safe")
430 add("-opt:safeicf");
431 else if (s == "none")
432 add("-opt:noicf");
433 else
434 error(msg: "unknown parameter: --icf=" + s);
435 } else {
436 add("-opt:noicf");
437 }
438
439 if (auto *a = args.getLastArg(Ids: OPT_m)) {
440 StringRef s = a->getValue();
441 if (s == "i386pe")
442 add("-machine:x86");
443 else if (s == "i386pep")
444 add("-machine:x64");
445 else if (s == "thumb2pe")
446 add("-machine:arm");
447 else if (s == "arm64pe")
448 add("-machine:arm64");
449 else if (s == "arm64ecpe")
450 add("-machine:arm64ec");
451 else
452 error(msg: "unknown parameter: -m" + s);
453 }
454
455 if (args.hasFlag(Pos: OPT_guard_cf, Neg: OPT_no_guard_cf, Default: false)) {
456 if (args.hasFlag(Pos: OPT_guard_longjmp, Neg: OPT_no_guard_longjmp, Default: true))
457 add("-guard:cf,longjmp");
458 else
459 add("-guard:cf,nolongjmp");
460 } else if (args.hasFlag(Pos: OPT_guard_longjmp, Neg: OPT_no_guard_longjmp, Default: false)) {
461 auto *a = args.getLastArg(Ids: OPT_guard_longjmp);
462 warn(msg: "parameter " + a->getSpelling() +
463 " only takes effect when used with --guard-cf");
464 }
465
466 if (auto *a = args.getLastArg(Ids: OPT_error_limit)) {
467 int n;
468 StringRef s = a->getValue();
469 if (s.getAsInteger(Radix: 10, Result&: n))
470 error(msg: a->getSpelling() + ": number expected, but got " + s);
471 else
472 add("-errorlimit:" + s);
473 }
474
475 if (auto *a = args.getLastArg(Ids: OPT_rpath))
476 warn(msg: "parameter " + a->getSpelling() + " has no effect on PE/COFF targets");
477
478 for (auto *a : args.filtered(Ids: OPT_mllvm))
479 add("-mllvm:" + StringRef(a->getValue()));
480
481 if (auto *arg = args.getLastArg(Ids: OPT_plugin_opt_mcpu_eq))
482 add("-mllvm:-mcpu=" + StringRef(arg->getValue()));
483 if (auto *arg = args.getLastArg(Ids: OPT_lto_O))
484 add("-opt:lldlto=" + StringRef(arg->getValue()));
485 if (auto *arg = args.getLastArg(Ids: OPT_lto_CGO))
486 add("-opt:lldltocgo=" + StringRef(arg->getValue()));
487 if (auto *arg = args.getLastArg(Ids: OPT_plugin_opt_dwo_dir_eq))
488 add("-dwodir:" + StringRef(arg->getValue()));
489 if (args.hasArg(Ids: OPT_lto_cs_profile_generate))
490 add("-lto-cs-profile-generate");
491 if (auto *arg = args.getLastArg(Ids: OPT_lto_cs_profile_file))
492 add("-lto-cs-profile-file:" + StringRef(arg->getValue()));
493 if (args.hasArg(Ids: OPT_plugin_opt_emit_llvm))
494 add("-lldemit:llvm");
495 if (args.hasArg(Ids: OPT_lto_emit_asm))
496 add("-lldemit:asm");
497 if (auto *arg = args.getLastArg(Ids: OPT_lto_sample_profile))
498 add("-lto-sample-profile:" + StringRef(arg->getValue()));
499
500 if (auto *a = args.getLastArg(Ids: OPT_thinlto_cache_dir))
501 add("-lldltocache:" + StringRef(a->getValue()));
502 if (auto *a = args.getLastArg(Ids: OPT_thinlto_cache_policy))
503 add("-lldltocachepolicy:" + StringRef(a->getValue()));
504 if (args.hasArg(Ids: OPT_thinlto_emit_imports_files))
505 add("-thinlto-emit-imports-files");
506 if (args.hasArg(Ids: OPT_thinlto_index_only))
507 add("-thinlto-index-only");
508 if (auto *arg = args.getLastArg(Ids: OPT_thinlto_index_only_eq))
509 add("-thinlto-index-only:" + StringRef(arg->getValue()));
510 if (auto *arg = args.getLastArg(Ids: OPT_thinlto_jobs_eq))
511 add("-opt:lldltojobs=" + StringRef(arg->getValue()));
512 if (auto *arg = args.getLastArg(Ids: OPT_thinlto_object_suffix_replace_eq))
513 add("-thinlto-object-suffix-replace:" + StringRef(arg->getValue()));
514 if (auto *arg = args.getLastArg(Ids: OPT_thinlto_prefix_replace_eq))
515 add("-thinlto-prefix-replace:" + StringRef(arg->getValue()));
516
517 for (auto *a : args.filtered(Ids: OPT_plugin_opt_eq_minus))
518 add("-mllvm:-" + StringRef(a->getValue()));
519
520 // GCC collect2 passes -plugin-opt=path/to/lto-wrapper with an absolute or
521 // relative path. Just ignore. If not ended with "lto-wrapper" (or
522 // "lto-wrapper.exe" for GCC cross-compiled for Windows), consider it an
523 // unsupported LLVMgold.so option and error.
524 for (opt::Arg *arg : args.filtered(Ids: OPT_plugin_opt_eq)) {
525 StringRef v(arg->getValue());
526 if (!v.ends_with(Suffix: "lto-wrapper") && !v.ends_with(Suffix: "lto-wrapper.exe"))
527 error(msg: arg->getSpelling() + ": unknown plugin option '" + arg->getValue() +
528 "'");
529 }
530
531 for (auto *a : args.filtered(Ids: OPT_Xlink))
532 add(a->getValue());
533
534 if (isI386Target(args, defaultTarget))
535 add("-alternatename:__image_base__=___ImageBase");
536 else
537 add("-alternatename:__image_base__=__ImageBase");
538
539 for (auto *a : args.filtered(Ids: OPT_require_defined))
540 add("-include:" + StringRef(a->getValue()));
541 for (auto *a : args.filtered(Ids: OPT_undefined_glob))
542 add("-includeglob:" + StringRef(a->getValue()));
543 for (auto *a : args.filtered(Ids: OPT_undefined))
544 add("-includeoptional:" + StringRef(a->getValue()));
545 for (auto *a : args.filtered(Ids: OPT_delayload))
546 add("-delayload:" + StringRef(a->getValue()));
547 for (auto *a : args.filtered(Ids: OPT_wrap))
548 add("-wrap:" + StringRef(a->getValue()));
549 for (auto *a : args.filtered(Ids: OPT_exclude_symbols))
550 add("-exclude-symbols:" + StringRef(a->getValue()));
551
552 std::vector<StringRef> searchPaths;
553 for (auto *a : args.filtered(Ids: OPT_L)) {
554 searchPaths.push_back(x: a->getValue());
555 add("-libpath:" + StringRef(a->getValue()));
556 }
557
558 StringRef dllPrefix = "lib";
559 if (auto *arg = args.getLastArg(Ids: OPT_dll_search_prefix))
560 dllPrefix = arg->getValue();
561
562 StringRef prefix = "";
563 bool isStatic = false;
564 for (auto *a : args) {
565 switch (a->getOption().getID()) {
566 case OPT_INPUT:
567 if (StringRef(a->getValue()).ends_with_insensitive(Suffix: ".def"))
568 add("-def:" + StringRef(a->getValue()));
569 else
570 add(prefix + StringRef(a->getValue()));
571 break;
572 case OPT_l:
573 add(prefix +
574 searchLibrary(name: a->getValue(), searchPaths, bStatic: isStatic, prefix: dllPrefix));
575 break;
576 case OPT_whole_archive:
577 prefix = "-wholearchive:";
578 break;
579 case OPT_no_whole_archive:
580 prefix = "";
581 break;
582 case OPT_Bstatic:
583 isStatic = true;
584 break;
585 case OPT_Bdynamic:
586 isStatic = false;
587 break;
588 }
589 }
590
591 if (errorCount())
592 return false;
593
594 if (args.hasArg(Ids: OPT_verbose) || args.hasArg(Ids: OPT__HASH_HASH_HASH))
595 ctx->e.errs() << llvm::join(R&: linkArgs, Separator: " ") << "\n";
596
597 if (args.hasArg(Ids: OPT__HASH_HASH_HASH))
598 return true;
599
600 // Repack vector of strings to vector of const char pointers for coff::link.
601 std::vector<const char *> vec;
602 for (const std::string &s : linkArgs)
603 vec.push_back(x: s.c_str());
604 // Pass the actual binary name, to make error messages be printed with
605 // the right prefix.
606 vec[0] = argsArr[0];
607
608 // The context will be re-created in the COFF driver.
609 lld::CommonLinkerContext::destroy();
610
611 return coff::link(argsArr: vec, stdoutOS, stderrOS, exitEarly, disableOutput);
612}
613} // namespace mingw
614} // namespace lld
615