╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ zig_llvm-ar.cpp ──────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭ find file ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╮ ╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │ │ │http│ ssh │ │ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╯ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
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