llvm-ar.cpp revision dce4a407a24b04eebc6a376f8e62b41aaa7b071f
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/IR/LLVMContext.h" 16#include "llvm/IR/Module.h" 17#include "llvm/Object/Archive.h" 18#include "llvm/Object/ObjectFile.h" 19#include "llvm/Support/CommandLine.h" 20#include "llvm/Support/FileSystem.h" 21#include "llvm/Support/Format.h" 22#include "llvm/Support/ManagedStatic.h" 23#include "llvm/Support/MemoryBuffer.h" 24#include "llvm/Support/PrettyStackTrace.h" 25#include "llvm/Support/Signals.h" 26#include "llvm/Support/ToolOutputFile.h" 27#include "llvm/Support/raw_ostream.h" 28#include <algorithm> 29#include <cstdlib> 30#include <memory> 31 32#if !defined(_MSC_VER) && !defined(__MINGW32__) 33#include <unistd.h> 34#else 35#include <io.h> 36#endif 37 38using namespace llvm; 39 40// The name this program was invoked as. 41static StringRef ToolName; 42 43static const char *TemporaryOutput; 44static int TmpArchiveFD = -1; 45 46// fail - Show the error message and exit. 47LLVM_ATTRIBUTE_NORETURN static void fail(Twine Error) { 48 outs() << ToolName << ": " << Error << ".\n"; 49 if (TmpArchiveFD != -1) 50 close(TmpArchiveFD); 51 if (TemporaryOutput) 52 sys::fs::remove(TemporaryOutput); 53 exit(1); 54} 55 56static void failIfError(error_code EC, Twine Context = "") { 57 if (!EC) 58 return; 59 60 std::string ContextStr = Context.str(); 61 if (ContextStr == "") 62 fail(EC.message()); 63 fail(Context + ": " + EC.message()); 64} 65 66// llvm-ar/llvm-ranlib remaining positional arguments. 67static cl::list<std::string> 68RestOfArgs(cl::Positional, cl::OneOrMore, 69 cl::desc("[relpos] [count] <archive-file> [members]...")); 70 71std::string Options; 72 73// MoreHelp - Provide additional help output explaining the operations and 74// modifiers of llvm-ar. This object instructs the CommandLine library 75// to print the text of the constructor when the --help option is given. 76static cl::extrahelp MoreHelp( 77 "\nOPERATIONS:\n" 78 " d[NsS] - delete file(s) from the archive\n" 79 " m[abiSs] - move file(s) in the archive\n" 80 " p[kN] - print file(s) found in the archive\n" 81 " q[ufsS] - quick append file(s) to the archive\n" 82 " r[abfiuRsS] - replace or insert file(s) into the archive\n" 83 " t - display contents of archive\n" 84 " x[No] - extract file(s) from the archive\n" 85 "\nMODIFIERS (operation specific):\n" 86 " [a] - put file(s) after [relpos]\n" 87 " [b] - put file(s) before [relpos] (same as [i])\n" 88 " [i] - put file(s) before [relpos] (same as [b])\n" 89 " [N] - use instance [count] of name\n" 90 " [o] - preserve original dates\n" 91 " [s] - create an archive index (cf. ranlib)\n" 92 " [S] - do not build a symbol table\n" 93 " [u] - update only files newer than archive contents\n" 94 "\nMODIFIERS (generic):\n" 95 " [c] - do not warn if the library had to be created\n" 96 " [v] - be verbose about actions taken\n" 97); 98 99// This enumeration delineates the kinds of operations on an archive 100// that are permitted. 101enum ArchiveOperation { 102 Print, ///< Print the contents of the archive 103 Delete, ///< Delete the specified members 104 Move, ///< Move members to end or as given by {a,b,i} modifiers 105 QuickAppend, ///< Quickly append to end of archive 106 ReplaceOrInsert, ///< Replace or Insert members 107 DisplayTable, ///< Display the table of contents 108 Extract, ///< Extract files back to file system 109 CreateSymTab ///< Create a symbol table in an existing archive 110}; 111 112// Modifiers to follow operation to vary behavior 113static bool AddAfter = false; ///< 'a' modifier 114static bool AddBefore = false; ///< 'b' modifier 115static bool Create = false; ///< 'c' modifier 116static bool OriginalDates = false; ///< 'o' modifier 117static bool OnlyUpdate = false; ///< 'u' modifier 118static bool Verbose = false; ///< 'v' modifier 119static bool Symtab = true; ///< 's' modifier 120 121// Relative Positional Argument (for insert/move). This variable holds 122// the name of the archive member to which the 'a', 'b' or 'i' modifier 123// refers. Only one of 'a', 'b' or 'i' can be specified so we only need 124// one variable. 125static std::string RelPos; 126 127// This variable holds the name of the archive file as given on the 128// command line. 129static std::string ArchiveName; 130 131// This variable holds the list of member files to proecess, as given 132// on the command line. 133static std::vector<std::string> Members; 134 135// show_help - Show the error message, the help message and exit. 136LLVM_ATTRIBUTE_NORETURN static void 137show_help(const std::string &msg) { 138 errs() << ToolName << ": " << msg << "\n\n"; 139 cl::PrintHelpMessage(); 140 std::exit(1); 141} 142 143// getRelPos - Extract the member filename from the command line for 144// the [relpos] argument associated with a, b, and i modifiers 145static void getRelPos() { 146 if(RestOfArgs.size() == 0) 147 show_help("Expected [relpos] for a, b, or i modifier"); 148 RelPos = RestOfArgs[0]; 149 RestOfArgs.erase(RestOfArgs.begin()); 150} 151 152static void getOptions() { 153 if(RestOfArgs.size() == 0) 154 show_help("Expected options"); 155 Options = RestOfArgs[0]; 156 RestOfArgs.erase(RestOfArgs.begin()); 157} 158 159// getArchive - Get the archive file name from the command line 160static void getArchive() { 161 if(RestOfArgs.size() == 0) 162 show_help("An archive name must be specified"); 163 ArchiveName = RestOfArgs[0]; 164 RestOfArgs.erase(RestOfArgs.begin()); 165} 166 167// getMembers - Copy over remaining items in RestOfArgs to our Members vector 168// This is just for clarity. 169static void getMembers() { 170 if(RestOfArgs.size() > 0) 171 Members = std::vector<std::string>(RestOfArgs); 172} 173 174// parseCommandLine - Parse the command line options as presented and return the 175// operation specified. Process all modifiers and check to make sure that 176// constraints on modifier/operation pairs have not been violated. 177static ArchiveOperation parseCommandLine() { 178 getOptions(); 179 180 // Keep track of number of operations. We can only specify one 181 // per execution. 182 unsigned NumOperations = 0; 183 184 // Keep track of the number of positional modifiers (a,b,i). Only 185 // one can be specified. 186 unsigned NumPositional = 0; 187 188 // Keep track of which operation was requested 189 ArchiveOperation Operation; 190 191 bool MaybeJustCreateSymTab = false; 192 193 for(unsigned i=0; i<Options.size(); ++i) { 194 switch(Options[i]) { 195 case 'd': ++NumOperations; Operation = Delete; break; 196 case 'm': ++NumOperations; Operation = Move ; break; 197 case 'p': ++NumOperations; Operation = Print; break; 198 case 'q': ++NumOperations; Operation = QuickAppend; break; 199 case 'r': ++NumOperations; Operation = ReplaceOrInsert; break; 200 case 't': ++NumOperations; Operation = DisplayTable; break; 201 case 'x': ++NumOperations; Operation = Extract; break; 202 case 'c': Create = true; break; 203 case 'l': /* accepted but unused */ break; 204 case 'o': OriginalDates = true; break; 205 case 's': 206 Symtab = true; 207 MaybeJustCreateSymTab = true; 208 break; 209 case 'S': 210 Symtab = false; 211 break; 212 case 'u': OnlyUpdate = true; break; 213 case 'v': Verbose = true; break; 214 case 'a': 215 getRelPos(); 216 AddAfter = true; 217 NumPositional++; 218 break; 219 case 'b': 220 getRelPos(); 221 AddBefore = true; 222 NumPositional++; 223 break; 224 case 'i': 225 getRelPos(); 226 AddBefore = true; 227 NumPositional++; 228 break; 229 default: 230 cl::PrintHelpMessage(); 231 } 232 } 233 234 // At this point, the next thing on the command line must be 235 // the archive name. 236 getArchive(); 237 238 // Everything on the command line at this point is a member. 239 getMembers(); 240 241 if (NumOperations == 0 && MaybeJustCreateSymTab) { 242 NumOperations = 1; 243 Operation = CreateSymTab; 244 if (!Members.empty()) 245 show_help("The s operation takes only an archive as argument"); 246 } 247 248 // Perform various checks on the operation/modifier specification 249 // to make sure we are dealing with a legal request. 250 if (NumOperations == 0) 251 show_help("You must specify at least one of the operations"); 252 if (NumOperations > 1) 253 show_help("Only one operation may be specified"); 254 if (NumPositional > 1) 255 show_help("You may only specify one of a, b, and i modifiers"); 256 if (AddAfter || AddBefore) { 257 if (Operation != Move && Operation != ReplaceOrInsert) 258 show_help("The 'a', 'b' and 'i' modifiers can only be specified with " 259 "the 'm' or 'r' operations"); 260 } 261 if (OriginalDates && Operation != Extract) 262 show_help("The 'o' modifier is only applicable to the 'x' operation"); 263 if (OnlyUpdate && Operation != ReplaceOrInsert) 264 show_help("The 'u' modifier is only applicable to the 'r' operation"); 265 266 // Return the parsed operation to the caller 267 return Operation; 268} 269 270// Implements the 'p' operation. This function traverses the archive 271// looking for members that match the path list. 272static void doPrint(StringRef Name, object::Archive::child_iterator I) { 273 if (Verbose) 274 outs() << "Printing " << Name << "\n"; 275 276 StringRef Data = I->getBuffer(); 277 outs().write(Data.data(), Data.size()); 278} 279 280// putMode - utility function for printing out the file mode when the 't' 281// operation is in verbose mode. 282static void printMode(unsigned mode) { 283 if (mode & 004) 284 outs() << "r"; 285 else 286 outs() << "-"; 287 if (mode & 002) 288 outs() << "w"; 289 else 290 outs() << "-"; 291 if (mode & 001) 292 outs() << "x"; 293 else 294 outs() << "-"; 295} 296 297// Implement the 't' operation. This function prints out just 298// the file names of each of the members. However, if verbose mode is requested 299// ('v' modifier) then the file type, permission mode, user, group, size, and 300// modification time are also printed. 301static void doDisplayTable(StringRef Name, object::Archive::child_iterator I) { 302 if (Verbose) { 303 sys::fs::perms Mode = I->getAccessMode(); 304 printMode((Mode >> 6) & 007); 305 printMode((Mode >> 3) & 007); 306 printMode(Mode & 007); 307 outs() << ' ' << I->getUID(); 308 outs() << '/' << I->getGID(); 309 outs() << ' ' << format("%6llu", I->getSize()); 310 outs() << ' ' << I->getLastModified().str(); 311 outs() << ' '; 312 } 313 outs() << Name << "\n"; 314} 315 316// Implement the 'x' operation. This function extracts files back to the file 317// system. 318static void doExtract(StringRef Name, object::Archive::child_iterator I) { 319 // Retain the original mode. 320 sys::fs::perms Mode = I->getAccessMode(); 321 SmallString<128> Storage = Name; 322 323 int FD; 324 failIfError( 325 sys::fs::openFileForWrite(Storage.c_str(), FD, sys::fs::F_None, Mode), 326 Storage.c_str()); 327 328 { 329 raw_fd_ostream file(FD, false); 330 331 // Get the data and its length 332 StringRef Data = I->getBuffer(); 333 334 // Write the data. 335 file.write(Data.data(), Data.size()); 336 } 337 338 // If we're supposed to retain the original modification times, etc. do so 339 // now. 340 if (OriginalDates) 341 failIfError( 342 sys::fs::setLastModificationAndAccessTime(FD, I->getLastModified())); 343 344 if (close(FD)) 345 fail("Could not close the file"); 346} 347 348static bool shouldCreateArchive(ArchiveOperation Op) { 349 switch (Op) { 350 case Print: 351 case Delete: 352 case Move: 353 case DisplayTable: 354 case Extract: 355 case CreateSymTab: 356 return false; 357 358 case QuickAppend: 359 case ReplaceOrInsert: 360 return true; 361 } 362 363 llvm_unreachable("Missing entry in covered switch."); 364} 365 366static void performReadOperation(ArchiveOperation Operation, 367 object::Archive *OldArchive) { 368 for (object::Archive::child_iterator I = OldArchive->child_begin(), 369 E = OldArchive->child_end(); 370 I != E; ++I) { 371 StringRef Name; 372 failIfError(I->getName(Name)); 373 374 if (!Members.empty() && 375 std::find(Members.begin(), Members.end(), Name) == Members.end()) 376 continue; 377 378 switch (Operation) { 379 default: 380 llvm_unreachable("Not a read operation"); 381 case Print: 382 doPrint(Name, I); 383 break; 384 case DisplayTable: 385 doDisplayTable(Name, I); 386 break; 387 case Extract: 388 doExtract(Name, I); 389 break; 390 } 391 } 392} 393 394namespace { 395class NewArchiveIterator { 396 bool IsNewMember; 397 StringRef Name; 398 399 object::Archive::child_iterator OldI; 400 401 std::string NewFilename; 402 mutable int NewFD; 403 mutable sys::fs::file_status NewStatus; 404 405public: 406 NewArchiveIterator(object::Archive::child_iterator I, StringRef Name); 407 NewArchiveIterator(std::string *I, StringRef Name); 408 NewArchiveIterator(); 409 bool isNewMember() const; 410 StringRef getName() const; 411 412 object::Archive::child_iterator getOld() const; 413 414 const char *getNew() const; 415 int getFD() const; 416 const sys::fs::file_status &getStatus() const; 417}; 418} 419 420NewArchiveIterator::NewArchiveIterator() {} 421 422NewArchiveIterator::NewArchiveIterator(object::Archive::child_iterator I, 423 StringRef Name) 424 : IsNewMember(false), Name(Name), OldI(I) {} 425 426NewArchiveIterator::NewArchiveIterator(std::string *NewFilename, StringRef Name) 427 : IsNewMember(true), Name(Name), NewFilename(*NewFilename), NewFD(-1) {} 428 429StringRef NewArchiveIterator::getName() const { return Name; } 430 431bool NewArchiveIterator::isNewMember() const { return IsNewMember; } 432 433object::Archive::child_iterator NewArchiveIterator::getOld() const { 434 assert(!IsNewMember); 435 return OldI; 436} 437 438const char *NewArchiveIterator::getNew() const { 439 assert(IsNewMember); 440 return NewFilename.c_str(); 441} 442 443int NewArchiveIterator::getFD() const { 444 assert(IsNewMember); 445 if (NewFD != -1) 446 return NewFD; 447 failIfError(sys::fs::openFileForRead(NewFilename, NewFD), NewFilename); 448 assert(NewFD != -1); 449 450 failIfError(sys::fs::status(NewFD, NewStatus), NewFilename); 451 452 // Opening a directory doesn't make sense. Let it fail. 453 // Linux cannot open directories with open(2), although 454 // cygwin and *bsd can. 455 if (NewStatus.type() == sys::fs::file_type::directory_file) 456 failIfError(error_code(errc::is_a_directory, posix_category()), 457 NewFilename); 458 459 return NewFD; 460} 461 462const sys::fs::file_status &NewArchiveIterator::getStatus() const { 463 assert(IsNewMember); 464 assert(NewFD != -1 && "Must call getFD first"); 465 return NewStatus; 466} 467 468template <typename T> 469void addMember(std::vector<NewArchiveIterator> &Members, T I, StringRef Name, 470 int Pos = -1) { 471 NewArchiveIterator NI(I, Name); 472 if (Pos == -1) 473 Members.push_back(NI); 474 else 475 Members[Pos] = NI; 476} 477 478enum InsertAction { 479 IA_AddOldMember, 480 IA_AddNewMeber, 481 IA_Delete, 482 IA_MoveOldMember, 483 IA_MoveNewMember 484}; 485 486static InsertAction 487computeInsertAction(ArchiveOperation Operation, 488 object::Archive::child_iterator I, StringRef Name, 489 std::vector<std::string>::iterator &Pos) { 490 if (Operation == QuickAppend || Members.empty()) 491 return IA_AddOldMember; 492 493 std::vector<std::string>::iterator MI = std::find_if( 494 Members.begin(), Members.end(), 495 [Name](StringRef Path) { return Name == sys::path::filename(Path); }); 496 497 if (MI == Members.end()) 498 return IA_AddOldMember; 499 500 Pos = MI; 501 502 if (Operation == Delete) 503 return IA_Delete; 504 505 if (Operation == Move) 506 return IA_MoveOldMember; 507 508 if (Operation == ReplaceOrInsert) { 509 StringRef PosName = sys::path::filename(RelPos); 510 if (!OnlyUpdate) { 511 if (PosName.empty()) 512 return IA_AddNewMeber; 513 return IA_MoveNewMember; 514 } 515 516 // We could try to optimize this to a fstat, but it is not a common 517 // operation. 518 sys::fs::file_status Status; 519 failIfError(sys::fs::status(*MI, Status), *MI); 520 if (Status.getLastModificationTime() < I->getLastModified()) { 521 if (PosName.empty()) 522 return IA_AddOldMember; 523 return IA_MoveOldMember; 524 } 525 526 if (PosName.empty()) 527 return IA_AddNewMeber; 528 return IA_MoveNewMember; 529 } 530 llvm_unreachable("No such operation"); 531} 532 533// We have to walk this twice and computing it is not trivial, so creating an 534// explicit std::vector is actually fairly efficient. 535static std::vector<NewArchiveIterator> 536computeNewArchiveMembers(ArchiveOperation Operation, 537 object::Archive *OldArchive) { 538 std::vector<NewArchiveIterator> Ret; 539 std::vector<NewArchiveIterator> Moved; 540 int InsertPos = -1; 541 StringRef PosName = sys::path::filename(RelPos); 542 if (OldArchive) { 543 for (object::Archive::child_iterator I = OldArchive->child_begin(), 544 E = OldArchive->child_end(); 545 I != E; ++I) { 546 int Pos = Ret.size(); 547 StringRef Name; 548 failIfError(I->getName(Name)); 549 if (Name == PosName) { 550 assert(AddAfter || AddBefore); 551 if (AddBefore) 552 InsertPos = Pos; 553 else 554 InsertPos = Pos + 1; 555 } 556 557 std::vector<std::string>::iterator MemberI = Members.end(); 558 InsertAction Action = computeInsertAction(Operation, I, Name, MemberI); 559 switch (Action) { 560 case IA_AddOldMember: 561 addMember(Ret, I, Name); 562 break; 563 case IA_AddNewMeber: 564 addMember(Ret, &*MemberI, Name); 565 break; 566 case IA_Delete: 567 break; 568 case IA_MoveOldMember: 569 addMember(Moved, I, Name); 570 break; 571 case IA_MoveNewMember: 572 addMember(Moved, &*MemberI, Name); 573 break; 574 } 575 if (MemberI != Members.end()) 576 Members.erase(MemberI); 577 } 578 } 579 580 if (Operation == Delete) 581 return Ret; 582 583 if (!RelPos.empty() && InsertPos == -1) 584 fail("Insertion point not found"); 585 586 if (RelPos.empty()) 587 InsertPos = Ret.size(); 588 589 assert(unsigned(InsertPos) <= Ret.size()); 590 Ret.insert(Ret.begin() + InsertPos, Moved.begin(), Moved.end()); 591 592 Ret.insert(Ret.begin() + InsertPos, Members.size(), NewArchiveIterator()); 593 int Pos = InsertPos; 594 for (std::vector<std::string>::iterator I = Members.begin(), 595 E = Members.end(); 596 I != E; ++I, ++Pos) { 597 StringRef Name = sys::path::filename(*I); 598 addMember(Ret, &*I, Name, Pos); 599 } 600 601 return Ret; 602} 603 604template <typename T> 605static void printWithSpacePadding(raw_fd_ostream &OS, T Data, unsigned Size, 606 bool MayTruncate = false) { 607 uint64_t OldPos = OS.tell(); 608 OS << Data; 609 unsigned SizeSoFar = OS.tell() - OldPos; 610 if (Size > SizeSoFar) { 611 unsigned Remaining = Size - SizeSoFar; 612 for (unsigned I = 0; I < Remaining; ++I) 613 OS << ' '; 614 } else if (Size < SizeSoFar) { 615 assert(MayTruncate && "Data doesn't fit in Size"); 616 // Some of the data this is used for (like UID) can be larger than the 617 // space available in the archive format. Truncate in that case. 618 OS.seek(OldPos + Size); 619 } 620} 621 622static void print32BE(raw_fd_ostream &Out, unsigned Val) { 623 for (int I = 3; I >= 0; --I) { 624 char V = (Val >> (8 * I)) & 0xff; 625 Out << V; 626 } 627} 628 629static void printRestOfMemberHeader(raw_fd_ostream &Out, 630 const sys::TimeValue &ModTime, unsigned UID, 631 unsigned GID, unsigned Perms, 632 unsigned Size) { 633 printWithSpacePadding(Out, ModTime.toEpochTime(), 12); 634 printWithSpacePadding(Out, UID, 6, true); 635 printWithSpacePadding(Out, GID, 6, true); 636 printWithSpacePadding(Out, format("%o", Perms), 8); 637 printWithSpacePadding(Out, Size, 10); 638 Out << "`\n"; 639} 640 641static void printMemberHeader(raw_fd_ostream &Out, StringRef Name, 642 const sys::TimeValue &ModTime, unsigned UID, 643 unsigned GID, unsigned Perms, unsigned Size) { 644 printWithSpacePadding(Out, Twine(Name) + "/", 16); 645 printRestOfMemberHeader(Out, ModTime, UID, GID, Perms, Size); 646} 647 648static void printMemberHeader(raw_fd_ostream &Out, unsigned NameOffset, 649 const sys::TimeValue &ModTime, unsigned UID, 650 unsigned GID, unsigned Perms, unsigned Size) { 651 Out << '/'; 652 printWithSpacePadding(Out, NameOffset, 15); 653 printRestOfMemberHeader(Out, ModTime, UID, GID, Perms, Size); 654} 655 656static void writeStringTable(raw_fd_ostream &Out, 657 ArrayRef<NewArchiveIterator> Members, 658 std::vector<unsigned> &StringMapIndexes) { 659 unsigned StartOffset = 0; 660 for (ArrayRef<NewArchiveIterator>::iterator I = Members.begin(), 661 E = Members.end(); 662 I != E; ++I) { 663 StringRef Name = I->getName(); 664 if (Name.size() < 16) 665 continue; 666 if (StartOffset == 0) { 667 printWithSpacePadding(Out, "//", 58); 668 Out << "`\n"; 669 StartOffset = Out.tell(); 670 } 671 StringMapIndexes.push_back(Out.tell() - StartOffset); 672 Out << Name << "/\n"; 673 } 674 if (StartOffset == 0) 675 return; 676 if (Out.tell() % 2) 677 Out << '\n'; 678 int Pos = Out.tell(); 679 Out.seek(StartOffset - 12); 680 printWithSpacePadding(Out, Pos - StartOffset, 10); 681 Out.seek(Pos); 682} 683 684static void writeSymbolTable( 685 raw_fd_ostream &Out, ArrayRef<NewArchiveIterator> Members, 686 ArrayRef<MemoryBuffer *> Buffers, 687 std::vector<std::pair<unsigned, unsigned> > &MemberOffsetRefs) { 688 unsigned StartOffset = 0; 689 unsigned MemberNum = 0; 690 std::string NameBuf; 691 raw_string_ostream NameOS(NameBuf); 692 unsigned NumSyms = 0; 693 std::vector<object::SymbolicFile *> DeleteIt; 694 LLVMContext &Context = getGlobalContext(); 695 for (ArrayRef<NewArchiveIterator>::iterator I = Members.begin(), 696 E = Members.end(); 697 I != E; ++I, ++MemberNum) { 698 MemoryBuffer *MemberBuffer = Buffers[MemberNum]; 699 ErrorOr<object::SymbolicFile *> ObjOrErr = 700 object::SymbolicFile::createSymbolicFile( 701 MemberBuffer, false, sys::fs::file_magic::unknown, &Context); 702 if (!ObjOrErr) 703 continue; // FIXME: check only for "not an object file" errors. 704 object::SymbolicFile *Obj = ObjOrErr.get(); 705 706 DeleteIt.push_back(Obj); 707 if (!StartOffset) { 708 printMemberHeader(Out, "", sys::TimeValue::now(), 0, 0, 0, 0); 709 StartOffset = Out.tell(); 710 print32BE(Out, 0); 711 } 712 713 for (object::basic_symbol_iterator I = Obj->symbol_begin(), 714 E = Obj->symbol_end(); 715 I != E; ++I) { 716 uint32_t Symflags = I->getFlags(); 717 if (Symflags & object::SymbolRef::SF_FormatSpecific) 718 continue; 719 if (!(Symflags & object::SymbolRef::SF_Global)) 720 continue; 721 if (Symflags & object::SymbolRef::SF_Undefined) 722 continue; 723 failIfError(I->printName(NameOS)); 724 NameOS << '\0'; 725 ++NumSyms; 726 MemberOffsetRefs.push_back(std::make_pair(Out.tell(), MemberNum)); 727 print32BE(Out, 0); 728 } 729 } 730 Out << NameOS.str(); 731 732 for (std::vector<object::SymbolicFile *>::iterator I = DeleteIt.begin(), 733 E = DeleteIt.end(); 734 I != E; ++I) { 735 object::SymbolicFile *O = *I; 736 delete O; 737 } 738 739 if (StartOffset == 0) 740 return; 741 742 if (Out.tell() % 2) 743 Out << '\0'; 744 745 unsigned Pos = Out.tell(); 746 Out.seek(StartOffset - 12); 747 printWithSpacePadding(Out, Pos - StartOffset, 10); 748 Out.seek(StartOffset); 749 print32BE(Out, NumSyms); 750 Out.seek(Pos); 751} 752 753static void performWriteOperation(ArchiveOperation Operation, 754 object::Archive *OldArchive) { 755 SmallString<128> TmpArchive; 756 failIfError(sys::fs::createUniqueFile(ArchiveName + ".temp-archive-%%%%%%%.a", 757 TmpArchiveFD, TmpArchive)); 758 759 TemporaryOutput = TmpArchive.c_str(); 760 tool_output_file Output(TemporaryOutput, TmpArchiveFD); 761 raw_fd_ostream &Out = Output.os(); 762 Out << "!<arch>\n"; 763 764 std::vector<NewArchiveIterator> NewMembers = 765 computeNewArchiveMembers(Operation, OldArchive); 766 767 std::vector<std::pair<unsigned, unsigned> > MemberOffsetRefs; 768 769 std::vector<MemoryBuffer *> MemberBuffers; 770 MemberBuffers.resize(NewMembers.size()); 771 772 for (unsigned I = 0, N = NewMembers.size(); I < N; ++I) { 773 std::unique_ptr<MemoryBuffer> MemberBuffer; 774 NewArchiveIterator &Member = NewMembers[I]; 775 776 if (Member.isNewMember()) { 777 const char *Filename = Member.getNew(); 778 int FD = Member.getFD(); 779 const sys::fs::file_status &Status = Member.getStatus(); 780 failIfError(MemoryBuffer::getOpenFile(FD, Filename, MemberBuffer, 781 Status.getSize(), false), 782 Filename); 783 784 } else { 785 object::Archive::child_iterator OldMember = Member.getOld(); 786 failIfError(OldMember->getMemoryBuffer(MemberBuffer)); 787 } 788 MemberBuffers[I] = MemberBuffer.release(); 789 } 790 791 if (Symtab) { 792 writeSymbolTable(Out, NewMembers, MemberBuffers, MemberOffsetRefs); 793 } 794 795 std::vector<unsigned> StringMapIndexes; 796 writeStringTable(Out, NewMembers, StringMapIndexes); 797 798 std::vector<std::pair<unsigned, unsigned> >::iterator MemberRefsI = 799 MemberOffsetRefs.begin(); 800 801 unsigned MemberNum = 0; 802 unsigned LongNameMemberNum = 0; 803 for (std::vector<NewArchiveIterator>::iterator I = NewMembers.begin(), 804 E = NewMembers.end(); 805 I != E; ++I, ++MemberNum) { 806 807 unsigned Pos = Out.tell(); 808 while (MemberRefsI != MemberOffsetRefs.end() && 809 MemberRefsI->second == MemberNum) { 810 Out.seek(MemberRefsI->first); 811 print32BE(Out, Pos); 812 ++MemberRefsI; 813 } 814 Out.seek(Pos); 815 816 const MemoryBuffer *File = MemberBuffers[MemberNum]; 817 if (I->isNewMember()) { 818 const char *FileName = I->getNew(); 819 const sys::fs::file_status &Status = I->getStatus(); 820 821 StringRef Name = sys::path::filename(FileName); 822 if (Name.size() < 16) 823 printMemberHeader(Out, Name, Status.getLastModificationTime(), 824 Status.getUser(), Status.getGroup(), 825 Status.permissions(), Status.getSize()); 826 else 827 printMemberHeader(Out, StringMapIndexes[LongNameMemberNum++], 828 Status.getLastModificationTime(), Status.getUser(), 829 Status.getGroup(), Status.permissions(), 830 Status.getSize()); 831 } else { 832 object::Archive::child_iterator OldMember = I->getOld(); 833 StringRef Name = I->getName(); 834 835 if (Name.size() < 16) 836 printMemberHeader(Out, Name, OldMember->getLastModified(), 837 OldMember->getUID(), OldMember->getGID(), 838 OldMember->getAccessMode(), OldMember->getSize()); 839 else 840 printMemberHeader(Out, StringMapIndexes[LongNameMemberNum++], 841 OldMember->getLastModified(), OldMember->getUID(), 842 OldMember->getGID(), OldMember->getAccessMode(), 843 OldMember->getSize()); 844 } 845 846 Out << File->getBuffer(); 847 848 if (Out.tell() % 2) 849 Out << '\n'; 850 } 851 852 for (unsigned I = 0, N = MemberBuffers.size(); I < N; ++I) { 853 delete MemberBuffers[I]; 854 } 855 856 Output.keep(); 857 Out.close(); 858 sys::fs::rename(TemporaryOutput, ArchiveName); 859 TemporaryOutput = nullptr; 860} 861 862static void createSymbolTable(object::Archive *OldArchive) { 863 // When an archive is created or modified, if the s option is given, the 864 // resulting archive will have a current symbol table. If the S option 865 // is given, it will have no symbol table. 866 // In summary, we only need to update the symbol table if we have none. 867 // This is actually very common because of broken build systems that think 868 // they have to run ranlib. 869 if (OldArchive->hasSymbolTable()) 870 return; 871 872 performWriteOperation(CreateSymTab, OldArchive); 873} 874 875static void performOperation(ArchiveOperation Operation, 876 object::Archive *OldArchive) { 877 switch (Operation) { 878 case Print: 879 case DisplayTable: 880 case Extract: 881 performReadOperation(Operation, OldArchive); 882 return; 883 884 case Delete: 885 case Move: 886 case QuickAppend: 887 case ReplaceOrInsert: 888 performWriteOperation(Operation, OldArchive); 889 return; 890 case CreateSymTab: 891 createSymbolTable(OldArchive); 892 return; 893 } 894 llvm_unreachable("Unknown operation."); 895} 896 897static int ar_main(char **argv); 898static int ranlib_main(); 899 900// main - main program for llvm-ar .. see comments in the code 901int main(int argc, char **argv) { 902 ToolName = argv[0]; 903 // Print a stack trace if we signal out. 904 sys::PrintStackTraceOnErrorSignal(); 905 PrettyStackTraceProgram X(argc, argv); 906 llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. 907 908 // Have the command line options parsed and handle things 909 // like --help and --version. 910 cl::ParseCommandLineOptions(argc, argv, 911 "LLVM Archiver (llvm-ar)\n\n" 912 " This program archives bitcode files into single libraries\n" 913 ); 914 915 StringRef Stem = sys::path::stem(ToolName); 916 if (Stem.find("ar") != StringRef::npos) 917 return ar_main(argv); 918 if (Stem.find("ranlib") != StringRef::npos) 919 return ranlib_main(); 920 fail("Not ranlib or ar!"); 921} 922 923static int performOperation(ArchiveOperation Operation); 924 925int ranlib_main() { 926 if (RestOfArgs.size() != 1) 927 fail(ToolName + "takes just one archive as argument"); 928 ArchiveName = RestOfArgs[0]; 929 return performOperation(CreateSymTab); 930} 931 932int ar_main(char **argv) { 933 // Do our own parsing of the command line because the CommandLine utility 934 // can't handle the grouped positional parameters without a dash. 935 ArchiveOperation Operation = parseCommandLine(); 936 return performOperation(Operation); 937} 938 939static int performOperation(ArchiveOperation Operation) { 940 // Create or open the archive object. 941 std::unique_ptr<MemoryBuffer> Buf; 942 error_code EC = MemoryBuffer::getFile(ArchiveName, Buf, -1, false); 943 if (EC && EC != llvm::errc::no_such_file_or_directory) { 944 errs() << ToolName << ": error opening '" << ArchiveName 945 << "': " << EC.message() << "!\n"; 946 return 1; 947 } 948 949 if (!EC) { 950 object::Archive Archive(Buf.release(), EC); 951 952 if (EC) { 953 errs() << ToolName << ": error loading '" << ArchiveName 954 << "': " << EC.message() << "!\n"; 955 return 1; 956 } 957 performOperation(Operation, &Archive); 958 return 0; 959 } 960 961 assert(EC == llvm::errc::no_such_file_or_directory); 962 963 if (!shouldCreateArchive(Operation)) { 964 failIfError(EC, Twine("error loading '") + ArchiveName + "'"); 965 } else { 966 if (!Create) { 967 // Produce a warning if we should and we're creating the archive 968 errs() << ToolName << ": creating " << ArchiveName << "\n"; 969 } 970 } 971 972 performOperation(Operation, nullptr); 973 return 0; 974} 975