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