╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ zig_llvm-ar.cpp ──────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭ find file ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╮ ╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │ │ │http│ ssh │ │ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╯ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
375 CompareFullPath = true; 376 break; 377 case 's': 378 Symtab = SymtabWritingMode::NormalSymtab; 379 MaybeJustCreateSymTab = true; 380 break; 381 case 'S': 382 Symtab = SymtabWritingMode::NoSymtab; 383 break; 384 case 'u': 385 OnlyUpdate = true; 386 break; 387 case 'v': 388 Verbose = true; 389 break; 390 case 'a': 391 getRelPos(); 392 AddAfter = true; 393 NumPositional++; 394 break; 395 case 'b': 396 getRelPos(); 397 AddBefore = true; 398 NumPositional++; 399 break; 400 case 'i': 401 getRelPos(); 402 AddBefore = true; 403 NumPositional++; 404 break; 405 case 'D': 406 Deterministic = true; 407 break; 408 case 'U': 409 Deterministic = false; 410 break; 411 case 'N': 412 getCountParam(); 413 break; 414 case 'T': 415 Thin = true; 416 break; 417 case 'L': 418 AddLibrary = true; 419 break; 420 case 'V': 421 cl::PrintVersionMessage(); 422 exit(0); 423 case 'h': 424 printHelpMessage(); 425 exit(0); 426 default: 427 badUsage(std::string("unknown option ") + Options[i]); 428 } 429 } 430 431 // Thin archives store path names, so P should be forced. 432 if (Thin) 433 CompareFullPath = true; 434 435 // At this point, the next thing on the command line must be 436 // the archive name. 437 getArchive(); 438 439 // Everything on the command line at this point is a member. 440 Members.assign(PositionalArgs.begin(), PositionalArgs.end()); 441 442 if (NumOperations == 0 && MaybeJustCreateSymTab) { 443 NumOperations = 1; 444 Operation = CreateSymTab; 445 if (!Members.empty()) 446 badUsage("the 's' operation takes only an archive as argument"); 447 } 448 449 // Perform various checks on the operation/modifier specification 450 // to make sure we are dealing with a legal request. 451 if (NumOperations == 0) 452 badUsage("you must specify at least one of the operations"); 453 if (NumOperations > 1) 454 badUsage("only one operation may be specified"); 455 if (NumPositional > 1) 456 badUsage("you may only specify one of 'a', 'b', and 'i' modifiers"); 457 if (AddAfter || AddBefore) 458 if (Operation != Move && Operation != ReplaceOrInsert) 459 badUsage("the 'a', 'b' and 'i' modifiers can only be specified with " 460 "the 'm' or 'r' operations"); 461 if (CountParam) 462 if (Operation != Extract && Operation != Delete) 463 badUsage("the 'N' modifier can only be specified with the 'x' or 'd' " 464 "operations"); 465 if (OriginalDates && Operation != Extract) 466 badUsage("the 'o' modifier is only applicable to the 'x' operation"); 467 if (OnlyUpdate && Operation != ReplaceOrInsert) 468 badUsage("the 'u' modifier is only applicable to the 'r' operation"); 469 if (AddLibrary && Operation != QuickAppend) 470 badUsage("the 'L' modifier is only applicable to the 'q' operation"); 471 472 if (!OutputDir.empty()) { 473 if (Operation != Extract) 474 badUsage("--output is only applicable to the 'x' operation"); 475 bool IsDir = false; 476 // If OutputDir is not a directory, create_directories may still succeed if 477 // all components of the path prefix are directories. Test is_directory as 478 // well. 479 if (!sys::fs::create_directories(OutputDir)) 480 sys::fs::is_directory(OutputDir, IsDir); 481 if (!IsDir) 482 fail("'" + OutputDir + "' is not a directory"); 483 } 484 485 // Return the parsed operation to the caller 486 return Operation; 487 } 488 489 // Implements the 'p' operation. This function traverses the archive 490 // looking for members that match the path list. 491 static void doPrint(StringRef Name, const object::Archive::Child &C) { 492 if (Verbose) 493 outs() << "Printing " << Name << "\n"; 494 495 Expected<StringRef> DataOrErr = C.getBuffer(); 496 failIfError(DataOrErr.takeError()); 497 StringRef Data = *DataOrErr; 498 outs().write(Data.data(), Data.size()); 499 } 500 501 // Utility function for printing out the file mode when the 't' operation is in 502 // verbose mode. 503 static void printMode(unsigned mode) { 504 outs() << ((mode & 004) ? "r" : "-"); 505 outs() << ((mode & 002) ? "w" : "-"); 506 outs() << ((mode & 001) ? "x" : "-"); 507 } 508 509 // Implement the 't' operation. This function prints out just 510 // the file names of each of the members. However, if verbose mode is requested 511 // ('v' modifier) then the file type, permission mode, user, group, size, and 512 // modification time are also printed. 513 static void doDisplayTable(StringRef Name, const object::Archive::Child &C) { 514 if (Verbose) { 515 Expected<sys::fs::perms> ModeOrErr = C.getAccessMode(); 516 failIfError(ModeOrErr.takeError()); 517 sys::fs::perms Mode = ModeOrErr.get(); 518 printMode((Mode >> 6) & 007); 519 printMode((Mode >> 3) & 007); 520 printMode(Mode & 007); 521 Expected<unsigned> UIDOrErr = C.getUID(); 522 failIfError(UIDOrErr.takeError()); 523 outs() << ' ' << UIDOrErr.get(); 524 Expected<unsigned> GIDOrErr = C.getGID(); 525 failIfError(GIDOrErr.takeError()); 526 outs() << '/' << GIDOrErr.get(); 527 Expected<uint64_t> Size = C.getSize(); 528 failIfError(Size.takeError()); 529 outs() << ' ' << format("%6llu", Size.get()); 530 auto ModTimeOrErr = C.getLastModified(); 531 failIfError(ModTimeOrErr.takeError()); 532 // Note: formatv() only handles the default TimePoint<>, which is in 533 // nanoseconds. 534 // TODO: fix format_provider<TimePoint<>> to allow other units. 535 sys::TimePoint<> ModTimeInNs = ModTimeOrErr.get(); 536 outs() << ' ' << formatv("{0:%b %e %H:%M %Y}", ModTimeInNs); 537 outs() << ' '; 538 } 539 540 if (C.getParent()->isThin()) { 541 if (!sys::path::is_absolute(Name)) { 542 StringRef ParentDir = sys::path::parent_path(ArchiveName); 543 if (!ParentDir.empty()) 544 outs() << sys::path::convert_to_slash(ParentDir) << '/'; 545 } 546 outs() << Name; 547 } else { 548 outs() << Name; 549 if (DisplayMemberOffsets) 550 outs() << " 0x" << utohexstr(C.getDataOffset(), true); 551 } 552 outs() << '\n'; 553 } 554 555 static std::string normalizePath(StringRef Path) { 556 return CompareFullPath ? sys::path::convert_to_slash(Path) 557 : std::string(sys::path::filename(Path)); 558 } 559 560 static bool comparePaths(StringRef Path1, StringRef Path2) { 561 // When on Windows this function calls CompareStringOrdinal 562 // as Windows file paths are case-insensitive. 563 // CompareStringOrdinal compares two Unicode strings for 564 // binary equivalence and allows for case insensitivity. 565 #ifdef _WIN32 566 SmallVector<wchar_t, 128> WPath1, WPath2; 567 failIfError(sys::windows::UTF8ToUTF16(normalizePath(Path1), WPath1)); 568 failIfError(sys::windows::UTF8ToUTF16(normalizePath(Path2), WPath2)); 569 570 return CompareStringOrdinal(WPath1.data(), WPath1.size(), WPath2.data(), 571 WPath2.size(), true) == CSTR_EQUAL; 572 #else 573 return normalizePath(Path1) == normalizePath(Path2); 574 #endif 575 } 576 577 // Implement the 'x' operation. This function extracts files back to the file 578 // system. 579 static void doExtract(StringRef Name, const object::Archive::Child &C) { 580 // Retain the original mode. 581 Expected<sys::fs::perms> ModeOrErr = C.getAccessMode(); 582 failIfError(ModeOrErr.takeError()); 583 sys::fs::perms Mode = ModeOrErr.get(); 584 585 StringRef outputFilePath; 586 SmallString<128> path; 587 if (OutputDir.empty()) { 588 outputFilePath = sys::path::filename(Name); 589 } else { 590 sys::path::append(path, OutputDir, sys::path::filename(Name)); 591 outputFilePath = path.str(); 592 } 593 594 if (Verbose) 595 outs() << "x - " << outputFilePath << '\n'; 596 597 int FD; 598 failIfError(sys::fs::openFileForWrite(outputFilePath, FD, 599 sys::fs::CD_CreateAlways, 600 sys::fs::OF_None, Mode), 601 Name); 602 603 { 604 raw_fd_ostream file(FD, false); 605 606 // Get the data and its length 607 Expected<StringRef> BufOrErr = C.getBuffer(); 608 failIfError(BufOrErr.takeError()); 609 StringRef Data = BufOrErr.get(); 610 611 // Write the data. 612 file.write(Data.data(), Data.size()); 613 } 614 615 // If we're supposed to retain the original modification times, etc. do so 616 // now. 617 if (OriginalDates) { 618 auto ModTimeOrErr = C.getLastModified(); 619 failIfError(ModTimeOrErr.takeError()); 620 failIfError( 621 sys::fs::setLastAccessAndModificationTime(FD, ModTimeOrErr.get())); 622 } 623 624 if (close(FD)) 625 fail("Could not close the file"); 626 } 627 628 static bool shouldCreateArchive(ArchiveOperation Op) { 629 switch (Op) { 630 case Print: 631 case Delete: 632 case Move: 633 case DisplayTable: 634 case Extract: 635 case CreateSymTab: 636 return false; 637 638 case QuickAppend: 639 case ReplaceOrInsert: 640 return true; 641 } 642 643 llvm_unreachable("Missing entry in covered switch."); 644 } 645 646 static bool isValidInBitMode(Binary &Bin) { 647 if (BitMode == BitModeTy::Bit32_64 || BitMode == BitModeTy::Any) 648 return true; 649 650 if (SymbolicFile *SymFile = dyn_cast<SymbolicFile>(&Bin)) { 651 bool Is64Bit = SymFile->is64Bit(); 652 if ((Is64Bit && (BitMode == BitModeTy::Bit32)) || 653 (!Is64Bit && (BitMode == BitModeTy::Bit64))) 654 return false; 655 } 656 // In AIX "ar", non-object files are always considered to have a valid bit 657 // mode. 658 return true; 659 } 660 661 Expected<std::unique_ptr<Binary>> getAsBinary(const NewArchiveMember &NM, 662 LLVMContext *Context) { 663 auto BinaryOrErr = createBinary(NM.Buf->getMemBufferRef(), Context); 664 if (BinaryOrErr) 665 return std::move(*BinaryOrErr); 666 return BinaryOrErr.takeError(); 667 } 668 669 Expected<std::unique_ptr<Binary>> getAsBinary(const Archive::Child &C, 670 LLVMContext *Context) { 671 return C.getAsBinary(Context); 672 } 673 674 template <class A> static bool isValidInBitMode(const A &Member) { 675 if (object::Archive::getDefaultKind() != object::Archive::K_AIXBIG) 676 return true; 677 LLVMContext Context; 678 Expected<std::unique_ptr<Binary>> BinOrErr = getAsBinary(Member, &Context); 679 // In AIX "ar", if there is a non-object file member, it is never ignored due 680 // to the bit mode setting. 681 if (!BinOrErr) { 682 consumeError(BinOrErr.takeError()); 683 return true; 684 } 685 return isValidInBitMode(*BinOrErr.get()); 686 } 687 688 static void warnInvalidObjectForFileMode(Twine Name) { 689 warn("'" + Name + "' is not valid with the current object file mode"); 690 } 691 692 static void performReadOperation(ArchiveOperation Operation, 693 object::Archive *OldArchive) { 694 if (Operation == Extract && OldArchive->isThin()) 695 fail("extracting from a thin archive is not supported"); 696 697 bool Filter = !Members.empty(); 698 StringMap<int> MemberCount; 699 { 700 Error Err = Error::success(); 701 for (auto &C : OldArchive->children(Err)) { 702 Expected<StringRef> NameOrErr = C.getName(); 703 failIfError(NameOrErr.takeError()); 704 StringRef Name = NameOrErr.get(); 705 706 // Check whether to ignore this object due to its bitness. 707 if (!isValidInBitMode(C)) 708 continue; 709 710 if (Filter) { 711 auto I = find_if(Members, [Name](StringRef Path) { 712 return comparePaths(Name, Path); 713 }); 714 if (I == Members.end()) 715 continue; 716 if (CountParam && ++MemberCount[Name] != CountParam) 717 continue; 718 Members.erase(I); 719 } 720 721 switch (Operation) { 722 default: 723 llvm_unreachable("Not a read operation"); 724 case Print: 725 doPrint(Name, C); 726 break; 727 case DisplayTable: 728 doDisplayTable(Name, C); 729 break; 730 case Extract: 731 doExtract(Name, C); 732 break; 733 } 734 } 735 failIfError(std::move(Err)); 736 } 737 738 if (Members.empty()) 739 return; 740 for (StringRef Name : Members) 741 WithColor::error(errs(), ToolName) << "'" << Name << "' was not found\n"; 742 exit(1); 743 } 744 745 static void addChildMember(std::vector<NewArchiveMember> &Members, 746 const object::Archive::Child &M, 747 bool FlattenArchive = false) { 748 Expected<NewArchiveMember> NMOrErr = 749 NewArchiveMember::getOldMember(M, Deterministic); 750 failIfError(NMOrErr.takeError()); 751 // If the child member we're trying to add is thin, use the path relative to 752 // the archive it's in, so the file resolves correctly. 753 if (Thin && FlattenArchive) { 754 StringSaver Saver(Alloc); 755 Expected<std::string> FileNameOrErr(M.getName()); 756 failIfError(FileNameOrErr.takeError()); 757 if (sys::path::is_absolute(*FileNameOrErr)) { 758 NMOrErr->MemberName = Saver.save(sys::path::convert_to_slash(*FileNameOrErr)); 759 } else { 760 FileNameOrErr = M.getFullName(); 761 failIfError(FileNameOrErr.takeError()); 762 Expected<std::string> PathOrErr = 763 computeArchiveRelativePath(ArchiveName, *FileNameOrErr); 764 NMOrErr->MemberName = Saver.save( 765 PathOrErr ? *PathOrErr : sys::path::convert_to_slash(*FileNameOrErr)); 766 } 767 } 768 if (FlattenArchive && 769 identify_magic(NMOrErr->Buf->getBuffer()) == file_magic::archive) { 770 Expected<std::string> FileNameOrErr = M.getFullName(); 771 failIfError(FileNameOrErr.takeError()); 772 object::Archive &Lib = readLibrary(*FileNameOrErr); 773 // When creating thin archives, only flatten if the member is also thin. 774 if (!Thin || Lib.isThin()) { 775 Error Err = Error::success(); 776 // Only Thin archives are recursively flattened. 777 for (auto &Child : Lib.children(Err)) 778 addChildMember(Members, Child, /*FlattenArchive=*/Thin); 779 failIfError(std::move(Err)); 780 return; 781 } 782 } 783 Members.push_back(std::move(*NMOrErr)); 784 } 785 786 static NewArchiveMember getArchiveMember(StringRef FileName) { 787 Expected<NewArchiveMember> NMOrErr = 788 NewArchiveMember::getFile(FileName, Deterministic); 789 failIfError(NMOrErr.takeError(), FileName); 790 StringSaver Saver(Alloc); 791 // For regular archives, use the basename of the object path for the member 792 // name. For thin archives, use the full relative paths so the file resolves 793 // correctly. 794 if (!Thin) { 795 NMOrErr->MemberName = sys::path::filename(NMOrErr->MemberName); 796 } else { 797 if (sys::path::is_absolute(FileName)) 798 NMOrErr->MemberName = Saver.save(sys::path::convert_to_slash(FileName)); 799 else { 800 Expected<std::string> PathOrErr = 801 computeArchiveRelativePath(ArchiveName, FileName); 802 NMOrErr->MemberName = Saver.save( 803 PathOrErr ? *PathOrErr : sys::path::convert_to_slash(FileName)); 804 } 805 } 806 return std::move(*NMOrErr); 807 } 808 809 static void addMember(std::vector<NewArchiveMember> &Members, 810 NewArchiveMember &NM) { 811 Members.push_back(std::move(NM)); 812 } 813 814 static void addMember(std::vector<NewArchiveMember> &Members, 815 StringRef FileName, bool FlattenArchive = false) { 816 NewArchiveMember NM = getArchiveMember(FileName); 817 if (!isValidInBitMode(NM)) { 818 warnInvalidObjectForFileMode(FileName); 819 return; 820 } 821 822 if (FlattenArchive && 823 identify_magic(NM.Buf->getBuffer()) == file_magic::archive) { 824 object::Archive &Lib = readLibrary(FileName); 825 // When creating thin archives, only flatten if the member is also thin. 826 if (!Thin || Lib.isThin()) { 827 Error Err = Error::success(); 828 // Only Thin archives are recursively flattened. 829 for (auto &Child : Lib.children(Err)) 830 addChildMember(Members, Child, /*FlattenArchive=*/Thin); 831 failIfError(std::move(Err)); 832 return; 833 } 834 } 835 Members.push_back(std::move(NM)); 836 } 837 838 enum InsertAction { 839 IA_AddOldMember, 840 IA_AddNewMember, 841 IA_Delete, 842 IA_MoveOldMember, 843 IA_MoveNewMember 844 }; 845 846 static InsertAction computeInsertAction(ArchiveOperation Operation, 847 const object::Archive::Child &Member, 848 StringRef Name, 849 std::vector<StringRef>::iterator &Pos, 850 StringMap<int> &MemberCount) { 851 if (!isValidInBitMode(Member)) 852 return IA_AddOldMember; 853 854 if (Operation == QuickAppend || Members.empty()) 855 return IA_AddOldMember; 856 857 auto MI = find_if(Members, [Name](StringRef Path) { 858 if (Thin && !sys::path::is_absolute(Path)) { 859 Expected<std::string> PathOrErr = 860 computeArchiveRelativePath(ArchiveName, Path); 861 return comparePaths(Name, PathOrErr ? *PathOrErr : Path); 862 } else { 863 return comparePaths(Name, Path); 864 } 865 }); 866 867 if (MI == Members.end()) 868 return IA_AddOldMember; 869 870 Pos = MI; 871 872 if (Operation == Delete) { 873 if (CountParam && ++MemberCount[Name] != CountParam) 874 return IA_AddOldMember; 875 return IA_Delete; 876 } 877 878 if (Operation == Move) 879 return IA_MoveOldMember; 880 881 if (Operation == ReplaceOrInsert) { 882 if (!OnlyUpdate) { 883 if (RelPos.empty()) 884 return IA_AddNewMember; 885 return IA_MoveNewMember; 886 } 887 888 // We could try to optimize this to a fstat, but it is not a common 889 // operation. 890 sys::fs::file_status Status; 891 failIfError(sys::fs::status(*MI, Status), *MI); 892 auto ModTimeOrErr = Member.getLastModified(); 893 failIfError(ModTimeOrErr.takeError()); 894 if (Status.getLastModificationTime() < ModTimeOrErr.get()) { 895 if (RelPos.empty()) 896 return IA_AddOldMember; 897 return IA_MoveOldMember; 898 } 899 900 if (RelPos.empty()) 901 return IA_AddNewMember; 902 return IA_MoveNewMember; 903 } 904 llvm_unreachable("No such operation"); 905 } 906 907 // We have to walk this twice and computing it is not trivial, so creating an 908 // explicit std::vector is actually fairly efficient. 909 static std::vector<NewArchiveMember> 910 computeNewArchiveMembers(ArchiveOperation Operation, 911 object::Archive *OldArchive) { 912 std::vector<NewArchiveMember> Ret; 913 std::vector<NewArchiveMember> Moved; 914 int InsertPos = -1; 915 if (OldArchive) { 916 Error Err = Error::success(); 917 StringMap<int> MemberCount; 918 for (auto &Child : OldArchive->children(Err)) { 919 int Pos = Ret.size(); 920 Expected<StringRef> NameOrErr = Child.getName(); 921 failIfError(NameOrErr.takeError()); 922 std::string Name = std::string(NameOrErr.get()); 923 if (comparePaths(Name, RelPos) && isValidInBitMode(Child)) { 924 assert(AddAfter || AddBefore); 925 if (AddBefore) 926 InsertPos = Pos; 927 else 928 InsertPos = Pos + 1; 929 } 930 931 std::vector<StringRef>::iterator MemberI = Members.end(); 932 InsertAction Action = 933 computeInsertAction(Operation, Child, Name, MemberI, MemberCount); 934 935 auto HandleNewMember = [](auto Member, auto &Members, auto &Child) { 936 NewArchiveMember NM = getArchiveMember(*Member); 937 if (isValidInBitMode(NM)) 938 addMember(Members, NM); 939 else { 940 // If a new member is not a valid object for the bit mode, add 941 // the old member back. 942 warnInvalidObjectForFileMode(*Member); 943 addChildMember(Members, Child, /*FlattenArchive=*/Thin); 944 } 945 }; 946 947 switch (Action) { 948 case IA_AddOldMember: 949 addChildMember(Ret, Child, /*FlattenArchive=*/Thin); 950 break; 951 case IA_AddNewMember: 952 HandleNewMember(MemberI, Ret, Child); 953 break; 954 case IA_Delete: 955 break; 956 case IA_MoveOldMember: 957 addChildMember(Moved, Child, /*FlattenArchive=*/Thin); 958 break; 959 case IA_MoveNewMember: 960 HandleNewMember(MemberI, Moved, Child); 961 break; 962 } 963 // When processing elements with the count param, we need to preserve the 964 // full members list when iterating over all archive members. For 965 // instance, "llvm-ar dN 2 archive.a member.o" should delete the second 966 // file named member.o it sees; we are not done with member.o the first 967 // time we see it in the archive. 968 if (MemberI != Members.end() && !CountParam) 969 Members.erase(MemberI); 970 } 971 failIfError(std::move(Err)); 972 } 973 974 if (Operation == Delete) 975 return Ret; 976 977 if (!RelPos.empty() && InsertPos == -1) 978 fail("insertion point not found"); 979 980 if (RelPos.empty()) 981 InsertPos = Ret.size(); 982 983 assert(unsigned(InsertPos) <= Ret.size()); 984 int Pos = InsertPos; 985 for (auto &M : Moved) { 986 Ret.insert(Ret.begin() + Pos, std::move(M)); 987 ++Pos; 988 } 989 990 if (AddLibrary) { 991 assert(Operation == QuickAppend); 992 for (auto &Member : Members) 993 addMember(Ret, Member, /*FlattenArchive=*/true); 994 return Ret; 995 } 996 997 std::vector<NewArchiveMember> NewMembers; 998 for (auto &Member : Members) 999 addMember(NewMembers, Member, /*FlattenArchive=*/Thin); 1000 Ret.reserve(Ret.size() + NewMembers.size()); 1001 std::move(NewMembers.begin(), NewMembers.end(), 1002 std::inserter(Ret, std::next(Ret.begin(), InsertPos))); 1003 1004 return Ret; 1005 } 1006 1007 static void performWriteOperation(ArchiveOperation Operation, 1008 object::Archive *OldArchive, 1009 std::unique_ptr<MemoryBuffer> OldArchiveBuf, 1010 std::vector<NewArchiveMember> *NewMembersP) { 1011 if (OldArchive) { 1012 if (Thin && !OldArchive->isThin()) 1013 fail("cannot convert a regular archive to a thin one"); 1014 1015 if (OldArchive->isThin()) 1016 Thin = true; 1017 } 1018 1019 std::vector<NewArchiveMember> NewMembers; 1020 if (!NewMembersP) 1021 NewMembers = computeNewArchiveMembers(Operation, OldArchive); 1022 1023 object::Archive::Kind Kind; 1024 switch (FormatType) { 1025 case Default: 1026 if (Thin) 1027 Kind = object::Archive::K_GNU; 1028 else if (OldArchive) { 1029 Kind = OldArchive->kind(); 1030 std::optional<object::Archive::Kind> AltKind; 1031 if (Kind == object::Archive::K_BSD) 1032 AltKind = object::Archive::K_DARWIN; 1033 else if (Kind == object::Archive::K_GNU && !OldArchive->hasSymbolTable()) 1034 // If there is no symbol table, we can't tell GNU from COFF format 1035 // from the old archive type. 1036 AltKind = object::Archive::K_COFF; 1037 if (AltKind) { 1038 auto InferredKind = Kind; 1039 if (NewMembersP && !NewMembersP->empty()) 1040 InferredKind = NewMembersP->front().detectKindFromObject(); 1041 else if (!NewMembers.empty()) 1042 InferredKind = NewMembers.front().detectKindFromObject(); 1043 if (InferredKind == AltKind) 1044 Kind = *AltKind; 1045 } 1046 } else if (NewMembersP) 1047 Kind = !NewMembersP->empty() ? NewMembersP->front().detectKindFromObject() 1048 : object::Archive::getDefaultKind(); 1049 else 1050 Kind = !NewMembers.empty() ? NewMembers.front().detectKindFromObject() 1051 : object::Archive::getDefaultKind(); 1052 break; 1053 case GNU: 1054 Kind = object::Archive::K_GNU; 1055 break; 1056 case COFF: 1057 Kind = object::Archive::K_COFF; 1058 break; 1059 case BSD: 1060 if (Thin) 1061 fail("only the gnu format has a thin mode"); 1062 Kind = object::Archive::K_BSD; 1063 break; 1064 case DARWIN: 1065 if (Thin) 1066 fail("only the gnu format has a thin mode"); 1067 Kind = object::Archive::K_DARWIN; 1068 break; 1069 case BIGARCHIVE: 1070 if (Thin) 1071 fail("only the gnu format has a thin mode"); 1072 Kind = object::Archive::K_AIXBIG; 1073 break; 1074 case Unknown: 1075 llvm_unreachable(""); 1076 } 1077 1078 Error E = 1079 writeArchive(ArchiveName, NewMembersP ? *NewMembersP : NewMembers, Symtab, 1080 Kind, Deterministic, Thin, std::move(OldArchiveBuf)); 1081 failIfError(std::move(E), ArchiveName); 1082 } 1083 1084 static void createSymbolTable(object::Archive *OldArchive) { 1085 // When an archive is created or modified, if the s option is given, the 1086 // resulting archive will have a current symbol table. If the S option 1087 // is given, it will have no symbol table. 1088 // In summary, we only need to update the symbol table if we have none. 1089 // This is actually very common because of broken build systems that think 1090 // they have to run ranlib. 1091 if (OldArchive->hasSymbolTable()) { 1092 if (OldArchive->kind() != object::Archive::K_AIXBIG) 1093 return; 1094 1095 // For archives in the Big Archive format, the bit mode option specifies 1096 // which symbol table to generate. The presence of a symbol table that does 1097 // not match the specified bit mode does not prevent creation of the symbol 1098 // table that has been requested. 1099 if (OldArchive->kind() == object::Archive::K_AIXBIG) { 1100 BigArchive *BigArc = dyn_cast<BigArchive>(OldArchive); 1101 if (BigArc->has32BitGlobalSymtab() && 1102 Symtab == SymtabWritingMode::BigArchive32) 1103 return; 1104 1105 if (BigArc->has64BitGlobalSymtab() && 1106 Symtab == SymtabWritingMode::BigArchive64) 1107 return; 1108 1109 if (BigArc->has32BitGlobalSymtab() && BigArc->has64BitGlobalSymtab() && 1110 Symtab == SymtabWritingMode::NormalSymtab) 1111 return; 1112 1113 Symtab = SymtabWritingMode::NormalSymtab; 1114 } 1115 } 1116 if (OldArchive->isThin()) 1117 Thin = true; 1118 performWriteOperation(CreateSymTab, OldArchive, nullptr, nullptr); 1119 } 1120 1121 static void performOperation(ArchiveOperation Operation, 1122 object::Archive *OldArchive, 1123 std::unique_ptr<MemoryBuffer> OldArchiveBuf, 1124 std::vector<NewArchiveMember> *NewMembers) { 1125 switch (Operation) { 1126 case Print: 1127 case DisplayTable: 1128 case Extract: 1129 performReadOperation(Operation, OldArchive); 1130 return; 1131 1132 case Delete: 1133 case Move: 1134 case QuickAppend: 1135 case ReplaceOrInsert: 1136 performWriteOperation(Operation, OldArchive, std::move(OldArchiveBuf), 1137 NewMembers); 1138 return; 1139 case CreateSymTab: 1140 createSymbolTable(OldArchive); 1141 return; 1142 } 1143 llvm_unreachable("Unknown operation."); 1144 } 1145 1146 static int performOperation(ArchiveOperation Operation) { 1147 // Create or open the archive object. 1148 ErrorOr<std::unique_ptr<MemoryBuffer>> Buf = MemoryBuffer::getFile( 1149 ArchiveName, /*IsText=*/false, /*RequiresNullTerminator=*/false); 1150 std::error_code EC = Buf.getError(); 1151 if (EC && EC != errc::no_such_file_or_directory) 1152 fail("unable to open '" + ArchiveName + "': " + EC.message()); 1153 1154 if (!EC) { 1155 Expected<std::unique_ptr<object::Archive>> ArchiveOrError = 1156 object::Archive::create(Buf.get()->getMemBufferRef()); 1157 if (!ArchiveOrError) 1158 failIfError(ArchiveOrError.takeError(), 1159 "unable to load '" + ArchiveName + "'"); 1160 1161 std::unique_ptr<object::Archive> Archive = std::move(ArchiveOrError.get()); 1162 if (Archive->isThin()) 1163 CompareFullPath = true; 1164 performOperation(Operation, Archive.get(), std::move(Buf.get()), 1165 /*NewMembers=*/nullptr); 1166 return 0; 1167 } 1168 1169 assert(EC == errc::no_such_file_or_directory); 1170 1171 if (!shouldCreateArchive(Operation)) { 1172 failIfError(EC, Twine("unable to load '") + ArchiveName + "'"); 1173 } else { 1174 if (!Create) { 1175 // Produce a warning if we should and we're creating the archive 1176 warn("creating " + ArchiveName); 1177 } 1178 } 1179 1180 performOperation(Operation, nullptr, nullptr, /*NewMembers=*/nullptr); 1181 return 0; 1182 } 1183 1184 static void runMRIScript() { 1185 enum class MRICommand { AddLib, AddMod, Create, CreateThin, Delete, Save, End, Invalid }; 1186 1187 ErrorOr<std::unique_ptr<MemoryBuffer>> Buf = MemoryBuffer::getSTDIN(); 1188 failIfError(Buf.getError()); 1189 const MemoryBuffer &Ref = *Buf.get(); 1190 bool Saved = false; 1191 std::vector<NewArchiveMember> NewMembers; 1192 ParsingMRIScript = true; 1193 1194 for (line_iterator I(Ref, /*SkipBlanks*/ false), E; I != E; ++I) { 1195 ++MRILineNumber; 1196 StringRef Line = *I; 1197 Line = Line.split(';').first; 1198 Line = Line.split('*').first; 1199 Line = Line.trim(); 1200 if (Line.empty()) 1201 continue; 1202 StringRef CommandStr, Rest; 1203 std::tie(CommandStr, Rest) = Line.split(' '); 1204 Rest = Rest.trim(); 1205 if (!Rest.empty() && Rest.front() == '"' && Rest.back() == '"') 1206 Rest = Rest.drop_front().drop_back(); 1207 auto Command = StringSwitch<MRICommand>(CommandStr.lower()) 1208 .Case("addlib", MRICommand::AddLib) 1209 .Case("addmod", MRICommand::AddMod) 1210 .Case("create", MRICommand::Create) 1211 .Case("createthin", MRICommand::CreateThin) 1212 .Case("delete", MRICommand::Delete) 1213 .Case("save", MRICommand::Save) 1214 .Case("end", MRICommand::End) 1215 .Default(MRICommand::Invalid); 1216 1217 switch (Command) { 1218 case MRICommand::AddLib: { 1219 if (!Create) 1220 fail("no output archive has been opened"); 1221 object::Archive &Lib = readLibrary(Rest); 1222 { 1223 if (Thin && !Lib.isThin()) 1224 fail("cannot add a regular archive's contents to a thin archive"); 1225 Error Err = Error::success(); 1226 for (auto &Member : Lib.children(Err)) 1227 addChildMember(NewMembers, Member, /*FlattenArchive=*/Thin); 1228 failIfError(std::move(Err)); 1229 } 1230 break; 1231 } 1232 case MRICommand::AddMod: 1233 if (!Create) 1234 fail("no output archive has been opened"); 1235 addMember(NewMembers, Rest); 1236 break; 1237 case MRICommand::CreateThin: 1238 Thin = true; 1239 [[fallthrough]]; 1240 case MRICommand::Create: 1241 Create = true; 1242 if (!ArchiveName.empty()) 1243 fail("editing multiple archives not supported"); 1244 if (Saved) 1245 fail("file already saved"); 1246 ArchiveName = std::string(Rest); 1247 if (ArchiveName.empty()) 1248 fail("missing archive name"); 1249 break; 1250 case MRICommand::Delete: { 1251 llvm::erase_if(NewMembers, [=](NewArchiveMember &M) { 1252 return comparePaths(M.MemberName, Rest); 1253 }); 1254 break; 1255 } 1256 case MRICommand::Save: 1257 Saved = true; 1258 break; 1259 case MRICommand::End: 1260 break; 1261 case MRICommand::Invalid: 1262 fail("unknown command: " + CommandStr); 1263 } 1264 } 1265 1266 ParsingMRIScript = false; 1267 1268 // Nothing to do if not saved. 1269 if (Saved) 1270 performOperation(ReplaceOrInsert, /*OldArchive=*/nullptr, 1271 /*OldArchiveBuf=*/nullptr, &NewMembers); 1272 exit(0); 1273 } 1274 1275 static bool handleGenericOption(StringRef arg) { 1276 if (arg == "--help" || arg == "-h") { 1277 printHelpMessage(); 1278 return true; 1279 } 1280 if (arg == "--version") { 1281 cl::PrintVersionMessage(); 1282 return true; 1283 } 1284 return false; 1285 } 1286 1287 static BitModeTy getBitMode(const char *RawBitMode) { 1288 return StringSwitch<BitModeTy>(RawBitMode) 1289 .Case("32", BitModeTy::Bit32) 1290 .Case("64", BitModeTy::Bit64) 1291 .Case("32_64", BitModeTy::Bit32_64) 1292 .Case("any", BitModeTy::Any) 1293 .Default(BitModeTy::Unknown); 1294 } 1295 1296 static const char *matchFlagWithArg(StringRef Expected, 1297 ArrayRef<const char *>::iterator &ArgIt, 1298 ArrayRef<const char *> Args) { 1299 StringRef Arg = *ArgIt; 1300 1301 Arg.consume_front("--"); 1302 1303 size_t len = Expected.size(); 1304 if (Arg == Expected) { 1305 if (++ArgIt == Args.end()) 1306 fail(std::string(Expected) + " requires an argument"); 1307 1308 return *ArgIt; 1309 } 1310 if (Arg.starts_with(Expected) && Arg.size() > len && Arg[len] == '=') 1311 return Arg.data() + len + 1; 1312 1313 return nullptr; 1314 } 1315 1316 static cl::TokenizerCallback getRspQuoting(ArrayRef<const char *> ArgsArr) { 1317 cl::TokenizerCallback Ret = 1318 Triple(sys::getProcessTriple()).getOS() == Triple::Win32 1319 ? cl::TokenizeWindowsCommandLine 1320 : cl::TokenizeGNUCommandLine; 1321 1322 for (ArrayRef<const char *>::iterator ArgIt = ArgsArr.begin(); 1323 ArgIt != ArgsArr.end(); ++ArgIt) { 1324 if (const char *Match = matchFlagWithArg("rsp-quoting", ArgIt, ArgsArr)) { 1325 StringRef MatchRef = Match; 1326 if (MatchRef == "posix") 1327 Ret = cl::TokenizeGNUCommandLine; 1328 else if (MatchRef == "windows") 1329 Ret = cl::TokenizeWindowsCommandLine; 1330 else 1331 fail(std::string("Invalid response file quoting style ") + Match); 1332 } 1333 } 1334 1335 return Ret; 1336 } 1337 1338 static int ar_main(int argc, char **argv) { 1339 SmallVector<const char *, 0> Argv(argv + 1, argv + argc); 1340 StringSaver Saver(Alloc); 1341 1342 cl::ExpandResponseFiles(Saver, getRspQuoting(ArrayRef(argv, argc)), Argv); 1343 1344 // Get BitMode from enviorment variable "OBJECT_MODE" for AIX OS, if 1345 // specified. 1346 if (object::Archive::getDefaultKind() == object::Archive::K_AIXBIG) { 1347 BitMode = getBitMode(getenv("OBJECT_MODE")); 1348 if (BitMode == BitModeTy::Unknown) 1349 BitMode = BitModeTy::Bit32; 1350 } 1351 1352 for (ArrayRef<const char *>::iterator ArgIt = Argv.begin(); 1353 ArgIt != Argv.end(); ++ArgIt) { 1354 const char *Match = nullptr; 1355 1356 if (handleGenericOption(*ArgIt)) 1357 return 0; 1358 if (strcmp(*ArgIt, "--") == 0) { 1359 ++ArgIt; 1360 for (; ArgIt != Argv.end(); ++ArgIt) 1361 PositionalArgs.push_back(*ArgIt); 1362 break; 1363 } 1364 1365 if (*ArgIt[0] != '-') { 1366 if (Options.empty()) 1367 Options += *ArgIt; 1368 else 1369 PositionalArgs.push_back(*ArgIt); 1370 continue; 1371 } 1372 1373 if (strcmp(*ArgIt, "-M") == 0) { 1374 MRI = true; 1375 continue; 1376 } 1377 1378 if (strcmp(*ArgIt, "--thin") == 0) { 1379 Thin = true; 1380 continue; 1381 } 1382 1383 Match = matchFlagWithArg("format", ArgIt, Argv); 1384 if (Match) { 1385 FormatType = StringSwitch<Format>(Match) 1386 .Case("default", Default) 1387 .Case("gnu", GNU) 1388 .Case("darwin", DARWIN) 1389 .Case("bsd", BSD) 1390 .Case("bigarchive", BIGARCHIVE) 1391 .Case("coff", COFF) 1392 .Default(Unknown); 1393 if (FormatType == Unknown) 1394 fail(std::string("Invalid format ") + Match); 1395 continue; 1396 } 1397 1398 if ((Match = matchFlagWithArg("output", ArgIt, Argv))) { 1399 OutputDir = Match; 1400 continue; 1401 } 1402 1403 if (matchFlagWithArg("plugin", ArgIt, Argv) || 1404 matchFlagWithArg("rsp-quoting", ArgIt, Argv)) 1405 continue; 1406 1407 if (strncmp(*ArgIt, "-X", 2) == 0) { 1408 if (object::Archive::getDefaultKind() == object::Archive::K_AIXBIG) { 1409 Match = *(*ArgIt + 2) != '\0' ? *ArgIt + 2 : *(++ArgIt); 1410 BitMode = getBitMode(Match); 1411 if (BitMode == BitModeTy::Unknown) 1412 fail(Twine("invalid bit mode: ") + Match); 1413 continue; 1414 } else { 1415 fail(Twine(*ArgIt) + " option not supported on non AIX OS"); 1416 } 1417 } 1418 1419 Options += *ArgIt + 1; 1420 } 1421 1422 return performOperation(parseCommandLine()); 1423 } 1424 1425 static int ranlib_main(int argc, char **argv) { 1426 std::vector<StringRef> Archives; 1427 bool HasAIXXOption = false; 1428 1429 for (int i = 1; i < argc; ++i) { 1430 StringRef arg(argv[i]); 1431 if (handleGenericOption(arg)) { 1432 return 0; 1433 } else if (arg.consume_front("-")) { 1434 // Handle the -D/-U flag 1435 while (!arg.empty()) { 1436 if (arg.front() == 'D') { 1437 Deterministic = true; 1438 } else if (arg.front() == 'U') { 1439 Deterministic = false; 1440 } else if (arg.front() == 'h') { 1441 printHelpMessage(); 1442 return 0; 1443 } else if (arg.front() == 'V') { 1444 cl::PrintVersionMessage(); 1445 return 0; 1446 } else if (arg.front() == 'X') { 1447 if (object::Archive::getDefaultKind() == object::Archive::K_AIXBIG) { 1448 HasAIXXOption = true; 1449 arg.consume_front("X"); 1450 const char *Xarg = arg.data(); 1451 if (Xarg[0] == '\0') { 1452 if (argv[i + 1][0] != '-') 1453 BitMode = getBitMode(argv[++i]); 1454 else 1455 BitMode = BitModeTy::Unknown; 1456 } else 1457 BitMode = getBitMode(arg.data()); 1458 1459 if (BitMode == BitModeTy::Unknown) 1460 fail("the specified object mode is not valid. Specify -X32, " 1461 "-X64, -X32_64, or -Xany"); 1462 } else { 1463 fail(Twine("-") + Twine(arg) + 1464 " option not supported on non AIX OS"); 1465 } 1466 break; 1467 } else { 1468 // TODO: GNU ranlib also supports a -t flag 1469 fail("Invalid option: '-" + arg + "'"); 1470 } 1471 arg = arg.drop_front(1); 1472 } 1473 } else { 1474 Archives.push_back(arg); 1475 } 1476 } 1477 1478 if (object::Archive::getDefaultKind() == object::Archive::K_AIXBIG) { 1479 // If not specify -X option, get BitMode from enviorment variable 1480 // "OBJECT_MODE" for AIX OS if specify. 1481 if (!HasAIXXOption) { 1482 if (char *EnvObjectMode = getenv("OBJECT_MODE")) { 1483 BitMode = getBitMode(EnvObjectMode); 1484 if (BitMode == BitModeTy::Unknown) 1485 fail("the OBJECT_MODE environment variable has an invalid value. " 1486 "OBJECT_MODE must be 32, 64, 32_64, or any"); 1487 } 1488 } 1489 1490 switch (BitMode) { 1491 case BitModeTy::Bit32: 1492 Symtab = SymtabWritingMode::BigArchive32; 1493 break; 1494 case BitModeTy::Bit64: 1495 Symtab = SymtabWritingMode::BigArchive64; 1496 break; 1497 default: 1498 Symtab = SymtabWritingMode::NormalSymtab; 1499 break; 1500 } 1501 } 1502 1503 for (StringRef Archive : Archives) { 1504 ArchiveName = Archive.str(); 1505 performOperation(CreateSymTab); 1506 } 1507 if (Archives.empty()) 1508 badUsage("an archive name must be specified"); 1509 return 0; 1510 } 1511 1512 static int llvm_ar_main(int argc, char **argv, const llvm::ToolContext &) { 1513 ToolName = argv[0]; 1514 1515 llvm::InitializeAllTargetInfos(); 1516 llvm::InitializeAllTargetMCs(); 1517 llvm::InitializeAllAsmParsers(); 1518 1519 Stem = sys::path::stem(ToolName); 1520 auto Is = [](StringRef Tool) { 1521 // We need to recognize the following filenames. 1522 // 1523 // Lib.exe -> lib (see D44808, MSBuild runs Lib.exe) 1524 // dlltool.exe -> dlltool 1525 // arm-pokymllib32-linux-gnueabi-llvm-ar-10 -> ar 1526 auto I = Stem.rfind_insensitive(Tool); 1527 return I != StringRef::npos && 1528 (I + Tool.size() == Stem.size() || !isAlnum(Stem[I + Tool.size()])); 1529 }; 1530 1531 if (Is("dlltool")) 1532 return dlltoolDriverMain(ArrayRef(argv, argc)); 1533 if (Is("ranlib")) 1534 return ranlib_main(argc, argv); 1535 if (Is("lib")) 1536 return libDriverMain(ArrayRef(argv, argc)); 1537 if (Is("ar")) 1538 return ar_main(argc, argv); 1539 1540 fail("not ranlib, ar, lib or dlltool"); 1541 } 1542 1543 extern "C" int ZigLlvmAr_main(int, char **); 1544 int ZigLlvmAr_main(int argc, char **argv) { 1545 return llvm_ar_main(argc, argv, {argv[0], nullptr, false}); 1546 } 1547