llvm-ar.cpp revision 341825
138494Sobrien//===-- llvm-ar.cpp - LLVM archive librarian utility ----------------------===// 2310490Scy// 338494Sobrien// The LLVM Compiler Infrastructure 438494Sobrien// 538494Sobrien// This file is distributed under the University of Illinois Open Source 638494Sobrien// License. See LICENSE.TXT for details. 738494Sobrien// 838494Sobrien//===----------------------------------------------------------------------===// 938494Sobrien// 1038494Sobrien// Builds up (relatively) standard unix archive files (.a) containing LLVM 1138494Sobrien// bitcode or other files. 1238494Sobrien// 1338494Sobrien//===----------------------------------------------------------------------===// 1438494Sobrien 1538494Sobrien#include "llvm/ADT/StringSwitch.h" 1638494Sobrien#include "llvm/ADT/Triple.h" 1738494Sobrien#include "llvm/IR/LLVMContext.h" 1838494Sobrien#include "llvm/Object/Archive.h" 19310490Scy#include "llvm/Object/ArchiveWriter.h" 2038494Sobrien#include "llvm/Object/MachO.h" 2138494Sobrien#include "llvm/Object/ObjectFile.h" 2238494Sobrien#include "llvm/Support/Chrono.h" 2338494Sobrien#include "llvm/Support/CommandLine.h" 2438494Sobrien#include "llvm/Support/Errc.h" 2538494Sobrien#include "llvm/Support/FileSystem.h" 2638494Sobrien#include "llvm/Support/Format.h" 2738494Sobrien#include "llvm/Support/InitLLVM.h" 2838494Sobrien#include "llvm/Support/LineIterator.h" 2938494Sobrien#include "llvm/Support/MemoryBuffer.h" 3038494Sobrien#include "llvm/Support/Path.h" 3138494Sobrien#include "llvm/Support/Process.h" 3238494Sobrien#include "llvm/Support/StringSaver.h" 3338494Sobrien#include "llvm/Support/TargetSelect.h" 3438494Sobrien#include "llvm/Support/ToolOutputFile.h" 3538494Sobrien#include "llvm/Support/raw_ostream.h" 36174294Sobrien#include "llvm/ToolDrivers/llvm-dlltool/DlltoolDriver.h" 3738494Sobrien#include "llvm/ToolDrivers/llvm-lib/LibDriver.h" 3838494Sobrien 3938494Sobrien#if !defined(_MSC_VER) && !defined(__MINGW32__) 4038494Sobrien#include <unistd.h> 4138494Sobrien#else 4238494Sobrien#include <io.h> 4338494Sobrien#endif 4438494Sobrien 4538494Sobrienusing namespace llvm; 4638494Sobrien 4738494Sobrien// The name this program was invoked as. 4838494Sobrienstatic StringRef ToolName; 4938494Sobrien 5038494Sobrien// The basename of this program. 5138494Sobrienstatic StringRef Stem; 5238494Sobrien 5338494Sobrienconst char RanlibHelp[] = R"( 54174294SobrienOVERVIEW: LLVM Ranlib (llvm-ranlib) 55174294Sobrien 56174294Sobrien This program generates an index to speed access to archives 57174294Sobrien 5838494SobrienUSAGE: llvm-ranlib <archive-file> 59174294Sobrien 6038494SobrienOPTIONS: 6138494Sobrien -help - Display available options 6238494Sobrien -version - Display the version of this program 6338494Sobrien)"; 6438494Sobrien 6538494Sobrienconst char ArHelp[] = R"( 6638494SobrienOVERVIEW: LLVM Archiver 6738494Sobrien 6838494SobrienUSAGE: llvm-ar [options] [-]<operation>[modifiers] [relpos] <archive> [files] 6938494Sobrien llvm-ar -M [<mri-script] 7038494Sobrien 7138494SobrienOPTIONS: 7238494Sobrien --format - Archive format to create 7338494Sobrien =default - default 7438494Sobrien =gnu - gnu 7538494Sobrien =darwin - darwin 7638494Sobrien =bsd - bsd 7738494Sobrien --plugin=<string> - Ignored for compatibility 7838494Sobrien --help - Display available options 7938494Sobrien --version - Display the version of this program 8038494Sobrien 8138494SobrienOPERATIONS: 8238494Sobrien d - delete [files] from the archive 8338494Sobrien m - move [files] in the archive 8438494Sobrien p - print [files] found in the archive 8538494Sobrien q - quick append [files] to the archive 8638494Sobrien r - replace or insert [files] into the archive 8738494Sobrien s - act as ranlib 8838494Sobrien t - display contents of archive 8938494Sobrien x - extract [files] from the archive 9038494Sobrien 9138494SobrienMODIFIERS: 92174294Sobrien [a] - put [files] after [relpos] 9338494Sobrien [b] - put [files] before [relpos] (same as [i]) 9438494Sobrien [c] - do not warn if archive had to be created 9538494Sobrien [D] - use zero for timestamps and uids/gids (default) 9638494Sobrien [i] - put [files] before [relpos] (same as [b]) 97174294Sobrien [l] - ignored for compatibility 9838494Sobrien [o] - preserve original dates 9938494Sobrien [s] - create an archive index (cf. ranlib) 10038494Sobrien [S] - do not build a symbol table 10138494Sobrien [T] - create a thin archive 10238494Sobrien [u] - update only [files] newer than archive contents 10338494Sobrien [U] - use actual timestamps and uids/gids 10438494Sobrien [v] - be verbose about actions taken 10538494Sobrien)"; 10638494Sobrien 10738494Sobrienvoid printHelpMessage() { 10838494Sobrien if (Stem.contains_lower("ranlib")) 10938494Sobrien outs() << RanlibHelp; 11038494Sobrien else if (Stem.contains_lower("ar")) 11138494Sobrien outs() << ArHelp; 11238494Sobrien} 113174294Sobrien 11438494Sobrien// Show the error message and exit. 11538494SobrienLLVM_ATTRIBUTE_NORETURN static void fail(Twine Error) { 11638494Sobrien errs() << ToolName << ": " << Error << ".\n"; 11738494Sobrien printHelpMessage(); 11838494Sobrien exit(1); 11938494Sobrien} 12038494Sobrien 12138494Sobrienstatic void failIfError(std::error_code EC, Twine Context = "") { 122174294Sobrien if (!EC) 12338494Sobrien return; 12438494Sobrien 12542629Sobrien std::string ContextStr = Context.str(); 12638494Sobrien if (ContextStr == "") 12738494Sobrien fail(EC.message()); 12838494Sobrien fail(Context + ": " + EC.message()); 12938494Sobrien} 13038494Sobrien 13138494Sobrienstatic void failIfError(Error E, Twine Context = "") { 13238494Sobrien if (!E) 13338494Sobrien return; 13438494Sobrien 13538494Sobrien handleAllErrors(std::move(E), [&](const llvm::ErrorInfoBase &EIB) { 13638494Sobrien std::string ContextStr = Context.str(); 13738494Sobrien if (ContextStr == "") 13838494Sobrien fail(EIB.message()); 13938494Sobrien fail(Context + ": " + EIB.message()); 14038494Sobrien }); 141174294Sobrien} 14238494Sobrien 14338494Sobrienstatic SmallVector<const char *, 256> PositionalArgs; 14438494Sobrien 14538494Sobrienstatic bool MRI; 14638494Sobrien 14738494Sobriennamespace { 14838494Sobrienenum Format { Default, GNU, BSD, DARWIN, Unknown }; 14938494Sobrien} 15038494Sobrien 15138494Sobrienstatic Format FormatType = Default; 15238494Sobrien 153174294Sobrienstatic std::string Options; 15438494Sobrien 15538494Sobrien// This enumeration delineates the kinds of operations on an archive 15638494Sobrien// that are permitted. 15738494Sobrienenum ArchiveOperation { 15838494Sobrien Print, ///< Print the contents of the archive 15938494Sobrien Delete, ///< Delete the specified members 160174294Sobrien Move, ///< Move members to end or as given by {a,b,i} modifiers 16138494Sobrien QuickAppend, ///< Quickly append to end of archive 16238494Sobrien ReplaceOrInsert, ///< Replace or Insert members 163174294Sobrien DisplayTable, ///< Display the table of contents 16438494Sobrien Extract, ///< Extract files back to file system 16538494Sobrien CreateSymTab ///< Create a symbol table in an existing archive 16638494Sobrien}; 16738494Sobrien 16838494Sobrien// Modifiers to follow operation to vary behavior 16938494Sobrienstatic bool AddAfter = false; ///< 'a' modifier 17038494Sobrienstatic bool AddBefore = false; ///< 'b' modifier 17138494Sobrienstatic bool Create = false; ///< 'c' modifier 17238494Sobrienstatic bool OriginalDates = false; ///< 'o' modifier 17338494Sobrienstatic bool OnlyUpdate = false; ///< 'u' modifier 17438494Sobrienstatic bool Verbose = false; ///< 'v' modifier 17538494Sobrienstatic bool Symtab = true; ///< 's' modifier 17638494Sobrienstatic bool Deterministic = true; ///< 'D' and 'U' modifiers 177174294Sobrienstatic bool Thin = false; ///< 'T' modifier 17838494Sobrien 17938494Sobrien// Relative Positional Argument (for insert/move). This variable holds 18038494Sobrien// the name of the archive member to which the 'a', 'b' or 'i' modifier 18138494Sobrien// refers. Only one of 'a', 'b' or 'i' can be specified so we only need 18238494Sobrien// one variable. 18338494Sobrienstatic std::string RelPos; 18438494Sobrien 185174294Sobrien// This variable holds the name of the archive file as given on the 18638494Sobrien// command line. 18738494Sobrienstatic std::string ArchiveName; 18838494Sobrien 18938494Sobrien// This variable holds the list of member files to proecess, as given 19038494Sobrien// on the command line. 19138494Sobrienstatic std::vector<StringRef> Members; 19238494Sobrien 19338494Sobrien// Extract the member filename from the command line for the [relpos] argument 19438494Sobrien// associated with a, b, and i modifiers 19538494Sobrienstatic void getRelPos() { 19638494Sobrien if (PositionalArgs.size() == 0) 19738494Sobrien fail("Expected [relpos] for a, b, or i modifier"); 19838494Sobrien RelPos = PositionalArgs[0]; 199174294Sobrien PositionalArgs.erase(PositionalArgs.begin()); 20038494Sobrien} 201174294Sobrien 20238494Sobrien// Get the archive file name from the command line 20338494Sobrienstatic void getArchive() { 20438494Sobrien if (PositionalArgs.size() == 0) 205174294Sobrien fail("An archive name must be specified"); 206174294Sobrien ArchiveName = PositionalArgs[0]; 207174294Sobrien PositionalArgs.erase(PositionalArgs.begin()); 208174294Sobrien} 209174294Sobrien 210174294Sobrien// Copy over remaining items in PositionalArgs to our Members vector 211174294Sobrienstatic void getMembers() { 212174294Sobrien for (auto &Arg : PositionalArgs) 213174294Sobrien Members.push_back(Arg); 214174294Sobrien} 215174294Sobrien 21638494Sobrienstatic void runMRIScript(); 21738494Sobrien 21838494Sobrien// Parse the command line options as presented and return the operation 21938494Sobrien// specified. Process all modifiers and check to make sure that constraints on 22038494Sobrien// modifier/operation pairs have not been violated. 22138494Sobrienstatic ArchiveOperation parseCommandLine() { 22238494Sobrien if (MRI) { 22338494Sobrien if (!PositionalArgs.empty() || !Options.empty()) 22438494Sobrien fail("Cannot mix -M and other options"); 22538494Sobrien runMRIScript(); 22682794Sobrien } 22738494Sobrien 22838494Sobrien // Keep track of number of operations. We can only specify one 22938494Sobrien // per execution. 23038494Sobrien unsigned NumOperations = 0; 23138494Sobrien 23238494Sobrien // Keep track of the number of positional modifiers (a,b,i). Only 23338494Sobrien // one can be specified. 23438494Sobrien unsigned NumPositional = 0; 23538494Sobrien 23638494Sobrien // Keep track of which operation was requested 23738494Sobrien ArchiveOperation Operation; 23838494Sobrien 23938494Sobrien bool MaybeJustCreateSymTab = false; 24038494Sobrien 24138494Sobrien for(unsigned i=0; i<Options.size(); ++i) { 24242629Sobrien switch(Options[i]) { 243174294Sobrien case 'd': ++NumOperations; Operation = Delete; break; 244174294Sobrien case 'm': ++NumOperations; Operation = Move ; break; 245174294Sobrien case 'p': ++NumOperations; Operation = Print; break; 24638494Sobrien case 'q': ++NumOperations; Operation = QuickAppend; break; 24738494Sobrien case 'r': ++NumOperations; Operation = ReplaceOrInsert; break; 24838494Sobrien case 't': ++NumOperations; Operation = DisplayTable; break; 24938494Sobrien case 'x': ++NumOperations; Operation = Extract; break; 25038494Sobrien case 'c': Create = true; break; 25138494Sobrien case 'l': /* accepted but unused */ break; 25238494Sobrien case 'o': OriginalDates = true; break; 25338494Sobrien case 's': 25438494Sobrien Symtab = true; 25538494Sobrien MaybeJustCreateSymTab = true; 25638494Sobrien break; 25738494Sobrien case 'S': 25838494Sobrien Symtab = false; 25938494Sobrien break; 26038494Sobrien case 'u': OnlyUpdate = true; break; 261310490Scy case 'v': Verbose = true; break; 26238494Sobrien case 'a': 26338494Sobrien getRelPos(); 26438494Sobrien AddAfter = true; 26538494Sobrien NumPositional++; 26638494Sobrien break; 26738494Sobrien case 'b': 26838494Sobrien getRelPos(); 26938494Sobrien AddBefore = true; 27038494Sobrien NumPositional++; 27138494Sobrien break; 27238494Sobrien case 'i': 27338494Sobrien getRelPos(); 27438494Sobrien AddBefore = true; 27538494Sobrien NumPositional++; 27638494Sobrien break; 27738494Sobrien case 'D': 27838494Sobrien Deterministic = true; 27938494Sobrien break; 28038494Sobrien case 'U': 28138494Sobrien Deterministic = false; 282174294Sobrien break; 28338494Sobrien case 'T': 28438494Sobrien Thin = true; 28538494Sobrien break; 28638494Sobrien default: 287174294Sobrien fail(std::string("unknown option ") + Options[i]); 28838494Sobrien } 28938494Sobrien } 290174294Sobrien 291174294Sobrien // At this point, the next thing on the command line must be 29238494Sobrien // the archive name. 29338494Sobrien getArchive(); 29438494Sobrien 29538494Sobrien // Everything on the command line at this point is a member. 29638494Sobrien getMembers(); 29738494Sobrien 29838494Sobrien if (NumOperations == 0 && MaybeJustCreateSymTab) { 29938494Sobrien NumOperations = 1; 30038494Sobrien 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. 329static 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. 341static 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. 351static 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. 383static 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 420static 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 438static 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 482static 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 497static 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 510enum InsertAction { 511 IA_AddOldMember, 512 IA_AddNewMember, 513 IA_Delete, 514 IA_MoveOldMember, 515 IA_MoveNewMember 516}; 517 518static 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. 569static std::vector<NewArchiveMember> 570computeNewArchiveMembers(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 643static object::Archive::Kind getDefaultForHost() { 644 return Triple(sys::getProcessTriple()).isOSDarwin() 645 ? object::Archive::K_DARWIN 646 : object::Archive::K_GNU; 647} 648 649static 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 663static void 664performWriteOperation(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 709static 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 722static 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 747static 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 781static 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 860static 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 872static 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 933static 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 948int 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