|
19 | 19 | #include "llvm/ADT/Optional.h"
|
20 | 20 | #include "llvm/ADT/StringSwitch.h"
|
21 | 21 | #include "llvm/LibDriver/LibDriver.h"
|
| 22 | +#include "llvm/Object/ArchiveWriter.h" |
22 | 23 | #include "llvm/Option/Arg.h"
|
23 | 24 | #include "llvm/Option/ArgList.h"
|
24 | 25 | #include "llvm/Option/Option.h"
|
@@ -136,9 +137,6 @@ void LinkerDriver::enqueuePath(StringRef Path) {
|
136 | 137 | fatal(MBOrErr.second, "could not open " + PathStr);
|
137 | 138 | Driver->addBuffer(std::move(MBOrErr.first));
|
138 | 139 | });
|
139 |
| - |
140 |
| - if (Config->OutputFile == "") |
141 |
| - Config->OutputFile = getOutputPath(Path); |
142 | 140 | }
|
143 | 141 |
|
144 | 142 | void LinkerDriver::addArchiveBuffer(MemoryBufferRef MB, StringRef SymName,
|
@@ -417,71 +415,130 @@ static std::string getMapFile(const opt::InputArgList &Args) {
|
417 | 415 | return (OutFile.substr(0, OutFile.rfind('.')) + ".map").str();
|
418 | 416 | }
|
419 | 417 |
|
420 |
| -// Returns true if a given file is a LLVM bitcode file. If it is a |
421 |
| -// static library, this function returns true if all files in the |
422 |
| -// archive are bitcode files. |
423 |
| -static bool isBitcodeFile(StringRef Path) { |
424 |
| - using namespace sys::fs; |
| 418 | +std::vector<MemoryBufferRef> getArchiveMembers(Archive *File) { |
| 419 | + std::vector<MemoryBufferRef> V; |
| 420 | + Error Err = Error::success(); |
| 421 | + for (const ErrorOr<Archive::Child> &COrErr : File->children(Err)) { |
| 422 | + Archive::Child C = |
| 423 | + check(COrErr, |
| 424 | + File->getFileName() + ": could not get the child of the archive"); |
| 425 | + MemoryBufferRef MBRef = |
| 426 | + check(C.getMemoryBufferRef(), |
| 427 | + File->getFileName() + |
| 428 | + ": could not get the buffer for a child of the archive"); |
| 429 | + V.push_back(MBRef); |
| 430 | + } |
| 431 | + if (Err) |
| 432 | + fatal(File->getFileName() + |
| 433 | + ": Archive::children failed: " + toString(std::move(Err))); |
| 434 | + return V; |
| 435 | +} |
| 436 | + |
| 437 | +// A helper function for filterBitcodeFiles. |
| 438 | +static bool needsRebuilding(MemoryBufferRef MB) { |
| 439 | + // The MSVC linker doesn't support thin archives, so if it's a thin |
| 440 | + // archive, we always need to rebuild it. |
| 441 | + std::unique_ptr<Archive> File = |
| 442 | + check(Archive::create(MB), "Failed to read " + MB.getBufferIdentifier()); |
| 443 | + if (File->isThin()) |
| 444 | + return true; |
| 445 | + |
| 446 | + // Returns true if the archive contains at least one bitcode file. |
| 447 | + for (MemoryBufferRef Member : getArchiveMembers(File.get())) |
| 448 | + if (identify_magic(Member.getBuffer()) == file_magic::bitcode) |
| 449 | + return true; |
| 450 | + return false; |
| 451 | +} |
425 | 452 |
|
| 453 | +// Opens a given path as an archive file and removes bitcode files |
| 454 | +// from them if exists. This function is to appease the MSVC linker as |
| 455 | +// their linker doesn't like archive files containing non-native |
| 456 | +// object files. |
| 457 | +// |
| 458 | +// If a given archive doesn't contain bitcode files, the archive path |
| 459 | +// is returned as-is. Otherwise, a new temporary file is created and |
| 460 | +// its path is returned. |
| 461 | +static Optional<std::string> |
| 462 | +filterBitcodeFiles(StringRef Path, std::vector<std::string> &TemporaryFiles) { |
426 | 463 | std::unique_ptr<MemoryBuffer> MB = check(
|
427 | 464 | MemoryBuffer::getFile(Path, -1, false, true), "could not open " + Path);
|
428 |
| - file_magic Magic = identify_magic(MB->getBuffer()); |
| 465 | + MemoryBufferRef MBRef = MB->getMemBufferRef(); |
| 466 | + file_magic Magic = identify_magic(MBRef.getBuffer()); |
429 | 467 |
|
430 | 468 | if (Magic == file_magic::bitcode)
|
431 |
| - return true; |
| 469 | + return None; |
| 470 | + if (Magic != file_magic::archive) |
| 471 | + return Path.str(); |
| 472 | + if (!needsRebuilding(MBRef)) |
| 473 | + return Path.str(); |
432 | 474 |
|
433 |
| - if (Magic == file_magic::archive) { |
434 |
| - std::unique_ptr<Archive> File = |
435 |
| - check(Archive::create(MB->getMemBufferRef())); |
436 |
| - |
437 |
| - Error Err = Error::success(); |
438 |
| - for (const ErrorOr<Archive::Child> &COrErr : File->children(Err)) { |
439 |
| - if (Err) |
440 |
| - return false; |
441 |
| - Archive::Child C = check(COrErr); |
442 |
| - MemoryBufferRef MBRef = check(C.getMemoryBufferRef()); |
443 |
| - if (identify_magic(MBRef.getBuffer()) != file_magic::bitcode) |
444 |
| - return false; |
445 |
| - } |
446 |
| - if (Err) |
447 |
| - return false; |
448 |
| - return true; |
449 |
| - } |
| 475 | + std::unique_ptr<Archive> File = |
| 476 | + check(Archive::create(MBRef), |
| 477 | + MBRef.getBufferIdentifier() + ": failed to parse archive"); |
450 | 478 |
|
451 |
| - return false; |
| 479 | + std::vector<NewArchiveMember> New; |
| 480 | + for (MemoryBufferRef Member : getArchiveMembers(File.get())) |
| 481 | + if (identify_magic(Member.getBuffer()) != file_magic::bitcode) |
| 482 | + New.emplace_back(Member); |
| 483 | + |
| 484 | + if (New.empty()) |
| 485 | + return None; |
| 486 | + |
| 487 | + log("Creating a temporary archive for " + Path + " to remove bitcode files"); |
| 488 | + |
| 489 | + SmallString<128> S; |
| 490 | + if (auto EC = sys::fs::createTemporaryFile("lld-" + sys::path::stem(Path), |
| 491 | + ".lib", S)) |
| 492 | + fatal(EC, "cannot create a temporary file"); |
| 493 | + std::string Temp = S.str(); |
| 494 | + TemporaryFiles.push_back(Temp); |
| 495 | + |
| 496 | + std::pair<StringRef, std::error_code> Ret = |
| 497 | + llvm::writeArchive(Temp, New, /*WriteSymtab=*/true, Archive::Kind::K_GNU, |
| 498 | + /*Deterministics=*/true, |
| 499 | + /*Thin=*/false); |
| 500 | + if (Ret.second) |
| 501 | + error("failed to create a new archive " + S.str() + ": " + Ret.first); |
| 502 | + return Temp; |
452 | 503 | }
|
453 | 504 |
|
454 | 505 | // Create response file contents and invoke the MSVC linker.
|
455 | 506 | void LinkerDriver::invokeMSVC(opt::InputArgList &Args) {
|
456 | 507 | std::string Rsp = "/nologo ";
|
| 508 | + std::vector<std::string> Temps; |
457 | 509 |
|
458 | 510 | for (auto *Arg : Args) {
|
459 | 511 | switch (Arg->getOption().getID()) {
|
460 | 512 | case OPT_linkrepro:
|
461 | 513 | case OPT_lldmap:
|
462 | 514 | case OPT_lldmap_file:
|
| 515 | + case OPT_lldsavetemps: |
463 | 516 | case OPT_msvclto:
|
464 | 517 | // LLD-specific options are stripped.
|
465 | 518 | break;
|
466 | 519 | case OPT_opt:
|
467 | 520 | if (!StringRef(Arg->getValue()).startswith("lld"))
|
468 | 521 | Rsp += toString(Arg) + " ";
|
469 | 522 | break;
|
470 |
| - case OPT_INPUT: |
471 |
| - // Bitcode files are stripped as they've been compiled to |
472 |
| - // native object files. |
473 |
| - if (Optional<StringRef> Path = doFindFile(Arg->getValue())) |
474 |
| - if (isBitcodeFile(*Path)) |
475 |
| - break; |
| 523 | + case OPT_INPUT: { |
| 524 | + if (Optional<StringRef> Path = doFindFile(Arg->getValue())) { |
| 525 | + if (Optional<std::string> S = filterBitcodeFiles(*Path, Temps)) |
| 526 | + Rsp += quote(*S) + " "; |
| 527 | + continue; |
| 528 | + } |
476 | 529 | Rsp += quote(Arg->getValue()) + " ";
|
477 | 530 | break;
|
| 531 | + } |
478 | 532 | default:
|
479 | 533 | Rsp += toString(Arg) + " ";
|
480 | 534 | }
|
481 | 535 | }
|
482 | 536 |
|
483 | 537 | std::vector<StringRef> ObjectFiles = Symtab.compileBitcodeFiles();
|
484 | 538 | runMSVCLinker(Rsp, ObjectFiles);
|
| 539 | + |
| 540 | + for (StringRef Path : Temps) |
| 541 | + sys::fs::remove(Path); |
485 | 542 | }
|
486 | 543 |
|
487 | 544 | void LinkerDriver::enqueueTask(std::function<void()> Task) {
|
@@ -517,6 +574,13 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
|
517 | 574 | // Parse command line options.
|
518 | 575 | opt::InputArgList Args = Parser.parseLINK(ArgsArr.slice(1));
|
519 | 576 |
|
| 577 | + // Parse and evaluate -mllvm options. |
| 578 | + std::vector<const char *> V; |
| 579 | + V.push_back("lld-link (LLVM option parsing)"); |
| 580 | + for (auto *Arg : Args.filtered(OPT_mllvm)) |
| 581 | + V.push_back(Arg->getValue()); |
| 582 | + cl::ParseCommandLineOptions(V.size(), V.data()); |
| 583 | + |
520 | 584 | // Handle /help
|
521 | 585 | if (Args.hasArg(OPT_help)) {
|
522 | 586 | printHelp(ArgsArr[0]);
|
@@ -827,6 +891,22 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
|
827 | 891 | }
|
828 | 892 | }
|
829 | 893 |
|
| 894 | + // Set default image name if neither /out or /def set it. |
| 895 | + if (Config->OutputFile.empty()) { |
| 896 | + Config->OutputFile = |
| 897 | + getOutputPath((*Args.filtered_begin(OPT_INPUT))->getValue()); |
| 898 | + } |
| 899 | + |
| 900 | + // Put the PDB next to the image if no /pdb flag was passed. |
| 901 | + if (Config->Debug && Config->PDBPath.empty()) { |
| 902 | + Config->PDBPath = Config->OutputFile; |
| 903 | + sys::path::replace_extension(Config->PDBPath, ".pdb"); |
| 904 | + } |
| 905 | + |
| 906 | + // Disable PDB generation if the user requested it. |
| 907 | + if (Args.hasArg(OPT_nopdb)) |
| 908 | + Config->PDBPath = ""; |
| 909 | + |
830 | 910 | // Set default image base if /base is not given.
|
831 | 911 | if (Config->ImageBase == uint64_t(-1))
|
832 | 912 | Config->ImageBase = getDefaultImageBase();
|
|
0 commit comments