Martell Malone | 894dbbe | 2017-09-11 17:02:59 | [diff] [blame] | 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 | |
Rui Ueyama | 6cb7141 | 2017-10-02 22:05:46 | [diff] [blame^] | 14 | #include "lld/Common/Driver.h" |
Martell Malone | 894dbbe | 2017-09-11 17:02:59 | [diff] [blame] | 15 | #include "llvm/ADT/ArrayRef.h" |
| 16 | #include "llvm/ADT/Optional.h" |
Martin Storsjo | a79762a | 2017-09-11 20:43:39 | [diff] [blame] | 17 | #include "llvm/ADT/StringExtras.h" |
Martell Malone | 894dbbe | 2017-09-11 17:02:59 | [diff] [blame] | 18 | #include "llvm/ADT/StringRef.h" |
Martell Malone | 894dbbe | 2017-09-11 17:02:59 | [diff] [blame] | 19 | #include "llvm/Option/Arg.h" |
| 20 | #include "llvm/Option/ArgList.h" |
| 21 | #include "llvm/Option/Option.h" |
| 22 | #include "llvm/Support/CommandLine.h" |
| 23 | #include "llvm/Support/FileSystem.h" |
| 24 | #include "llvm/Support/Path.h" |
| 25 | |
| 26 | #if !defined(_MSC_VER) && !defined(__MINGW32__) |
| 27 | #include <unistd.h> |
| 28 | #endif |
| 29 | |
| 30 | using namespace lld; |
| 31 | using namespace llvm; |
| 32 | |
Rui Ueyama | d2da71f | 2017-09-11 22:04:37 | [diff] [blame] | 33 | LLVM_ATTRIBUTE_NORETURN static void error(const Twine &Msg) { |
| 34 | errs() << Msg << "\n"; |
| 35 | exit(1); |
| 36 | } |
| 37 | |
Martell Malone | 894dbbe | 2017-09-11 17:02:59 | [diff] [blame] | 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 |
Rui Ueyama | c16fd25 | 2017-09-11 22:04:13 | [diff] [blame] | 47 | #define PREFIX(NAME, VALUE) static const char *const NAME[] = VALUE; |
Martell Malone | 894dbbe | 2017-09-11 17:02:59 | [diff] [blame] | 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 | |
Rui Ueyama | c16fd25 | 2017-09-11 22:04:13 | [diff] [blame] | 60 | namespace { |
Rui Ueyama | 4474796 | 2017-09-11 22:04:25 | [diff] [blame] | 61 | class MinGWOptTable : public opt::OptTable { |
Martell Malone | 894dbbe | 2017-09-11 17:02:59 | [diff] [blame] | 62 | public: |
Rui Ueyama | 4474796 | 2017-09-11 22:04:25 | [diff] [blame] | 63 | MinGWOptTable() : OptTable(InfoTable, false) {} |
Martell Malone | 894dbbe | 2017-09-11 17:02:59 | [diff] [blame] | 64 | opt::InputArgList parse(ArrayRef<const char *> Argv); |
| 65 | }; |
Martell Malone | 894dbbe | 2017-09-11 17:02:59 | [diff] [blame] | 66 | } // namespace |
| 67 | |
Rui Ueyama | d2da71f | 2017-09-11 22:04:37 | [diff] [blame] | 68 | opt::InputArgList MinGWOptTable::parse(ArrayRef<const char *> Argv) { |
| 69 | unsigned MissingIndex; |
| 70 | unsigned MissingCount; |
| 71 | |
| 72 | SmallVector<const char *, 256> Vec(Argv.data(), Argv.data() + Argv.size()); |
| 73 | opt::InputArgList Args = this->ParseArgs(Vec, MissingIndex, MissingCount); |
| 74 | |
| 75 | if (MissingCount) |
| 76 | error(StringRef(Args.getArgString(MissingIndex)) + ": missing argument"); |
| 77 | for (auto *Arg : Args.filtered(OPT_UNKNOWN)) |
| 78 | error("unknown argument: " + Arg->getSpelling()); |
Rui Ueyama | a835bab | 2017-09-13 20:30:59 | [diff] [blame] | 79 | if (!Args.hasArg(OPT_INPUT) && !Args.hasArg(OPT_l)) |
Rui Ueyama | d2da71f | 2017-09-11 22:04:37 | [diff] [blame] | 80 | error("no input files"); |
| 81 | return Args; |
Martell Malone | 894dbbe | 2017-09-11 17:02:59 | [diff] [blame] | 82 | } |
| 83 | |
| 84 | // Find a file by concatenating given paths. |
| 85 | static Optional<std::string> findFile(StringRef Path1, const Twine &Path2) { |
| 86 | SmallString<128> S; |
| 87 | sys::path::append(S, Path1, Path2); |
| 88 | if (sys::fs::exists(S)) |
| 89 | return S.str().str(); |
| 90 | return None; |
| 91 | } |
| 92 | |
Martell Malone | 894dbbe | 2017-09-11 17:02:59 | [diff] [blame] | 93 | // This is for -lfoo. We'll look for libfoo.dll.a or libfoo.a from search paths. |
Rui Ueyama | 5941b0b | 2017-09-11 20:14:47 | [diff] [blame] | 94 | static std::string |
| 95 | searchLibrary(StringRef Name, ArrayRef<StringRef> SearchPaths, bool BStatic) { |
| 96 | if (Name.startswith(":")) { |
| 97 | for (StringRef Dir : SearchPaths) |
| 98 | if (Optional<std::string> S = findFile(Dir, Name.substr(1))) |
| 99 | return *S; |
Martell Malone | 894dbbe | 2017-09-11 17:02:59 | [diff] [blame] | 100 | error("unable to find library -l" + Name); |
Martell Malone | 894dbbe | 2017-09-11 17:02:59 | [diff] [blame] | 101 | } |
Martell Malone | 894dbbe | 2017-09-11 17:02:59 | [diff] [blame] | 102 | |
Rui Ueyama | 5941b0b | 2017-09-11 20:14:47 | [diff] [blame] | 103 | for (StringRef Dir : SearchPaths) { |
| 104 | if (!BStatic) |
| 105 | if (Optional<std::string> S = findFile(Dir, "lib" + Name + ".dll.a")) |
| 106 | return *S; |
| 107 | if (Optional<std::string> S = findFile(Dir, "lib" + Name + ".a")) |
| 108 | return *S; |
Martell Malone | 894dbbe | 2017-09-11 17:02:59 | [diff] [blame] | 109 | } |
Rui Ueyama | 5941b0b | 2017-09-11 20:14:47 | [diff] [blame] | 110 | error("unable to find library -l" + Name); |
Martell Malone | 894dbbe | 2017-09-11 17:02:59 | [diff] [blame] | 111 | } |
| 112 | |
Rui Ueyama | 5941b0b | 2017-09-11 20:14:47 | [diff] [blame] | 113 | // Convert Unix-ish command line arguments to Windows-ish ones and |
| 114 | // then call coff::link. |
Rui Ueyama | 95114b4 | 2017-09-11 22:04:01 | [diff] [blame] | 115 | bool mingw::link(ArrayRef<const char *> ArgsArr, raw_ostream &Diag) { |
Rui Ueyama | 4474796 | 2017-09-11 22:04:25 | [diff] [blame] | 116 | MinGWOptTable Parser; |
Martell Malone | 894dbbe | 2017-09-11 17:02:59 | [diff] [blame] | 117 | opt::InputArgList Args = Parser.parse(ArgsArr.slice(1)); |
Martell Malone | 894dbbe | 2017-09-11 17:02:59 | [diff] [blame] | 118 | |
Rui Ueyama | 5941b0b | 2017-09-11 20:14:47 | [diff] [blame] | 119 | std::vector<std::string> LinkArgs; |
| 120 | auto Add = [&](const Twine &S) { LinkArgs.push_back(S.str()); }; |
Martell Malone | 894dbbe | 2017-09-11 17:02:59 | [diff] [blame] | 121 | |
Martin Storsjo | a79762a | 2017-09-11 20:43:39 | [diff] [blame] | 122 | Add("lld-link"); |
Martin Storsjo | 31fe4cd | 2017-09-13 19:29:39 | [diff] [blame] | 123 | Add("-lldmingw"); |
Martell Malone | 894dbbe | 2017-09-11 17:02:59 | [diff] [blame] | 124 | |
Martin Storsjo | 6d8dace | 2017-09-12 19:23:54 | [diff] [blame] | 125 | if (auto *A = Args.getLastArg(OPT_entry)) { |
| 126 | StringRef S = A->getValue(); |
| 127 | if (Args.getLastArgValue(OPT_m) == "i386pe" && S.startswith("_")) |
| 128 | Add("-entry:" + S.substr(1)); |
| 129 | else |
| 130 | Add("-entry:" + S); |
| 131 | } |
| 132 | |
Rui Ueyama | 5941b0b | 2017-09-11 20:14:47 | [diff] [blame] | 133 | if (auto *A = Args.getLastArg(OPT_subs)) |
| 134 | Add("-subsystem:" + StringRef(A->getValue())); |
Rui Ueyama | c3e4602 | 2017-09-11 20:54:51 | [diff] [blame] | 135 | if (auto *A = Args.getLastArg(OPT_out_implib)) |
Rui Ueyama | 5941b0b | 2017-09-11 20:14:47 | [diff] [blame] | 136 | Add("-implib:" + StringRef(A->getValue())); |
| 137 | if (auto *A = Args.getLastArg(OPT_stack)) |
| 138 | Add("-stack:" + StringRef(A->getValue())); |
Martell Malone | 894dbbe | 2017-09-11 17:02:59 | [diff] [blame] | 139 | |
Rui Ueyama | 5941b0b | 2017-09-11 20:14:47 | [diff] [blame] | 140 | if (auto *A = Args.getLastArg(OPT_o)) |
| 141 | Add("-out:" + StringRef(A->getValue())); |
| 142 | else if (Args.hasArg(OPT_shared)) |
| 143 | Add("-out:a.dll"); |
Martell Malone | 894dbbe | 2017-09-11 17:02:59 | [diff] [blame] | 144 | else |
Rui Ueyama | 5941b0b | 2017-09-11 20:14:47 | [diff] [blame] | 145 | Add("-out:a.exe"); |
Martell Malone | 894dbbe | 2017-09-11 17:02:59 | [diff] [blame] | 146 | |
Rui Ueyama | 5941b0b | 2017-09-11 20:14:47 | [diff] [blame] | 147 | if (Args.hasArg(OPT_shared)) |
| 148 | Add("-dll"); |
Rui Ueyama | 7d306a5 | 2017-09-13 19:40:07 | [diff] [blame] | 149 | if (Args.hasArg(OPT_verbose)) |
| 150 | Add("-verbose"); |
Rui Ueyama | 5941b0b | 2017-09-11 20:14:47 | [diff] [blame] | 151 | |
| 152 | if (auto *A = Args.getLastArg(OPT_m)) { |
| 153 | StringRef S = A->getValue(); |
| 154 | if (S == "i386pe") |
| 155 | Add("-machine:x86"); |
| 156 | else if (S == "i386pep") |
| 157 | Add("-machine:x64"); |
| 158 | else if (S == "thumb2pe") |
| 159 | Add("-machine:arm"); |
| 160 | else if (S == "arm64pe") |
| 161 | Add("-machine:arm64"); |
| 162 | else |
| 163 | error("unknown parameter: -m" + S); |
| 164 | } |
| 165 | |
Martell Malone | 0d17638 | 2017-09-11 21:36:37 | [diff] [blame] | 166 | for (auto *A : Args.filtered(OPT_mllvm)) |
| 167 | Add("-mllvm:" + StringRef(A->getValue())); |
| 168 | |
Rui Ueyama | 5941b0b | 2017-09-11 20:14:47 | [diff] [blame] | 169 | if (Args.getLastArgValue(OPT_m) == "i386pe") |
| 170 | Add("-alternatename:__image_base__=___ImageBase"); |
| 171 | else |
| 172 | Add("-alternatename:__image_base__=__ImageBase"); |
| 173 | |
| 174 | std::vector<StringRef> SearchPaths; |
| 175 | for (auto *A : Args.filtered(OPT_L)) |
| 176 | SearchPaths.push_back(A->getValue()); |
| 177 | |
Martin Storsjo | 32e1626 | 2017-09-13 07:28:09 | [diff] [blame] | 178 | StringRef Prefix = ""; |
Martin Storsjo | 2ba37d4 | 2017-09-13 19:29:44 | [diff] [blame] | 179 | bool Static = false; |
| 180 | for (auto *A : Args) { |
Rui Ueyama | 9c37d8c | 2017-09-13 19:44:36 | [diff] [blame] | 181 | switch (A->getOption().getUnaliasedOption().getID()) { |
Martin Storsjo | 32e1626 | 2017-09-13 07:28:09 | [diff] [blame] | 182 | case OPT_INPUT: |
Rui Ueyama | b359263 | 2017-09-14 18:33:09 | [diff] [blame] | 183 | if (StringRef(A->getValue()).endswith_lower(".def")) |
Martin Storsjo | 064b0fa | 2017-09-13 07:28:13 | [diff] [blame] | 184 | Add("-def:" + StringRef(A->getValue())); |
| 185 | else |
| 186 | Add(Prefix + StringRef(A->getValue())); |
Martin Storsjo | 32e1626 | 2017-09-13 07:28:09 | [diff] [blame] | 187 | break; |
| 188 | case OPT_l: |
Martin Storsjo | 2ba37d4 | 2017-09-13 19:29:44 | [diff] [blame] | 189 | Add(Prefix + searchLibrary(A->getValue(), SearchPaths, Static)); |
Martin Storsjo | 32e1626 | 2017-09-13 07:28:09 | [diff] [blame] | 190 | break; |
| 191 | case OPT_whole_archive: |
| 192 | Prefix = "-wholearchive:"; |
| 193 | break; |
| 194 | case OPT_no_whole_archive: |
| 195 | Prefix = ""; |
| 196 | break; |
Martin Storsjo | 2ba37d4 | 2017-09-13 19:29:44 | [diff] [blame] | 197 | case OPT_Bstatic: |
| 198 | Static = true; |
| 199 | break; |
| 200 | case OPT_Bdynamic: |
| 201 | Static = false; |
| 202 | break; |
Martin Storsjo | 32e1626 | 2017-09-13 07:28:09 | [diff] [blame] | 203 | } |
Rui Ueyama | 5941b0b | 2017-09-11 20:14:47 | [diff] [blame] | 204 | } |
| 205 | |
Martin Storsjo | a79762a | 2017-09-11 20:43:39 | [diff] [blame] | 206 | if (Args.hasArg(OPT_verbose) || Args.hasArg(OPT__HASH_HASH_HASH)) |
| 207 | outs() << llvm::join(LinkArgs, " ") << "\n"; |
| 208 | |
| 209 | if (Args.hasArg(OPT__HASH_HASH_HASH)) |
| 210 | return true; |
| 211 | |
Rui Ueyama | 5941b0b | 2017-09-11 20:14:47 | [diff] [blame] | 212 | // Repack vector of strings to vector of const char pointers for coff::link. |
Martell Malone | 894dbbe | 2017-09-11 17:02:59 | [diff] [blame] | 213 | std::vector<const char *> Vec; |
| 214 | for (const std::string &S : LinkArgs) |
| 215 | Vec.push_back(S.c_str()); |
| 216 | return coff::link(Vec); |
| 217 | } |