llvm-ar.cpp revision 344779
1//===-- llvm-ar.cpp - LLVM archive librarian utility ----------------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// Builds up (relatively) standard unix archive files (.a) containing LLVM 11// bitcode or other files. 12// 13//===----------------------------------------------------------------------===// 14 15#include "llvm/ADT/StringSwitch.h" 16#include "llvm/ADT/Triple.h" 17#include "llvm/IR/LLVMContext.h" 18#include "llvm/Object/Archive.h" 19#include "llvm/Object/ArchiveWriter.h" 20#include "llvm/Object/MachO.h" 21#include "llvm/Object/ObjectFile.h" 22#include "llvm/Support/Chrono.h" 23#include "llvm/Support/CommandLine.h" 24#include "llvm/Support/Errc.h" 25#include "llvm/Support/FileSystem.h" 26#include "llvm/Support/Format.h" 27#include "llvm/Support/FormatVariadic.h" 28#include "llvm/Support/InitLLVM.h" 29#include "llvm/Support/LineIterator.h" 30#include "llvm/Support/MemoryBuffer.h" 31#include "llvm/Support/Path.h" 32#include "llvm/Support/Process.h" 33#include "llvm/Support/StringSaver.h" 34#include "llvm/Support/TargetSelect.h" 35#include "llvm/Support/ToolOutputFile.h" 36#include "llvm/Support/WithColor.h" 37#include "llvm/Support/raw_ostream.h" 38#include "llvm/ToolDrivers/llvm-dlltool/DlltoolDriver.h" 39#include "llvm/ToolDrivers/llvm-lib/LibDriver.h" 40 41#if !defined(_MSC_VER) && !defined(__MINGW32__) 42#include <unistd.h> 43#else 44#include <io.h> 45#endif 46 47using namespace llvm; 48 49// The name this program was invoked as. 50static StringRef ToolName; 51 52// The basename of this program. 53static StringRef Stem; 54 55const char RanlibHelp[] = R"( 56OVERVIEW: LLVM Ranlib (llvm-ranlib) 57 58 This program generates an index to speed access to archives 59 60USAGE: llvm-ranlib <archive-file> 61 62OPTIONS: 63 -help - Display available options 64 -version - Display the version of this program 65)"; 66 67const char ArHelp[] = R"( 68OVERVIEW: LLVM Archiver 69 70USAGE: llvm-ar [options] [-]<operation>[modifiers] [relpos] <archive> [files] 71 llvm-ar -M [<mri-script] 72 73OPTIONS: 74 --format - Archive format to create 75 =default - default 76 =gnu - gnu 77 =darwin - darwin 78 =bsd - bsd 79 --plugin=<string> - Ignored for compatibility 80 --help - Display available options 81 --version - Display the version of this program 82 83OPERATIONS: 84 d - delete [files] from the archive 85 m - move [files] in the archive 86 p - print [files] found in the archive 87 q - quick append [files] to the archive 88 r - replace or insert [files] into the archive 89 s - act as ranlib 90 t - display contents of archive 91 x - extract [files] from the archive 92 93MODIFIERS: 94 [a] - put [files] after [relpos] 95 [b] - put [files] before [relpos] (same as [i]) 96 [c] - do not warn if archive had to be created 97 [D] - use zero for timestamps and uids/gids (default) 98 [i] - put [files] before [relpos] (same as [b]) 99 [l] - ignored for compatibility 100 [L] - add archive's contents 101 [o] - preserve original dates 102 [s] - create an archive index (cf. ranlib) 103 [S] - do not build a symbol table 104 [T] - create a thin archive 105 [u] - update only [files] newer than archive contents 106 [U] - use actual timestamps and uids/gids 107 [v] - be verbose about actions taken 108)"; 109 110void printHelpMessage() { 111 if (Stem.contains_lower("ranlib")) 112 outs() << RanlibHelp; 113 else if (Stem.contains_lower("ar")) 114 outs() << ArHelp; 115} 116 117// Show the error message and exit. 118LLVM_ATTRIBUTE_NORETURN static void fail(Twine Error) { 119 WithColor::error(errs(), ToolName) << Error << ".\n"; 120 printHelpMessage(); 121 exit(1); 122} 123 124static void failIfError(std::error_code EC, Twine Context = "") { 125 if (!EC) 126 return; 127 128 std::string ContextStr = Context.str(); 129 if (ContextStr.empty()) 130 fail(EC.message()); 131 fail(Context + ": " + EC.message()); 132} 133 134static void failIfError(Error E, Twine Context = "") { 135 if (!E) 136 return; 137 138 handleAllErrors(std::move(E), [&](const llvm::ErrorInfoBase &EIB) { 139 std::string ContextStr = Context.str(); 140 if (ContextStr.empty()) 141 fail(EIB.message()); 142 fail(Context + ": " + EIB.message()); 143 }); 144} 145 146static SmallVector<const char *, 256> PositionalArgs; 147 148static bool MRI; 149 150namespace { 151enum Format { Default, GNU, BSD, DARWIN, Unknown }; 152} 153 154static Format FormatType = Default; 155 156static std::string Options; 157 158// This enumeration delineates the kinds of operations on an archive 159// that are permitted. 160enum ArchiveOperation { 161 Print, ///< Print the contents of the archive 162 Delete, ///< Delete the specified members 163 Move, ///< Move members to end or as given by {a,b,i} modifiers 164 QuickAppend, ///< Quickly append to end of archive 165 ReplaceOrInsert, ///< Replace or Insert members 166 DisplayTable, ///< Display the table of contents 167 Extract, ///< Extract files back to file system 168 CreateSymTab ///< Create a symbol table in an existing archive 169}; 170 171// Modifiers to follow operation to vary behavior 172static bool AddAfter = false; ///< 'a' modifier 173static bool AddBefore = false; ///< 'b' modifier 174static bool Create = false; ///< 'c' modifier 175static bool OriginalDates = false; ///< 'o' modifier 176static bool OnlyUpdate = false; ///< 'u' modifier 177static bool Verbose = false; ///< 'v' modifier 178static bool Symtab = true; ///< 's' modifier 179static bool Deterministic = true; ///< 'D' and 'U' modifiers 180static bool Thin = false; ///< 'T' modifier 181static bool AddLibrary = false; ///< 'L' modifier 182 183// Relative Positional Argument (for insert/move). This variable holds 184// the name of the archive member to which the 'a', 'b' or 'i' modifier 185// refers. Only one of 'a', 'b' or 'i' can be specified so we only need 186// one variable. 187static std::string RelPos; 188 189// This variable holds the name of the archive file as given on the 190// command line. 191static std::string ArchiveName; 192 193// This variable holds the list of member files to proecess, as given 194// on the command line. 195static std::vector<StringRef> Members; 196 197// Extract the member filename from the command line for the [relpos] argument 198// associated with a, b, and i modifiers 199static void getRelPos() { 200 if (PositionalArgs.empty()) 201 fail("Expected [relpos] for a, b, or i modifier"); 202 RelPos = PositionalArgs[0]; 203 PositionalArgs.erase(PositionalArgs.begin()); 204} 205 206// Get the archive file name from the command line 207static void getArchive() { 208 if (PositionalArgs.empty()) 209 fail("An archive name must be specified"); 210 ArchiveName = PositionalArgs[0]; 211 PositionalArgs.erase(PositionalArgs.begin()); 212} 213 214// Copy over remaining items in PositionalArgs to our Members vector 215static void getMembers() { 216 for (auto &Arg : PositionalArgs) 217 Members.push_back(Arg); 218} 219 220std::vector<std::unique_ptr<MemoryBuffer>> ArchiveBuffers; 221std::vector<std::unique_ptr<object::Archive>> Archives; 222 223static object::Archive &readLibrary(const Twine &Library) { 224 auto BufOrErr = MemoryBuffer::getFile(Library, -1, false); 225 failIfError(BufOrErr.getError(), "Could not open library " + Library); 226 ArchiveBuffers.push_back(std::move(*BufOrErr)); 227 auto LibOrErr = 228 object::Archive::create(ArchiveBuffers.back()->getMemBufferRef()); 229 failIfError(errorToErrorCode(LibOrErr.takeError()), 230 "Could not parse library"); 231 Archives.push_back(std::move(*LibOrErr)); 232 return *Archives.back(); 233} 234 235static void runMRIScript(); 236 237// Parse the command line options as presented and return the operation 238// specified. Process all modifiers and check to make sure that constraints on 239// modifier/operation pairs have not been violated. 240static ArchiveOperation parseCommandLine() { 241 if (MRI) { 242 if (!PositionalArgs.empty() || !Options.empty()) 243 fail("Cannot mix -M and other options"); 244 runMRIScript(); 245 } 246 247 // Keep track of number of operations. We can only specify one 248 // per execution. 249 unsigned NumOperations = 0; 250 251 // Keep track of the number of positional modifiers (a,b,i). Only 252 // one can be specified. 253 unsigned NumPositional = 0; 254 255 // Keep track of which operation was requested 256 ArchiveOperation Operation; 257 258 bool MaybeJustCreateSymTab = false; 259 260 for (unsigned i = 0; i < Options.size(); ++i) { 261 switch (Options[i]) { 262 case 'd': 263 ++NumOperations; 264 Operation = Delete; 265 break; 266 case 'm': 267 ++NumOperations; 268 Operation = Move; 269 break; 270 case 'p': 271 ++NumOperations; 272 Operation = Print; 273 break; 274 case 'q': 275 ++NumOperations; 276 Operation = QuickAppend; 277 break; 278 case 'r': 279 ++NumOperations; 280 Operation = ReplaceOrInsert; 281 break; 282 case 't': 283 ++NumOperations; 284 Operation = DisplayTable; 285 break; 286 case 'x': 287 ++NumOperations; 288 Operation = Extract; 289 break; 290 case 'c': 291 Create = true; 292 break; 293 case 'l': /* accepted but unused */ 294 break; 295 case 'o': 296 OriginalDates = true; 297 break; 298 case 's': 299 Symtab = true; 300 MaybeJustCreateSymTab = true; 301 break; 302 case 'S': 303 Symtab = false; 304 break; 305 case 'u': 306 OnlyUpdate = true; 307 break; 308 case 'v': 309 Verbose = true; 310 break; 311 case 'a': 312 getRelPos(); 313 AddAfter = true; 314 NumPositional++; 315 break; 316 case 'b': 317 getRelPos(); 318 AddBefore = true; 319 NumPositional++; 320 break; 321 case 'i': 322 getRelPos(); 323 AddBefore = true; 324 NumPositional++; 325 break; 326 case 'D': 327 Deterministic = true; 328 break; 329 case 'U': 330 Deterministic = false; 331 break; 332 case 'T': 333 Thin = true; 334 break; 335 case 'L': 336 AddLibrary = true; 337 break; 338 default: 339 fail(std::string("unknown option ") + Options[i]); 340 } 341 } 342 343 // At this point, the next thing on the command line must be 344 // the archive name. 345 getArchive(); 346 347 // Everything on the command line at this point is a member. 348 getMembers(); 349 350 if (NumOperations == 0 && MaybeJustCreateSymTab) { 351 NumOperations = 1; 352 Operation = CreateSymTab; 353 if (!Members.empty()) 354 fail("The s operation takes only an archive as argument"); 355 } 356 357 // Perform various checks on the operation/modifier specification 358 // to make sure we are dealing with a legal request. 359 if (NumOperations == 0) 360 fail("You must specify at least one of the operations"); 361 if (NumOperations > 1) 362 fail("Only one operation may be specified"); 363 if (NumPositional > 1) 364 fail("You may only specify one of a, b, and i modifiers"); 365 if (AddAfter || AddBefore) { 366 if (Operation != Move && Operation != ReplaceOrInsert) 367 fail("The 'a', 'b' and 'i' modifiers can only be specified with " 368 "the 'm' or 'r' operations"); 369 } 370 if (OriginalDates && Operation != Extract) 371 fail("The 'o' modifier is only applicable to the 'x' operation"); 372 if (OnlyUpdate && Operation != ReplaceOrInsert) 373 fail("The 'u' modifier is only applicable to the 'r' operation"); 374 if (AddLibrary && Operation != QuickAppend) 375 fail("The 'L' modifier is only applicable to the 'q' operation"); 376 377 // Return the parsed operation to the caller 378 return Operation; 379} 380 381// Implements the 'p' operation. This function traverses the archive 382// looking for members that match the path list. 383static void doPrint(StringRef Name, const object::Archive::Child &C) { 384 if (Verbose) 385 outs() << "Printing " << Name << "\n"; 386 387 Expected<StringRef> DataOrErr = C.getBuffer(); 388 failIfError(DataOrErr.takeError()); 389 StringRef Data = *DataOrErr; 390 outs().write(Data.data(), Data.size()); 391} 392 393// Utility function for printing out the file mode when the 't' operation is in 394// verbose mode. 395static void printMode(unsigned mode) { 396 outs() << ((mode & 004) ? "r" : "-"); 397 outs() << ((mode & 002) ? "w" : "-"); 398 outs() << ((mode & 001) ? "x" : "-"); 399} 400 401// Implement the 't' operation. This function prints out just 402// the file names of each of the members. However, if verbose mode is requested 403// ('v' modifier) then the file type, permission mode, user, group, size, and 404// modification time are also printed. 405static void doDisplayTable(StringRef Name, const object::Archive::Child &C) { 406 if (Verbose) { 407 Expected<sys::fs::perms> ModeOrErr = C.getAccessMode(); 408 failIfError(ModeOrErr.takeError()); 409 sys::fs::perms Mode = ModeOrErr.get(); 410 printMode((Mode >> 6) & 007); 411 printMode((Mode >> 3) & 007); 412 printMode(Mode & 007); 413 Expected<unsigned> UIDOrErr = C.getUID(); 414 failIfError(UIDOrErr.takeError()); 415 outs() << ' ' << UIDOrErr.get(); 416 Expected<unsigned> GIDOrErr = C.getGID(); 417 failIfError(GIDOrErr.takeError()); 418 outs() << '/' << GIDOrErr.get(); 419 Expected<uint64_t> Size = C.getSize(); 420 failIfError(Size.takeError()); 421 outs() << ' ' << format("%6llu", Size.get()); 422 auto ModTimeOrErr = C.getLastModified(); 423 failIfError(ModTimeOrErr.takeError()); 424 // Note: formatv() only handles the default TimePoint<>, which is in 425 // nanoseconds. 426 // TODO: fix format_provider<TimePoint<>> to allow other units. 427 sys::TimePoint<> ModTimeInNs = ModTimeOrErr.get(); 428 outs() << ' ' << formatv("{0:%b %e %H:%M %Y}", ModTimeInNs); 429 outs() << ' '; 430 } 431 432 if (C.getParent()->isThin()) { 433 outs() << sys::path::parent_path(ArchiveName); 434 outs() << '/'; 435 } 436 outs() << Name << "\n"; 437} 438 439// Implement the 'x' operation. This function extracts files back to the file 440// system. 441static void doExtract(StringRef Name, const object::Archive::Child &C) { 442 // Retain the original mode. 443 Expected<sys::fs::perms> ModeOrErr = C.getAccessMode(); 444 failIfError(ModeOrErr.takeError()); 445 sys::fs::perms Mode = ModeOrErr.get(); 446 447 int FD; 448 failIfError(sys::fs::openFileForWrite(sys::path::filename(Name), FD, 449 sys::fs::CD_CreateAlways, 450 sys::fs::F_None, Mode), 451 Name); 452 453 { 454 raw_fd_ostream file(FD, false); 455 456 // Get the data and its length 457 Expected<StringRef> BufOrErr = C.getBuffer(); 458 failIfError(BufOrErr.takeError()); 459 StringRef Data = BufOrErr.get(); 460 461 // Write the data. 462 file.write(Data.data(), Data.size()); 463 } 464 465 // If we're supposed to retain the original modification times, etc. do so 466 // now. 467 if (OriginalDates) { 468 auto ModTimeOrErr = C.getLastModified(); 469 failIfError(ModTimeOrErr.takeError()); 470 failIfError( 471 sys::fs::setLastAccessAndModificationTime(FD, ModTimeOrErr.get())); 472 } 473 474 if (close(FD)) 475 fail("Could not close the file"); 476} 477 478static bool shouldCreateArchive(ArchiveOperation Op) { 479 switch (Op) { 480 case Print: 481 case Delete: 482 case Move: 483 case DisplayTable: 484 case Extract: 485 case CreateSymTab: 486 return false; 487 488 case QuickAppend: 489 case ReplaceOrInsert: 490 return true; 491 } 492 493 llvm_unreachable("Missing entry in covered switch."); 494} 495 496static void performReadOperation(ArchiveOperation Operation, 497 object::Archive *OldArchive) { 498 if (Operation == Extract && OldArchive->isThin()) 499 fail("extracting from a thin archive is not supported"); 500 501 bool Filter = !Members.empty(); 502 { 503 Error Err = Error::success(); 504 for (auto &C : OldArchive->children(Err)) { 505 Expected<StringRef> NameOrErr = C.getName(); 506 failIfError(NameOrErr.takeError()); 507 StringRef Name = NameOrErr.get(); 508 509 if (Filter) { 510 auto I = find(Members, Name); 511 if (I == Members.end()) 512 continue; 513 Members.erase(I); 514 } 515 516 switch (Operation) { 517 default: 518 llvm_unreachable("Not a read operation"); 519 case Print: 520 doPrint(Name, C); 521 break; 522 case DisplayTable: 523 doDisplayTable(Name, C); 524 break; 525 case Extract: 526 doExtract(Name, C); 527 break; 528 } 529 } 530 failIfError(std::move(Err)); 531 } 532 533 if (Members.empty()) 534 return; 535 for (StringRef Name : Members) 536 WithColor::error(errs(), ToolName) << "'" << Name << "' was not found\n"; 537 exit(1); 538} 539 540static void addChildMember(std::vector<NewArchiveMember> &Members, 541 const object::Archive::Child &M, 542 bool FlattenArchive = false) { 543 if (Thin && !M.getParent()->isThin()) 544 fail("Cannot convert a regular archive to a thin one"); 545 Expected<NewArchiveMember> NMOrErr = 546 NewArchiveMember::getOldMember(M, Deterministic); 547 failIfError(NMOrErr.takeError()); 548 if (FlattenArchive && 549 identify_magic(NMOrErr->Buf->getBuffer()) == file_magic::archive) { 550 Expected<std::string> FileNameOrErr = M.getFullName(); 551 failIfError(FileNameOrErr.takeError()); 552 object::Archive &Lib = readLibrary(*FileNameOrErr); 553 // When creating thin archives, only flatten if the member is also thin. 554 if (!Thin || Lib.isThin()) { 555 Error Err = Error::success(); 556 // Only Thin archives are recursively flattened. 557 for (auto &Child : Lib.children(Err)) 558 addChildMember(Members, Child, /*FlattenArchive=*/Thin); 559 failIfError(std::move(Err)); 560 return; 561 } 562 } 563 Members.push_back(std::move(*NMOrErr)); 564} 565 566static void addMember(std::vector<NewArchiveMember> &Members, 567 StringRef FileName, bool FlattenArchive = false) { 568 Expected<NewArchiveMember> NMOrErr = 569 NewArchiveMember::getFile(FileName, Deterministic); 570 failIfError(NMOrErr.takeError(), FileName); 571 if (FlattenArchive && 572 identify_magic(NMOrErr->Buf->getBuffer()) == file_magic::archive) { 573 object::Archive &Lib = readLibrary(FileName); 574 // When creating thin archives, only flatten if the member is also thin. 575 if (!Thin || Lib.isThin()) { 576 Error Err = Error::success(); 577 // Only Thin archives are recursively flattened. 578 for (auto &Child : Lib.children(Err)) 579 addChildMember(Members, Child, /*FlattenArchive=*/Thin); 580 failIfError(std::move(Err)); 581 return; 582 } 583 } 584 // Use the basename of the object path for the member name. 585 NMOrErr->MemberName = sys::path::filename(NMOrErr->MemberName); 586 Members.push_back(std::move(*NMOrErr)); 587} 588 589enum InsertAction { 590 IA_AddOldMember, 591 IA_AddNewMember, 592 IA_Delete, 593 IA_MoveOldMember, 594 IA_MoveNewMember 595}; 596 597static InsertAction computeInsertAction(ArchiveOperation Operation, 598 const object::Archive::Child &Member, 599 StringRef Name, 600 std::vector<StringRef>::iterator &Pos) { 601 if (Operation == QuickAppend || Members.empty()) 602 return IA_AddOldMember; 603 604 auto MI = find_if(Members, [Name](StringRef Path) { 605 return Name == sys::path::filename(Path); 606 }); 607 608 if (MI == Members.end()) 609 return IA_AddOldMember; 610 611 Pos = MI; 612 613 if (Operation == Delete) 614 return IA_Delete; 615 616 if (Operation == Move) 617 return IA_MoveOldMember; 618 619 if (Operation == ReplaceOrInsert) { 620 StringRef PosName = sys::path::filename(RelPos); 621 if (!OnlyUpdate) { 622 if (PosName.empty()) 623 return IA_AddNewMember; 624 return IA_MoveNewMember; 625 } 626 627 // We could try to optimize this to a fstat, but it is not a common 628 // operation. 629 sys::fs::file_status Status; 630 failIfError(sys::fs::status(*MI, Status), *MI); 631 auto ModTimeOrErr = Member.getLastModified(); 632 failIfError(ModTimeOrErr.takeError()); 633 if (Status.getLastModificationTime() < ModTimeOrErr.get()) { 634 if (PosName.empty()) 635 return IA_AddOldMember; 636 return IA_MoveOldMember; 637 } 638 639 if (PosName.empty()) 640 return IA_AddNewMember; 641 return IA_MoveNewMember; 642 } 643 llvm_unreachable("No such operation"); 644} 645 646// We have to walk this twice and computing it is not trivial, so creating an 647// explicit std::vector is actually fairly efficient. 648static std::vector<NewArchiveMember> 649computeNewArchiveMembers(ArchiveOperation Operation, 650 object::Archive *OldArchive) { 651 std::vector<NewArchiveMember> Ret; 652 std::vector<NewArchiveMember> Moved; 653 int InsertPos = -1; 654 StringRef PosName = sys::path::filename(RelPos); 655 if (OldArchive) { 656 Error Err = Error::success(); 657 for (auto &Child : OldArchive->children(Err)) { 658 int Pos = Ret.size(); 659 Expected<StringRef> NameOrErr = Child.getName(); 660 failIfError(NameOrErr.takeError()); 661 StringRef Name = NameOrErr.get(); 662 if (Name == PosName) { 663 assert(AddAfter || AddBefore); 664 if (AddBefore) 665 InsertPos = Pos; 666 else 667 InsertPos = Pos + 1; 668 } 669 670 std::vector<StringRef>::iterator MemberI = Members.end(); 671 InsertAction Action = 672 computeInsertAction(Operation, Child, Name, MemberI); 673 switch (Action) { 674 case IA_AddOldMember: 675 addChildMember(Ret, Child); 676 break; 677 case IA_AddNewMember: 678 addMember(Ret, *MemberI); 679 break; 680 case IA_Delete: 681 break; 682 case IA_MoveOldMember: 683 addChildMember(Moved, Child); 684 break; 685 case IA_MoveNewMember: 686 addMember(Moved, *MemberI); 687 break; 688 } 689 if (MemberI != Members.end()) 690 Members.erase(MemberI); 691 } 692 failIfError(std::move(Err)); 693 } 694 695 if (Operation == Delete) 696 return Ret; 697 698 if (!RelPos.empty() && InsertPos == -1) 699 fail("Insertion point not found"); 700 701 if (RelPos.empty()) 702 InsertPos = Ret.size(); 703 704 assert(unsigned(InsertPos) <= Ret.size()); 705 int Pos = InsertPos; 706 for (auto &M : Moved) { 707 Ret.insert(Ret.begin() + Pos, std::move(M)); 708 ++Pos; 709 } 710 711 if (AddLibrary) { 712 assert(Operation == QuickAppend); 713 for (auto &Member : Members) 714 addMember(Ret, Member, /*FlattenArchive=*/true); 715 return Ret; 716 } 717 718 std::vector<NewArchiveMember> NewMembers; 719 for (auto &Member : Members) 720 addMember(NewMembers, Member, /*FlattenArchive=*/Thin); 721 Ret.reserve(Ret.size() + NewMembers.size()); 722 std::move(NewMembers.begin(), NewMembers.end(), 723 std::inserter(Ret, std::next(Ret.begin(), InsertPos))); 724 725 return Ret; 726} 727 728static object::Archive::Kind getDefaultForHost() { 729 return Triple(sys::getProcessTriple()).isOSDarwin() 730 ? object::Archive::K_DARWIN 731 : object::Archive::K_GNU; 732} 733 734static object::Archive::Kind getKindFromMember(const NewArchiveMember &Member) { 735 Expected<std::unique_ptr<object::ObjectFile>> OptionalObject = 736 object::ObjectFile::createObjectFile(Member.Buf->getMemBufferRef()); 737 738 if (OptionalObject) 739 return isa<object::MachOObjectFile>(**OptionalObject) 740 ? object::Archive::K_DARWIN 741 : object::Archive::K_GNU; 742 743 // squelch the error in case we had a non-object file 744 consumeError(OptionalObject.takeError()); 745 return getDefaultForHost(); 746} 747 748static void performWriteOperation(ArchiveOperation Operation, 749 object::Archive *OldArchive, 750 std::unique_ptr<MemoryBuffer> OldArchiveBuf, 751 std::vector<NewArchiveMember> *NewMembersP) { 752 std::vector<NewArchiveMember> NewMembers; 753 if (!NewMembersP) 754 NewMembers = computeNewArchiveMembers(Operation, OldArchive); 755 756 object::Archive::Kind Kind; 757 switch (FormatType) { 758 case Default: 759 if (Thin) 760 Kind = object::Archive::K_GNU; 761 else if (OldArchive) 762 Kind = OldArchive->kind(); 763 else if (NewMembersP) 764 Kind = !NewMembersP->empty() ? getKindFromMember(NewMembersP->front()) 765 : getDefaultForHost(); 766 else 767 Kind = !NewMembers.empty() ? getKindFromMember(NewMembers.front()) 768 : getDefaultForHost(); 769 break; 770 case GNU: 771 Kind = object::Archive::K_GNU; 772 break; 773 case BSD: 774 if (Thin) 775 fail("Only the gnu format has a thin mode"); 776 Kind = object::Archive::K_BSD; 777 break; 778 case DARWIN: 779 if (Thin) 780 fail("Only the gnu format has a thin mode"); 781 Kind = object::Archive::K_DARWIN; 782 break; 783 case Unknown: 784 llvm_unreachable(""); 785 } 786 787 Error E = 788 writeArchive(ArchiveName, NewMembersP ? *NewMembersP : NewMembers, Symtab, 789 Kind, Deterministic, Thin, std::move(OldArchiveBuf)); 790 failIfError(std::move(E), ArchiveName); 791} 792 793static void createSymbolTable(object::Archive *OldArchive) { 794 // When an archive is created or modified, if the s option is given, the 795 // resulting archive will have a current symbol table. If the S option 796 // is given, it will have no symbol table. 797 // In summary, we only need to update the symbol table if we have none. 798 // This is actually very common because of broken build systems that think 799 // they have to run ranlib. 800 if (OldArchive->hasSymbolTable()) 801 return; 802 803 performWriteOperation(CreateSymTab, OldArchive, nullptr, nullptr); 804} 805 806static void performOperation(ArchiveOperation Operation, 807 object::Archive *OldArchive, 808 std::unique_ptr<MemoryBuffer> OldArchiveBuf, 809 std::vector<NewArchiveMember> *NewMembers) { 810 switch (Operation) { 811 case Print: 812 case DisplayTable: 813 case Extract: 814 performReadOperation(Operation, OldArchive); 815 return; 816 817 case Delete: 818 case Move: 819 case QuickAppend: 820 case ReplaceOrInsert: 821 performWriteOperation(Operation, OldArchive, std::move(OldArchiveBuf), 822 NewMembers); 823 return; 824 case CreateSymTab: 825 createSymbolTable(OldArchive); 826 return; 827 } 828 llvm_unreachable("Unknown operation."); 829} 830 831static int performOperation(ArchiveOperation Operation, 832 std::vector<NewArchiveMember> *NewMembers) { 833 // Create or open the archive object. 834 ErrorOr<std::unique_ptr<MemoryBuffer>> Buf = 835 MemoryBuffer::getFile(ArchiveName, -1, false); 836 std::error_code EC = Buf.getError(); 837 if (EC && EC != errc::no_such_file_or_directory) 838 fail("error opening '" + ArchiveName + "': " + EC.message() + "!"); 839 840 if (!EC) { 841 Error Err = Error::success(); 842 object::Archive Archive(Buf.get()->getMemBufferRef(), Err); 843 EC = errorToErrorCode(std::move(Err)); 844 failIfError(EC, 845 "error loading '" + ArchiveName + "': " + EC.message() + "!"); 846 performOperation(Operation, &Archive, std::move(Buf.get()), NewMembers); 847 return 0; 848 } 849 850 assert(EC == errc::no_such_file_or_directory); 851 852 if (!shouldCreateArchive(Operation)) { 853 failIfError(EC, Twine("error loading '") + ArchiveName + "'"); 854 } else { 855 if (!Create) { 856 // Produce a warning if we should and we're creating the archive 857 WithColor::warning(errs(), ToolName) 858 << "creating " << ArchiveName << "\n"; 859 } 860 } 861 862 performOperation(Operation, nullptr, nullptr, NewMembers); 863 return 0; 864} 865 866static void runMRIScript() { 867 enum class MRICommand { AddLib, AddMod, Create, Delete, Save, End, Invalid }; 868 869 ErrorOr<std::unique_ptr<MemoryBuffer>> Buf = MemoryBuffer::getSTDIN(); 870 failIfError(Buf.getError()); 871 const MemoryBuffer &Ref = *Buf.get(); 872 bool Saved = false; 873 std::vector<NewArchiveMember> NewMembers; 874 875 for (line_iterator I(Ref, /*SkipBlanks*/ false), E; I != E; ++I) { 876 StringRef Line = *I; 877 Line = Line.split(';').first; 878 Line = Line.split('*').first; 879 Line = Line.trim(); 880 if (Line.empty()) 881 continue; 882 StringRef CommandStr, Rest; 883 std::tie(CommandStr, Rest) = Line.split(' '); 884 Rest = Rest.trim(); 885 if (!Rest.empty() && Rest.front() == '"' && Rest.back() == '"') 886 Rest = Rest.drop_front().drop_back(); 887 auto Command = StringSwitch<MRICommand>(CommandStr.lower()) 888 .Case("addlib", MRICommand::AddLib) 889 .Case("addmod", MRICommand::AddMod) 890 .Case("create", MRICommand::Create) 891 .Case("delete", MRICommand::Delete) 892 .Case("save", MRICommand::Save) 893 .Case("end", MRICommand::End) 894 .Default(MRICommand::Invalid); 895 896 switch (Command) { 897 case MRICommand::AddLib: { 898 object::Archive &Lib = readLibrary(Rest); 899 { 900 Error Err = Error::success(); 901 for (auto &Member : Lib.children(Err)) 902 addChildMember(NewMembers, Member); 903 failIfError(std::move(Err)); 904 } 905 break; 906 } 907 case MRICommand::AddMod: 908 addMember(NewMembers, Rest); 909 break; 910 case MRICommand::Create: 911 Create = true; 912 if (!ArchiveName.empty()) 913 fail("Editing multiple archives not supported"); 914 if (Saved) 915 fail("File already saved"); 916 ArchiveName = Rest; 917 break; 918 case MRICommand::Delete: { 919 StringRef Name = sys::path::filename(Rest); 920 llvm::erase_if(NewMembers, 921 [=](NewArchiveMember &M) { return M.MemberName == Name; }); 922 break; 923 } 924 case MRICommand::Save: 925 Saved = true; 926 break; 927 case MRICommand::End: 928 break; 929 case MRICommand::Invalid: 930 fail("Unknown command: " + CommandStr); 931 } 932 } 933 934 // Nothing to do if not saved. 935 if (Saved) 936 performOperation(ReplaceOrInsert, &NewMembers); 937 exit(0); 938} 939 940static bool handleGenericOption(StringRef arg) { 941 if (arg == "-help" || arg == "--help") { 942 printHelpMessage(); 943 return true; 944 } 945 if (arg == "-version" || arg == "--version") { 946 cl::PrintVersionMessage(); 947 return true; 948 } 949 return false; 950} 951 952static int ar_main(int argc, char **argv) { 953 SmallVector<const char *, 0> Argv(argv, argv + argc); 954 BumpPtrAllocator Alloc; 955 StringSaver Saver(Alloc); 956 cl::ExpandResponseFiles(Saver, cl::TokenizeGNUCommandLine, Argv); 957 for (size_t i = 1; i < Argv.size(); ++i) { 958 StringRef Arg = Argv[i]; 959 const char *match; 960 auto MatchFlagWithArg = [&](const char *expected) { 961 size_t len = strlen(expected); 962 if (Arg == expected) { 963 if (++i >= Argv.size()) 964 fail(std::string(expected) + " requires an argument"); 965 match = Argv[i]; 966 return true; 967 } 968 if (Arg.startswith(expected) && Arg.size() > len && Arg[len] == '=') { 969 match = Arg.data() + len + 1; 970 return true; 971 } 972 return false; 973 }; 974 if (handleGenericOption(Argv[i])) 975 return 0; 976 if (Arg == "--") { 977 for (; i < Argv.size(); ++i) 978 PositionalArgs.push_back(Argv[i]); 979 break; 980 } 981 if (Arg[0] == '-') { 982 if (Arg.startswith("--")) 983 Arg = Argv[i] + 2; 984 else 985 Arg = Argv[i] + 1; 986 if (Arg == "M") { 987 MRI = true; 988 } else if (MatchFlagWithArg("format")) { 989 FormatType = StringSwitch<Format>(match) 990 .Case("default", Default) 991 .Case("gnu", GNU) 992 .Case("darwin", DARWIN) 993 .Case("bsd", BSD) 994 .Default(Unknown); 995 if (FormatType == Unknown) 996 fail(std::string("Invalid format ") + match); 997 } else if (MatchFlagWithArg("plugin")) { 998 // Ignored. 999 } else { 1000 Options += Argv[i] + 1; 1001 } 1002 } else if (Options.empty()) { 1003 Options += Argv[i]; 1004 } else { 1005 PositionalArgs.push_back(Argv[i]); 1006 } 1007 } 1008 ArchiveOperation Operation = parseCommandLine(); 1009 return performOperation(Operation, nullptr); 1010} 1011 1012static int ranlib_main(int argc, char **argv) { 1013 bool ArchiveSpecified = false; 1014 for (int i = 1; i < argc; ++i) { 1015 if (handleGenericOption(argv[i])) { 1016 return 0; 1017 } else { 1018 if (ArchiveSpecified) 1019 fail("Exactly one archive should be specified"); 1020 ArchiveSpecified = true; 1021 ArchiveName = argv[i]; 1022 } 1023 } 1024 return performOperation(CreateSymTab, nullptr); 1025} 1026 1027int main(int argc, char **argv) { 1028 InitLLVM X(argc, argv); 1029 ToolName = argv[0]; 1030 1031 llvm::InitializeAllTargetInfos(); 1032 llvm::InitializeAllTargetMCs(); 1033 llvm::InitializeAllAsmParsers(); 1034 1035 Stem = sys::path::stem(ToolName); 1036 if (Stem.contains_lower("dlltool")) 1037 return dlltoolDriverMain(makeArrayRef(argv, argc)); 1038 1039 if (Stem.contains_lower("ranlib")) 1040 return ranlib_main(argc, argv); 1041 1042 if (Stem.contains_lower("lib")) 1043 return libDriverMain(makeArrayRef(argv, argc)); 1044 1045 if (Stem.contains_lower("ar")) 1046 return ar_main(argc, argv); 1047 fail("Not ranlib, ar, lib or dlltool!"); 1048} 1049