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/StringExtras.h" 15 #include "llvm/ADT/StringSwitch.h" 16 #include "llvm/ADT/Triple.h" 17 #include "llvm/BinaryFormat/Magic.h" 18 #include "llvm/IR/LLVMContext.h" 19 #include "llvm/Object/Archive.h" 20 #include "llvm/Object/ArchiveWriter.h" 21 #include "llvm/Object/COFFImportFile.h" 22 #include "llvm/Object/ELFObjectFile.h" 23 #include "llvm/Object/IRObjectFile.h" 24 #include "llvm/Object/MachO.h" 25 #include "llvm/Object/ObjectFile.h" 26 #include "llvm/Object/SymbolicFile.h" 27 #include "llvm/Object/TapiFile.h" 28 #include "llvm/Object/Wasm.h" 29 #include "llvm/Object/XCOFFObjectFile.h" 30 #include "llvm/Support/Chrono.h" 31 #include "llvm/Support/CommandLine.h" 32 #include "llvm/Support/ConvertUTF.h" 33 #include "llvm/Support/Errc.h" 34 #include "llvm/Support/FileSystem.h" 35 #include "llvm/Support/Format.h" 36 #include "llvm/Support/FormatVariadic.h" 37 #include "llvm/Support/Host.h" 38 #include "llvm/Support/InitLLVM.h" 39 #include "llvm/Support/LineIterator.h" 40 #include "llvm/Support/MemoryBuffer.h" 41 #include "llvm/Support/Path.h" 42 #include "llvm/Support/Process.h" 43 #include "llvm/Support/StringSaver.h" 44 #include "llvm/Support/TargetSelect.h" 45 #include "llvm/Support/ToolOutputFile.h" 46 #include "llvm/Support/WithColor.h" 47 #include "llvm/Support/raw_ostream.h" 48 #include "llvm/ToolDrivers/llvm-dlltool/DlltoolDriver.h" 49 #include "llvm/ToolDrivers/llvm-lib/LibDriver.h" 50 51 #if !defined(_MSC_VER) && !defined(__MINGW32__) 52 #include <unistd.h> 53 #else 54 #include <io.h> 55 #endif 56 57 #ifdef _WIN32 58 #include "llvm/Support/Windows/WindowsSupport.h" 59 #endif 60 61 using namespace llvm; 62 using namespace llvm::object; 63 64 // The name this program was invoked as. 65 static StringRef ToolName; 66 67 // The basename of this program. 68 static StringRef Stem; 69 70 static void printRanLibHelp(StringRef ToolName) { 71 outs() << "OVERVIEW: LLVM Ranlib\n\n" 72 << "This program generates an index to speed access to archives\n\n" 73 << "USAGE: " + ToolName + " <archive-file>\n\n" 74 << "OPTIONS:\n" 75 << " -h --help - Display available options\n" 76 << " -v --version - Display the version of this program\n" 77 << " -D - Use zero for timestamps and uids/gids " 78 "(default)\n" 79 << " -U - Use actual timestamps and uids/gids\n"; 80 } 81 82 static void printArHelp(StringRef ToolName) { 83 const char ArOptions[] = 84 R"(OPTIONS: 85 --format - archive format to create 86 =default - default 87 =gnu - gnu 88 =darwin - darwin 89 =bsd - bsd 90 =bigarchive - big archive (AIX OS) 91 --plugin=<string> - ignored for compatibility 92 -h --help - display this help and exit 93 --output - the directory to extract archive members to 94 --rsp-quoting - quoting style for response files 95 =posix - posix 96 =windows - windows 97 --thin - create a thin archive 98 --version - print the version and exit 99 -X{32|64|32_64|any} - object mode (only for AIX OS) 100 @<file> - read options from <file> 101 102 OPERATIONS: 103 d - delete [files] from the archive 104 m - move [files] in the archive 105 p - print contents of [files] found in the archive 106 q - quick append [files] to the archive 107 r - replace or insert [files] into the archive 108 s - act as ranlib 109 t - display list of files in archive 110 x - extract [files] from the archive 111 112 MODIFIERS: 113 [a] - put [files] after [relpos] 114 [b] - put [files] before [relpos] (same as [i]) 115 [c] - do not warn if archive had to be created 116 [D] - use zero for timestamps and uids/gids (default) 117 [h] - display this help and exit 118 [i] - put [files] before [relpos] (same as [b]) 119 [l] - ignored for compatibility 120 [L] - add archive's contents 121 [N] - use instance [count] of name 122 [o] - preserve original dates 123 [O] - display member offsets 124 [P] - use full names when matching (implied for thin archives) 125 [s] - create an archive index (cf. ranlib) 126 [S] - do not build a symbol table 127 [T] - deprecated, use --thin instead 128 [u] - update only [files] newer than archive contents 129 [U] - use actual timestamps and uids/gids 130 [v] - be verbose about actions taken 131 [V] - display the version and exit 132 )"; 133 134 outs() << "OVERVIEW: LLVM Archiver\n\n" 135 << "USAGE: " + ToolName + 136 " [options] [-]<operation>[modifiers] [relpos] " 137 "[count] <archive> [files]\n" 138 << " " + ToolName + " -M [<mri-script]\n\n"; 139 140 outs() << ArOptions; 141 } 142 143 static void printHelpMessage() { 144 if (Stem.contains_insensitive("ranlib")) 145 printRanLibHelp(Stem); 146 else if (Stem.contains_insensitive("ar")) 147 printArHelp(Stem); 148 } 149 150 static unsigned MRILineNumber; 151 static bool ParsingMRIScript; 152 153 // Show the error plus the usage message, and exit. 154 [[noreturn]] static void badUsage(Twine Error) { 155 WithColor::error(errs(), ToolName) << Error << "\n"; 156 printHelpMessage(); 157 exit(1); 158 } 159 160 // Show the error message and exit. 161 [[noreturn]] static void fail(Twine Error) { 162 if (ParsingMRIScript) { 163 WithColor::error(errs(), ToolName) 164 << "script line " << MRILineNumber << ": " << Error << "\n"; 165 } else { 166 WithColor::error(errs(), ToolName) << Error << "\n"; 167 } 168 exit(1); 169 } 170 171 static void failIfError(std::error_code EC, Twine Context = "") { 172 if (!EC) 173 return; 174 175 std::string ContextStr = Context.str(); 176 if (ContextStr.empty()) 177 fail(EC.message()); 178 fail(Context + ": " + EC.message()); 179 } 180 181 static void failIfError(Error E, Twine Context = "") { 182 if (!E) 183 return; 184 185 handleAllErrors(std::move(E), [&](const llvm::ErrorInfoBase &EIB) { 186 std::string ContextStr = Context.str(); 187 if (ContextStr.empty()) 188 fail(EIB.message()); 189 fail(Context + ": " + EIB.message()); 190 }); 191 } 192 193 static void warn(Twine Message) { 194 WithColor::warning(errs(), ToolName) << Message << "\n"; 195 } 196 197 static SmallVector<const char *, 256> PositionalArgs; 198 199 static bool MRI; 200 201 namespace { 202 enum Format { Default, GNU, BSD, DARWIN, BIGARCHIVE, Unknown }; 203 } 204 205 static Format FormatType = Default; 206 207 static std::string Options; 208 209 // This enumeration delineates the kinds of operations on an archive 210 // that are permitted. 211 enum ArchiveOperation { 212 Print, ///< Print the contents of the archive 213 Delete, ///< Delete the specified members 214 Move, ///< Move members to end or as given by {a,b,i} modifiers 215 QuickAppend, ///< Quickly append to end of archive 216 ReplaceOrInsert, ///< Replace or Insert members 217 DisplayTable, ///< Display the table of contents 218 Extract, ///< Extract files back to file system 219 CreateSymTab ///< Create a symbol table in an existing archive 220 }; 221 222 enum class BitModeTy { Bit32, Bit64, Bit32_64, Any, Unknown }; 223 224 static BitModeTy BitMode = BitModeTy::Bit32; 225 226 // Modifiers to follow operation to vary behavior 227 static bool AddAfter = false; ///< 'a' modifier 228 static bool AddBefore = false; ///< 'b' modifier 229 static bool Create = false; ///< 'c' modifier 230 static bool OriginalDates = false; ///< 'o' modifier 231 static bool DisplayMemberOffsets = false; ///< 'O' modifier 232 static bool CompareFullPath = false; ///< 'P' modifier 233 static bool OnlyUpdate = false; ///< 'u' modifier 234 static bool Verbose = false; ///< 'v' modifier 235 static bool Symtab = true; ///< 's' modifier 236 static bool Deterministic = true; ///< 'D' and 'U' modifiers 237 static bool Thin = false; ///< 'T' modifier 238 static bool AddLibrary = false; ///< 'L' modifier 239 240 // Relative Positional Argument (for insert/move). This variable holds 241 // the name of the archive member to which the 'a', 'b' or 'i' modifier 242 // refers. Only one of 'a', 'b' or 'i' can be specified so we only need 243 // one variable. 244 static std::string RelPos; 245 246 // Count parameter for 'N' modifier. This variable specifies which file should 247 // match for extract/delete operations when there are multiple matches. This is 248 // 1-indexed. A value of 0 is invalid, and implies 'N' is not used. 249 static int CountParam = 0; 250 251 // This variable holds the name of the archive file as given on the 252 // command line. 253 static std::string ArchiveName; 254 255 // Output directory specified by --output. 256 static std::string OutputDir; 257 258 static std::vector<std::unique_ptr<MemoryBuffer>> ArchiveBuffers; 259 static std::vector<std::unique_ptr<object::Archive>> Archives; 260 261 // This variable holds the list of member files to proecess, as given 262 // on the command line. 263 static std::vector<StringRef> Members; 264 265 // Static buffer to hold StringRefs. 266 static BumpPtrAllocator Alloc; 267 268 // Extract the member filename from the command line for the [relpos] argument 269 // associated with a, b, and i modifiers 270 static void getRelPos() { 271 if (PositionalArgs.empty()) 272 fail("expected [relpos] for 'a', 'b', or 'i' modifier"); 273 RelPos = PositionalArgs[0]; 274 PositionalArgs.erase(PositionalArgs.begin()); 275 } 276 277 // Extract the parameter from the command line for the [count] argument 278 // associated with the N modifier 279 static void getCountParam() { 280 if (PositionalArgs.empty()) 281 badUsage("expected [count] for 'N' modifier"); 282 auto CountParamArg = StringRef(PositionalArgs[0]); 283 if (CountParamArg.getAsInteger(10, CountParam)) 284 badUsage("value for [count] must be numeric, got: " + CountParamArg); 285 if (CountParam < 1) 286 badUsage("value for [count] must be positive, got: " + CountParamArg); 287 PositionalArgs.erase(PositionalArgs.begin()); 288 } 289 290 // Get the archive file name from the command line 291 static void getArchive() { 292 if (PositionalArgs.empty()) 293 badUsage("an archive name must be specified"); 294 ArchiveName = PositionalArgs[0]; 295 PositionalArgs.erase(PositionalArgs.begin()); 296 } 297 298 static object::Archive &readLibrary(const Twine &Library) { 299 auto BufOrErr = MemoryBuffer::getFile(Library, /*IsText=*/false, 300 /*RequiresNullTerminator=*/false); 301 failIfError(BufOrErr.getError(), "could not open library " + Library); 302 ArchiveBuffers.push_back(std::move(*BufOrErr)); 303 auto LibOrErr = 304 object::Archive::create(ArchiveBuffers.back()->getMemBufferRef()); 305 failIfError(errorToErrorCode(LibOrErr.takeError()), 306 "could not parse library"); 307 Archives.push_back(std::move(*LibOrErr)); 308 return *Archives.back(); 309 } 310 311 static void runMRIScript(); 312 313 // Parse the command line options as presented and return the operation 314 // specified. Process all modifiers and check to make sure that constraints on 315 // modifier/operation pairs have not been violated. 316 static ArchiveOperation parseCommandLine() { 317 if (MRI) { 318 if (!PositionalArgs.empty() || !Options.empty()) 319 badUsage("cannot mix -M and other options"); 320 runMRIScript(); 321 } 322 323 // Keep track of number of operations. We can only specify one 324 // per execution. 325 unsigned NumOperations = 0; 326 327 // Keep track of the number of positional modifiers (a,b,i). Only 328 // one can be specified. 329 unsigned NumPositional = 0; 330 331 // Keep track of which operation was requested 332 ArchiveOperation Operation; 333 334 bool MaybeJustCreateSymTab = false; 335 336 for (unsigned i = 0; i < Options.size(); ++i) { 337 switch (Options[i]) { 338 case 'd': 339 ++NumOperations; 340 Operation = Delete; 341 break; 342 case 'm': 343 ++NumOperations; 344 Operation = Move; 345 break; 346 case 'p': 347 ++NumOperations; 348 Operation = Print; 349 break; 350 case 'q': 351 ++NumOperations; 352 Operation = QuickAppend; 353 break; 354 case 'r': 355 ++NumOperations; 356 Operation = ReplaceOrInsert; 357 break; 358 case 't': 359 ++NumOperations; 360 Operation = DisplayTable; 361 break; 362 case 'x': 363 ++NumOperations; 364 Operation = Extract; 365 break; 366 case 'c': 367 Create = true; 368 break; 369 case 'l': /* accepted but unused */ 370 break; 371 case 'o': 372 OriginalDates = true; 373 break; 374 case 'O': 375 DisplayMemberOffsets = true; 376 break; 377 case 'P': 378 CompareFullPath = true; 379 break; 380 case 's': 381 Symtab = true; 382 MaybeJustCreateSymTab = true; 383 break; 384 case 'S': 385 Symtab = false; 386 break; 387 case 'u': 388 OnlyUpdate = true; 389 break; 390 case 'v': 391 Verbose = true; 392 break; 393 case 'a': 394 getRelPos(); 395 AddAfter = true; 396 NumPositional++; 397 break; 398 case 'b': 399 getRelPos(); 400 AddBefore = true; 401 NumPositional++; 402 break; 403 case 'i': 404 getRelPos(); 405 AddBefore = true; 406 NumPositional++; 407 break; 408 case 'D': 409 Deterministic = true; 410 break; 411 case 'U': 412 Deterministic = false; 413 break; 414 case 'N': 415 getCountParam(); 416 break; 417 case 'T': 418 Thin = true; 419 break; 420 case 'L': 421 AddLibrary = true; 422 break; 423 case 'V': 424 cl::PrintVersionMessage(); 425 exit(0); 426 case 'h': 427 printHelpMessage(); 428 exit(0); 429 default: 430 badUsage(std::string("unknown option ") + Options[i]); 431 } 432 } 433 434 // Thin archives store path names, so P should be forced. 435 if (Thin) 436 CompareFullPath = true; 437 438 // At this point, the next thing on the command line must be 439 // the archive name. 440 getArchive(); 441 442 // Everything on the command line at this point is a member. 443 Members.assign(PositionalArgs.begin(), PositionalArgs.end()); 444 445 if (NumOperations == 0 && MaybeJustCreateSymTab) { 446 NumOperations = 1; 447 Operation = CreateSymTab; 448 if (!Members.empty()) 449 badUsage("the 's' operation takes only an archive as argument"); 450 } 451 452 // Perform various checks on the operation/modifier specification 453 // to make sure we are dealing with a legal request. 454 if (NumOperations == 0) 455 badUsage("you must specify at least one of the operations"); 456 if (NumOperations > 1) 457 badUsage("only one operation may be specified"); 458 if (NumPositional > 1) 459 badUsage("you may only specify one of 'a', 'b', and 'i' modifiers"); 460 if (AddAfter || AddBefore) 461 if (Operation != Move && Operation != ReplaceOrInsert) 462 badUsage("the 'a', 'b' and 'i' modifiers can only be specified with " 463 "the 'm' or 'r' operations"); 464 if (CountParam) 465 if (Operation != Extract && Operation != Delete) 466 badUsage("the 'N' modifier can only be specified with the 'x' or 'd' " 467 "operations"); 468 if (OriginalDates && Operation != Extract) 469 badUsage("the 'o' modifier is only applicable to the 'x' operation"); 470 if (OnlyUpdate && Operation != ReplaceOrInsert) 471 badUsage("the 'u' modifier is only applicable to the 'r' operation"); 472 if (AddLibrary && Operation != QuickAppend) 473 badUsage("the 'L' modifier is only applicable to the 'q' operation"); 474 475 if (!OutputDir.empty()) { 476 if (Operation != Extract) 477 badUsage("--output is only applicable to the 'x' operation"); 478 bool IsDir = false; 479 // If OutputDir is not a directory, create_directories may still succeed if 480 // all components of the path prefix are directories. Test is_directory as 481 // well. 482 if (!sys::fs::create_directories(OutputDir)) 483 sys::fs::is_directory(OutputDir, IsDir); 484 if (!IsDir) 485 fail("'" + OutputDir + "' is not a directory"); 486 } 487 488 // Return the parsed operation to the caller 489 return Operation; 490 } 491 492 // Implements the 'p' operation. This function traverses the archive 493 // looking for members that match the path list. 494 static void doPrint(StringRef Name, const object::Archive::Child &C) { 495 if (Verbose) 496 outs() << "Printing " << Name << "\n"; 497 498 Expected<StringRef> DataOrErr = C.getBuffer(); 499 failIfError(DataOrErr.takeError()); 500 StringRef Data = *DataOrErr; 501 outs().write(Data.data(), Data.size()); 502 } 503 504 // Utility function for printing out the file mode when the 't' operation is in 505 // verbose mode. 506 static void printMode(unsigned mode) { 507 outs() << ((mode & 004) ? "r" : "-"); 508 outs() << ((mode & 002) ? "w" : "-"); 509 outs() << ((mode & 001) ? "x" : "-"); 510 } 511 512 // Implement the 't' operation. This function prints out just 513 // the file names of each of the members. However, if verbose mode is requested 514 // ('v' modifier) then the file type, permission mode, user, group, size, and 515 // modification time are also printed. 516 static void doDisplayTable(StringRef Name, const object::Archive::Child &C) { 517 if (Verbose) { 518 Expected<sys::fs::perms> ModeOrErr = C.getAccessMode(); 519 failIfError(ModeOrErr.takeError()); 520 sys::fs::perms Mode = ModeOrErr.get(); 521 printMode((Mode >> 6) & 007); 522 printMode((Mode >> 3) & 007); 523 printMode(Mode & 007); 524 Expected<unsigned> UIDOrErr = C.getUID(); 525 failIfError(UIDOrErr.takeError()); 526 outs() << ' ' << UIDOrErr.get(); 527 Expected<unsigned> GIDOrErr = C.getGID(); 528 failIfError(GIDOrErr.takeError()); 529 outs() << '/' << GIDOrErr.get(); 530 Expected<uint64_t> Size = C.getSize(); 531 failIfError(Size.takeError()); 532 outs() << ' ' << format("%6llu", Size.get()); 533 auto ModTimeOrErr = C.getLastModified(); 534 failIfError(ModTimeOrErr.takeError()); 535 // Note: formatv() only handles the default TimePoint<>, which is in 536 // nanoseconds. 537 // TODO: fix format_provider<TimePoint<>> to allow other units. 538 sys::TimePoint<> ModTimeInNs = ModTimeOrErr.get(); 539 outs() << ' ' << formatv("{0:%b %e %H:%M %Y}", ModTimeInNs); 540 outs() << ' '; 541 } 542 543 if (C.getParent()->isThin()) { 544 if (!sys::path::is_absolute(Name)) { 545 StringRef ParentDir = sys::path::parent_path(ArchiveName); 546 if (!ParentDir.empty()) 547 outs() << sys::path::convert_to_slash(ParentDir) << '/'; 548 } 549 outs() << Name; 550 } else { 551 outs() << Name; 552 if (DisplayMemberOffsets) 553 outs() << " 0x" << utohexstr(C.getDataOffset(), true); 554 } 555 outs() << '\n'; 556 } 557 558 static std::string normalizePath(StringRef Path) { 559 return CompareFullPath ? sys::path::convert_to_slash(Path) 560 : std::string(sys::path::filename(Path)); 561 } 562 563 static bool comparePaths(StringRef Path1, StringRef Path2) { 564 // When on Windows this function calls CompareStringOrdinal 565 // as Windows file paths are case-insensitive. 566 // CompareStringOrdinal compares two Unicode strings for 567 // binary equivalence and allows for case insensitivity. 568 #ifdef _WIN32 569 SmallVector<wchar_t, 128> WPath1, WPath2; 570 failIfError(sys::windows::UTF8ToUTF16(normalizePath(Path1), WPath1)); 571 failIfError(sys::windows::UTF8ToUTF16(normalizePath(Path2), WPath2)); 572 573 return CompareStringOrdinal(WPath1.data(), WPath1.size(), WPath2.data(), 574 WPath2.size(), true) == CSTR_EQUAL; 575 #else 576 return normalizePath(Path1) == normalizePath(Path2); 577 #endif 578 } 579 580 // Implement the 'x' operation. This function extracts files back to the file 581 // system. 582 static void doExtract(StringRef Name, const object::Archive::Child &C) { 583 // Retain the original mode. 584 Expected<sys::fs::perms> ModeOrErr = C.getAccessMode(); 585 failIfError(ModeOrErr.takeError()); 586 sys::fs::perms Mode = ModeOrErr.get(); 587 588 StringRef outputFilePath; 589 SmallString<128> path; 590 if (OutputDir.empty()) { 591 outputFilePath = sys::path::filename(Name); 592 } else { 593 sys::path::append(path, OutputDir, sys::path::filename(Name)); 594 outputFilePath = path.str(); 595 } 596 597 if (Verbose) 598 outs() << "x - " << outputFilePath << '\n'; 599 600 int FD; 601 failIfError(sys::fs::openFileForWrite(outputFilePath, FD, 602 sys::fs::CD_CreateAlways, 603 sys::fs::OF_None, Mode), 604 Name); 605 606 { 607 raw_fd_ostream file(FD, false); 608 609 // Get the data and its length 610 Expected<StringRef> BufOrErr = C.getBuffer(); 611 failIfError(BufOrErr.takeError()); 612 StringRef Data = BufOrErr.get(); 613 614 // Write the data. 615 file.write(Data.data(), Data.size()); 616 } 617 618 // If we're supposed to retain the original modification times, etc. do so 619 // now. 620 if (OriginalDates) { 621 auto ModTimeOrErr = C.getLastModified(); 622 failIfError(ModTimeOrErr.takeError()); 623 failIfError( 624 sys::fs::setLastAccessAndModificationTime(FD, ModTimeOrErr.get())); 625 } 626 627 if (close(FD)) 628 fail("Could not close the file"); 629 } 630 631 static bool shouldCreateArchive(ArchiveOperation Op) { 632 switch (Op) { 633 case Print: 634 case Delete: 635 case Move: 636 case DisplayTable: 637 case Extract: 638 case CreateSymTab: 639 return false; 640 641 case QuickAppend: 642 case ReplaceOrInsert: 643 return true; 644 } 645 646 llvm_unreachable("Missing entry in covered switch."); 647 } 648 649 static bool is64BitSymbolicFile(SymbolicFile &Obj) { 650 if (auto *IRObj = dyn_cast<IRObjectFile>(&Obj)) 651 return Triple(IRObj->getTargetTriple()).isArch64Bit(); 652 if (isa<COFFObjectFile>(Obj) || isa<COFFImportFile>(Obj)) 653 return false; 654 if (XCOFFObjectFile *XCOFFObj = dyn_cast<XCOFFObjectFile>(&Obj)) 655 return XCOFFObj->is64Bit(); 656 if (isa<WasmObjectFile>(Obj)) 657 return false; 658 if (TapiFile *Tapi = dyn_cast<TapiFile>(&Obj)) 659 return Tapi->is64Bit(); 660 if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj)) 661 return MachO->is64Bit(); 662 if (ELFObjectFileBase *ElfO = dyn_cast<ELFObjectFileBase>(&Obj)) 663 return ElfO->getBytesInAddress() == 8; 664 665 fail("unsupported file format"); 666 } 667 668 static bool isValidInBitMode(Binary &Bin) { 669 if (BitMode == BitModeTy::Bit32_64 || BitMode == BitModeTy::Any) 670 return true; 671 672 if (SymbolicFile *SymFile = dyn_cast<SymbolicFile>(&Bin)) { 673 bool Is64Bit = is64BitSymbolicFile(*SymFile); 674 if ((Is64Bit && (BitMode == BitModeTy::Bit32)) || 675 (!Is64Bit && (BitMode == BitModeTy::Bit64))) 676 return false; 677 } 678 // In AIX "ar", non-object files are always considered to have a valid bit 679 // mode. 680 return true; 681 } 682 683 Expected<std::unique_ptr<Binary>> getAsBinary(const NewArchiveMember &NM, 684 LLVMContext *Context) { 685 auto BinaryOrErr = createBinary(NM.Buf->getMemBufferRef(), Context); 686 if (BinaryOrErr) 687 return std::move(*BinaryOrErr); 688 return BinaryOrErr.takeError(); 689 } 690 691 Expected<std::unique_ptr<Binary>> getAsBinary(const Archive::Child &C, 692 LLVMContext *Context) { 693 return C.getAsBinary(Context); 694 } 695 696 template <class A> static bool isValidInBitMode(const A &Member) { 697 if (object::Archive::getDefaultKindForHost() != object::Archive::K_AIXBIG) 698 return true; 699 LLVMContext Context; 700 Expected<std::unique_ptr<Binary>> BinOrErr = getAsBinary(Member, &Context); 701 // In AIX "ar", if there is a non-object file member, it is never ignored due 702 // to the bit mode setting. 703 if (!BinOrErr) { 704 consumeError(BinOrErr.takeError()); 705 return true; 706 } 707 return isValidInBitMode(*BinOrErr.get()); 708 } 709 710 static void warnInvalidObjectForFileMode(Twine Name) { 711 warn("'" + Name + "' is not valid with the current object file mode"); 712 } 713 714 static void performReadOperation(ArchiveOperation Operation, 715 object::Archive *OldArchive) { 716 if (Operation == Extract && OldArchive->isThin()) 717 fail("extracting from a thin archive is not supported"); 718 719 bool Filter = !Members.empty(); 720 StringMap<int> MemberCount; 721 { 722 Error Err = Error::success(); 723 for (auto &C : OldArchive->children(Err)) { 724 Expected<StringRef> NameOrErr = C.getName(); 725 failIfError(NameOrErr.takeError()); 726 StringRef Name = NameOrErr.get(); 727 728 // Check whether to ignore this object due to its bitness. 729 if (!isValidInBitMode(C)) 730 continue; 731 732 if (Filter) { 733 auto I = find_if(Members, [Name](StringRef Path) { 734 return comparePaths(Name, Path); 735 }); 736 if (I == Members.end()) 737 continue; 738 if (CountParam && ++MemberCount[Name] != CountParam) 739 continue; 740 Members.erase(I); 741 } 742 743 switch (Operation) { 744 default: 745 llvm_unreachable("Not a read operation"); 746 case Print: 747 doPrint(Name, C); 748 break; 749 case DisplayTable: 750 doDisplayTable(Name, C); 751 break; 752 case Extract: 753 doExtract(Name, C); 754 break; 755 } 756 } 757 failIfError(std::move(Err)); 758 } 759 760 if (Members.empty()) 761 return; 762 for (StringRef Name : Members) 763 WithColor::error(errs(), ToolName) << "'" << Name << "' was not found\n"; 764 exit(1); 765 } 766 767 static void addChildMember(std::vector<NewArchiveMember> &Members, 768 const object::Archive::Child &M, 769 bool FlattenArchive = false) { 770 Expected<NewArchiveMember> NMOrErr = 771 NewArchiveMember::getOldMember(M, Deterministic); 772 failIfError(NMOrErr.takeError()); 773 // If the child member we're trying to add is thin, use the path relative to 774 // the archive it's in, so the file resolves correctly. 775 if (Thin && FlattenArchive) { 776 StringSaver Saver(Alloc); 777 Expected<std::string> FileNameOrErr(M.getName()); 778 failIfError(FileNameOrErr.takeError()); 779 if (sys::path::is_absolute(*FileNameOrErr)) { 780 NMOrErr->MemberName = Saver.save(sys::path::convert_to_slash(*FileNameOrErr)); 781 } else { 782 FileNameOrErr = M.getFullName(); 783 failIfError(FileNameOrErr.takeError()); 784 Expected<std::string> PathOrErr = 785 computeArchiveRelativePath(ArchiveName, *FileNameOrErr); 786 NMOrErr->MemberName = Saver.save( 787 PathOrErr ? *PathOrErr : sys::path::convert_to_slash(*FileNameOrErr)); 788 } 789 } 790 if (FlattenArchive && 791 identify_magic(NMOrErr->Buf->getBuffer()) == file_magic::archive) { 792 Expected<std::string> FileNameOrErr = M.getFullName(); 793 failIfError(FileNameOrErr.takeError()); 794 object::Archive &Lib = readLibrary(*FileNameOrErr); 795 // When creating thin archives, only flatten if the member is also thin. 796 if (!Thin || Lib.isThin()) { 797 Error Err = Error::success(); 798 // Only Thin archives are recursively flattened. 799 for (auto &Child : Lib.children(Err)) 800 addChildMember(Members, Child, /*FlattenArchive=*/Thin); 801 failIfError(std::move(Err)); 802 return; 803 } 804 } 805 Members.push_back(std::move(*NMOrErr)); 806 } 807 808 static NewArchiveMember getArchiveMember(StringRef FileName) { 809 Expected<NewArchiveMember> NMOrErr = 810 NewArchiveMember::getFile(FileName, Deterministic); 811 failIfError(NMOrErr.takeError(), FileName); 812 StringSaver Saver(Alloc); 813 // For regular archives, use the basename of the object path for the member 814 // name. For thin archives, use the full relative paths so the file resolves 815 // correctly. 816 if (!Thin) { 817 NMOrErr->MemberName = sys::path::filename(NMOrErr->MemberName); 818 } else { 819 if (sys::path::is_absolute(FileName)) 820 NMOrErr->MemberName = Saver.save(sys::path::convert_to_slash(FileName)); 821 else { 822 Expected<std::string> PathOrErr = 823 computeArchiveRelativePath(ArchiveName, FileName); 824 NMOrErr->MemberName = Saver.save( 825 PathOrErr ? *PathOrErr : sys::path::convert_to_slash(FileName)); 826 } 827 } 828 return std::move(*NMOrErr); 829 } 830 831 static void addMember(std::vector<NewArchiveMember> &Members, 832 NewArchiveMember &NM) { 833 Members.push_back(std::move(NM)); 834 } 835 836 static void addMember(std::vector<NewArchiveMember> &Members, 837 StringRef FileName, bool FlattenArchive = false) { 838 NewArchiveMember NM = getArchiveMember(FileName); 839 if (!isValidInBitMode(NM)) { 840 warnInvalidObjectForFileMode(FileName); 841 return; 842 } 843 844 if (FlattenArchive && 845 identify_magic(NM.Buf->getBuffer()) == file_magic::archive) { 846 object::Archive &Lib = readLibrary(FileName); 847 // When creating thin archives, only flatten if the member is also thin. 848 if (!Thin || Lib.isThin()) { 849 Error Err = Error::success(); 850 // Only Thin archives are recursively flattened. 851 for (auto &Child : Lib.children(Err)) 852 addChildMember(Members, Child, /*FlattenArchive=*/Thin); 853 failIfError(std::move(Err)); 854 return; 855 } 856 } 857 Members.push_back(std::move(NM)); 858 } 859 860 enum InsertAction { 861 IA_AddOldMember, 862 IA_AddNewMember, 863 IA_Delete, 864 IA_MoveOldMember, 865 IA_MoveNewMember 866 }; 867 868 static InsertAction computeInsertAction(ArchiveOperation Operation, 869 const object::Archive::Child &Member, 870 StringRef Name, 871 std::vector<StringRef>::iterator &Pos, 872 StringMap<int> &MemberCount) { 873 if (!isValidInBitMode(Member)) 874 return IA_AddOldMember; 875 876 if (Operation == QuickAppend || Members.empty()) 877 return IA_AddOldMember; 878 auto MI = find_if( 879 Members, [Name](StringRef Path) { return comparePaths(Name, Path); }); 880 881 if (MI == Members.end()) 882 return IA_AddOldMember; 883 884 Pos = MI; 885 886 if (Operation == Delete) { 887 if (CountParam && ++MemberCount[Name] != CountParam) 888 return IA_AddOldMember; 889 return IA_Delete; 890 } 891 892 if (Operation == Move) 893 return IA_MoveOldMember; 894 895 if (Operation == ReplaceOrInsert) { 896 if (!OnlyUpdate) { 897 if (RelPos.empty()) 898 return IA_AddNewMember; 899 return IA_MoveNewMember; 900 } 901 902 // We could try to optimize this to a fstat, but it is not a common 903 // operation. 904 sys::fs::file_status Status; 905 failIfError(sys::fs::status(*MI, Status), *MI); 906 auto ModTimeOrErr = Member.getLastModified(); 907 failIfError(ModTimeOrErr.takeError()); 908 if (Status.getLastModificationTime() < ModTimeOrErr.get()) { 909 if (RelPos.empty()) 910 return IA_AddOldMember; 911 return IA_MoveOldMember; 912 } 913 914 if (RelPos.empty()) 915 return IA_AddNewMember; 916 return IA_MoveNewMember; 917 } 918 llvm_unreachable("No such operation"); 919 } 920 921 // We have to walk this twice and computing it is not trivial, so creating an 922 // explicit std::vector is actually fairly efficient. 923 static std::vector<NewArchiveMember> 924 computeNewArchiveMembers(ArchiveOperation Operation, 925 object::Archive *OldArchive) { 926 std::vector<NewArchiveMember> Ret; 927 std::vector<NewArchiveMember> Moved; 928 int InsertPos = -1; 929 if (OldArchive) { 930 Error Err = Error::success(); 931 StringMap<int> MemberCount; 932 for (auto &Child : OldArchive->children(Err)) { 933 int Pos = Ret.size(); 934 Expected<StringRef> NameOrErr = Child.getName(); 935 failIfError(NameOrErr.takeError()); 936 std::string Name = std::string(NameOrErr.get()); 937 if (comparePaths(Name, RelPos) && isValidInBitMode(Child)) { 938 assert(AddAfter || AddBefore); 939 if (AddBefore) 940 InsertPos = Pos; 941 else 942 InsertPos = Pos + 1; 943 } 944 945 std::vector<StringRef>::iterator MemberI = Members.end(); 946 InsertAction Action = 947 computeInsertAction(Operation, Child, Name, MemberI, MemberCount); 948 949 auto HandleNewMember = [](auto Member, auto &Members, auto &Child) { 950 NewArchiveMember NM = getArchiveMember(*Member); 951 if (isValidInBitMode(NM)) 952 addMember(Members, NM); 953 else { 954 // If a new member is not a valid object for the bit mode, add 955 // the old member back. 956 warnInvalidObjectForFileMode(*Member); 957 addChildMember(Members, Child, /*FlattenArchive=*/Thin); 958 } 959 }; 960 961 switch (Action) { 962 case IA_AddOldMember: 963 addChildMember(Ret, Child, /*FlattenArchive=*/Thin); 964 break; 965 case IA_AddNewMember: 966 HandleNewMember(MemberI, Ret, Child); 967 break; 968 case IA_Delete: 969 break; 970 case IA_MoveOldMember: 971 addChildMember(Moved, Child, /*FlattenArchive=*/Thin); 972 break; 973 case IA_MoveNewMember: 974 HandleNewMember(MemberI, Moved, Child); 975 break; 976 } 977 // When processing elements with the count param, we need to preserve the 978 // full members list when iterating over all archive members. For 979 // instance, "llvm-ar dN 2 archive.a member.o" should delete the second 980 // file named member.o it sees; we are not done with member.o the first 981 // time we see it in the archive. 982 if (MemberI != Members.end() && !CountParam) 983 Members.erase(MemberI); 984 } 985 failIfError(std::move(Err)); 986 } 987 988 if (Operation == Delete) 989 return Ret; 990 991 if (!RelPos.empty() && InsertPos == -1) 992 fail("insertion point not found"); 993 994 if (RelPos.empty()) 995 InsertPos = Ret.size(); 996 997 assert(unsigned(InsertPos) <= Ret.size()); 998 int Pos = InsertPos; 999 for (auto &M : Moved) { 1000 Ret.insert(Ret.begin() + Pos, std::move(M)); 1001 ++Pos; 1002 } 1003 1004 if (AddLibrary) { 1005 assert(Operation == QuickAppend); 1006 for (auto &Member : Members) 1007 addMember(Ret, Member, /*FlattenArchive=*/true); 1008 return Ret; 1009 } 1010 1011 std::vector<NewArchiveMember> NewMembers; 1012 for (auto &Member : Members) 1013 addMember(NewMembers, Member, /*FlattenArchive=*/Thin); 1014 Ret.reserve(Ret.size() + NewMembers.size()); 1015 std::move(NewMembers.begin(), NewMembers.end(), 1016 std::inserter(Ret, std::next(Ret.begin(), InsertPos))); 1017 1018 return Ret; 1019 } 1020 1021 static void performWriteOperation(ArchiveOperation Operation, 1022 object::Archive *OldArchive, 1023 std::unique_ptr<MemoryBuffer> OldArchiveBuf, 1024 std::vector<NewArchiveMember> *NewMembersP) { 1025 if (OldArchive) { 1026 if (Thin && !OldArchive->isThin()) 1027 fail("cannot convert a regular archive to a thin one"); 1028 1029 if (OldArchive->isThin()) 1030 Thin = true; 1031 } 1032 1033 std::vector<NewArchiveMember> NewMembers; 1034 if (!NewMembersP) 1035 NewMembers = computeNewArchiveMembers(Operation, OldArchive); 1036 1037 object::Archive::Kind Kind; 1038 switch (FormatType) { 1039 case Default: 1040 if (Thin) 1041 Kind = object::Archive::K_GNU; 1042 else if (OldArchive) { 1043 Kind = OldArchive->kind(); 1044 if (Kind == object::Archive::K_BSD) { 1045 auto InferredKind = object::Archive::K_BSD; 1046 if (NewMembersP && !NewMembersP->empty()) 1047 InferredKind = NewMembersP->front().detectKindFromObject(); 1048 else if (!NewMembers.empty()) 1049 InferredKind = NewMembers.front().detectKindFromObject(); 1050 if (InferredKind == object::Archive::K_DARWIN) 1051 Kind = object::Archive::K_DARWIN; 1052 } 1053 } else if (NewMembersP) 1054 Kind = !NewMembersP->empty() ? NewMembersP->front().detectKindFromObject() 1055 : object::Archive::getDefaultKindForHost(); 1056 else 1057 Kind = !NewMembers.empty() ? NewMembers.front().detectKindFromObject() 1058 : object::Archive::getDefaultKindForHost(); 1059 break; 1060 case GNU: 1061 Kind = object::Archive::K_GNU; 1062 break; 1063 case BSD: 1064 if (Thin) 1065 fail("only the gnu format has a thin mode"); 1066 Kind = object::Archive::K_BSD; 1067 break; 1068 case DARWIN: 1069 if (Thin) 1070 fail("only the gnu format has a thin mode"); 1071 Kind = object::Archive::K_DARWIN; 1072 break; 1073 case BIGARCHIVE: 1074 if (Thin) 1075 fail("only the gnu format has a thin mode"); 1076 Kind = object::Archive::K_AIXBIG; 1077 break; 1078 case Unknown: 1079 llvm_unreachable(""); 1080 } 1081 1082 Error E = 1083 writeArchive(ArchiveName, NewMembersP ? *NewMembersP : NewMembers, Symtab, 1084 Kind, Deterministic, Thin, std::move(OldArchiveBuf)); 1085 failIfError(std::move(E), ArchiveName); 1086 } 1087 1088 static void createSymbolTable(object::Archive *OldArchive) { 1089 // When an archive is created or modified, if the s option is given, the 1090 // resulting archive will have a current symbol table. If the S option 1091 // is given, it will have no symbol table. 1092 // In summary, we only need to update the symbol table if we have none. 1093 // This is actually very common because of broken build systems that think 1094 // they have to run ranlib. 1095 if (OldArchive->hasSymbolTable()) 1096 return; 1097 1098 if (OldArchive->isThin()) 1099 Thin = true; 1100 performWriteOperation(CreateSymTab, OldArchive, nullptr, nullptr); 1101 } 1102 1103 static void performOperation(ArchiveOperation Operation, 1104 object::Archive *OldArchive, 1105 std::unique_ptr<MemoryBuffer> OldArchiveBuf, 1106 std::vector<NewArchiveMember> *NewMembers) { 1107 switch (Operation) { 1108 case Print: 1109 case DisplayTable: 1110 case Extract: 1111 performReadOperation(Operation, OldArchive); 1112 return; 1113 1114 case Delete: 1115 case Move: 1116 case QuickAppend: 1117 case ReplaceOrInsert: 1118 performWriteOperation(Operation, OldArchive, std::move(OldArchiveBuf), 1119 NewMembers); 1120 return; 1121 case CreateSymTab: 1122 createSymbolTable(OldArchive); 1123 return; 1124 } 1125 llvm_unreachable("Unknown operation."); 1126 } 1127 1128 static int performOperation(ArchiveOperation Operation, 1129 std::vector<NewArchiveMember> *NewMembers) { 1130 // Create or open the archive object. 1131 ErrorOr<std::unique_ptr<MemoryBuffer>> Buf = MemoryBuffer::getFile( 1132 ArchiveName, /*IsText=*/false, /*RequiresNullTerminator=*/false); 1133 std::error_code EC = Buf.getError(); 1134 if (EC && EC != errc::no_such_file_or_directory) 1135 fail("unable to open '" + ArchiveName + "': " + EC.message()); 1136 1137 if (!EC) { 1138 Expected<std::unique_ptr<object::Archive>> ArchiveOrError = 1139 object::Archive::create(Buf.get()->getMemBufferRef()); 1140 if (!ArchiveOrError) 1141 failIfError(ArchiveOrError.takeError(), 1142 "unable to load '" + ArchiveName + "'"); 1143 1144 std::unique_ptr<object::Archive> Archive = std::move(ArchiveOrError.get()); 1145 if (Archive->isThin()) 1146 CompareFullPath = true; 1147 performOperation(Operation, Archive.get(), std::move(Buf.get()), 1148 NewMembers); 1149 return 0; 1150 } 1151 1152 assert(EC == errc::no_such_file_or_directory); 1153 1154 if (!shouldCreateArchive(Operation)) { 1155 failIfError(EC, Twine("unable to load '") + ArchiveName + "'"); 1156 } else { 1157 if (!Create) { 1158 // Produce a warning if we should and we're creating the archive 1159 warn("creating " + ArchiveName); 1160 } 1161 } 1162 1163 performOperation(Operation, nullptr, nullptr, NewMembers); 1164 return 0; 1165 } 1166 1167 static void runMRIScript() { 1168 enum class MRICommand { AddLib, AddMod, Create, CreateThin, Delete, Save, End, Invalid }; 1169 1170 ErrorOr<std::unique_ptr<MemoryBuffer>> Buf = MemoryBuffer::getSTDIN(); 1171 failIfError(Buf.getError()); 1172 const MemoryBuffer &Ref = *Buf.get(); 1173 bool Saved = false; 1174 std::vector<NewArchiveMember> NewMembers; 1175 ParsingMRIScript = true; 1176 1177 for (line_iterator I(Ref, /*SkipBlanks*/ false), E; I != E; ++I) { 1178 ++MRILineNumber; 1179 StringRef Line = *I; 1180 Line = Line.split(';').first; 1181 Line = Line.split('*').first; 1182 Line = Line.trim(); 1183 if (Line.empty()) 1184 continue; 1185 StringRef CommandStr, Rest; 1186 std::tie(CommandStr, Rest) = Line.split(' '); 1187 Rest = Rest.trim(); 1188 if (!Rest.empty() && Rest.front() == '"' && Rest.back() == '"') 1189 Rest = Rest.drop_front().drop_back(); 1190 auto Command = StringSwitch<MRICommand>(CommandStr.lower()) 1191 .Case("addlib", MRICommand::AddLib) 1192 .Case("addmod", MRICommand::AddMod) 1193 .Case("create", MRICommand::Create) 1194 .Case("createthin", MRICommand::CreateThin) 1195 .Case("delete", MRICommand::Delete) 1196 .Case("save", MRICommand::Save) 1197 .Case("end", MRICommand::End) 1198 .Default(MRICommand::Invalid); 1199 1200 switch (Command) { 1201 case MRICommand::AddLib: { 1202 if (!Create) 1203 fail("no output archive has been opened"); 1204 object::Archive &Lib = readLibrary(Rest); 1205 { 1206 if (Thin && !Lib.isThin()) 1207 fail("cannot add a regular archive's contents to a thin archive"); 1208 Error Err = Error::success(); 1209 for (auto &Member : Lib.children(Err)) 1210 addChildMember(NewMembers, Member, /*FlattenArchive=*/Thin); 1211 failIfError(std::move(Err)); 1212 } 1213 break; 1214 } 1215 case MRICommand::AddMod: 1216 if (!Create) 1217 fail("no output archive has been opened"); 1218 addMember(NewMembers, Rest); 1219 break; 1220 case MRICommand::CreateThin: 1221 Thin = true; 1222 LLVM_FALLTHROUGH; 1223 case MRICommand::Create: 1224 Create = true; 1225 if (!ArchiveName.empty()) 1226 fail("editing multiple archives not supported"); 1227 if (Saved) 1228 fail("file already saved"); 1229 ArchiveName = std::string(Rest); 1230 if (ArchiveName.empty()) 1231 fail("missing archive name"); 1232 break; 1233 case MRICommand::Delete: { 1234 llvm::erase_if(NewMembers, [=](NewArchiveMember &M) { 1235 return comparePaths(M.MemberName, Rest); 1236 }); 1237 break; 1238 } 1239 case MRICommand::Save: 1240 Saved = true; 1241 break; 1242 case MRICommand::End: 1243 break; 1244 case MRICommand::Invalid: 1245 fail("unknown command: " + CommandStr); 1246 } 1247 } 1248 1249 ParsingMRIScript = false; 1250 1251 // Nothing to do if not saved. 1252 if (Saved) 1253 performOperation(ReplaceOrInsert, /*OldArchive=*/nullptr, 1254 /*OldArchiveBuf=*/nullptr, &NewMembers); 1255 exit(0); 1256 } 1257 1258 static bool handleGenericOption(StringRef arg) { 1259 if (arg == "--help" || arg == "-h") { 1260 printHelpMessage(); 1261 return true; 1262 } 1263 if (arg == "--version") { 1264 cl::PrintVersionMessage(); 1265 return true; 1266 } 1267 return false; 1268 } 1269 1270 static BitModeTy getBitMode(const char *RawBitMode) { 1271 return StringSwitch<BitModeTy>(RawBitMode) 1272 .Case("32", BitModeTy::Bit32) 1273 .Case("64", BitModeTy::Bit64) 1274 .Case("32_64", BitModeTy::Bit32_64) 1275 .Case("any", BitModeTy::Any) 1276 .Default(BitModeTy::Unknown); 1277 } 1278 1279 static const char *matchFlagWithArg(StringRef Expected, 1280 ArrayRef<const char *>::iterator &ArgIt, 1281 ArrayRef<const char *> Args) { 1282 StringRef Arg = *ArgIt; 1283 1284 if (Arg.startswith("--")) 1285 Arg = Arg.substr(2); 1286 1287 size_t len = Expected.size(); 1288 if (Arg == Expected) { 1289 if (++ArgIt == Args.end()) 1290 fail(std::string(Expected) + " requires an argument"); 1291 1292 return *ArgIt; 1293 } 1294 if (Arg.startswith(Expected) && Arg.size() > len && Arg[len] == '=') 1295 return Arg.data() + len + 1; 1296 1297 return nullptr; 1298 } 1299 1300 static cl::TokenizerCallback getRspQuoting(ArrayRef<const char *> ArgsArr) { 1301 cl::TokenizerCallback Ret = 1302 Triple(sys::getProcessTriple()).getOS() == Triple::Win32 1303 ? cl::TokenizeWindowsCommandLine 1304 : cl::TokenizeGNUCommandLine; 1305 1306 for (ArrayRef<const char *>::iterator ArgIt = ArgsArr.begin(); 1307 ArgIt != ArgsArr.end(); ++ArgIt) { 1308 if (const char *Match = matchFlagWithArg("rsp-quoting", ArgIt, ArgsArr)) { 1309 StringRef MatchRef = Match; 1310 if (MatchRef == "posix") 1311 Ret = cl::TokenizeGNUCommandLine; 1312 else if (MatchRef == "windows") 1313 Ret = cl::TokenizeWindowsCommandLine; 1314 else 1315 fail(std::string("Invalid response file quoting style ") + Match); 1316 } 1317 } 1318 1319 return Ret; 1320 } 1321 1322 static int ar_main(int argc, char **argv) { 1323 SmallVector<const char *, 0> Argv(argv + 1, argv + argc); 1324 StringSaver Saver(Alloc); 1325 1326 cl::ExpandResponseFiles(Saver, getRspQuoting(makeArrayRef(argv, argc)), Argv); 1327 1328 // Get BitMode from enviorment variable "OBJECT_MODE" for AIX OS, if 1329 // specified. 1330 if (object::Archive::getDefaultKindForHost() == object::Archive::K_AIXBIG) { 1331 BitMode = getBitMode(getenv("OBJECT_MODE")); 1332 if (BitMode == BitModeTy::Unknown) 1333 BitMode = BitModeTy::Bit32; 1334 } 1335 1336 for (ArrayRef<const char *>::iterator ArgIt = Argv.begin(); 1337 ArgIt != Argv.end(); ++ArgIt) { 1338 const char *Match = nullptr; 1339 1340 if (handleGenericOption(*ArgIt)) 1341 return 0; 1342 if (strcmp(*ArgIt, "--") == 0) { 1343 ++ArgIt; 1344 for (; ArgIt != Argv.end(); ++ArgIt) 1345 PositionalArgs.push_back(*ArgIt); 1346 break; 1347 } 1348 1349 if (*ArgIt[0] != '-') { 1350 if (Options.empty()) 1351 Options += *ArgIt; 1352 else 1353 PositionalArgs.push_back(*ArgIt); 1354 continue; 1355 } 1356 1357 if (strcmp(*ArgIt, "-M") == 0) { 1358 MRI = true; 1359 continue; 1360 } 1361 1362 if (strcmp(*ArgIt, "--thin") == 0) { 1363 Thin = true; 1364 continue; 1365 } 1366 1367 Match = matchFlagWithArg("format", ArgIt, Argv); 1368 if (Match) { 1369 FormatType = StringSwitch<Format>(Match) 1370 .Case("default", Default) 1371 .Case("gnu", GNU) 1372 .Case("darwin", DARWIN) 1373 .Case("bsd", BSD) 1374 .Case("bigarchive", BIGARCHIVE) 1375 .Default(Unknown); 1376 if (FormatType == Unknown) 1377 fail(std::string("Invalid format ") + Match); 1378 continue; 1379 } 1380 1381 if ((Match = matchFlagWithArg("output", ArgIt, Argv))) { 1382 OutputDir = Match; 1383 continue; 1384 } 1385 1386 if (matchFlagWithArg("plugin", ArgIt, Argv) || 1387 matchFlagWithArg("rsp-quoting", ArgIt, Argv)) 1388 continue; 1389 1390 if (strncmp(*ArgIt, "-X", 2) == 0) { 1391 if (object::Archive::getDefaultKindForHost() == 1392 object::Archive::K_AIXBIG) { 1393 Match = *(*ArgIt + 2) != '\0' ? *ArgIt + 2 : *(++ArgIt); 1394 BitMode = getBitMode(Match); 1395 if (BitMode == BitModeTy::Unknown) 1396 fail(Twine("invalid bit mode: ") + Match); 1397 continue; 1398 } else { 1399 fail(Twine(*ArgIt) + " option not supported on non AIX OS"); 1400 } 1401 } 1402 1403 Options += *ArgIt + 1; 1404 } 1405 1406 ArchiveOperation Operation = parseCommandLine(); 1407 return performOperation(Operation, nullptr); 1408 } 1409 1410 static int ranlib_main(int argc, char **argv) { 1411 bool ArchiveSpecified = false; 1412 for (int i = 1; i < argc; ++i) { 1413 StringRef arg(argv[i]); 1414 if (handleGenericOption(arg)) { 1415 return 0; 1416 } else if (arg.consume_front("-")) { 1417 // Handle the -D/-U flag 1418 while (!arg.empty()) { 1419 if (arg.front() == 'D') { 1420 Deterministic = true; 1421 } else if (arg.front() == 'U') { 1422 Deterministic = false; 1423 } else if (arg.front() == 'h') { 1424 printHelpMessage(); 1425 return 0; 1426 } else if (arg.front() == 'v') { 1427 cl::PrintVersionMessage(); 1428 return 0; 1429 } else { 1430 // TODO: GNU ranlib also supports a -t flag 1431 fail("Invalid option: '-" + arg + "'"); 1432 } 1433 arg = arg.drop_front(1); 1434 } 1435 } else { 1436 if (ArchiveSpecified) 1437 fail("exactly one archive should be specified"); 1438 ArchiveSpecified = true; 1439 ArchiveName = arg.str(); 1440 } 1441 } 1442 if (!ArchiveSpecified) { 1443 badUsage("an archive name must be specified"); 1444 } 1445 return performOperation(CreateSymTab, nullptr); 1446 } 1447 1448 int llvm_ar_main(int argc, char **argv) { 1449 InitLLVM X(argc, argv); 1450 ToolName = argv[0]; 1451 1452 llvm::InitializeAllTargetInfos(); 1453 llvm::InitializeAllTargetMCs(); 1454 llvm::InitializeAllAsmParsers(); 1455 1456 Stem = sys::path::stem(ToolName); 1457 auto Is = [](StringRef Tool) { 1458 // We need to recognize the following filenames. 1459 // 1460 // Lib.exe -> lib (see D44808, MSBuild runs Lib.exe) 1461 // dlltool.exe -> dlltool 1462 // arm-pokymllib32-linux-gnueabi-llvm-ar-10 -> ar 1463 auto I = Stem.rfind_insensitive(Tool); 1464 return I != StringRef::npos && 1465 (I + Tool.size() == Stem.size() || !isAlnum(Stem[I + Tool.size()])); 1466 }; 1467 1468 if (Is("dlltool")) 1469 return dlltoolDriverMain(makeArrayRef(argv, argc)); 1470 if (Is("ranlib")) 1471 return ranlib_main(argc, argv); 1472 if (Is("lib")) 1473 return libDriverMain(makeArrayRef(argv, argc)); 1474 if (Is("ar")) 1475 return ar_main(argc, argv); 1476 1477 fail("not ranlib, ar, lib or dlltool"); 1478 } 1479