1 //===- DriverUtils.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 // This file contains utility functions for the driver. Because there 11 // are so many small functions, we created this separate file to make 12 // Driver.cpp less cluttered. 13 // 14 //===----------------------------------------------------------------------===// 15 16 #include "Config.h" 17 #include "Driver.h" 18 #include "Error.h" 19 #include "llvm/ADT/Optional.h" 20 #include "llvm/ADT/STLExtras.h" 21 #include "llvm/ADT/StringSwitch.h" 22 #include "llvm/Object/COFF.h" 23 #include "llvm/Option/Arg.h" 24 #include "llvm/Option/ArgList.h" 25 #include "llvm/Option/Option.h" 26 #include "llvm/Support/CommandLine.h" 27 #include "llvm/Support/FileUtilities.h" 28 #include "llvm/Support/Path.h" 29 #include "llvm/Support/Process.h" 30 #include "llvm/Support/Program.h" 31 #include "llvm/Support/raw_ostream.h" 32 #include <memory> 33 34 using namespace llvm::COFF; 35 using namespace llvm; 36 using llvm::cl::ExpandResponseFiles; 37 using llvm::cl::TokenizeWindowsCommandLine; 38 using llvm::sys::Process; 39 40 namespace lld { 41 namespace coff { 42 namespace { 43 44 class Executor { 45 public: 46 explicit Executor(StringRef S) : Saver(Alloc), Prog(Saver.save(S)) {} 47 void add(StringRef S) { Args.push_back(Saver.save(S)); } 48 void add(std::string &S) { Args.push_back(Saver.save(S)); } 49 void add(Twine S) { Args.push_back(Saver.save(S)); } 50 void add(const char *S) { Args.push_back(Saver.save(S)); } 51 52 std::error_code run() { 53 ErrorOr<std::string> ExeOrErr = llvm::sys::findProgramByName(Prog); 54 if (auto EC = ExeOrErr.getError()) { 55 llvm::errs() << "unable to find " << Prog << " in PATH: " 56 << EC.message() << "\n"; 57 return make_error_code(LLDError::InvalidOption); 58 } 59 const char *Exe = Saver.save(ExeOrErr.get()); 60 Args.insert(Args.begin(), Exe); 61 Args.push_back(nullptr); 62 if (llvm::sys::ExecuteAndWait(Args[0], Args.data()) != 0) { 63 for (const char *S : Args) 64 if (S) 65 llvm::errs() << S << " "; 66 llvm::errs() << "failed\n"; 67 return make_error_code(LLDError::InvalidOption); 68 } 69 return std::error_code(); 70 } 71 72 private: 73 llvm::BumpPtrAllocator Alloc; 74 llvm::BumpPtrStringSaver Saver; 75 StringRef Prog; 76 std::vector<const char *> Args; 77 }; 78 79 } // anonymous namespace 80 81 // Returns /machine's value. 82 ErrorOr<MachineTypes> getMachineType(StringRef S) { 83 MachineTypes MT = StringSwitch<MachineTypes>(S.lower()) 84 .Case("x64", IMAGE_FILE_MACHINE_AMD64) 85 .Case("amd64", IMAGE_FILE_MACHINE_AMD64) 86 .Case("x86", IMAGE_FILE_MACHINE_I386) 87 .Case("i386", IMAGE_FILE_MACHINE_I386) 88 .Case("arm", IMAGE_FILE_MACHINE_ARMNT) 89 .Default(IMAGE_FILE_MACHINE_UNKNOWN); 90 if (MT != IMAGE_FILE_MACHINE_UNKNOWN) 91 return MT; 92 llvm::errs() << "unknown /machine argument" << S << "\n"; 93 return make_error_code(LLDError::InvalidOption); 94 } 95 96 StringRef machineTypeToStr(MachineTypes MT) { 97 switch (MT) { 98 case IMAGE_FILE_MACHINE_ARMNT: 99 return "arm"; 100 case IMAGE_FILE_MACHINE_AMD64: 101 return "x64"; 102 case IMAGE_FILE_MACHINE_I386: 103 return "x86"; 104 default: 105 llvm_unreachable("unknown machine type"); 106 } 107 } 108 109 // Parses a string in the form of "<integer>[,<integer>]". 110 std::error_code parseNumbers(StringRef Arg, uint64_t *Addr, uint64_t *Size) { 111 StringRef S1, S2; 112 std::tie(S1, S2) = Arg.split(','); 113 if (S1.getAsInteger(0, *Addr)) { 114 llvm::errs() << "invalid number: " << S1 << "\n"; 115 return make_error_code(LLDError::InvalidOption); 116 } 117 if (Size && !S2.empty() && S2.getAsInteger(0, *Size)) { 118 llvm::errs() << "invalid number: " << S2 << "\n"; 119 return make_error_code(LLDError::InvalidOption); 120 } 121 return std::error_code(); 122 } 123 124 // Parses a string in the form of "<integer>[.<integer>]". 125 // If second number is not present, Minor is set to 0. 126 std::error_code parseVersion(StringRef Arg, uint32_t *Major, uint32_t *Minor) { 127 StringRef S1, S2; 128 std::tie(S1, S2) = Arg.split('.'); 129 if (S1.getAsInteger(0, *Major)) { 130 llvm::errs() << "invalid number: " << S1 << "\n"; 131 return make_error_code(LLDError::InvalidOption); 132 } 133 *Minor = 0; 134 if (!S2.empty() && S2.getAsInteger(0, *Minor)) { 135 llvm::errs() << "invalid number: " << S2 << "\n"; 136 return make_error_code(LLDError::InvalidOption); 137 } 138 return std::error_code(); 139 } 140 141 // Parses a string in the form of "<subsystem>[,<integer>[.<integer>]]". 142 std::error_code parseSubsystem(StringRef Arg, WindowsSubsystem *Sys, 143 uint32_t *Major, uint32_t *Minor) { 144 StringRef SysStr, Ver; 145 std::tie(SysStr, Ver) = Arg.split(','); 146 *Sys = StringSwitch<WindowsSubsystem>(SysStr.lower()) 147 .Case("boot_application", IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION) 148 .Case("console", IMAGE_SUBSYSTEM_WINDOWS_CUI) 149 .Case("efi_application", IMAGE_SUBSYSTEM_EFI_APPLICATION) 150 .Case("efi_boot_service_driver", IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) 151 .Case("efi_rom", IMAGE_SUBSYSTEM_EFI_ROM) 152 .Case("efi_runtime_driver", IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) 153 .Case("native", IMAGE_SUBSYSTEM_NATIVE) 154 .Case("posix", IMAGE_SUBSYSTEM_POSIX_CUI) 155 .Case("windows", IMAGE_SUBSYSTEM_WINDOWS_GUI) 156 .Default(IMAGE_SUBSYSTEM_UNKNOWN); 157 if (*Sys == IMAGE_SUBSYSTEM_UNKNOWN) { 158 llvm::errs() << "unknown subsystem: " << SysStr << "\n"; 159 return make_error_code(LLDError::InvalidOption); 160 } 161 if (!Ver.empty()) 162 if (auto EC = parseVersion(Ver, Major, Minor)) 163 return EC; 164 return std::error_code(); 165 } 166 167 // Parse a string of the form of "<from>=<to>". 168 // Results are directly written to Config. 169 std::error_code parseAlternateName(StringRef S) { 170 StringRef From, To; 171 std::tie(From, To) = S.split('='); 172 if (From.empty() || To.empty()) { 173 llvm::errs() << "/alternatename: invalid argument: " << S << "\n"; 174 return make_error_code(LLDError::InvalidOption); 175 } 176 auto It = Config->AlternateNames.find(From); 177 if (It != Config->AlternateNames.end() && It->second != To) { 178 llvm::errs() << "/alternatename: conflicts: " << S << "\n"; 179 return make_error_code(LLDError::InvalidOption); 180 } 181 Config->AlternateNames.insert(It, std::make_pair(From, To)); 182 return std::error_code(); 183 } 184 185 // Parse a string of the form of "<from>=<to>". 186 // Results are directly written to Config. 187 std::error_code parseMerge(StringRef S) { 188 StringRef From, To; 189 std::tie(From, To) = S.split('='); 190 if (From.empty() || To.empty()) { 191 llvm::errs() << "/merge: invalid argument: " << S << "\n"; 192 return make_error_code(LLDError::InvalidOption); 193 } 194 auto Pair = Config->Merge.insert(std::make_pair(From, To)); 195 bool Inserted = Pair.second; 196 if (!Inserted) { 197 StringRef Existing = Pair.first->second; 198 if (Existing != To) 199 llvm::errs() << "warning: " << S << ": already merged into " 200 << Existing << "\n"; 201 } 202 return std::error_code(); 203 } 204 205 // Parses a string in the form of "EMBED[,=<integer>]|NO". 206 // Results are directly written to Config. 207 std::error_code parseManifest(StringRef Arg) { 208 if (Arg.equals_lower("no")) { 209 Config->Manifest = Configuration::No; 210 return std::error_code(); 211 } 212 if (!Arg.startswith_lower("embed")) 213 return make_error_code(LLDError::InvalidOption); 214 Config->Manifest = Configuration::Embed; 215 Arg = Arg.substr(strlen("embed")); 216 if (Arg.empty()) 217 return std::error_code(); 218 if (!Arg.startswith_lower(",id=")) 219 return make_error_code(LLDError::InvalidOption); 220 Arg = Arg.substr(strlen(",id=")); 221 if (Arg.getAsInteger(0, Config->ManifestID)) 222 return make_error_code(LLDError::InvalidOption); 223 return std::error_code(); 224 } 225 226 // Parses a string in the form of "level=<string>|uiAccess=<string>|NO". 227 // Results are directly written to Config. 228 std::error_code parseManifestUAC(StringRef Arg) { 229 if (Arg.equals_lower("no")) { 230 Config->ManifestUAC = false; 231 return std::error_code(); 232 } 233 for (;;) { 234 Arg = Arg.ltrim(); 235 if (Arg.empty()) 236 return std::error_code(); 237 if (Arg.startswith_lower("level=")) { 238 Arg = Arg.substr(strlen("level=")); 239 std::tie(Config->ManifestLevel, Arg) = Arg.split(" "); 240 continue; 241 } 242 if (Arg.startswith_lower("uiaccess=")) { 243 Arg = Arg.substr(strlen("uiaccess=")); 244 std::tie(Config->ManifestUIAccess, Arg) = Arg.split(" "); 245 continue; 246 } 247 return make_error_code(LLDError::InvalidOption); 248 } 249 } 250 251 // Quote each line with "". Existing double-quote is converted 252 // to two double-quotes. 253 static void quoteAndPrint(raw_ostream &Out, StringRef S) { 254 while (!S.empty()) { 255 StringRef Line; 256 std::tie(Line, S) = S.split("\n"); 257 if (Line.empty()) 258 continue; 259 Out << '\"'; 260 for (int I = 0, E = Line.size(); I != E; ++I) { 261 if (Line[I] == '\"') { 262 Out << "\"\""; 263 } else { 264 Out << Line[I]; 265 } 266 } 267 Out << "\"\n"; 268 } 269 } 270 271 // Create a manifest file contents. 272 static std::string createManifestXml() { 273 std::string S; 274 llvm::raw_string_ostream OS(S); 275 // Emit the XML. Note that we do *not* verify that the XML attributes are 276 // syntactically correct. This is intentional for link.exe compatibility. 277 OS << "<?xml version=\"1.0\" standalone=\"yes\"?>\n" 278 << "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\"\n" 279 << " manifestVersion=\"1.0\">\n"; 280 if (Config->ManifestUAC) { 281 OS << " <trustInfo>\n" 282 << " <security>\n" 283 << " <requestedPrivileges>\n" 284 << " <requestedExecutionLevel level=" << Config->ManifestLevel 285 << " uiAccess=" << Config->ManifestUIAccess << "/>\n" 286 << " </requestedPrivileges>\n" 287 << " </security>\n" 288 << " </trustInfo>\n"; 289 if (!Config->ManifestDependency.empty()) { 290 OS << " <dependency>\n" 291 << " <dependentAssembly>\n" 292 << " <assemblyIdentity " << Config->ManifestDependency << " />\n" 293 << " </dependentAssembly>\n" 294 << " </dependency>\n"; 295 } 296 } 297 OS << "</assembly>\n"; 298 OS.flush(); 299 return S; 300 } 301 302 // Create a resource file containing a manifest XML. 303 ErrorOr<std::unique_ptr<MemoryBuffer>> createManifestRes() { 304 // Create a temporary file for the resource script file. 305 SmallString<128> RCPath; 306 if (sys::fs::createTemporaryFile("tmp", "rc", RCPath)) { 307 llvm::errs() << "cannot create a temporary file\n"; 308 return make_error_code(LLDError::InvalidOption); 309 } 310 FileRemover RCRemover(RCPath); 311 312 // Open the temporary file for writing. 313 std::error_code EC; 314 llvm::raw_fd_ostream Out(RCPath, EC, sys::fs::F_Text); 315 if (EC) { 316 llvm::errs() << "failed to open " << RCPath << ": " << EC.message() << "\n"; 317 return make_error_code(LLDError::InvalidOption); 318 } 319 320 // Write resource script to the RC file. 321 Out << "#define LANG_ENGLISH 9\n" 322 << "#define SUBLANG_DEFAULT 1\n" 323 << "#define APP_MANIFEST " << Config->ManifestID << "\n" 324 << "#define RT_MANIFEST 24\n" 325 << "LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT\n" 326 << "APP_MANIFEST RT_MANIFEST {\n"; 327 quoteAndPrint(Out, createManifestXml()); 328 Out << "}\n"; 329 Out.close(); 330 331 // Create output resource file. 332 SmallString<128> ResPath; 333 if (sys::fs::createTemporaryFile("tmp", "res", ResPath)) { 334 llvm::errs() << "cannot create a temporary file\n"; 335 return make_error_code(LLDError::InvalidOption); 336 } 337 338 Executor E("rc.exe"); 339 E.add("/fo"); 340 E.add(ResPath.str()); 341 E.add("/nologo"); 342 E.add(RCPath.str()); 343 if (auto EC = E.run()) 344 return EC; 345 return MemoryBuffer::getFile(ResPath); 346 } 347 348 std::error_code createSideBySideManifest() { 349 std::string Path = Config->ManifestFile; 350 if (Path == "") 351 Path = (Twine(Config->OutputFile) + ".manifest").str(); 352 std::error_code EC; 353 llvm::raw_fd_ostream Out(Path, EC, llvm::sys::fs::F_Text); 354 if (EC) { 355 llvm::errs() << EC.message() << "\n"; 356 return EC; 357 } 358 Out << createManifestXml(); 359 return std::error_code(); 360 } 361 362 // Parse a string in the form of 363 // "<name>[=<internalname>][,@ordinal[,NONAME]][,DATA][,PRIVATE]". 364 // Used for parsing /export arguments. 365 ErrorOr<Export> parseExport(StringRef Arg) { 366 Export E; 367 StringRef Rest; 368 std::tie(E.Name, Rest) = Arg.split(","); 369 if (E.Name.empty()) 370 goto err; 371 if (E.Name.find('=') != StringRef::npos) { 372 std::tie(E.ExtName, E.Name) = E.Name.split("="); 373 if (E.Name.empty()) 374 goto err; 375 } else { 376 E.ExtName = E.Name; 377 } 378 379 while (!Rest.empty()) { 380 StringRef Tok; 381 std::tie(Tok, Rest) = Rest.split(","); 382 if (Tok.equals_lower("noname")) { 383 if (E.Ordinal == 0) 384 goto err; 385 E.Noname = true; 386 continue; 387 } 388 if (Tok.equals_lower("data")) { 389 E.Data = true; 390 continue; 391 } 392 if (Tok.equals_lower("private")) { 393 E.Private = true; 394 continue; 395 } 396 if (Tok.startswith("@")) { 397 int32_t Ord; 398 if (Tok.substr(1).getAsInteger(0, Ord)) 399 goto err; 400 if (Ord <= 0 || 65535 < Ord) 401 goto err; 402 E.Ordinal = Ord; 403 continue; 404 } 405 goto err; 406 } 407 return E; 408 409 err: 410 llvm::errs() << "invalid /export: " << Arg << "\n"; 411 return make_error_code(LLDError::InvalidOption); 412 } 413 414 // Performs error checking on all /export arguments. 415 // It also sets ordinals. 416 std::error_code fixupExports() { 417 // Symbol ordinals must be unique. 418 std::set<uint16_t> Ords; 419 for (Export &E : Config->Exports) { 420 if (E.Ordinal == 0) 421 continue; 422 if (!Ords.insert(E.Ordinal).second) { 423 llvm::errs() << "duplicate export ordinal: " << E.Name << "\n"; 424 return make_error_code(LLDError::InvalidOption); 425 } 426 } 427 428 // Uniquefy by name. 429 std::map<StringRef, Export *> Map; 430 std::vector<Export> V; 431 for (Export &E : Config->Exports) { 432 auto Pair = Map.insert(std::make_pair(E.Name, &E)); 433 bool Inserted = Pair.second; 434 if (Inserted) { 435 V.push_back(E); 436 continue; 437 } 438 Export *Existing = Pair.first->second; 439 if (E == *Existing) 440 continue; 441 llvm::errs() << "warning: duplicate /export option: " << E.Name << "\n"; 442 continue; 443 } 444 Config->Exports = std::move(V); 445 446 // Sort by name. 447 std::sort( 448 Config->Exports.begin(), Config->Exports.end(), 449 [](const Export &A, const Export &B) { return A.ExtName < B.ExtName; }); 450 451 // Assign unique ordinals if default (= 0). 452 uint16_t Max = 0; 453 for (Export &E : Config->Exports) 454 Max = std::max(Max, E.Ordinal); 455 for (Export &E : Config->Exports) 456 if (E.Ordinal == 0) 457 E.Ordinal = ++Max; 458 return std::error_code(); 459 } 460 461 // Parses a string in the form of "key=value" and check 462 // if value matches previous values for the same key. 463 std::error_code checkFailIfMismatch(StringRef Arg) { 464 StringRef K, V; 465 std::tie(K, V) = Arg.split('='); 466 if (K.empty() || V.empty()) { 467 llvm::errs() << "/failifmismatch: invalid argument: " << Arg << "\n"; 468 return make_error_code(LLDError::InvalidOption); 469 } 470 StringRef Existing = Config->MustMatch[K]; 471 if (!Existing.empty() && V != Existing) { 472 llvm::errs() << "/failifmismatch: mismatch detected: " 473 << Existing << " and " << V << " for key " << K << "\n"; 474 return make_error_code(LLDError::InvalidOption); 475 } 476 Config->MustMatch[K] = V; 477 return std::error_code(); 478 } 479 480 // Convert Windows resource files (.res files) to a .obj file 481 // using cvtres.exe. 482 ErrorOr<std::unique_ptr<MemoryBuffer>> 483 convertResToCOFF(const std::vector<MemoryBufferRef> &MBs) { 484 // Create an output file path. 485 SmallString<128> Path; 486 if (llvm::sys::fs::createTemporaryFile("resource", "obj", Path)) 487 return make_error_code(LLDError::InvalidOption); 488 489 // Execute cvtres.exe. 490 Executor E("cvtres.exe"); 491 E.add("/machine:" + machineTypeToStr(Config->MachineType)); 492 E.add("/readonly"); 493 E.add("/nologo"); 494 E.add("/out:" + Path); 495 for (MemoryBufferRef MB : MBs) 496 E.add(MB.getBufferIdentifier()); 497 if (auto EC = E.run()) 498 return EC; 499 return MemoryBuffer::getFile(Path); 500 } 501 502 static std::string writeToTempFile(StringRef Contents) { 503 SmallString<128> Path; 504 int FD; 505 if (llvm::sys::fs::createTemporaryFile("tmp", "def", FD, Path)) { 506 llvm::errs() << "failed to create a temporary file\n"; 507 return ""; 508 } 509 llvm::raw_fd_ostream OS(FD, /*shouldClose*/ true); 510 OS << Contents; 511 return Path.str(); 512 } 513 514 /// Creates a .def file containing the list of exported symbols. 515 static std::string createModuleDefinitionFile() { 516 std::string S; 517 llvm::raw_string_ostream OS(S); 518 OS << "LIBRARY \"" << llvm::sys::path::filename(Config->OutputFile) << "\"\n" 519 << "EXPORTS\n"; 520 for (Export &E : Config->Exports) { 521 OS << " " << E.ExtName; 522 if (E.Ordinal > 0) 523 OS << " @" << E.Ordinal; 524 if (E.Noname) 525 OS << " NONAME"; 526 if (E.Data) 527 OS << " DATA"; 528 if (E.Private) 529 OS << " PRIVATE"; 530 OS << "\n"; 531 } 532 OS.flush(); 533 return S; 534 } 535 536 // Creates a .def file and runs lib.exe on it to create an import library. 537 std::error_code writeImportLibrary() { 538 std::string Contents = createModuleDefinitionFile(); 539 std::string Def = writeToTempFile(Contents); 540 llvm::FileRemover TempFile(Def); 541 542 Executor E("lib.exe"); 543 E.add("/nologo"); 544 E.add("/machine:" + machineTypeToStr(Config->MachineType)); 545 E.add(Twine("/def:") + Def); 546 if (Config->Implib.empty()) { 547 SmallString<128> Out = StringRef(Config->OutputFile); 548 sys::path::replace_extension(Out, ".lib"); 549 E.add("/out:" + Out); 550 } else { 551 E.add("/out:" + Config->Implib); 552 } 553 return E.run(); 554 } 555 556 void touchFile(StringRef Path) { 557 int FD; 558 if (sys::fs::openFileForWrite(Path, FD, sys::fs::F_Append)) 559 report_fatal_error("failed to create a file"); 560 sys::Process::SafelyCloseFileDescriptor(FD); 561 } 562 563 // Create OptTable 564 565 // Create prefix string literals used in Options.td 566 #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; 567 #include "Options.inc" 568 #undef PREFIX 569 570 // Create table mapping all options defined in Options.td 571 static const llvm::opt::OptTable::Info infoTable[] = { 572 #define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X6, X7, X8, X9, X10) \ 573 { \ 574 X1, X2, X9, X10, OPT_##ID, llvm::opt::Option::KIND##Class, X8, X7, \ 575 OPT_##GROUP, OPT_##ALIAS, X6 \ 576 }, 577 #include "Options.inc" 578 #undef OPTION 579 }; 580 581 class COFFOptTable : public llvm::opt::OptTable { 582 public: 583 COFFOptTable() : OptTable(infoTable, llvm::array_lengthof(infoTable), true) {} 584 }; 585 586 // Parses a given list of options. 587 ErrorOr<llvm::opt::InputArgList> 588 ArgParser::parse(ArrayRef<const char *> ArgsArr) { 589 // First, replace respnose files (@<file>-style options). 590 auto ArgvOrErr = replaceResponseFiles(ArgsArr); 591 if (auto EC = ArgvOrErr.getError()) { 592 llvm::errs() << "error while reading response file: " << EC.message() 593 << "\n"; 594 return EC; 595 } 596 std::vector<const char *> Argv = std::move(ArgvOrErr.get()); 597 598 // Make InputArgList from string vectors. 599 COFFOptTable Table; 600 unsigned MissingIndex; 601 unsigned MissingCount; 602 llvm::opt::InputArgList Args = 603 Table.ParseArgs(Argv, MissingIndex, MissingCount); 604 if (MissingCount) { 605 llvm::errs() << "missing arg value for \"" 606 << Args.getArgString(MissingIndex) << "\", expected " 607 << MissingCount 608 << (MissingCount == 1 ? " argument.\n" : " arguments.\n"); 609 return make_error_code(LLDError::InvalidOption); 610 } 611 for (auto *Arg : Args.filtered(OPT_UNKNOWN)) 612 llvm::errs() << "ignoring unknown argument: " << Arg->getSpelling() << "\n"; 613 return std::move(Args); 614 } 615 616 ErrorOr<llvm::opt::InputArgList> 617 ArgParser::parseLINK(ArrayRef<const char *> Args) { 618 // Concatenate LINK env and given arguments and parse them. 619 Optional<std::string> Env = Process::GetEnv("LINK"); 620 if (!Env) 621 return parse(Args); 622 std::vector<const char *> V = tokenize(*Env); 623 V.insert(V.end(), Args.begin(), Args.end()); 624 return parse(V); 625 } 626 627 std::vector<const char *> ArgParser::tokenize(StringRef S) { 628 SmallVector<const char *, 16> Tokens; 629 BumpPtrStringSaver Saver(AllocAux); 630 llvm::cl::TokenizeWindowsCommandLine(S, Saver, Tokens); 631 return std::vector<const char *>(Tokens.begin(), Tokens.end()); 632 } 633 634 // Creates a new command line by replacing options starting with '@' 635 // character. '@<filename>' is replaced by the file's contents. 636 ErrorOr<std::vector<const char *>> 637 ArgParser::replaceResponseFiles(std::vector<const char *> Argv) { 638 SmallVector<const char *, 256> Tokens(Argv.data(), Argv.data() + Argv.size()); 639 BumpPtrStringSaver Saver(AllocAux); 640 ExpandResponseFiles(Saver, TokenizeWindowsCommandLine, Tokens); 641 return std::vector<const char *>(Tokens.begin(), Tokens.end()); 642 } 643 644 void printHelp(const char *Argv0) { 645 COFFOptTable Table; 646 Table.PrintHelp(llvm::outs(), Argv0, "LLVM Linker", false); 647 } 648 649 } // namespace coff 650 } // namespace lld 651