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