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 << "Generate an index for archives\n\n" 73 << "USAGE: " + ToolName + " archive...\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 // Create or open the archive object. 1130 ErrorOr<std::unique_ptr<MemoryBuffer>> Buf = MemoryBuffer::getFile( 1131 ArchiveName, /*IsText=*/false, /*RequiresNullTerminator=*/false); 1132 std::error_code EC = Buf.getError(); 1133 if (EC && EC != errc::no_such_file_or_directory) 1134 fail("unable to open '" + ArchiveName + "': " + EC.message()); 1135 1136 if (!EC) { 1137 Expected<std::unique_ptr<object::Archive>> ArchiveOrError = 1138 object::Archive::create(Buf.get()->getMemBufferRef()); 1139 if (!ArchiveOrError) 1140 failIfError(ArchiveOrError.takeError(), 1141 "unable to load '" + ArchiveName + "'"); 1142 1143 std::unique_ptr<object::Archive> Archive = std::move(ArchiveOrError.get()); 1144 if (Archive->isThin()) 1145 CompareFullPath = true; 1146 performOperation(Operation, Archive.get(), std::move(Buf.get()), 1147 /*NewMembers=*/nullptr); 1148 return 0; 1149 } 1150 1151 assert(EC == errc::no_such_file_or_directory); 1152 1153 if (!shouldCreateArchive(Operation)) { 1154 failIfError(EC, Twine("unable to load '") + ArchiveName + "'"); 1155 } else { 1156 if (!Create) { 1157 // Produce a warning if we should and we're creating the archive 1158 warn("creating " + ArchiveName); 1159 } 1160 } 1161 1162 performOperation(Operation, nullptr, nullptr, /*NewMembers=*/nullptr); 1163 return 0; 1164 } 1165 1166 static void runMRIScript() { 1167 enum class MRICommand { AddLib, AddMod, Create, CreateThin, Delete, Save, End, Invalid }; 1168 1169 ErrorOr<std::unique_ptr<MemoryBuffer>> Buf = MemoryBuffer::getSTDIN(); 1170 failIfError(Buf.getError()); 1171 const MemoryBuffer &Ref = *Buf.get(); 1172 bool Saved = false; 1173 std::vector<NewArchiveMember> NewMembers; 1174 ParsingMRIScript = true; 1175 1176 for (line_iterator I(Ref, /*SkipBlanks*/ false), E; I != E; ++I) { 1177 ++MRILineNumber; 1178 StringRef Line = *I; 1179 Line = Line.split(';').first; 1180 Line = Line.split('*').first; 1181 Line = Line.trim(); 1182 if (Line.empty()) 1183 continue; 1184 StringRef CommandStr, Rest; 1185 std::tie(CommandStr, Rest) = Line.split(' '); 1186 Rest = Rest.trim(); 1187 if (!Rest.empty() && Rest.front() == '"' && Rest.back() == '"') 1188 Rest = Rest.drop_front().drop_back(); 1189 auto Command = StringSwitch<MRICommand>(CommandStr.lower()) 1190 .Case("addlib", MRICommand::AddLib) 1191 .Case("addmod", MRICommand::AddMod) 1192 .Case("create", MRICommand::Create) 1193 .Case("createthin", MRICommand::CreateThin) 1194 .Case("delete", MRICommand::Delete) 1195 .Case("save", MRICommand::Save) 1196 .Case("end", MRICommand::End) 1197 .Default(MRICommand::Invalid); 1198 1199 switch (Command) { 1200 case MRICommand::AddLib: { 1201 if (!Create) 1202 fail("no output archive has been opened"); 1203 object::Archive &Lib = readLibrary(Rest); 1204 { 1205 if (Thin && !Lib.isThin()) 1206 fail("cannot add a regular archive's contents to a thin archive"); 1207 Error Err = Error::success(); 1208 for (auto &Member : Lib.children(Err)) 1209 addChildMember(NewMembers, Member, /*FlattenArchive=*/Thin); 1210 failIfError(std::move(Err)); 1211 } 1212 break; 1213 } 1214 case MRICommand::AddMod: 1215 if (!Create) 1216 fail("no output archive has been opened"); 1217 addMember(NewMembers, Rest); 1218 break; 1219 case MRICommand::CreateThin: 1220 Thin = true; 1221 LLVM_FALLTHROUGH; 1222 case MRICommand::Create: 1223 Create = true; 1224 if (!ArchiveName.empty()) 1225 fail("editing multiple archives not supported"); 1226 if (Saved) 1227 fail("file already saved"); 1228 ArchiveName = std::string(Rest); 1229 if (ArchiveName.empty()) 1230 fail("missing archive name"); 1231 break; 1232 case MRICommand::Delete: { 1233 llvm::erase_if(NewMembers, [=](NewArchiveMember &M) { 1234 return comparePaths(M.MemberName, Rest); 1235 }); 1236 break; 1237 } 1238 case MRICommand::Save: 1239 Saved = true; 1240 break; 1241 case MRICommand::End: 1242 break; 1243 case MRICommand::Invalid: 1244 fail("unknown command: " + CommandStr); 1245 } 1246 } 1247 1248 ParsingMRIScript = false; 1249 1250 // Nothing to do if not saved. 1251 if (Saved) 1252 performOperation(ReplaceOrInsert, /*OldArchive=*/nullptr, 1253 /*OldArchiveBuf=*/nullptr, &NewMembers); 1254 exit(0); 1255 } 1256 1257 static bool handleGenericOption(StringRef arg) { 1258 if (arg == "--help" || arg == "-h") { 1259 printHelpMessage(); 1260 return true; 1261 } 1262 if (arg == "--version") { 1263 cl::PrintVersionMessage(); 1264 return true; 1265 } 1266 return false; 1267 } 1268 1269 static BitModeTy getBitMode(const char *RawBitMode) { 1270 return StringSwitch<BitModeTy>(RawBitMode) 1271 .Case("32", BitModeTy::Bit32) 1272 .Case("64", BitModeTy::Bit64) 1273 .Case("32_64", BitModeTy::Bit32_64) 1274 .Case("any", BitModeTy::Any) 1275 .Default(BitModeTy::Unknown); 1276 } 1277 1278 static const char *matchFlagWithArg(StringRef Expected, 1279 ArrayRef<const char *>::iterator &ArgIt, 1280 ArrayRef<const char *> Args) { 1281 StringRef Arg = *ArgIt; 1282 1283 if (Arg.startswith("--")) 1284 Arg = Arg.substr(2); 1285 1286 size_t len = Expected.size(); 1287 if (Arg == Expected) { 1288 if (++ArgIt == Args.end()) 1289 fail(std::string(Expected) + " requires an argument"); 1290 1291 return *ArgIt; 1292 } 1293 if (Arg.startswith(Expected) && Arg.size() > len && Arg[len] == '=') 1294 return Arg.data() + len + 1; 1295 1296 return nullptr; 1297 } 1298 1299 static cl::TokenizerCallback getRspQuoting(ArrayRef<const char *> ArgsArr) { 1300 cl::TokenizerCallback Ret = 1301 Triple(sys::getProcessTriple()).getOS() == Triple::Win32 1302 ? cl::TokenizeWindowsCommandLine 1303 : cl::TokenizeGNUCommandLine; 1304 1305 for (ArrayRef<const char *>::iterator ArgIt = ArgsArr.begin(); 1306 ArgIt != ArgsArr.end(); ++ArgIt) { 1307 if (const char *Match = matchFlagWithArg("rsp-quoting", ArgIt, ArgsArr)) { 1308 StringRef MatchRef = Match; 1309 if (MatchRef == "posix") 1310 Ret = cl::TokenizeGNUCommandLine; 1311 else if (MatchRef == "windows") 1312 Ret = cl::TokenizeWindowsCommandLine; 1313 else 1314 fail(std::string("Invalid response file quoting style ") + Match); 1315 } 1316 } 1317 1318 return Ret; 1319 } 1320 1321 static int ar_main(int argc, char **argv) { 1322 SmallVector<const char *, 0> Argv(argv + 1, argv + argc); 1323 StringSaver Saver(Alloc); 1324 1325 cl::ExpandResponseFiles(Saver, getRspQuoting(makeArrayRef(argv, argc)), Argv); 1326 1327 // Get BitMode from enviorment variable "OBJECT_MODE" for AIX OS, if 1328 // specified. 1329 if (object::Archive::getDefaultKindForHost() == object::Archive::K_AIXBIG) { 1330 BitMode = getBitMode(getenv("OBJECT_MODE")); 1331 if (BitMode == BitModeTy::Unknown) 1332 BitMode = BitModeTy::Bit32; 1333 } 1334 1335 for (ArrayRef<const char *>::iterator ArgIt = Argv.begin(); 1336 ArgIt != Argv.end(); ++ArgIt) { 1337 const char *Match = nullptr; 1338 1339 if (handleGenericOption(*ArgIt)) 1340 return 0; 1341 if (strcmp(*ArgIt, "--") == 0) { 1342 ++ArgIt; 1343 for (; ArgIt != Argv.end(); ++ArgIt) 1344 PositionalArgs.push_back(*ArgIt); 1345 break; 1346 } 1347 1348 if (*ArgIt[0] != '-') { 1349 if (Options.empty()) 1350 Options += *ArgIt; 1351 else 1352 PositionalArgs.push_back(*ArgIt); 1353 continue; 1354 } 1355 1356 if (strcmp(*ArgIt, "-M") == 0) { 1357 MRI = true; 1358 continue; 1359 } 1360 1361 if (strcmp(*ArgIt, "--thin") == 0) { 1362 Thin = true; 1363 continue; 1364 } 1365 1366 Match = matchFlagWithArg("format", ArgIt, Argv); 1367 if (Match) { 1368 FormatType = StringSwitch<Format>(Match) 1369 .Case("default", Default) 1370 .Case("gnu", GNU) 1371 .Case("darwin", DARWIN) 1372 .Case("bsd", BSD) 1373 .Case("bigarchive", BIGARCHIVE) 1374 .Default(Unknown); 1375 if (FormatType == Unknown) 1376 fail(std::string("Invalid format ") + Match); 1377 continue; 1378 } 1379 1380 if ((Match = matchFlagWithArg("output", ArgIt, Argv))) { 1381 OutputDir = Match; 1382 continue; 1383 } 1384 1385 if (matchFlagWithArg("plugin", ArgIt, Argv) || 1386 matchFlagWithArg("rsp-quoting", ArgIt, Argv)) 1387 continue; 1388 1389 if (strncmp(*ArgIt, "-X", 2) == 0) { 1390 if (object::Archive::getDefaultKindForHost() == 1391 object::Archive::K_AIXBIG) { 1392 Match = *(*ArgIt + 2) != '\0' ? *ArgIt + 2 : *(++ArgIt); 1393 BitMode = getBitMode(Match); 1394 if (BitMode == BitModeTy::Unknown) 1395 fail(Twine("invalid bit mode: ") + Match); 1396 continue; 1397 } else { 1398 fail(Twine(*ArgIt) + " option not supported on non AIX OS"); 1399 } 1400 } 1401 1402 Options += *ArgIt + 1; 1403 } 1404 1405 return performOperation(parseCommandLine()); 1406 } 1407 1408 static int ranlib_main(int argc, char **argv) { 1409 std::vector<StringRef> Archives; 1410 for (int i = 1; i < argc; ++i) { 1411 StringRef arg(argv[i]); 1412 if (handleGenericOption(arg)) { 1413 return 0; 1414 } else if (arg.consume_front("-")) { 1415 // Handle the -D/-U flag 1416 while (!arg.empty()) { 1417 if (arg.front() == 'D') { 1418 Deterministic = true; 1419 } else if (arg.front() == 'U') { 1420 Deterministic = false; 1421 } else if (arg.front() == 'h') { 1422 printHelpMessage(); 1423 return 0; 1424 } else if (arg.front() == 'v') { 1425 cl::PrintVersionMessage(); 1426 return 0; 1427 } else { 1428 // TODO: GNU ranlib also supports a -t flag 1429 fail("Invalid option: '-" + arg + "'"); 1430 } 1431 arg = arg.drop_front(1); 1432 } 1433 } else { 1434 Archives.push_back(arg); 1435 } 1436 } 1437 1438 for (StringRef Archive : Archives) { 1439 ArchiveName = Archive.str(); 1440 performOperation(CreateSymTab); 1441 } 1442 if (Archives.empty()) 1443 badUsage("an archive name must be specified"); 1444 return 0; 1445 } 1446 1447 int llvm_ar_main(int argc, char **argv) { 1448 InitLLVM X(argc, argv); 1449 ToolName = argv[0]; 1450 1451 llvm::InitializeAllTargetInfos(); 1452 llvm::InitializeAllTargetMCs(); 1453 llvm::InitializeAllAsmParsers(); 1454 1455 Stem = sys::path::stem(ToolName); 1456 auto Is = [](StringRef Tool) { 1457 // We need to recognize the following filenames. 1458 // 1459 // Lib.exe -> lib (see D44808, MSBuild runs Lib.exe) 1460 // dlltool.exe -> dlltool 1461 // arm-pokymllib32-linux-gnueabi-llvm-ar-10 -> ar 1462 auto I = Stem.rfind_insensitive(Tool); 1463 return I != StringRef::npos && 1464 (I + Tool.size() == Stem.size() || !isAlnum(Stem[I + Tool.size()])); 1465 }; 1466 1467 if (Is("dlltool")) 1468 return dlltoolDriverMain(makeArrayRef(argv, argc)); 1469 if (Is("ranlib")) 1470 return ranlib_main(argc, argv); 1471 if (Is("lib")) 1472 return libDriverMain(makeArrayRef(argv, argc)); 1473 if (Is("ar")) 1474 return ar_main(argc, argv); 1475 1476 fail("not ranlib, ar, lib or dlltool"); 1477 } 1478