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 std::string normalizePath(StringRef Path) { 478 return CompareFullPath ? sys::path::convert_to_slash(Path) 479 : std::string(sys::path::filename(Path)); 480 } 481 482 // Implement the 'x' operation. This function extracts files back to the file 483 // system. 484 static void doExtract(StringRef Name, const object::Archive::Child &C) { 485 // Retain the original mode. 486 Expected<sys::fs::perms> ModeOrErr = C.getAccessMode(); 487 failIfError(ModeOrErr.takeError()); 488 sys::fs::perms Mode = ModeOrErr.get(); 489 490 int FD; 491 failIfError(sys::fs::openFileForWrite(sys::path::filename(Name), FD, 492 sys::fs::CD_CreateAlways, 493 sys::fs::OF_None, Mode), 494 Name); 495 496 { 497 raw_fd_ostream file(FD, false); 498 499 // Get the data and its length 500 Expected<StringRef> BufOrErr = C.getBuffer(); 501 failIfError(BufOrErr.takeError()); 502 StringRef Data = BufOrErr.get(); 503 504 // Write the data. 505 file.write(Data.data(), Data.size()); 506 } 507 508 // If we're supposed to retain the original modification times, etc. do so 509 // now. 510 if (OriginalDates) { 511 auto ModTimeOrErr = C.getLastModified(); 512 failIfError(ModTimeOrErr.takeError()); 513 failIfError( 514 sys::fs::setLastAccessAndModificationTime(FD, ModTimeOrErr.get())); 515 } 516 517 if (close(FD)) 518 fail("Could not close the file"); 519 } 520 521 static bool shouldCreateArchive(ArchiveOperation Op) { 522 switch (Op) { 523 case Print: 524 case Delete: 525 case Move: 526 case DisplayTable: 527 case Extract: 528 case CreateSymTab: 529 return false; 530 531 case QuickAppend: 532 case ReplaceOrInsert: 533 return true; 534 } 535 536 llvm_unreachable("Missing entry in covered switch."); 537 } 538 539 static void performReadOperation(ArchiveOperation Operation, 540 object::Archive *OldArchive) { 541 if (Operation == Extract && OldArchive->isThin()) 542 fail("extracting from a thin archive is not supported"); 543 544 bool Filter = !Members.empty(); 545 StringMap<int> MemberCount; 546 { 547 Error Err = Error::success(); 548 for (auto &C : OldArchive->children(Err)) { 549 Expected<StringRef> NameOrErr = C.getName(); 550 failIfError(NameOrErr.takeError()); 551 StringRef Name = NameOrErr.get(); 552 553 if (Filter) { 554 auto I = find_if(Members, [Name](StringRef Path) { 555 return Name == normalizePath(Path); 556 }); 557 if (I == Members.end()) 558 continue; 559 if (CountParam && ++MemberCount[Name] != CountParam) 560 continue; 561 Members.erase(I); 562 } 563 564 switch (Operation) { 565 default: 566 llvm_unreachable("Not a read operation"); 567 case Print: 568 doPrint(Name, C); 569 break; 570 case DisplayTable: 571 doDisplayTable(Name, C); 572 break; 573 case Extract: 574 doExtract(Name, C); 575 break; 576 } 577 } 578 failIfError(std::move(Err)); 579 } 580 581 if (Members.empty()) 582 return; 583 for (StringRef Name : Members) 584 WithColor::error(errs(), ToolName) << "'" << Name << "' was not found\n"; 585 exit(1); 586 } 587 588 static void addChildMember(std::vector<NewArchiveMember> &Members, 589 const object::Archive::Child &M, 590 bool FlattenArchive = false) { 591 if (Thin && !M.getParent()->isThin()) 592 fail("Cannot convert a regular archive to a thin one"); 593 Expected<NewArchiveMember> NMOrErr = 594 NewArchiveMember::getOldMember(M, Deterministic); 595 failIfError(NMOrErr.takeError()); 596 // If the child member we're trying to add is thin, use the path relative to 597 // the archive it's in, so the file resolves correctly. 598 if (Thin && FlattenArchive) { 599 StringSaver Saver(Alloc); 600 Expected<std::string> FileNameOrErr = M.getName(); 601 failIfError(FileNameOrErr.takeError()); 602 if (sys::path::is_absolute(*FileNameOrErr)) { 603 NMOrErr->MemberName = Saver.save(sys::path::convert_to_slash(*FileNameOrErr)); 604 } else { 605 FileNameOrErr = M.getFullName(); 606 failIfError(FileNameOrErr.takeError()); 607 Expected<std::string> PathOrErr = 608 computeArchiveRelativePath(ArchiveName, *FileNameOrErr); 609 NMOrErr->MemberName = Saver.save( 610 PathOrErr ? *PathOrErr : sys::path::convert_to_slash(*FileNameOrErr)); 611 } 612 } 613 if (FlattenArchive && 614 identify_magic(NMOrErr->Buf->getBuffer()) == file_magic::archive) { 615 Expected<std::string> FileNameOrErr = M.getFullName(); 616 failIfError(FileNameOrErr.takeError()); 617 object::Archive &Lib = readLibrary(*FileNameOrErr); 618 // When creating thin archives, only flatten if the member is also thin. 619 if (!Thin || Lib.isThin()) { 620 Error Err = Error::success(); 621 // Only Thin archives are recursively flattened. 622 for (auto &Child : Lib.children(Err)) 623 addChildMember(Members, Child, /*FlattenArchive=*/Thin); 624 failIfError(std::move(Err)); 625 return; 626 } 627 } 628 Members.push_back(std::move(*NMOrErr)); 629 } 630 631 static void addMember(std::vector<NewArchiveMember> &Members, 632 StringRef FileName, bool FlattenArchive = false) { 633 Expected<NewArchiveMember> NMOrErr = 634 NewArchiveMember::getFile(FileName, Deterministic); 635 failIfError(NMOrErr.takeError(), FileName); 636 StringSaver Saver(Alloc); 637 // For regular archives, use the basename of the object path for the member 638 // name. For thin archives, use the full relative paths so the file resolves 639 // correctly. 640 if (!Thin) { 641 NMOrErr->MemberName = sys::path::filename(NMOrErr->MemberName); 642 } else { 643 if (sys::path::is_absolute(FileName)) 644 NMOrErr->MemberName = Saver.save(sys::path::convert_to_slash(FileName)); 645 else { 646 Expected<std::string> PathOrErr = 647 computeArchiveRelativePath(ArchiveName, FileName); 648 NMOrErr->MemberName = Saver.save( 649 PathOrErr ? *PathOrErr : sys::path::convert_to_slash(FileName)); 650 } 651 } 652 653 if (FlattenArchive && 654 identify_magic(NMOrErr->Buf->getBuffer()) == file_magic::archive) { 655 object::Archive &Lib = readLibrary(FileName); 656 // When creating thin archives, only flatten if the member is also thin. 657 if (!Thin || Lib.isThin()) { 658 Error Err = Error::success(); 659 // Only Thin archives are recursively flattened. 660 for (auto &Child : Lib.children(Err)) 661 addChildMember(Members, Child, /*FlattenArchive=*/Thin); 662 failIfError(std::move(Err)); 663 return; 664 } 665 } 666 Members.push_back(std::move(*NMOrErr)); 667 } 668 669 enum InsertAction { 670 IA_AddOldMember, 671 IA_AddNewMember, 672 IA_Delete, 673 IA_MoveOldMember, 674 IA_MoveNewMember 675 }; 676 677 static InsertAction computeInsertAction(ArchiveOperation Operation, 678 const object::Archive::Child &Member, 679 StringRef Name, 680 std::vector<StringRef>::iterator &Pos, 681 StringMap<int> &MemberCount) { 682 if (Operation == QuickAppend || Members.empty()) 683 return IA_AddOldMember; 684 auto MI = find_if( 685 Members, [Name](StringRef Path) { return Name == normalizePath(Path); }); 686 687 if (MI == Members.end()) 688 return IA_AddOldMember; 689 690 Pos = MI; 691 692 if (Operation == Delete) { 693 if (CountParam && ++MemberCount[Name] != CountParam) 694 return IA_AddOldMember; 695 return IA_Delete; 696 } 697 698 if (Operation == Move) 699 return IA_MoveOldMember; 700 701 if (Operation == ReplaceOrInsert) { 702 if (!OnlyUpdate) { 703 if (RelPos.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 (RelPos.empty()) 716 return IA_AddOldMember; 717 return IA_MoveOldMember; 718 } 719 720 if (RelPos.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 if (OldArchive) { 736 std::string PosName = normalizePath(RelPos); 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 std::string 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