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 "lld/Common/Memory.h" 34 #include "lld/Common/Version.h" 35 #include "llvm/ADT/ArrayRef.h" 36 #include "llvm/ADT/Optional.h" 37 #include "llvm/ADT/StringExtras.h" 38 #include "llvm/ADT/StringRef.h" 39 #include "llvm/ADT/Triple.h" 40 #include "llvm/Option/Arg.h" 41 #include "llvm/Option/ArgList.h" 42 #include "llvm/Option/Option.h" 43 #include "llvm/Support/CommandLine.h" 44 #include "llvm/Support/FileSystem.h" 45 #include "llvm/Support/Path.h" 46 47 #if !defined(_MSC_VER) && !defined(__MINGW32__) 48 #include <unistd.h> 49 #endif 50 51 using namespace lld; 52 using namespace llvm; 53 54 // Create OptTable 55 enum { 56 OPT_INVALID = 0, 57 #define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11, _12) OPT_##ID, 58 #include "Options.inc" 59 #undef OPTION 60 }; 61 62 // Create prefix string literals used in Options.td 63 #define PREFIX(NAME, VALUE) static const char *const NAME[] = VALUE; 64 #include "Options.inc" 65 #undef PREFIX 66 67 // Create table mapping all options defined in Options.td 68 static const opt::OptTable::Info infoTable[] = { 69 #define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12) \ 70 {X1, X2, X10, X11, OPT_##ID, opt::Option::KIND##Class, \ 71 X9, X8, OPT_##GROUP, OPT_##ALIAS, X7, X12}, 72 #include "Options.inc" 73 #undef OPTION 74 }; 75 76 namespace { 77 class MinGWOptTable : public opt::OptTable { 78 public: 79 MinGWOptTable() : OptTable(infoTable, false) {} 80 opt::InputArgList parse(ArrayRef<const char *> argv); 81 }; 82 } // namespace 83 84 static void printHelp(const char *argv0) { 85 MinGWOptTable().PrintHelp( 86 lld::outs(), (std::string(argv0) + " [options] file...").c_str(), "lld", 87 false /*ShowHidden*/, true /*ShowAllAliases*/); 88 lld::outs() << "\n"; 89 } 90 91 static cl::TokenizerCallback getQuotingStyle() { 92 if (Triple(sys::getProcessTriple()).getOS() == Triple::Win32) 93 return cl::TokenizeWindowsCommandLine; 94 return cl::TokenizeGNUCommandLine; 95 } 96 97 opt::InputArgList MinGWOptTable::parse(ArrayRef<const char *> argv) { 98 unsigned missingIndex; 99 unsigned missingCount; 100 101 SmallVector<const char *, 256> vec(argv.data(), argv.data() + argv.size()); 102 cl::ExpandResponseFiles(saver, getQuotingStyle(), vec); 103 opt::InputArgList args = this->ParseArgs(vec, missingIndex, missingCount); 104 105 if (missingCount) 106 error(StringRef(args.getArgString(missingIndex)) + ": missing argument"); 107 for (auto *arg : args.filtered(OPT_UNKNOWN)) 108 error("unknown argument: " + arg->getAsString(args)); 109 return args; 110 } 111 112 // Find a file by concatenating given paths. 113 static Optional<std::string> findFile(StringRef path1, const Twine &path2) { 114 SmallString<128> s; 115 sys::path::append(s, path1, path2); 116 if (sys::fs::exists(s)) 117 return s.str().str(); 118 return None; 119 } 120 121 // This is for -lfoo. We'll look for libfoo.dll.a or libfoo.a from search paths. 122 static std::string 123 searchLibrary(StringRef name, ArrayRef<StringRef> searchPaths, bool bStatic) { 124 if (name.startswith(":")) { 125 for (StringRef dir : searchPaths) 126 if (Optional<std::string> s = findFile(dir, name.substr(1))) 127 return *s; 128 error("unable to find library -l" + name); 129 return ""; 130 } 131 132 for (StringRef dir : searchPaths) { 133 if (!bStatic) { 134 if (Optional<std::string> s = findFile(dir, "lib" + name + ".dll.a")) 135 return *s; 136 if (Optional<std::string> s = findFile(dir, name + ".dll.a")) 137 return *s; 138 } 139 if (Optional<std::string> s = findFile(dir, "lib" + name + ".a")) 140 return *s; 141 if (!bStatic) { 142 if (Optional<std::string> s = findFile(dir, name + ".lib")) 143 return *s; 144 if (Optional<std::string> s = findFile(dir, "lib" + name + ".dll")) { 145 error("lld doesn't support linking directly against " + *s + 146 ", use an import library"); 147 return ""; 148 } 149 if (Optional<std::string> s = findFile(dir, name + ".dll")) { 150 error("lld doesn't support linking directly against " + *s + 151 ", use an import library"); 152 return ""; 153 } 154 } 155 } 156 error("unable to find library -l" + name); 157 return ""; 158 } 159 160 // Convert Unix-ish command line arguments to Windows-ish ones and 161 // then call coff::link. 162 bool mingw::link(ArrayRef<const char *> argsArr, bool canExitEarly, 163 raw_ostream &stdoutOS, raw_ostream &stderrOS) { 164 lld::stdoutOS = &stdoutOS; 165 lld::stderrOS = &stderrOS; 166 167 stderrOS.enable_colors(stderrOS.has_colors()); 168 169 MinGWOptTable parser; 170 opt::InputArgList args = parser.parse(argsArr.slice(1)); 171 172 if (errorCount()) 173 return false; 174 175 if (args.hasArg(OPT_help)) { 176 printHelp(argsArr[0]); 177 return true; 178 } 179 180 // A note about "compatible with GNU linkers" message: this is a hack for 181 // scripts generated by GNU Libtool 2.4.6 (released in February 2014 and 182 // still the newest version in March 2017) or earlier to recognize LLD as 183 // a GNU compatible linker. As long as an output for the -v option 184 // contains "GNU" or "with BFD", they recognize us as GNU-compatible. 185 if (args.hasArg(OPT_v) || args.hasArg(OPT_version)) 186 message(getLLDVersion() + " (compatible with GNU linkers)"); 187 188 // The behavior of -v or --version is a bit strange, but this is 189 // needed for compatibility with GNU linkers. 190 if (args.hasArg(OPT_v) && !args.hasArg(OPT_INPUT) && !args.hasArg(OPT_l)) 191 return true; 192 if (args.hasArg(OPT_version)) 193 return true; 194 195 if (!args.hasArg(OPT_INPUT) && !args.hasArg(OPT_l)) { 196 error("no input files"); 197 return false; 198 } 199 200 std::vector<std::string> linkArgs; 201 auto add = [&](const Twine &s) { linkArgs.push_back(s.str()); }; 202 203 add("lld-link"); 204 add("-lldmingw"); 205 206 if (auto *a = args.getLastArg(OPT_entry)) { 207 StringRef s = a->getValue(); 208 if (args.getLastArgValue(OPT_m) == "i386pe" && s.startswith("_")) 209 add("-entry:" + s.substr(1)); 210 else 211 add("-entry:" + s); 212 } 213 214 if (args.hasArg(OPT_major_os_version, OPT_minor_os_version, 215 OPT_major_subsystem_version, OPT_minor_subsystem_version)) { 216 auto *majOSVer = args.getLastArg(OPT_major_os_version); 217 auto *minOSVer = args.getLastArg(OPT_minor_os_version); 218 auto *majSubSysVer = args.getLastArg(OPT_major_subsystem_version); 219 auto *minSubSysVer = args.getLastArg(OPT_minor_subsystem_version); 220 if (majOSVer && majSubSysVer && 221 StringRef(majOSVer->getValue()) != StringRef(majSubSysVer->getValue())) 222 warn("--major-os-version and --major-subsystem-version set to differing " 223 "versions, not supported"); 224 if (minOSVer && minSubSysVer && 225 StringRef(minOSVer->getValue()) != StringRef(minSubSysVer->getValue())) 226 warn("--minor-os-version and --minor-subsystem-version set to differing " 227 "versions, not supported"); 228 StringRef subSys = args.getLastArgValue(OPT_subs, "default"); 229 StringRef major = majOSVer ? majOSVer->getValue() 230 : majSubSysVer ? majSubSysVer->getValue() : "6"; 231 StringRef minor = minOSVer ? minOSVer->getValue() 232 : minSubSysVer ? minSubSysVer->getValue() : ""; 233 StringRef sep = minor.empty() ? "" : "."; 234 add("-subsystem:" + subSys + "," + major + sep + minor); 235 } else if (auto *a = args.getLastArg(OPT_subs)) { 236 add("-subsystem:" + StringRef(a->getValue())); 237 } 238 239 if (auto *a = args.getLastArg(OPT_out_implib)) 240 add("-implib:" + StringRef(a->getValue())); 241 if (auto *a = args.getLastArg(OPT_stack)) 242 add("-stack:" + StringRef(a->getValue())); 243 if (auto *a = args.getLastArg(OPT_output_def)) 244 add("-output-def:" + StringRef(a->getValue())); 245 if (auto *a = args.getLastArg(OPT_image_base)) 246 add("-base:" + StringRef(a->getValue())); 247 if (auto *a = args.getLastArg(OPT_map)) 248 add("-lldmap:" + StringRef(a->getValue())); 249 if (auto *a = args.getLastArg(OPT_reproduce)) 250 add("-reproduce:" + StringRef(a->getValue())); 251 252 if (auto *a = args.getLastArg(OPT_o)) 253 add("-out:" + StringRef(a->getValue())); 254 else if (args.hasArg(OPT_shared)) 255 add("-out:a.dll"); 256 else 257 add("-out:a.exe"); 258 259 if (auto *a = args.getLastArg(OPT_pdb)) { 260 add("-debug"); 261 StringRef v = a->getValue(); 262 if (!v.empty()) 263 add("-pdb:" + v); 264 } else if (args.hasArg(OPT_strip_debug)) { 265 add("-debug:symtab"); 266 } else if (!args.hasArg(OPT_strip_all)) { 267 add("-debug:dwarf"); 268 } 269 270 if (args.hasArg(OPT_shared)) 271 add("-dll"); 272 if (args.hasArg(OPT_verbose)) 273 add("-verbose"); 274 if (args.hasArg(OPT_exclude_all_symbols)) 275 add("-exclude-all-symbols"); 276 if (args.hasArg(OPT_export_all_symbols)) 277 add("-export-all-symbols"); 278 if (args.hasArg(OPT_large_address_aware)) 279 add("-largeaddressaware"); 280 if (args.hasArg(OPT_kill_at)) 281 add("-kill-at"); 282 if (args.hasArg(OPT_appcontainer)) 283 add("-appcontainer"); 284 285 if (args.getLastArgValue(OPT_m) != "thumb2pe" && 286 args.getLastArgValue(OPT_m) != "arm64pe" && !args.hasArg(OPT_dynamicbase)) 287 add("-dynamicbase:no"); 288 289 if (args.hasFlag(OPT_no_insert_timestamp, OPT_insert_timestamp, false)) 290 add("-timestamp:0"); 291 292 if (args.hasFlag(OPT_gc_sections, OPT_no_gc_sections, false)) 293 add("-opt:ref"); 294 else 295 add("-opt:noref"); 296 297 if (auto *a = args.getLastArg(OPT_icf)) { 298 StringRef s = a->getValue(); 299 if (s == "all") 300 add("-opt:icf"); 301 else if (s == "safe" || s == "none") 302 add("-opt:noicf"); 303 else 304 error("unknown parameter: --icf=" + s); 305 } else { 306 add("-opt:noicf"); 307 } 308 309 if (auto *a = args.getLastArg(OPT_m)) { 310 StringRef s = a->getValue(); 311 if (s == "i386pe") 312 add("-machine:x86"); 313 else if (s == "i386pep") 314 add("-machine:x64"); 315 else if (s == "thumb2pe") 316 add("-machine:arm"); 317 else if (s == "arm64pe") 318 add("-machine:arm64"); 319 else 320 error("unknown parameter: -m" + s); 321 } 322 323 for (auto *a : args.filtered(OPT_mllvm)) 324 add("-mllvm:" + StringRef(a->getValue())); 325 326 for (auto *a : args.filtered(OPT_Xlink)) 327 add(a->getValue()); 328 329 if (args.getLastArgValue(OPT_m) == "i386pe") 330 add("-alternatename:__image_base__=___ImageBase"); 331 else 332 add("-alternatename:__image_base__=__ImageBase"); 333 334 for (auto *a : args.filtered(OPT_require_defined)) 335 add("-include:" + StringRef(a->getValue())); 336 for (auto *a : args.filtered(OPT_undefined)) 337 add("-includeoptional:" + StringRef(a->getValue())); 338 for (auto *a : args.filtered(OPT_delayload)) 339 add("-delayload:" + StringRef(a->getValue())); 340 341 std::vector<StringRef> searchPaths; 342 for (auto *a : args.filtered(OPT_L)) { 343 searchPaths.push_back(a->getValue()); 344 add("-libpath:" + StringRef(a->getValue())); 345 } 346 347 StringRef prefix = ""; 348 bool isStatic = false; 349 for (auto *a : args) { 350 switch (a->getOption().getID()) { 351 case OPT_INPUT: 352 if (StringRef(a->getValue()).endswith_lower(".def")) 353 add("-def:" + StringRef(a->getValue())); 354 else 355 add(prefix + StringRef(a->getValue())); 356 break; 357 case OPT_l: 358 add(prefix + searchLibrary(a->getValue(), searchPaths, isStatic)); 359 break; 360 case OPT_whole_archive: 361 prefix = "-wholearchive:"; 362 break; 363 case OPT_no_whole_archive: 364 prefix = ""; 365 break; 366 case OPT_Bstatic: 367 isStatic = true; 368 break; 369 case OPT_Bdynamic: 370 isStatic = false; 371 break; 372 } 373 } 374 375 if (errorCount()) 376 return false; 377 378 if (args.hasArg(OPT_verbose) || args.hasArg(OPT__HASH_HASH_HASH)) 379 lld::outs() << llvm::join(linkArgs, " ") << "\n"; 380 381 if (args.hasArg(OPT__HASH_HASH_HASH)) 382 return true; 383 384 // Repack vector of strings to vector of const char pointers for coff::link. 385 std::vector<const char *> vec; 386 for (const std::string &s : linkArgs) 387 vec.push_back(s.c_str()); 388 return coff::link(vec, true, stdoutOS, stderrOS); 389 } 390