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