llvm-ar.cpp revision 02a1364bf8ede511ad603e5aa99ea7dbf11f0609
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/Support/CommandLine.h" 19#include "llvm/Support/FileSystem.h" 20#include "llvm/Support/Format.h" 21#include "llvm/Support/ManagedStatic.h" 22#include "llvm/Support/MemoryBuffer.h" 23#include "llvm/Support/PrettyStackTrace.h" 24#include "llvm/Support/Signals.h" 25#include "llvm/Support/ToolOutputFile.h" 26#include "llvm/Support/raw_ostream.h" 27#include <algorithm> 28#include <cstdlib> 29#include <memory> 30 31#if !defined(_MSC_VER) && !defined(__MINGW32__) 32#include <unistd.h> 33#else 34#include <io.h> 35#endif 36 37using namespace llvm; 38 39// The name this program was invoked as. 40static StringRef ToolName; 41 42static const char *TemporaryOutput; 43static int TmpArchiveFD = -1; 44 45// fail - Show the error message and exit. 46LLVM_ATTRIBUTE_NORETURN static void fail(Twine Error) { 47 outs() << ToolName << ": " << Error << ".\n"; 48 if (TmpArchiveFD != -1) 49 close(TmpArchiveFD); 50 if (TemporaryOutput) 51 sys::fs::remove(TemporaryOutput); 52 exit(1); 53} 54 55static void failIfError(error_code EC, Twine Context = "") { 56 if (!EC) 57 return; 58 59 std::string ContextStr = Context.str(); 60 if (ContextStr == "") 61 fail(EC.message()); 62 fail(Context + ": " + EC.message()); 63} 64 65// Option for compatibility with AIX, not used but must allow it to be present. 66static cl::opt<bool> 67X32Option ("X32_64", cl::Hidden, 68 cl::desc("Ignored option for compatibility with AIX")); 69 70// llvm-ar operation code and modifier flags. This must come first. 71static cl::opt<std::string> 72Options(cl::Positional, cl::Required, cl::desc("{operation}[modifiers]...")); 73 74// llvm-ar remaining positional arguments. 75static cl::list<std::string> 76RestOfArgs(cl::Positional, cl::OneOrMore, 77 cl::desc("[relpos] [count] <archive-file> [members]...")); 78 79// MoreHelp - Provide additional help output explaining the operations and 80// modifiers of llvm-ar. This object instructs the CommandLine library 81// to print the text of the constructor when the --help option is given. 82static cl::extrahelp MoreHelp( 83 "\nOPERATIONS:\n" 84 " d[NsS] - delete file(s) from the archive\n" 85 " m[abiSs] - move file(s) in the archive\n" 86 " p[kN] - print file(s) found in the archive\n" 87 " q[ufsS] - quick append file(s) to the archive\n" 88 " r[abfiuRsS] - replace or insert file(s) into the archive\n" 89 " t - display contents of archive\n" 90 " x[No] - extract file(s) from the archive\n" 91 "\nMODIFIERS (operation specific):\n" 92 " [a] - put file(s) after [relpos]\n" 93 " [b] - put file(s) before [relpos] (same as [i])\n" 94 " [i] - put file(s) before [relpos] (same as [b])\n" 95 " [N] - use instance [count] of name\n" 96 " [o] - preserve original dates\n" 97 " [s] - create an archive index (cf. ranlib)\n" 98 " [S] - do not build a symbol table\n" 99 " [u] - update only files newer than archive contents\n" 100 "\nMODIFIERS (generic):\n" 101 " [c] - do not warn if the library had to be created\n" 102 " [v] - be verbose about actions taken\n" 103); 104 105// This enumeration delineates the kinds of operations on an archive 106// that are permitted. 107enum ArchiveOperation { 108 Print, ///< Print the contents of the archive 109 Delete, ///< Delete the specified members 110 Move, ///< Move members to end or as given by {a,b,i} modifiers 111 QuickAppend, ///< Quickly append to end of archive 112 ReplaceOrInsert, ///< Replace or Insert members 113 DisplayTable, ///< Display the table of contents 114 Extract ///< Extract files back to file system 115}; 116 117// Modifiers to follow operation to vary behavior 118static bool AddAfter = false; ///< 'a' modifier 119static bool AddBefore = false; ///< 'b' modifier 120static bool Create = false; ///< 'c' modifier 121static bool OriginalDates = false; ///< 'o' modifier 122static bool OnlyUpdate = false; ///< 'u' modifier 123static bool Verbose = false; ///< 'v' modifier 124 125// Relative Positional Argument (for insert/move). This variable holds 126// the name of the archive member to which the 'a', 'b' or 'i' modifier 127// refers. Only one of 'a', 'b' or 'i' can be specified so we only need 128// one variable. 129static std::string RelPos; 130 131// This variable holds the name of the archive file as given on the 132// command line. 133static std::string ArchiveName; 134 135// This variable holds the list of member files to proecess, as given 136// on the command line. 137static std::vector<std::string> Members; 138 139// show_help - Show the error message, the help message and exit. 140LLVM_ATTRIBUTE_NORETURN static void 141show_help(const std::string &msg) { 142 errs() << ToolName << ": " << msg << "\n\n"; 143 cl::PrintHelpMessage(); 144 std::exit(1); 145} 146 147// getRelPos - Extract the member filename from the command line for 148// the [relpos] argument associated with a, b, and i modifiers 149static void getRelPos() { 150 if(RestOfArgs.size() == 0) 151 show_help("Expected [relpos] for a, b, or i modifier"); 152 RelPos = RestOfArgs[0]; 153 RestOfArgs.erase(RestOfArgs.begin()); 154} 155 156// getArchive - Get the archive file name from the command line 157static void getArchive() { 158 if(RestOfArgs.size() == 0) 159 show_help("An archive name must be specified"); 160 ArchiveName = RestOfArgs[0]; 161 RestOfArgs.erase(RestOfArgs.begin()); 162} 163 164// getMembers - Copy over remaining items in RestOfArgs to our Members vector 165// This is just for clarity. 166static void getMembers() { 167 if(RestOfArgs.size() > 0) 168 Members = std::vector<std::string>(RestOfArgs); 169} 170 171// parseCommandLine - Parse the command line options as presented and return the 172// operation specified. Process all modifiers and check to make sure that 173// constraints on modifier/operation pairs have not been violated. 174static ArchiveOperation parseCommandLine() { 175 176 // Keep track of number of operations. We can only specify one 177 // per execution. 178 unsigned NumOperations = 0; 179 180 // Keep track of the number of positional modifiers (a,b,i). Only 181 // one can be specified. 182 unsigned NumPositional = 0; 183 184 // Keep track of which operation was requested 185 ArchiveOperation Operation; 186 187 for(unsigned i=0; i<Options.size(); ++i) { 188 switch(Options[i]) { 189 case 'd': ++NumOperations; Operation = Delete; break; 190 case 'm': ++NumOperations; Operation = Move ; break; 191 case 'p': ++NumOperations; Operation = Print; break; 192 case 'q': ++NumOperations; Operation = QuickAppend; break; 193 case 'r': ++NumOperations; Operation = ReplaceOrInsert; break; 194 case 't': ++NumOperations; Operation = DisplayTable; break; 195 case 'x': ++NumOperations; Operation = Extract; break; 196 case 'c': Create = true; break; 197 case 'l': /* accepted but unused */ break; 198 case 'o': OriginalDates = true; break; 199 case 's': break; // Ignore for now. 200 case 'S': break; // Ignore for now. 201 case 'u': OnlyUpdate = true; break; 202 case 'v': Verbose = true; break; 203 case 'a': 204 getRelPos(); 205 AddAfter = true; 206 NumPositional++; 207 break; 208 case 'b': 209 getRelPos(); 210 AddBefore = true; 211 NumPositional++; 212 break; 213 case 'i': 214 getRelPos(); 215 AddBefore = true; 216 NumPositional++; 217 break; 218 default: 219 cl::PrintHelpMessage(); 220 } 221 } 222 223 // At this point, the next thing on the command line must be 224 // the archive name. 225 getArchive(); 226 227 // Everything on the command line at this point is a member. 228 getMembers(); 229 230 // Perform various checks on the operation/modifier specification 231 // to make sure we are dealing with a legal request. 232 if (NumOperations == 0) 233 show_help("You must specify at least one of the operations"); 234 if (NumOperations > 1) 235 show_help("Only one operation may be specified"); 236 if (NumPositional > 1) 237 show_help("You may only specify one of a, b, and i modifiers"); 238 if (AddAfter || AddBefore) { 239 if (Operation != Move && Operation != ReplaceOrInsert) 240 show_help("The 'a', 'b' and 'i' modifiers can only be specified with " 241 "the 'm' or 'r' operations"); 242 } 243 if (OriginalDates && Operation != Extract) 244 show_help("The 'o' modifier is only applicable to the 'x' operation"); 245 if (OnlyUpdate && Operation != ReplaceOrInsert) 246 show_help("The 'u' modifier is only applicable to the 'r' operation"); 247 248 // Return the parsed operation to the caller 249 return Operation; 250} 251 252// Implements the 'p' operation. This function traverses the archive 253// looking for members that match the path list. 254static void doPrint(StringRef Name, object::Archive::child_iterator I) { 255 if (Verbose) 256 outs() << "Printing " << Name << "\n"; 257 258 StringRef Data = I->getBuffer(); 259 outs().write(Data.data(), Data.size()); 260} 261 262// putMode - utility function for printing out the file mode when the 't' 263// operation is in verbose mode. 264static void printMode(unsigned mode) { 265 if (mode & 004) 266 outs() << "r"; 267 else 268 outs() << "-"; 269 if (mode & 002) 270 outs() << "w"; 271 else 272 outs() << "-"; 273 if (mode & 001) 274 outs() << "x"; 275 else 276 outs() << "-"; 277} 278 279// Implement the 't' operation. This function prints out just 280// the file names of each of the members. However, if verbose mode is requested 281// ('v' modifier) then the file type, permission mode, user, group, size, and 282// modification time are also printed. 283static void doDisplayTable(StringRef Name, object::Archive::child_iterator I) { 284 if (Verbose) { 285 sys::fs::perms Mode = I->getAccessMode(); 286 printMode((Mode >> 6) & 007); 287 printMode((Mode >> 3) & 007); 288 printMode(Mode & 007); 289 outs() << ' ' << I->getUID(); 290 outs() << '/' << I->getGID(); 291 outs() << ' ' << format("%6llu", I->getSize()); 292 outs() << ' ' << I->getLastModified().str(); 293 outs() << ' '; 294 } 295 outs() << Name << "\n"; 296} 297 298// Implement the 'x' operation. This function extracts files back to the file 299// system. 300static void doExtract(StringRef Name, object::Archive::child_iterator I) { 301 // Retain the original mode. 302 sys::fs::perms Mode = I->getAccessMode(); 303 SmallString<128> Storage = Name; 304 305 int FD; 306 failIfError( 307 sys::fs::openFileForWrite(Storage.c_str(), FD, sys::fs::F_Binary, Mode), 308 Storage.c_str()); 309 310 { 311 raw_fd_ostream file(FD, false); 312 313 // Get the data and its length 314 StringRef Data = I->getBuffer(); 315 316 // Write the data. 317 file.write(Data.data(), Data.size()); 318 } 319 320 // If we're supposed to retain the original modification times, etc. do so 321 // now. 322 if (OriginalDates) 323 failIfError( 324 sys::fs::setLastModificationAndAccessTime(FD, I->getLastModified())); 325 326 if (close(FD)) 327 fail("Could not close the file"); 328} 329 330static bool shouldCreateArchive(ArchiveOperation Op) { 331 switch (Op) { 332 case Print: 333 case Delete: 334 case Move: 335 case DisplayTable: 336 case Extract: 337 return false; 338 339 case QuickAppend: 340 case ReplaceOrInsert: 341 return true; 342 } 343 344 llvm_unreachable("Missing entry in covered switch."); 345} 346 347static void performReadOperation(ArchiveOperation Operation, 348 object::Archive *OldArchive) { 349 for (object::Archive::child_iterator I = OldArchive->begin_children(), 350 E = OldArchive->end_children(); 351 I != E; ++I) { 352 StringRef Name; 353 failIfError(I->getName(Name)); 354 355 if (!Members.empty() && 356 std::find(Members.begin(), Members.end(), Name) == Members.end()) 357 continue; 358 359 switch (Operation) { 360 default: 361 llvm_unreachable("Not a read operation"); 362 case Print: 363 doPrint(Name, I); 364 break; 365 case DisplayTable: 366 doDisplayTable(Name, I); 367 break; 368 case Extract: 369 doExtract(Name, I); 370 break; 371 } 372 } 373} 374 375namespace { 376class NewArchiveIterator { 377 bool IsNewMember; 378 SmallString<16> MemberName; 379 object::Archive::child_iterator OldI; 380 std::vector<std::string>::const_iterator NewI; 381 382public: 383 NewArchiveIterator(object::Archive::child_iterator I, Twine Name); 384 NewArchiveIterator(std::vector<std::string>::const_iterator I, Twine Name); 385 NewArchiveIterator(); 386 bool isNewMember() const; 387 object::Archive::child_iterator getOld() const; 388 const char *getNew() const; 389 StringRef getMemberName() const { return MemberName; } 390}; 391} 392 393NewArchiveIterator::NewArchiveIterator() {} 394 395NewArchiveIterator::NewArchiveIterator(object::Archive::child_iterator I, 396 Twine Name) 397 : IsNewMember(false), OldI(I) { 398 Name.toVector(MemberName); 399} 400 401NewArchiveIterator::NewArchiveIterator( 402 std::vector<std::string>::const_iterator I, Twine Name) 403 : IsNewMember(true), NewI(I) { 404 Name.toVector(MemberName); 405} 406 407bool NewArchiveIterator::isNewMember() const { return IsNewMember; } 408 409object::Archive::child_iterator NewArchiveIterator::getOld() const { 410 assert(!IsNewMember); 411 return OldI; 412} 413 414const char *NewArchiveIterator::getNew() const { 415 assert(IsNewMember); 416 return NewI->c_str(); 417} 418 419template <typename T> 420void addMember(std::vector<NewArchiveIterator> &Members, 421 std::string &StringTable, T I, StringRef Name, int Pos = -1) { 422 if (Name.size() < 16) { 423 NewArchiveIterator NI(I, Twine(Name) + "/"); 424 if (Pos == -1) 425 Members.push_back(NI); 426 else 427 Members[Pos] = NI; 428 } else { 429 int MapIndex = StringTable.size(); 430 NewArchiveIterator NI(I, Twine("/") + Twine(MapIndex)); 431 if (Pos == -1) 432 Members.push_back(NI); 433 else 434 Members[Pos] = NI; 435 StringTable += Name; 436 StringTable += "/\n"; 437 } 438} 439 440namespace { 441class HasName { 442 StringRef Name; 443 444public: 445 HasName(StringRef Name) : Name(Name) {} 446 bool operator()(StringRef Path) { return Name == sys::path::filename(Path); } 447}; 448} 449 450// We have to walk this twice and computing it is not trivial, so creating an 451// explicit std::vector is actually fairly efficient. 452static std::vector<NewArchiveIterator> 453computeNewArchiveMembers(ArchiveOperation Operation, 454 object::Archive *OldArchive, 455 std::string &StringTable) { 456 std::vector<NewArchiveIterator> Ret; 457 std::vector<NewArchiveIterator> Moved; 458 int InsertPos = -1; 459 StringRef PosName = sys::path::filename(RelPos); 460 if (OldArchive) { 461 for (object::Archive::child_iterator I = OldArchive->begin_children(), 462 E = OldArchive->end_children(); 463 I != E; ++I) { 464 int Pos = Ret.size(); 465 StringRef Name; 466 failIfError(I->getName(Name)); 467 if (Name == PosName) { 468 assert(AddAfter || AddBefore); 469 if (AddBefore) 470 InsertPos = Pos; 471 else 472 InsertPos = Pos + 1; 473 } 474 if (InsertPos == Pos) 475 Ret.resize(Ret.size() + Members.size()); 476 if (Operation != QuickAppend && !Members.empty()) { 477 std::vector<std::string>::iterator MI = 478 std::find_if(Members.begin(), Members.end(), HasName(Name)); 479 if (MI != Members.end()) { 480 if (Operation == Move) { 481 addMember(Moved, StringTable, I, Name); 482 continue; 483 } 484 if (Operation != ReplaceOrInsert || !OnlyUpdate) 485 continue; 486 // Ignore if the file if it is older than the member. 487 sys::fs::file_status Status; 488 failIfError(sys::fs::status(*MI, Status)); 489 if (Status.getLastModificationTime() < I->getLastModified()) 490 Members.erase(MI); 491 else 492 continue; 493 } 494 } 495 addMember(Ret, StringTable, I, Name); 496 } 497 } 498 499 if (Operation == Delete) 500 return Ret; 501 502 if (!RelPos.empty() && InsertPos == -1) 503 fail("Insertion point not found"); 504 505 if (Operation == Move) { 506 if (Members.size() != Moved.size()) 507 fail("A member to be moved is not present in the archive"); 508 509 if (RelPos.empty()) { 510 Ret.insert(Ret.end(), Moved.begin(), Moved.end()); 511 return Ret; 512 } 513 assert(unsigned(InsertPos) <= Ret.size()); 514 std::copy(Moved.begin(), Moved.end(), Ret.begin() + InsertPos); 515 return Ret; 516 } 517 518 int Pos = InsertPos; 519 for (std::vector<std::string>::iterator I = Members.begin(), 520 E = Members.end(); 521 I != E; ++I) { 522 StringRef Name = sys::path::filename(*I); 523 addMember(Ret, StringTable, I, Name, Pos); 524 if (Pos != -1) 525 ++Pos; 526 } 527 528 return Ret; 529} 530 531template <typename T> 532static void printWithSpacePadding(raw_ostream &OS, T Data, unsigned Size) { 533 uint64_t OldPos = OS.tell(); 534 OS << Data; 535 unsigned SizeSoFar = OS.tell() - OldPos; 536 assert(Size >= SizeSoFar && "Data doesn't fit in Size"); 537 unsigned Remaining = Size - SizeSoFar; 538 for (unsigned I = 0; I < Remaining; ++I) 539 OS << ' '; 540} 541 542static void performWriteOperation(ArchiveOperation Operation, 543 object::Archive *OldArchive) { 544 SmallString<128> TmpArchive; 545 failIfError(sys::fs::createUniqueFile(ArchiveName + ".temp-archive-%%%%%%%.a", 546 TmpArchiveFD, TmpArchive)); 547 548 TemporaryOutput = TmpArchive.c_str(); 549 tool_output_file Output(TemporaryOutput, TmpArchiveFD); 550 raw_fd_ostream &Out = Output.os(); 551 Out << "!<arch>\n"; 552 553 std::string StringTable; 554 std::vector<NewArchiveIterator> NewMembers = 555 computeNewArchiveMembers(Operation, OldArchive, StringTable); 556 if (!StringTable.empty()) { 557 if (StringTable.size() % 2) 558 StringTable += '\n'; 559 printWithSpacePadding(Out, "//", 48); 560 printWithSpacePadding(Out, StringTable.size(), 10); 561 Out << "`\n"; 562 Out << StringTable; 563 } 564 565 for (std::vector<NewArchiveIterator>::iterator I = NewMembers.begin(), 566 E = NewMembers.end(); 567 I != E; ++I) { 568 StringRef Name = I->getMemberName(); 569 printWithSpacePadding(Out, Name, 16); 570 571 if (I->isNewMember()) { 572 const char *FileName = I->getNew(); 573 574 int FD; 575 failIfError(sys::fs::openFileForRead(FileName, FD), FileName); 576 577 sys::fs::file_status Status; 578 failIfError(sys::fs::status(FD, Status), FileName); 579 580 OwningPtr<MemoryBuffer> File; 581 failIfError( 582 MemoryBuffer::getOpenFile(FD, FileName, File, Status.getSize()), 583 FileName); 584 585 uint64_t secondsSinceEpoch = 586 Status.getLastModificationTime().toEpochTime(); 587 printWithSpacePadding(Out, secondsSinceEpoch, 12); 588 589 printWithSpacePadding(Out, Status.getUser(), 6); 590 printWithSpacePadding(Out, Status.getGroup(), 6); 591 printWithSpacePadding(Out, format("%o", Status.permissions()), 8); 592 printWithSpacePadding(Out, Status.getSize(), 10); 593 Out << "`\n"; 594 595 Out << File->getBuffer(); 596 } else { 597 object::Archive::child_iterator OldMember = I->getOld(); 598 599 uint64_t secondsSinceEpoch = OldMember->getLastModified().toEpochTime(); 600 printWithSpacePadding(Out, secondsSinceEpoch, 12); 601 602 printWithSpacePadding(Out, OldMember->getUID(), 6); 603 printWithSpacePadding(Out, OldMember->getGID(), 6); 604 printWithSpacePadding(Out, format("%o", OldMember->getAccessMode()), 8); 605 printWithSpacePadding(Out, OldMember->getSize(), 10); 606 Out << "`\n"; 607 608 Out << OldMember->getBuffer(); 609 } 610 611 if (Out.tell() % 2) 612 Out << '\n'; 613 } 614 Output.keep(); 615 Out.close(); 616 sys::fs::rename(TemporaryOutput, ArchiveName); 617 TemporaryOutput = NULL; 618} 619 620static void performOperation(ArchiveOperation Operation, 621 object::Archive *OldArchive) { 622 switch (Operation) { 623 case Print: 624 case DisplayTable: 625 case Extract: 626 performReadOperation(Operation, OldArchive); 627 return; 628 629 case Delete: 630 case Move: 631 case QuickAppend: 632 case ReplaceOrInsert: 633 performWriteOperation(Operation, OldArchive); 634 return; 635 } 636 llvm_unreachable("Unknown operation."); 637} 638 639// main - main program for llvm-ar .. see comments in the code 640int main(int argc, char **argv) { 641 ToolName = argv[0]; 642 // Print a stack trace if we signal out. 643 sys::PrintStackTraceOnErrorSignal(); 644 PrettyStackTraceProgram X(argc, argv); 645 llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. 646 647 // Have the command line options parsed and handle things 648 // like --help and --version. 649 cl::ParseCommandLineOptions(argc, argv, 650 "LLVM Archiver (llvm-ar)\n\n" 651 " This program archives bitcode files into single libraries\n" 652 ); 653 654 // Do our own parsing of the command line because the CommandLine utility 655 // can't handle the grouped positional parameters without a dash. 656 ArchiveOperation Operation = parseCommandLine(); 657 658 // Create or open the archive object. 659 OwningPtr<MemoryBuffer> Buf; 660 error_code EC = MemoryBuffer::getFile(ArchiveName, Buf, -1, false); 661 if (EC && EC != llvm::errc::no_such_file_or_directory) { 662 errs() << argv[0] << ": error opening '" << ArchiveName 663 << "': " << EC.message() << "!\n"; 664 return 1; 665 } 666 667 if (!EC) { 668 object::Archive Archive(Buf.take(), EC); 669 670 if (EC) { 671 errs() << argv[0] << ": error loading '" << ArchiveName 672 << "': " << EC.message() << "!\n"; 673 return 1; 674 } 675 performOperation(Operation, &Archive); 676 return 0; 677 } 678 679 assert(EC == llvm::errc::no_such_file_or_directory); 680 681 if (!shouldCreateArchive(Operation)) { 682 failIfError(EC, Twine("error loading '") + ArchiveName + "'"); 683 } else { 684 if (!Create) { 685 // Produce a warning if we should and we're creating the archive 686 errs() << argv[0] << ": creating " << ArchiveName << "\n"; 687 } 688 } 689 690 performOperation(Operation, NULL); 691 return 0; 692} 693