|
| 1 | +//===- MinGW/Driver.cpp ---------------------------------------------------===// |
| 2 | +// |
| 3 | +// The LLVM Linker |
| 4 | +// |
| 5 | +// This file is distributed under the University of Illinois Open Source |
| 6 | +// License. See LICENSE.TXT for details. |
| 7 | +// |
| 8 | +//===----------------------------------------------------------------------===// |
| 9 | +/// |
| 10 | +/// GNU ld style linker driver for COFF currently supporting mingw-w64. |
| 11 | +/// |
| 12 | +//===----------------------------------------------------------------------===// |
| 13 | + |
| 14 | +#include "lld/Driver/Driver.h" |
| 15 | +#include "llvm/ADT/ArrayRef.h" |
| 16 | +#include "llvm/ADT/Optional.h" |
| 17 | +#include "llvm/ADT/StringRef.h" |
| 18 | +#include "llvm/ADT/StringSwitch.h" |
| 19 | +#include "llvm/ADT/Triple.h" |
| 20 | +#include "llvm/Option/Arg.h" |
| 21 | +#include "llvm/Option/ArgList.h" |
| 22 | +#include "llvm/Option/Option.h" |
| 23 | +#include "llvm/Support/CommandLine.h" |
| 24 | +#include "llvm/Support/FileSystem.h" |
| 25 | +#include "llvm/Support/Path.h" |
| 26 | + |
| 27 | +#if !defined(_MSC_VER) && !defined(__MINGW32__) |
| 28 | +#include <unistd.h> |
| 29 | +#endif |
| 30 | + |
| 31 | +using namespace lld; |
| 32 | +using namespace llvm; |
| 33 | + |
| 34 | +namespace lld { |
| 35 | +namespace mingw { |
| 36 | +namespace { |
| 37 | + |
| 38 | +// Create OptTable |
| 39 | +enum { |
| 40 | + OPT_INVALID = 0, |
| 41 | +#define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11, _12) OPT_##ID, |
| 42 | +#include "Options.inc" |
| 43 | +#undef OPTION |
| 44 | +}; |
| 45 | + |
| 46 | +// Create prefix string literals used in Options.td |
| 47 | +#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; |
| 48 | +#include "Options.inc" |
| 49 | +#undef PREFIX |
| 50 | + |
| 51 | +// Create table mapping all options defined in Options.td |
| 52 | +static const opt::OptTable::Info InfoTable[] = { |
| 53 | +#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12) \ |
| 54 | + {X1, X2, X10, X11, OPT_##ID, opt::Option::KIND##Class, \ |
| 55 | + X9, X8, OPT_##GROUP, OPT_##ALIAS, X7, X12}, |
| 56 | +#include "Options.inc" |
| 57 | +#undef OPTION |
| 58 | +}; |
| 59 | + |
| 60 | +class COFFLdOptTable : public opt::OptTable { |
| 61 | +public: |
| 62 | + COFFLdOptTable() : OptTable(InfoTable, false) {} |
| 63 | + opt::InputArgList parse(ArrayRef<const char *> Argv); |
| 64 | +}; |
| 65 | + |
| 66 | +} // namespace |
| 67 | + |
| 68 | +static std::vector<std::string> LinkArgs; |
| 69 | +static std::vector<StringRef> SearchPaths; |
| 70 | + |
| 71 | +static void error(const Twine &Msg) { |
| 72 | + errs() << Msg << "\n"; |
| 73 | + llvm_shutdown(); |
| 74 | + exit(1); |
| 75 | +} |
| 76 | + |
| 77 | +// Find a file by concatenating given paths. |
| 78 | +static Optional<std::string> findFile(StringRef Path1, const Twine &Path2) { |
| 79 | + SmallString<128> S; |
| 80 | + sys::path::append(S, Path1, Path2); |
| 81 | + if (sys::fs::exists(S)) |
| 82 | + return S.str().str(); |
| 83 | + return None; |
| 84 | +} |
| 85 | + |
| 86 | +static Optional<std::string> findFromSearchPaths(StringRef Path) { |
| 87 | + for (StringRef Dir : SearchPaths) |
| 88 | + if (Optional<std::string> S = findFile(Dir, Path)) |
| 89 | + return S; |
| 90 | + return None; |
| 91 | +} |
| 92 | + |
| 93 | +// This is for -lfoo. We'll look for libfoo.dll.a or libfoo.a from search paths. |
| 94 | +static Optional<std::string> searchLibrary(StringRef Name, bool StaticOnly) { |
| 95 | + if (Name.startswith(":")) |
| 96 | + return findFromSearchPaths(Name.substr(1)); |
| 97 | + for (StringRef Dir : SearchPaths) { |
| 98 | + if (!StaticOnly) |
| 99 | + if (Optional<std::string> S = findFile(Dir, "lib" + Name + ".dll.a")) |
| 100 | + return S; |
| 101 | + if (Optional<std::string> S = findFile(Dir, "lib" + Name + ".a")) |
| 102 | + return S; |
| 103 | + } |
| 104 | + return None; |
| 105 | +} |
| 106 | + |
| 107 | +// Add a given library by searching it from input search paths. |
| 108 | +static void addLibrary(StringRef Name, bool StaticOnly) { |
| 109 | + if (Optional<std::string> Path = searchLibrary(Name, StaticOnly)) |
| 110 | + LinkArgs.push_back(*Path); |
| 111 | + else |
| 112 | + error("unable to find library -l" + Name); |
| 113 | +} |
| 114 | + |
| 115 | +static void createFiles(opt::InputArgList &Args) { |
| 116 | + for (auto *Arg : Args) { |
| 117 | + switch (Arg->getOption().getUnaliasedOption().getID()) { |
| 118 | + case OPT_l: |
| 119 | + addLibrary(Arg->getValue(), Args.hasArg(OPT_Bstatic)); |
| 120 | + break; |
| 121 | + case OPT_INPUT: |
| 122 | + LinkArgs.push_back(Arg->getValue()); |
| 123 | + break; |
| 124 | + } |
| 125 | + } |
| 126 | +} |
| 127 | + |
| 128 | +static void forward(opt::InputArgList &Args, unsigned Key, |
| 129 | + const std::string &OutArg, std::string Default = "") { |
| 130 | + StringRef S = Args.getLastArgValue(Key); |
| 131 | + if (!S.empty()) |
| 132 | + LinkArgs.push_back(std::string("-").append(OutArg).append(":").append(S)); |
| 133 | + else if (!Default.empty()) |
| 134 | + LinkArgs.push_back( |
| 135 | + std::string("-").append(OutArg).append(":").append(Default)); |
| 136 | +} |
| 137 | + |
| 138 | +static void forwardValue(opt::InputArgList &Args, unsigned Key, |
| 139 | + const std::string &CmpArg, const std::string &OutArg) { |
| 140 | + StringRef S = Args.getLastArgValue(Key); |
| 141 | + if (S == CmpArg) |
| 142 | + LinkArgs.push_back(std::string("-").append(OutArg)); |
| 143 | +} |
| 144 | + |
| 145 | +static bool convertValue(opt::InputArgList &Args, unsigned Key, |
| 146 | + StringRef OutArg) { |
| 147 | + if (Args.hasArg(Key)) { |
| 148 | + LinkArgs.push_back(std::string("-").append(OutArg)); |
| 149 | + return true; |
| 150 | + } |
| 151 | + return false; |
| 152 | +} |
| 153 | + |
| 154 | +opt::InputArgList COFFLdOptTable::parse(ArrayRef<const char *> Argv) { |
| 155 | + unsigned MissingIndex; |
| 156 | + unsigned MissingCount; |
| 157 | + SmallVector<const char *, 256> Vec(Argv.data(), Argv.data() + Argv.size()); |
| 158 | + opt::InputArgList Args = this->ParseArgs(Vec, MissingIndex, MissingCount); |
| 159 | + if (MissingCount) |
| 160 | + error(Twine(Args.getArgString(MissingIndex)) + ": missing argument"); |
| 161 | + if (!Args.hasArgNoClaim(OPT_INPUT) && !Args.hasArgNoClaim(OPT_l)) |
| 162 | + error("no input files"); |
| 163 | + for (auto *Arg : Args.filtered(OPT_UNKNOWN)) |
| 164 | + error("unknown argument: " + Arg->getSpelling()); |
| 165 | + return Args; |
| 166 | +} |
| 167 | + |
| 168 | +bool link(ArrayRef<const char *> ArgsArr, raw_ostream &Diag) { |
| 169 | + COFFLdOptTable Parser; |
| 170 | + opt::InputArgList Args = Parser.parse(ArgsArr.slice(1)); |
| 171 | + LinkArgs.push_back(ArgsArr[0]); |
| 172 | + |
| 173 | + forwardValue(Args, OPT_m, "i386pe", "machine:x86"); |
| 174 | + forwardValue(Args, OPT_m, "i386pep", "machine:x64"); |
| 175 | + forwardValue(Args, OPT_m, "thumb2pe", "machine:arm"); |
| 176 | + forwardValue(Args, OPT_m, "arm64pe", "machine:arm64"); |
| 177 | + |
| 178 | + forward(Args, OPT_o, "out", |
| 179 | + convertValue(Args, OPT_shared, "dll") ? "a.dll" : "a.exe"); |
| 180 | + forward(Args, OPT_entry, "entry"); |
| 181 | + forward(Args, OPT_subs, "subsystem"); |
| 182 | + forward(Args, OPT_outlib, "implib"); |
| 183 | + forward(Args, OPT_stack, "stack"); |
| 184 | + |
| 185 | + for (auto *Arg : Args.filtered(OPT_L)) |
| 186 | + SearchPaths.push_back(Arg->getValue()); |
| 187 | + |
| 188 | + createFiles(Args); |
| 189 | + |
| 190 | + // handle __image_base__ |
| 191 | + if (Args.getLastArgValue(OPT_m) == "i386pe") |
| 192 | + LinkArgs.push_back("/alternatename:__image_base__=___ImageBase"); |
| 193 | + else |
| 194 | + LinkArgs.push_back("/alternatename:__image_base__=__ImageBase"); |
| 195 | + |
| 196 | + // repack vector of strings to vector of const char pointers for coff::link |
| 197 | + std::vector<const char *> Vec; |
| 198 | + for (const std::string &S : LinkArgs) |
| 199 | + Vec.push_back(S.c_str()); |
| 200 | + return coff::link(Vec); |
| 201 | +} |
| 202 | + |
| 203 | +} // namespace mingw |
| 204 | +} // namespace lld |
0 commit comments