xref: /freebsd-src/contrib/llvm-project/llvm/tools/llvm-ar/llvm-ar.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===-- llvm-ar.cpp - LLVM archive librarian utility ----------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // Builds up (relatively) standard unix archive files (.a) containing LLVM
100b57cec5SDimitry Andric // bitcode or other files.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
14480093f4SDimitry Andric #include "llvm/ADT/StringExtras.h"
150b57cec5SDimitry Andric #include "llvm/ADT/StringSwitch.h"
165ffd83dbSDimitry Andric #include "llvm/BinaryFormat/Magic.h"
170b57cec5SDimitry Andric #include "llvm/IR/LLVMContext.h"
180b57cec5SDimitry Andric #include "llvm/Object/Archive.h"
190b57cec5SDimitry Andric #include "llvm/Object/ArchiveWriter.h"
205ffd83dbSDimitry Andric #include "llvm/Object/SymbolicFile.h"
210b57cec5SDimitry Andric #include "llvm/Support/Chrono.h"
220b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h"
235ffd83dbSDimitry Andric #include "llvm/Support/ConvertUTF.h"
240b57cec5SDimitry Andric #include "llvm/Support/Errc.h"
250b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h"
260b57cec5SDimitry Andric #include "llvm/Support/Format.h"
270b57cec5SDimitry Andric #include "llvm/Support/FormatVariadic.h"
2806c3fb27SDimitry Andric #include "llvm/Support/LLVMDriver.h"
290b57cec5SDimitry Andric #include "llvm/Support/LineIterator.h"
300b57cec5SDimitry Andric #include "llvm/Support/MemoryBuffer.h"
310b57cec5SDimitry Andric #include "llvm/Support/Path.h"
320b57cec5SDimitry Andric #include "llvm/Support/Process.h"
330b57cec5SDimitry Andric #include "llvm/Support/StringSaver.h"
340b57cec5SDimitry Andric #include "llvm/Support/TargetSelect.h"
350b57cec5SDimitry Andric #include "llvm/Support/ToolOutputFile.h"
360b57cec5SDimitry Andric #include "llvm/Support/WithColor.h"
370b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
3806c3fb27SDimitry Andric #include "llvm/TargetParser/Host.h"
3906c3fb27SDimitry Andric #include "llvm/TargetParser/Triple.h"
400b57cec5SDimitry Andric #include "llvm/ToolDrivers/llvm-dlltool/DlltoolDriver.h"
410b57cec5SDimitry Andric #include "llvm/ToolDrivers/llvm-lib/LibDriver.h"
420b57cec5SDimitry Andric 
430b57cec5SDimitry Andric #if !defined(_MSC_VER) && !defined(__MINGW32__)
440b57cec5SDimitry Andric #include <unistd.h>
450b57cec5SDimitry Andric #else
460b57cec5SDimitry Andric #include <io.h>
470b57cec5SDimitry Andric #endif
480b57cec5SDimitry Andric 
498bcb0991SDimitry Andric #ifdef _WIN32
508c27c554SDimitry Andric #include "llvm/Support/Windows/WindowsSupport.h"
518bcb0991SDimitry Andric #endif
528bcb0991SDimitry Andric 
530b57cec5SDimitry Andric using namespace llvm;
54fcaf7f86SDimitry Andric using namespace llvm::object;
550b57cec5SDimitry Andric 
560b57cec5SDimitry Andric // The name this program was invoked as.
570b57cec5SDimitry Andric static StringRef ToolName;
580b57cec5SDimitry Andric 
590b57cec5SDimitry Andric // The basename of this program.
600b57cec5SDimitry Andric static StringRef Stem;
610b57cec5SDimitry Andric 
6281ad6265SDimitry Andric static void printRanLibHelp(StringRef ToolName) {
6361cfbce3SDimitry Andric   outs() << "OVERVIEW: LLVM ranlib\n\n"
6461cfbce3SDimitry Andric          << "Generate an index for archives\n\n"
6561cfbce3SDimitry Andric          << "USAGE: " + ToolName + " archive...\n\n"
6681ad6265SDimitry Andric          << "OPTIONS:\n"
6781ad6265SDimitry Andric          << "  -h --help             - Display available options\n"
68*0fca6ea1SDimitry Andric          << "  -V --version          - Display the version of this program\n"
6981ad6265SDimitry Andric          << "  -D                    - Use zero for timestamps and uids/gids "
7081ad6265SDimitry Andric             "(default)\n"
715f757f3fSDimitry Andric          << "  -U                    - Use actual timestamps and uids/gids\n"
725f757f3fSDimitry Andric          << "  -X{32|64|32_64|any}   - Specify which archive symbol tables "
735f757f3fSDimitry Andric             "should be generated if they do not already exist (AIX OS only)\n";
7481ad6265SDimitry Andric }
750b57cec5SDimitry Andric 
7681ad6265SDimitry Andric static void printArHelp(StringRef ToolName) {
7781ad6265SDimitry Andric   const char ArOptions[] =
7881ad6265SDimitry Andric       R"(OPTIONS:
798bcb0991SDimitry Andric   --format              - archive format to create
800b57cec5SDimitry Andric     =default            -   default
810b57cec5SDimitry Andric     =gnu                -   gnu
820b57cec5SDimitry Andric     =darwin             -   darwin
830b57cec5SDimitry Andric     =bsd                -   bsd
84fcaf7f86SDimitry Andric     =bigarchive         -   big archive (AIX OS)
85*0fca6ea1SDimitry Andric     =coff               -   coff
868bcb0991SDimitry Andric   --plugin=<string>     - ignored for compatibility
878bcb0991SDimitry Andric   -h --help             - display this help and exit
8881ad6265SDimitry Andric   --output              - the directory to extract archive members to
895ffd83dbSDimitry Andric   --rsp-quoting         - quoting style for response files
905ffd83dbSDimitry Andric     =posix              -   posix
915ffd83dbSDimitry Andric     =windows            -   windows
921fd87a68SDimitry Andric   --thin                - create a thin archive
938bcb0991SDimitry Andric   --version             - print the version and exit
94fcaf7f86SDimitry Andric   -X{32|64|32_64|any}   - object mode (only for AIX OS)
950b57cec5SDimitry Andric   @<file>               - read options from <file>
960b57cec5SDimitry Andric 
970b57cec5SDimitry Andric OPERATIONS:
980b57cec5SDimitry Andric   d - delete [files] from the archive
990b57cec5SDimitry Andric   m - move [files] in the archive
100349cc55cSDimitry Andric   p - print contents of [files] found in the archive
1010b57cec5SDimitry Andric   q - quick append [files] to the archive
1020b57cec5SDimitry Andric   r - replace or insert [files] into the archive
1030b57cec5SDimitry Andric   s - act as ranlib
104349cc55cSDimitry Andric   t - display list of files in archive
1050b57cec5SDimitry Andric   x - extract [files] from the archive
1060b57cec5SDimitry Andric 
1070b57cec5SDimitry Andric MODIFIERS:
1080b57cec5SDimitry Andric   [a] - put [files] after [relpos]
1090b57cec5SDimitry Andric   [b] - put [files] before [relpos] (same as [i])
1100b57cec5SDimitry Andric   [c] - do not warn if archive had to be created
1110b57cec5SDimitry Andric   [D] - use zero for timestamps and uids/gids (default)
1128bcb0991SDimitry Andric   [h] - display this help and exit
1130b57cec5SDimitry Andric   [i] - put [files] before [relpos] (same as [b])
1140b57cec5SDimitry Andric   [l] - ignored for compatibility
1150b57cec5SDimitry Andric   [L] - add archive's contents
1160b57cec5SDimitry Andric   [N] - use instance [count] of name
1170b57cec5SDimitry Andric   [o] - preserve original dates
1188bcb0991SDimitry Andric   [O] - display member offsets
1190b57cec5SDimitry Andric   [P] - use full names when matching (implied for thin archives)
1200b57cec5SDimitry Andric   [s] - create an archive index (cf. ranlib)
1210b57cec5SDimitry Andric   [S] - do not build a symbol table
1221fd87a68SDimitry Andric   [T] - deprecated, use --thin instead
1230b57cec5SDimitry Andric   [u] - update only [files] newer than archive contents
1240b57cec5SDimitry Andric   [U] - use actual timestamps and uids/gids
1250b57cec5SDimitry Andric   [v] - be verbose about actions taken
1268bcb0991SDimitry Andric   [V] - display the version and exit
1270b57cec5SDimitry Andric )";
1280b57cec5SDimitry Andric 
12981ad6265SDimitry Andric   outs() << "OVERVIEW: LLVM Archiver\n\n"
13081ad6265SDimitry Andric          << "USAGE: " + ToolName +
13181ad6265SDimitry Andric                 " [options] [-]<operation>[modifiers] [relpos] "
13281ad6265SDimitry Andric                 "[count] <archive> [files]\n"
13381ad6265SDimitry Andric          << "       " + ToolName + " -M [<mri-script]\n\n";
13481ad6265SDimitry Andric 
13581ad6265SDimitry Andric   outs() << ArOptions;
13681ad6265SDimitry Andric }
13781ad6265SDimitry Andric 
138e8d8bef9SDimitry Andric static void printHelpMessage() {
139fe6060f1SDimitry Andric   if (Stem.contains_insensitive("ranlib"))
14081ad6265SDimitry Andric     printRanLibHelp(Stem);
141fe6060f1SDimitry Andric   else if (Stem.contains_insensitive("ar"))
14281ad6265SDimitry Andric     printArHelp(Stem);
1430b57cec5SDimitry Andric }
1440b57cec5SDimitry Andric 
1458bcb0991SDimitry Andric static unsigned MRILineNumber;
1468bcb0991SDimitry Andric static bool ParsingMRIScript;
1478bcb0991SDimitry Andric 
148480093f4SDimitry Andric // Show the error plus the usage message, and exit.
149349cc55cSDimitry Andric [[noreturn]] static void badUsage(Twine Error) {
150480093f4SDimitry Andric   WithColor::error(errs(), ToolName) << Error << "\n";
151480093f4SDimitry Andric   printHelpMessage();
152480093f4SDimitry Andric   exit(1);
153480093f4SDimitry Andric }
154480093f4SDimitry Andric 
1550b57cec5SDimitry Andric // Show the error message and exit.
156349cc55cSDimitry Andric [[noreturn]] static void fail(Twine Error) {
1578bcb0991SDimitry Andric   if (ParsingMRIScript) {
1588bcb0991SDimitry Andric     WithColor::error(errs(), ToolName)
1598bcb0991SDimitry Andric         << "script line " << MRILineNumber << ": " << Error << "\n";
1608bcb0991SDimitry Andric   } else {
1618bcb0991SDimitry Andric     WithColor::error(errs(), ToolName) << Error << "\n";
1628bcb0991SDimitry Andric   }
1630b57cec5SDimitry Andric   exit(1);
1640b57cec5SDimitry Andric }
1650b57cec5SDimitry Andric 
1660b57cec5SDimitry Andric static void failIfError(std::error_code EC, Twine Context = "") {
1670b57cec5SDimitry Andric   if (!EC)
1680b57cec5SDimitry Andric     return;
1690b57cec5SDimitry Andric 
1700b57cec5SDimitry Andric   std::string ContextStr = Context.str();
1710b57cec5SDimitry Andric   if (ContextStr.empty())
1720b57cec5SDimitry Andric     fail(EC.message());
1730b57cec5SDimitry Andric   fail(Context + ": " + EC.message());
1740b57cec5SDimitry Andric }
1750b57cec5SDimitry Andric 
1760b57cec5SDimitry Andric static void failIfError(Error E, Twine Context = "") {
1770b57cec5SDimitry Andric   if (!E)
1780b57cec5SDimitry Andric     return;
1790b57cec5SDimitry Andric 
1800b57cec5SDimitry Andric   handleAllErrors(std::move(E), [&](const llvm::ErrorInfoBase &EIB) {
1810b57cec5SDimitry Andric     std::string ContextStr = Context.str();
1820b57cec5SDimitry Andric     if (ContextStr.empty())
1830b57cec5SDimitry Andric       fail(EIB.message());
1840b57cec5SDimitry Andric     fail(Context + ": " + EIB.message());
1850b57cec5SDimitry Andric   });
1860b57cec5SDimitry Andric }
1870b57cec5SDimitry Andric 
188fcaf7f86SDimitry Andric static void warn(Twine Message) {
189fcaf7f86SDimitry Andric   WithColor::warning(errs(), ToolName) << Message << "\n";
190fcaf7f86SDimitry Andric }
191fcaf7f86SDimitry Andric 
1920b57cec5SDimitry Andric static SmallVector<const char *, 256> PositionalArgs;
1930b57cec5SDimitry Andric 
1940b57cec5SDimitry Andric static bool MRI;
1950b57cec5SDimitry Andric 
1960b57cec5SDimitry Andric namespace {
197*0fca6ea1SDimitry Andric enum Format { Default, GNU, COFF, BSD, DARWIN, BIGARCHIVE, Unknown };
1980b57cec5SDimitry Andric }
1990b57cec5SDimitry Andric 
2000b57cec5SDimitry Andric static Format FormatType = Default;
2010b57cec5SDimitry Andric 
2020b57cec5SDimitry Andric static std::string Options;
2030b57cec5SDimitry Andric 
2040b57cec5SDimitry Andric // This enumeration delineates the kinds of operations on an archive
2050b57cec5SDimitry Andric // that are permitted.
2060b57cec5SDimitry Andric enum ArchiveOperation {
2070b57cec5SDimitry Andric   Print,           ///< Print the contents of the archive
2080b57cec5SDimitry Andric   Delete,          ///< Delete the specified members
2090b57cec5SDimitry Andric   Move,            ///< Move members to end or as given by {a,b,i} modifiers
2100b57cec5SDimitry Andric   QuickAppend,     ///< Quickly append to end of archive
2110b57cec5SDimitry Andric   ReplaceOrInsert, ///< Replace or Insert members
2120b57cec5SDimitry Andric   DisplayTable,    ///< Display the table of contents
2130b57cec5SDimitry Andric   Extract,         ///< Extract files back to file system
2140b57cec5SDimitry Andric   CreateSymTab     ///< Create a symbol table in an existing archive
2150b57cec5SDimitry Andric };
2160b57cec5SDimitry Andric 
217fcaf7f86SDimitry Andric enum class BitModeTy { Bit32, Bit64, Bit32_64, Any, Unknown };
218fcaf7f86SDimitry Andric 
219fcaf7f86SDimitry Andric static BitModeTy BitMode = BitModeTy::Bit32;
220fcaf7f86SDimitry Andric 
2210b57cec5SDimitry Andric // Modifiers to follow operation to vary behavior
2220b57cec5SDimitry Andric static bool AddAfter = false;             ///< 'a' modifier
2230b57cec5SDimitry Andric static bool AddBefore = false;            ///< 'b' modifier
2240b57cec5SDimitry Andric static bool Create = false;               ///< 'c' modifier
2250b57cec5SDimitry Andric static bool OriginalDates = false;        ///< 'o' modifier
2268bcb0991SDimitry Andric static bool DisplayMemberOffsets = false; ///< 'O' modifier
2270b57cec5SDimitry Andric static bool CompareFullPath = false;      ///< 'P' modifier
2280b57cec5SDimitry Andric static bool OnlyUpdate = false;           ///< 'u' modifier
2290b57cec5SDimitry Andric static bool Verbose = false;              ///< 'v' modifier
2305f757f3fSDimitry Andric static SymtabWritingMode Symtab =
2315f757f3fSDimitry Andric     SymtabWritingMode::NormalSymtab;      ///< 's' modifier
2320b57cec5SDimitry Andric static bool Deterministic = true;         ///< 'D' and 'U' modifiers
2330b57cec5SDimitry Andric static bool Thin = false;                 ///< 'T' modifier
2340b57cec5SDimitry Andric static bool AddLibrary = false;           ///< 'L' modifier
2350b57cec5SDimitry Andric 
2360b57cec5SDimitry Andric // Relative Positional Argument (for insert/move). This variable holds
2370b57cec5SDimitry Andric // the name of the archive member to which the 'a', 'b' or 'i' modifier
2380b57cec5SDimitry Andric // refers. Only one of 'a', 'b' or 'i' can be specified so we only need
2390b57cec5SDimitry Andric // one variable.
2400b57cec5SDimitry Andric static std::string RelPos;
2410b57cec5SDimitry Andric 
2420b57cec5SDimitry Andric // Count parameter for 'N' modifier. This variable specifies which file should
2430b57cec5SDimitry Andric // match for extract/delete operations when there are multiple matches. This is
2440b57cec5SDimitry Andric // 1-indexed. A value of 0 is invalid, and implies 'N' is not used.
2450b57cec5SDimitry Andric static int CountParam = 0;
2460b57cec5SDimitry Andric 
2470b57cec5SDimitry Andric // This variable holds the name of the archive file as given on the
2480b57cec5SDimitry Andric // command line.
2490b57cec5SDimitry Andric static std::string ArchiveName;
2500b57cec5SDimitry Andric 
25181ad6265SDimitry Andric // Output directory specified by --output.
25281ad6265SDimitry Andric static std::string OutputDir;
25381ad6265SDimitry Andric 
2548bcb0991SDimitry Andric static std::vector<std::unique_ptr<MemoryBuffer>> ArchiveBuffers;
2558bcb0991SDimitry Andric static std::vector<std::unique_ptr<object::Archive>> Archives;
2568bcb0991SDimitry Andric 
2570b57cec5SDimitry Andric // This variable holds the list of member files to proecess, as given
2580b57cec5SDimitry Andric // on the command line.
2590b57cec5SDimitry Andric static std::vector<StringRef> Members;
2600b57cec5SDimitry Andric 
2610b57cec5SDimitry Andric // Static buffer to hold StringRefs.
2620b57cec5SDimitry Andric static BumpPtrAllocator Alloc;
2630b57cec5SDimitry Andric 
2640b57cec5SDimitry Andric // Extract the member filename from the command line for the [relpos] argument
2650b57cec5SDimitry Andric // associated with a, b, and i modifiers
2660b57cec5SDimitry Andric static void getRelPos() {
2670b57cec5SDimitry Andric   if (PositionalArgs.empty())
2688bcb0991SDimitry Andric     fail("expected [relpos] for 'a', 'b', or 'i' modifier");
2690b57cec5SDimitry Andric   RelPos = PositionalArgs[0];
2700b57cec5SDimitry Andric   PositionalArgs.erase(PositionalArgs.begin());
2710b57cec5SDimitry Andric }
2720b57cec5SDimitry Andric 
2730b57cec5SDimitry Andric // Extract the parameter from the command line for the [count] argument
2740b57cec5SDimitry Andric // associated with the N modifier
2750b57cec5SDimitry Andric static void getCountParam() {
2760b57cec5SDimitry Andric   if (PositionalArgs.empty())
277480093f4SDimitry Andric     badUsage("expected [count] for 'N' modifier");
2780b57cec5SDimitry Andric   auto CountParamArg = StringRef(PositionalArgs[0]);
2790b57cec5SDimitry Andric   if (CountParamArg.getAsInteger(10, CountParam))
280480093f4SDimitry Andric     badUsage("value for [count] must be numeric, got: " + CountParamArg);
2810b57cec5SDimitry Andric   if (CountParam < 1)
282480093f4SDimitry Andric     badUsage("value for [count] must be positive, got: " + CountParamArg);
2830b57cec5SDimitry Andric   PositionalArgs.erase(PositionalArgs.begin());
2840b57cec5SDimitry Andric }
2850b57cec5SDimitry Andric 
2860b57cec5SDimitry Andric // Get the archive file name from the command line
2870b57cec5SDimitry Andric static void getArchive() {
2880b57cec5SDimitry Andric   if (PositionalArgs.empty())
289480093f4SDimitry Andric     badUsage("an archive name must be specified");
2900b57cec5SDimitry Andric   ArchiveName = PositionalArgs[0];
2910b57cec5SDimitry Andric   PositionalArgs.erase(PositionalArgs.begin());
2920b57cec5SDimitry Andric }
2930b57cec5SDimitry Andric 
2940b57cec5SDimitry Andric static object::Archive &readLibrary(const Twine &Library) {
295fe6060f1SDimitry Andric   auto BufOrErr = MemoryBuffer::getFile(Library, /*IsText=*/false,
296fe6060f1SDimitry Andric                                         /*RequiresNullTerminator=*/false);
2978bcb0991SDimitry Andric   failIfError(BufOrErr.getError(), "could not open library " + Library);
2980b57cec5SDimitry Andric   ArchiveBuffers.push_back(std::move(*BufOrErr));
2990b57cec5SDimitry Andric   auto LibOrErr =
3000b57cec5SDimitry Andric       object::Archive::create(ArchiveBuffers.back()->getMemBufferRef());
3010b57cec5SDimitry Andric   failIfError(errorToErrorCode(LibOrErr.takeError()),
3028bcb0991SDimitry Andric               "could not parse library");
3030b57cec5SDimitry Andric   Archives.push_back(std::move(*LibOrErr));
3040b57cec5SDimitry Andric   return *Archives.back();
3050b57cec5SDimitry Andric }
3060b57cec5SDimitry Andric 
3070b57cec5SDimitry Andric static void runMRIScript();
3080b57cec5SDimitry Andric 
3090b57cec5SDimitry Andric // Parse the command line options as presented and return the operation
3100b57cec5SDimitry Andric // specified. Process all modifiers and check to make sure that constraints on
3110b57cec5SDimitry Andric // modifier/operation pairs have not been violated.
3120b57cec5SDimitry Andric static ArchiveOperation parseCommandLine() {
3130b57cec5SDimitry Andric   if (MRI) {
3140b57cec5SDimitry Andric     if (!PositionalArgs.empty() || !Options.empty())
315480093f4SDimitry Andric       badUsage("cannot mix -M and other options");
3160b57cec5SDimitry Andric     runMRIScript();
3170b57cec5SDimitry Andric   }
3180b57cec5SDimitry Andric 
3190b57cec5SDimitry Andric   // Keep track of number of operations. We can only specify one
3200b57cec5SDimitry Andric   // per execution.
3210b57cec5SDimitry Andric   unsigned NumOperations = 0;
3220b57cec5SDimitry Andric 
3230b57cec5SDimitry Andric   // Keep track of the number of positional modifiers (a,b,i). Only
3240b57cec5SDimitry Andric   // one can be specified.
3250b57cec5SDimitry Andric   unsigned NumPositional = 0;
3260b57cec5SDimitry Andric 
3270b57cec5SDimitry Andric   // Keep track of which operation was requested
3280b57cec5SDimitry Andric   ArchiveOperation Operation;
3290b57cec5SDimitry Andric 
3300b57cec5SDimitry Andric   bool MaybeJustCreateSymTab = false;
3310b57cec5SDimitry Andric 
3320b57cec5SDimitry Andric   for (unsigned i = 0; i < Options.size(); ++i) {
3330b57cec5SDimitry Andric     switch (Options[i]) {
3340b57cec5SDimitry Andric     case 'd':
3350b57cec5SDimitry Andric       ++NumOperations;
3360b57cec5SDimitry Andric       Operation = Delete;
3370b57cec5SDimitry Andric       break;
3380b57cec5SDimitry Andric     case 'm':
3390b57cec5SDimitry Andric       ++NumOperations;
3400b57cec5SDimitry Andric       Operation = Move;
3410b57cec5SDimitry Andric       break;
3420b57cec5SDimitry Andric     case 'p':
3430b57cec5SDimitry Andric       ++NumOperations;
3440b57cec5SDimitry Andric       Operation = Print;
3450b57cec5SDimitry Andric       break;
3460b57cec5SDimitry Andric     case 'q':
3470b57cec5SDimitry Andric       ++NumOperations;
3480b57cec5SDimitry Andric       Operation = QuickAppend;
3490b57cec5SDimitry Andric       break;
3500b57cec5SDimitry Andric     case 'r':
3510b57cec5SDimitry Andric       ++NumOperations;
3520b57cec5SDimitry Andric       Operation = ReplaceOrInsert;
3530b57cec5SDimitry Andric       break;
3540b57cec5SDimitry Andric     case 't':
3550b57cec5SDimitry Andric       ++NumOperations;
3560b57cec5SDimitry Andric       Operation = DisplayTable;
3570b57cec5SDimitry Andric       break;
3580b57cec5SDimitry Andric     case 'x':
3590b57cec5SDimitry Andric       ++NumOperations;
3600b57cec5SDimitry Andric       Operation = Extract;
3610b57cec5SDimitry Andric       break;
3620b57cec5SDimitry Andric     case 'c':
3630b57cec5SDimitry Andric       Create = true;
3640b57cec5SDimitry Andric       break;
3650b57cec5SDimitry Andric     case 'l': /* accepted but unused */
3660b57cec5SDimitry Andric       break;
3670b57cec5SDimitry Andric     case 'o':
3680b57cec5SDimitry Andric       OriginalDates = true;
3690b57cec5SDimitry Andric       break;
3708bcb0991SDimitry Andric     case 'O':
3718bcb0991SDimitry Andric       DisplayMemberOffsets = true;
3728bcb0991SDimitry Andric       break;
3730b57cec5SDimitry Andric     case 'P':
3740b57cec5SDimitry Andric       CompareFullPath = true;
3750b57cec5SDimitry Andric       break;
3760b57cec5SDimitry Andric     case 's':
3775f757f3fSDimitry Andric       Symtab = SymtabWritingMode::NormalSymtab;
3780b57cec5SDimitry Andric       MaybeJustCreateSymTab = true;
3790b57cec5SDimitry Andric       break;
3800b57cec5SDimitry Andric     case 'S':
3815f757f3fSDimitry Andric       Symtab = SymtabWritingMode::NoSymtab;
3820b57cec5SDimitry Andric       break;
3830b57cec5SDimitry Andric     case 'u':
3840b57cec5SDimitry Andric       OnlyUpdate = true;
3850b57cec5SDimitry Andric       break;
3860b57cec5SDimitry Andric     case 'v':
3870b57cec5SDimitry Andric       Verbose = true;
3880b57cec5SDimitry Andric       break;
3890b57cec5SDimitry Andric     case 'a':
3900b57cec5SDimitry Andric       getRelPos();
3910b57cec5SDimitry Andric       AddAfter = true;
3920b57cec5SDimitry Andric       NumPositional++;
3930b57cec5SDimitry Andric       break;
3940b57cec5SDimitry Andric     case 'b':
3950b57cec5SDimitry Andric       getRelPos();
3960b57cec5SDimitry Andric       AddBefore = true;
3970b57cec5SDimitry Andric       NumPositional++;
3980b57cec5SDimitry Andric       break;
3990b57cec5SDimitry Andric     case 'i':
4000b57cec5SDimitry Andric       getRelPos();
4010b57cec5SDimitry Andric       AddBefore = true;
4020b57cec5SDimitry Andric       NumPositional++;
4030b57cec5SDimitry Andric       break;
4040b57cec5SDimitry Andric     case 'D':
4050b57cec5SDimitry Andric       Deterministic = true;
4060b57cec5SDimitry Andric       break;
4070b57cec5SDimitry Andric     case 'U':
4080b57cec5SDimitry Andric       Deterministic = false;
4090b57cec5SDimitry Andric       break;
4100b57cec5SDimitry Andric     case 'N':
4110b57cec5SDimitry Andric       getCountParam();
4120b57cec5SDimitry Andric       break;
4130b57cec5SDimitry Andric     case 'T':
4140b57cec5SDimitry Andric       Thin = true;
4150b57cec5SDimitry Andric       break;
4160b57cec5SDimitry Andric     case 'L':
4170b57cec5SDimitry Andric       AddLibrary = true;
4180b57cec5SDimitry Andric       break;
4198bcb0991SDimitry Andric     case 'V':
4208bcb0991SDimitry Andric       cl::PrintVersionMessage();
4218bcb0991SDimitry Andric       exit(0);
4228bcb0991SDimitry Andric     case 'h':
4238bcb0991SDimitry Andric       printHelpMessage();
4248bcb0991SDimitry Andric       exit(0);
4250b57cec5SDimitry Andric     default:
426480093f4SDimitry Andric       badUsage(std::string("unknown option ") + Options[i]);
4270b57cec5SDimitry Andric     }
4280b57cec5SDimitry Andric   }
4290b57cec5SDimitry Andric 
4301fd87a68SDimitry Andric   // Thin archives store path names, so P should be forced.
4311fd87a68SDimitry Andric   if (Thin)
4321fd87a68SDimitry Andric     CompareFullPath = true;
4331fd87a68SDimitry Andric 
4340b57cec5SDimitry Andric   // At this point, the next thing on the command line must be
4350b57cec5SDimitry Andric   // the archive name.
4360b57cec5SDimitry Andric   getArchive();
4370b57cec5SDimitry Andric 
4380b57cec5SDimitry Andric   // Everything on the command line at this point is a member.
4398bcb0991SDimitry Andric   Members.assign(PositionalArgs.begin(), PositionalArgs.end());
4400b57cec5SDimitry Andric 
4410b57cec5SDimitry Andric   if (NumOperations == 0 && MaybeJustCreateSymTab) {
4420b57cec5SDimitry Andric     NumOperations = 1;
4430b57cec5SDimitry Andric     Operation = CreateSymTab;
4440b57cec5SDimitry Andric     if (!Members.empty())
445480093f4SDimitry Andric       badUsage("the 's' operation takes only an archive as argument");
4460b57cec5SDimitry Andric   }
4470b57cec5SDimitry Andric 
4480b57cec5SDimitry Andric   // Perform various checks on the operation/modifier specification
4490b57cec5SDimitry Andric   // to make sure we are dealing with a legal request.
4500b57cec5SDimitry Andric   if (NumOperations == 0)
451480093f4SDimitry Andric     badUsage("you must specify at least one of the operations");
4520b57cec5SDimitry Andric   if (NumOperations > 1)
453480093f4SDimitry Andric     badUsage("only one operation may be specified");
4540b57cec5SDimitry Andric   if (NumPositional > 1)
455480093f4SDimitry Andric     badUsage("you may only specify one of 'a', 'b', and 'i' modifiers");
4560b57cec5SDimitry Andric   if (AddAfter || AddBefore)
4570b57cec5SDimitry Andric     if (Operation != Move && Operation != ReplaceOrInsert)
458480093f4SDimitry Andric       badUsage("the 'a', 'b' and 'i' modifiers can only be specified with "
4590b57cec5SDimitry Andric                "the 'm' or 'r' operations");
4600b57cec5SDimitry Andric   if (CountParam)
4610b57cec5SDimitry Andric     if (Operation != Extract && Operation != Delete)
462480093f4SDimitry Andric       badUsage("the 'N' modifier can only be specified with the 'x' or 'd' "
4630b57cec5SDimitry Andric                "operations");
4640b57cec5SDimitry Andric   if (OriginalDates && Operation != Extract)
465480093f4SDimitry Andric     badUsage("the 'o' modifier is only applicable to the 'x' operation");
4660b57cec5SDimitry Andric   if (OnlyUpdate && Operation != ReplaceOrInsert)
467480093f4SDimitry Andric     badUsage("the 'u' modifier is only applicable to the 'r' operation");
4680b57cec5SDimitry Andric   if (AddLibrary && Operation != QuickAppend)
469480093f4SDimitry Andric     badUsage("the 'L' modifier is only applicable to the 'q' operation");
4700b57cec5SDimitry Andric 
47181ad6265SDimitry Andric   if (!OutputDir.empty()) {
47281ad6265SDimitry Andric     if (Operation != Extract)
47381ad6265SDimitry Andric       badUsage("--output is only applicable to the 'x' operation");
47481ad6265SDimitry Andric     bool IsDir = false;
47581ad6265SDimitry Andric     // If OutputDir is not a directory, create_directories may still succeed if
47681ad6265SDimitry Andric     // all components of the path prefix are directories. Test is_directory as
47781ad6265SDimitry Andric     // well.
47881ad6265SDimitry Andric     if (!sys::fs::create_directories(OutputDir))
47981ad6265SDimitry Andric       sys::fs::is_directory(OutputDir, IsDir);
48081ad6265SDimitry Andric     if (!IsDir)
48181ad6265SDimitry Andric       fail("'" + OutputDir + "' is not a directory");
48281ad6265SDimitry Andric   }
48381ad6265SDimitry Andric 
4840b57cec5SDimitry Andric   // Return the parsed operation to the caller
4850b57cec5SDimitry Andric   return Operation;
4860b57cec5SDimitry Andric }
4870b57cec5SDimitry Andric 
4880b57cec5SDimitry Andric // Implements the 'p' operation. This function traverses the archive
4890b57cec5SDimitry Andric // looking for members that match the path list.
4900b57cec5SDimitry Andric static void doPrint(StringRef Name, const object::Archive::Child &C) {
4910b57cec5SDimitry Andric   if (Verbose)
4920b57cec5SDimitry Andric     outs() << "Printing " << Name << "\n";
4930b57cec5SDimitry Andric 
4940b57cec5SDimitry Andric   Expected<StringRef> DataOrErr = C.getBuffer();
4950b57cec5SDimitry Andric   failIfError(DataOrErr.takeError());
4960b57cec5SDimitry Andric   StringRef Data = *DataOrErr;
4970b57cec5SDimitry Andric   outs().write(Data.data(), Data.size());
4980b57cec5SDimitry Andric }
4990b57cec5SDimitry Andric 
5000b57cec5SDimitry Andric // Utility function for printing out the file mode when the 't' operation is in
5010b57cec5SDimitry Andric // verbose mode.
5020b57cec5SDimitry Andric static void printMode(unsigned mode) {
5030b57cec5SDimitry Andric   outs() << ((mode & 004) ? "r" : "-");
5040b57cec5SDimitry Andric   outs() << ((mode & 002) ? "w" : "-");
5050b57cec5SDimitry Andric   outs() << ((mode & 001) ? "x" : "-");
5060b57cec5SDimitry Andric }
5070b57cec5SDimitry Andric 
5080b57cec5SDimitry Andric // Implement the 't' operation. This function prints out just
5090b57cec5SDimitry Andric // the file names of each of the members. However, if verbose mode is requested
5100b57cec5SDimitry Andric // ('v' modifier) then the file type, permission mode, user, group, size, and
5110b57cec5SDimitry Andric // modification time are also printed.
5120b57cec5SDimitry Andric static void doDisplayTable(StringRef Name, const object::Archive::Child &C) {
5130b57cec5SDimitry Andric   if (Verbose) {
5140b57cec5SDimitry Andric     Expected<sys::fs::perms> ModeOrErr = C.getAccessMode();
5150b57cec5SDimitry Andric     failIfError(ModeOrErr.takeError());
5160b57cec5SDimitry Andric     sys::fs::perms Mode = ModeOrErr.get();
5170b57cec5SDimitry Andric     printMode((Mode >> 6) & 007);
5180b57cec5SDimitry Andric     printMode((Mode >> 3) & 007);
5190b57cec5SDimitry Andric     printMode(Mode & 007);
5200b57cec5SDimitry Andric     Expected<unsigned> UIDOrErr = C.getUID();
5210b57cec5SDimitry Andric     failIfError(UIDOrErr.takeError());
5220b57cec5SDimitry Andric     outs() << ' ' << UIDOrErr.get();
5230b57cec5SDimitry Andric     Expected<unsigned> GIDOrErr = C.getGID();
5240b57cec5SDimitry Andric     failIfError(GIDOrErr.takeError());
5250b57cec5SDimitry Andric     outs() << '/' << GIDOrErr.get();
5260b57cec5SDimitry Andric     Expected<uint64_t> Size = C.getSize();
5270b57cec5SDimitry Andric     failIfError(Size.takeError());
5280b57cec5SDimitry Andric     outs() << ' ' << format("%6llu", Size.get());
5290b57cec5SDimitry Andric     auto ModTimeOrErr = C.getLastModified();
5300b57cec5SDimitry Andric     failIfError(ModTimeOrErr.takeError());
5310b57cec5SDimitry Andric     // Note: formatv() only handles the default TimePoint<>, which is in
5320b57cec5SDimitry Andric     // nanoseconds.
5330b57cec5SDimitry Andric     // TODO: fix format_provider<TimePoint<>> to allow other units.
5340b57cec5SDimitry Andric     sys::TimePoint<> ModTimeInNs = ModTimeOrErr.get();
5350b57cec5SDimitry Andric     outs() << ' ' << formatv("{0:%b %e %H:%M %Y}", ModTimeInNs);
5360b57cec5SDimitry Andric     outs() << ' ';
5370b57cec5SDimitry Andric   }
5380b57cec5SDimitry Andric 
5390b57cec5SDimitry Andric   if (C.getParent()->isThin()) {
5400b57cec5SDimitry Andric     if (!sys::path::is_absolute(Name)) {
5410b57cec5SDimitry Andric       StringRef ParentDir = sys::path::parent_path(ArchiveName);
5420b57cec5SDimitry Andric       if (!ParentDir.empty())
5430b57cec5SDimitry Andric         outs() << sys::path::convert_to_slash(ParentDir) << '/';
5440b57cec5SDimitry Andric     }
5458bcb0991SDimitry Andric     outs() << Name;
5468bcb0991SDimitry Andric   } else {
5478bcb0991SDimitry Andric     outs() << Name;
5488bcb0991SDimitry Andric     if (DisplayMemberOffsets)
5498bcb0991SDimitry Andric       outs() << " 0x" << utohexstr(C.getDataOffset(), true);
5500b57cec5SDimitry Andric   }
5518bcb0991SDimitry Andric   outs() << '\n';
5520b57cec5SDimitry Andric }
5530b57cec5SDimitry Andric 
5548bcb0991SDimitry Andric static std::string normalizePath(StringRef Path) {
5558bcb0991SDimitry Andric   return CompareFullPath ? sys::path::convert_to_slash(Path)
5568bcb0991SDimitry Andric                          : std::string(sys::path::filename(Path));
5578bcb0991SDimitry Andric }
5588bcb0991SDimitry Andric 
5598bcb0991SDimitry Andric static bool comparePaths(StringRef Path1, StringRef Path2) {
5608bcb0991SDimitry Andric // When on Windows this function calls CompareStringOrdinal
5618bcb0991SDimitry Andric // as Windows file paths are case-insensitive.
5628bcb0991SDimitry Andric // CompareStringOrdinal compares two Unicode strings for
5638bcb0991SDimitry Andric // binary equivalence and allows for case insensitivity.
5648bcb0991SDimitry Andric #ifdef _WIN32
5658bcb0991SDimitry Andric   SmallVector<wchar_t, 128> WPath1, WPath2;
5665ffd83dbSDimitry Andric   failIfError(sys::windows::UTF8ToUTF16(normalizePath(Path1), WPath1));
5675ffd83dbSDimitry Andric   failIfError(sys::windows::UTF8ToUTF16(normalizePath(Path2), WPath2));
5688bcb0991SDimitry Andric 
5698bcb0991SDimitry Andric   return CompareStringOrdinal(WPath1.data(), WPath1.size(), WPath2.data(),
5708bcb0991SDimitry Andric                               WPath2.size(), true) == CSTR_EQUAL;
5718bcb0991SDimitry Andric #else
5728bcb0991SDimitry Andric   return normalizePath(Path1) == normalizePath(Path2);
5738bcb0991SDimitry Andric #endif
5740b57cec5SDimitry Andric }
5750b57cec5SDimitry Andric 
5760b57cec5SDimitry Andric // Implement the 'x' operation. This function extracts files back to the file
5770b57cec5SDimitry Andric // system.
5780b57cec5SDimitry Andric static void doExtract(StringRef Name, const object::Archive::Child &C) {
5790b57cec5SDimitry Andric   // Retain the original mode.
5800b57cec5SDimitry Andric   Expected<sys::fs::perms> ModeOrErr = C.getAccessMode();
5810b57cec5SDimitry Andric   failIfError(ModeOrErr.takeError());
5820b57cec5SDimitry Andric   sys::fs::perms Mode = ModeOrErr.get();
5830b57cec5SDimitry Andric 
58481ad6265SDimitry Andric   StringRef outputFilePath;
58581ad6265SDimitry Andric   SmallString<128> path;
58681ad6265SDimitry Andric   if (OutputDir.empty()) {
58781ad6265SDimitry Andric     outputFilePath = sys::path::filename(Name);
58881ad6265SDimitry Andric   } else {
58981ad6265SDimitry Andric     sys::path::append(path, OutputDir, sys::path::filename(Name));
59081ad6265SDimitry Andric     outputFilePath = path.str();
59181ad6265SDimitry Andric   }
59281ad6265SDimitry Andric 
593480093f4SDimitry Andric   if (Verbose)
594480093f4SDimitry Andric     outs() << "x - " << outputFilePath << '\n';
595480093f4SDimitry Andric 
5960b57cec5SDimitry Andric   int FD;
597480093f4SDimitry Andric   failIfError(sys::fs::openFileForWrite(outputFilePath, FD,
5980b57cec5SDimitry Andric                                         sys::fs::CD_CreateAlways,
5998bcb0991SDimitry Andric                                         sys::fs::OF_None, Mode),
6000b57cec5SDimitry Andric               Name);
6010b57cec5SDimitry Andric 
6020b57cec5SDimitry Andric   {
6030b57cec5SDimitry Andric     raw_fd_ostream file(FD, false);
6040b57cec5SDimitry Andric 
6050b57cec5SDimitry Andric     // Get the data and its length
6060b57cec5SDimitry Andric     Expected<StringRef> BufOrErr = C.getBuffer();
6070b57cec5SDimitry Andric     failIfError(BufOrErr.takeError());
6080b57cec5SDimitry Andric     StringRef Data = BufOrErr.get();
6090b57cec5SDimitry Andric 
6100b57cec5SDimitry Andric     // Write the data.
6110b57cec5SDimitry Andric     file.write(Data.data(), Data.size());
6120b57cec5SDimitry Andric   }
6130b57cec5SDimitry Andric 
6140b57cec5SDimitry Andric   // If we're supposed to retain the original modification times, etc. do so
6150b57cec5SDimitry Andric   // now.
6160b57cec5SDimitry Andric   if (OriginalDates) {
6170b57cec5SDimitry Andric     auto ModTimeOrErr = C.getLastModified();
6180b57cec5SDimitry Andric     failIfError(ModTimeOrErr.takeError());
6190b57cec5SDimitry Andric     failIfError(
6200b57cec5SDimitry Andric         sys::fs::setLastAccessAndModificationTime(FD, ModTimeOrErr.get()));
6210b57cec5SDimitry Andric   }
6220b57cec5SDimitry Andric 
6230b57cec5SDimitry Andric   if (close(FD))
6240b57cec5SDimitry Andric     fail("Could not close the file");
6250b57cec5SDimitry Andric }
6260b57cec5SDimitry Andric 
6270b57cec5SDimitry Andric static bool shouldCreateArchive(ArchiveOperation Op) {
6280b57cec5SDimitry Andric   switch (Op) {
6290b57cec5SDimitry Andric   case Print:
6300b57cec5SDimitry Andric   case Delete:
6310b57cec5SDimitry Andric   case Move:
6320b57cec5SDimitry Andric   case DisplayTable:
6330b57cec5SDimitry Andric   case Extract:
6340b57cec5SDimitry Andric   case CreateSymTab:
6350b57cec5SDimitry Andric     return false;
6360b57cec5SDimitry Andric 
6370b57cec5SDimitry Andric   case QuickAppend:
6380b57cec5SDimitry Andric   case ReplaceOrInsert:
6390b57cec5SDimitry Andric     return true;
6400b57cec5SDimitry Andric   }
6410b57cec5SDimitry Andric 
6420b57cec5SDimitry Andric   llvm_unreachable("Missing entry in covered switch.");
6430b57cec5SDimitry Andric }
6440b57cec5SDimitry Andric 
645fcaf7f86SDimitry Andric static bool isValidInBitMode(Binary &Bin) {
646fcaf7f86SDimitry Andric   if (BitMode == BitModeTy::Bit32_64 || BitMode == BitModeTy::Any)
647fcaf7f86SDimitry Andric     return true;
648fcaf7f86SDimitry Andric 
649fcaf7f86SDimitry Andric   if (SymbolicFile *SymFile = dyn_cast<SymbolicFile>(&Bin)) {
65006c3fb27SDimitry Andric     bool Is64Bit = SymFile->is64Bit();
651fcaf7f86SDimitry Andric     if ((Is64Bit && (BitMode == BitModeTy::Bit32)) ||
652fcaf7f86SDimitry Andric         (!Is64Bit && (BitMode == BitModeTy::Bit64)))
653fcaf7f86SDimitry Andric       return false;
654fcaf7f86SDimitry Andric   }
655fcaf7f86SDimitry Andric   // In AIX "ar", non-object files are always considered to have a valid bit
656fcaf7f86SDimitry Andric   // mode.
657fcaf7f86SDimitry Andric   return true;
658fcaf7f86SDimitry Andric }
659fcaf7f86SDimitry Andric 
660fcaf7f86SDimitry Andric Expected<std::unique_ptr<Binary>> getAsBinary(const NewArchiveMember &NM,
661fcaf7f86SDimitry Andric                                               LLVMContext *Context) {
662fcaf7f86SDimitry Andric   auto BinaryOrErr = createBinary(NM.Buf->getMemBufferRef(), Context);
663fcaf7f86SDimitry Andric   if (BinaryOrErr)
664fcaf7f86SDimitry Andric     return std::move(*BinaryOrErr);
665fcaf7f86SDimitry Andric   return BinaryOrErr.takeError();
666fcaf7f86SDimitry Andric }
667fcaf7f86SDimitry Andric 
668fcaf7f86SDimitry Andric Expected<std::unique_ptr<Binary>> getAsBinary(const Archive::Child &C,
669fcaf7f86SDimitry Andric                                               LLVMContext *Context) {
670fcaf7f86SDimitry Andric   return C.getAsBinary(Context);
671fcaf7f86SDimitry Andric }
672fcaf7f86SDimitry Andric 
673fcaf7f86SDimitry Andric template <class A> static bool isValidInBitMode(const A &Member) {
674*0fca6ea1SDimitry Andric   if (object::Archive::getDefaultKind() != object::Archive::K_AIXBIG)
675fcaf7f86SDimitry Andric     return true;
676fcaf7f86SDimitry Andric   LLVMContext Context;
677fcaf7f86SDimitry Andric   Expected<std::unique_ptr<Binary>> BinOrErr = getAsBinary(Member, &Context);
678fcaf7f86SDimitry Andric   // In AIX "ar", if there is a non-object file member, it is never ignored due
679fcaf7f86SDimitry Andric   // to the bit mode setting.
680fcaf7f86SDimitry Andric   if (!BinOrErr) {
681fcaf7f86SDimitry Andric     consumeError(BinOrErr.takeError());
682fcaf7f86SDimitry Andric     return true;
683fcaf7f86SDimitry Andric   }
684fcaf7f86SDimitry Andric   return isValidInBitMode(*BinOrErr.get());
685fcaf7f86SDimitry Andric }
686fcaf7f86SDimitry Andric 
687fcaf7f86SDimitry Andric static void warnInvalidObjectForFileMode(Twine Name) {
688fcaf7f86SDimitry Andric   warn("'" + Name + "' is not valid with the current object file mode");
689fcaf7f86SDimitry Andric }
690fcaf7f86SDimitry Andric 
6910b57cec5SDimitry Andric static void performReadOperation(ArchiveOperation Operation,
6920b57cec5SDimitry Andric                                  object::Archive *OldArchive) {
6930b57cec5SDimitry Andric   if (Operation == Extract && OldArchive->isThin())
6940b57cec5SDimitry Andric     fail("extracting from a thin archive is not supported");
6950b57cec5SDimitry Andric 
6960b57cec5SDimitry Andric   bool Filter = !Members.empty();
6970b57cec5SDimitry Andric   StringMap<int> MemberCount;
6980b57cec5SDimitry Andric   {
6990b57cec5SDimitry Andric     Error Err = Error::success();
7000b57cec5SDimitry Andric     for (auto &C : OldArchive->children(Err)) {
7010b57cec5SDimitry Andric       Expected<StringRef> NameOrErr = C.getName();
7020b57cec5SDimitry Andric       failIfError(NameOrErr.takeError());
7030b57cec5SDimitry Andric       StringRef Name = NameOrErr.get();
7040b57cec5SDimitry Andric 
705fcaf7f86SDimitry Andric       // Check whether to ignore this object due to its bitness.
706fcaf7f86SDimitry Andric       if (!isValidInBitMode(C))
707fcaf7f86SDimitry Andric         continue;
708fcaf7f86SDimitry Andric 
7090b57cec5SDimitry Andric       if (Filter) {
7100b57cec5SDimitry Andric         auto I = find_if(Members, [Name](StringRef Path) {
7118bcb0991SDimitry Andric           return comparePaths(Name, Path);
7120b57cec5SDimitry Andric         });
7130b57cec5SDimitry Andric         if (I == Members.end())
7140b57cec5SDimitry Andric           continue;
7150b57cec5SDimitry Andric         if (CountParam && ++MemberCount[Name] != CountParam)
7160b57cec5SDimitry Andric           continue;
7170b57cec5SDimitry Andric         Members.erase(I);
7180b57cec5SDimitry Andric       }
7190b57cec5SDimitry Andric 
7200b57cec5SDimitry Andric       switch (Operation) {
7210b57cec5SDimitry Andric       default:
7220b57cec5SDimitry Andric         llvm_unreachable("Not a read operation");
7230b57cec5SDimitry Andric       case Print:
7240b57cec5SDimitry Andric         doPrint(Name, C);
7250b57cec5SDimitry Andric         break;
7260b57cec5SDimitry Andric       case DisplayTable:
7270b57cec5SDimitry Andric         doDisplayTable(Name, C);
7280b57cec5SDimitry Andric         break;
7290b57cec5SDimitry Andric       case Extract:
7300b57cec5SDimitry Andric         doExtract(Name, C);
7310b57cec5SDimitry Andric         break;
7320b57cec5SDimitry Andric       }
7330b57cec5SDimitry Andric     }
7340b57cec5SDimitry Andric     failIfError(std::move(Err));
7350b57cec5SDimitry Andric   }
7360b57cec5SDimitry Andric 
7370b57cec5SDimitry Andric   if (Members.empty())
7380b57cec5SDimitry Andric     return;
7390b57cec5SDimitry Andric   for (StringRef Name : Members)
7400b57cec5SDimitry Andric     WithColor::error(errs(), ToolName) << "'" << Name << "' was not found\n";
7410b57cec5SDimitry Andric   exit(1);
7420b57cec5SDimitry Andric }
7430b57cec5SDimitry Andric 
7440b57cec5SDimitry Andric static void addChildMember(std::vector<NewArchiveMember> &Members,
7450b57cec5SDimitry Andric                            const object::Archive::Child &M,
7460b57cec5SDimitry Andric                            bool FlattenArchive = false) {
7470b57cec5SDimitry Andric   Expected<NewArchiveMember> NMOrErr =
7480b57cec5SDimitry Andric       NewArchiveMember::getOldMember(M, Deterministic);
7490b57cec5SDimitry Andric   failIfError(NMOrErr.takeError());
7500b57cec5SDimitry Andric   // If the child member we're trying to add is thin, use the path relative to
7510b57cec5SDimitry Andric   // the archive it's in, so the file resolves correctly.
7520b57cec5SDimitry Andric   if (Thin && FlattenArchive) {
7530b57cec5SDimitry Andric     StringSaver Saver(Alloc);
7545ffd83dbSDimitry Andric     Expected<std::string> FileNameOrErr(M.getName());
7550b57cec5SDimitry Andric     failIfError(FileNameOrErr.takeError());
7560b57cec5SDimitry Andric     if (sys::path::is_absolute(*FileNameOrErr)) {
7570b57cec5SDimitry Andric       NMOrErr->MemberName = Saver.save(sys::path::convert_to_slash(*FileNameOrErr));
7580b57cec5SDimitry Andric     } else {
7590b57cec5SDimitry Andric       FileNameOrErr = M.getFullName();
7600b57cec5SDimitry Andric       failIfError(FileNameOrErr.takeError());
7610b57cec5SDimitry Andric       Expected<std::string> PathOrErr =
7620b57cec5SDimitry Andric           computeArchiveRelativePath(ArchiveName, *FileNameOrErr);
7630b57cec5SDimitry Andric       NMOrErr->MemberName = Saver.save(
7640b57cec5SDimitry Andric           PathOrErr ? *PathOrErr : sys::path::convert_to_slash(*FileNameOrErr));
7650b57cec5SDimitry Andric     }
7660b57cec5SDimitry Andric   }
7670b57cec5SDimitry Andric   if (FlattenArchive &&
7680b57cec5SDimitry Andric       identify_magic(NMOrErr->Buf->getBuffer()) == file_magic::archive) {
7690b57cec5SDimitry Andric     Expected<std::string> FileNameOrErr = M.getFullName();
7700b57cec5SDimitry Andric     failIfError(FileNameOrErr.takeError());
7710b57cec5SDimitry Andric     object::Archive &Lib = readLibrary(*FileNameOrErr);
7720b57cec5SDimitry Andric     // When creating thin archives, only flatten if the member is also thin.
7730b57cec5SDimitry Andric     if (!Thin || Lib.isThin()) {
7740b57cec5SDimitry Andric       Error Err = Error::success();
7750b57cec5SDimitry Andric       // Only Thin archives are recursively flattened.
7760b57cec5SDimitry Andric       for (auto &Child : Lib.children(Err))
7770b57cec5SDimitry Andric         addChildMember(Members, Child, /*FlattenArchive=*/Thin);
7780b57cec5SDimitry Andric       failIfError(std::move(Err));
7790b57cec5SDimitry Andric       return;
7800b57cec5SDimitry Andric     }
7810b57cec5SDimitry Andric   }
7820b57cec5SDimitry Andric   Members.push_back(std::move(*NMOrErr));
7830b57cec5SDimitry Andric }
7840b57cec5SDimitry Andric 
785fcaf7f86SDimitry Andric static NewArchiveMember getArchiveMember(StringRef FileName) {
7860b57cec5SDimitry Andric   Expected<NewArchiveMember> NMOrErr =
7870b57cec5SDimitry Andric       NewArchiveMember::getFile(FileName, Deterministic);
7880b57cec5SDimitry Andric   failIfError(NMOrErr.takeError(), FileName);
7890b57cec5SDimitry Andric   StringSaver Saver(Alloc);
7900b57cec5SDimitry Andric   // For regular archives, use the basename of the object path for the member
7910b57cec5SDimitry Andric   // name. For thin archives, use the full relative paths so the file resolves
7920b57cec5SDimitry Andric   // correctly.
7930b57cec5SDimitry Andric   if (!Thin) {
7940b57cec5SDimitry Andric     NMOrErr->MemberName = sys::path::filename(NMOrErr->MemberName);
7950b57cec5SDimitry Andric   } else {
7960b57cec5SDimitry Andric     if (sys::path::is_absolute(FileName))
7970b57cec5SDimitry Andric       NMOrErr->MemberName = Saver.save(sys::path::convert_to_slash(FileName));
7980b57cec5SDimitry Andric     else {
7990b57cec5SDimitry Andric       Expected<std::string> PathOrErr =
8000b57cec5SDimitry Andric           computeArchiveRelativePath(ArchiveName, FileName);
8010b57cec5SDimitry Andric       NMOrErr->MemberName = Saver.save(
8020b57cec5SDimitry Andric           PathOrErr ? *PathOrErr : sys::path::convert_to_slash(FileName));
8030b57cec5SDimitry Andric     }
8040b57cec5SDimitry Andric   }
805fcaf7f86SDimitry Andric   return std::move(*NMOrErr);
806fcaf7f86SDimitry Andric }
807fcaf7f86SDimitry Andric 
808fcaf7f86SDimitry Andric static void addMember(std::vector<NewArchiveMember> &Members,
809fcaf7f86SDimitry Andric                       NewArchiveMember &NM) {
810fcaf7f86SDimitry Andric   Members.push_back(std::move(NM));
811fcaf7f86SDimitry Andric }
812fcaf7f86SDimitry Andric 
813fcaf7f86SDimitry Andric static void addMember(std::vector<NewArchiveMember> &Members,
814fcaf7f86SDimitry Andric                       StringRef FileName, bool FlattenArchive = false) {
815fcaf7f86SDimitry Andric   NewArchiveMember NM = getArchiveMember(FileName);
816fcaf7f86SDimitry Andric   if (!isValidInBitMode(NM)) {
817fcaf7f86SDimitry Andric     warnInvalidObjectForFileMode(FileName);
818fcaf7f86SDimitry Andric     return;
819fcaf7f86SDimitry Andric   }
8200b57cec5SDimitry Andric 
8210b57cec5SDimitry Andric   if (FlattenArchive &&
822fcaf7f86SDimitry Andric       identify_magic(NM.Buf->getBuffer()) == file_magic::archive) {
8230b57cec5SDimitry Andric     object::Archive &Lib = readLibrary(FileName);
8240b57cec5SDimitry Andric     // When creating thin archives, only flatten if the member is also thin.
8250b57cec5SDimitry Andric     if (!Thin || Lib.isThin()) {
8260b57cec5SDimitry Andric       Error Err = Error::success();
8270b57cec5SDimitry Andric       // Only Thin archives are recursively flattened.
8280b57cec5SDimitry Andric       for (auto &Child : Lib.children(Err))
8290b57cec5SDimitry Andric         addChildMember(Members, Child, /*FlattenArchive=*/Thin);
8300b57cec5SDimitry Andric       failIfError(std::move(Err));
8310b57cec5SDimitry Andric       return;
8320b57cec5SDimitry Andric     }
8330b57cec5SDimitry Andric   }
834fcaf7f86SDimitry Andric   Members.push_back(std::move(NM));
8350b57cec5SDimitry Andric }
8360b57cec5SDimitry Andric 
8370b57cec5SDimitry Andric enum InsertAction {
8380b57cec5SDimitry Andric   IA_AddOldMember,
8390b57cec5SDimitry Andric   IA_AddNewMember,
8400b57cec5SDimitry Andric   IA_Delete,
8410b57cec5SDimitry Andric   IA_MoveOldMember,
8420b57cec5SDimitry Andric   IA_MoveNewMember
8430b57cec5SDimitry Andric };
8440b57cec5SDimitry Andric 
8450b57cec5SDimitry Andric static InsertAction computeInsertAction(ArchiveOperation Operation,
8460b57cec5SDimitry Andric                                         const object::Archive::Child &Member,
8470b57cec5SDimitry Andric                                         StringRef Name,
8480b57cec5SDimitry Andric                                         std::vector<StringRef>::iterator &Pos,
8490b57cec5SDimitry Andric                                         StringMap<int> &MemberCount) {
850fcaf7f86SDimitry Andric   if (!isValidInBitMode(Member))
851fcaf7f86SDimitry Andric     return IA_AddOldMember;
852fcaf7f86SDimitry Andric 
8530b57cec5SDimitry Andric   if (Operation == QuickAppend || Members.empty())
8540b57cec5SDimitry Andric     return IA_AddOldMember;
855bdd1243dSDimitry Andric 
856bdd1243dSDimitry Andric   auto MI = find_if(Members, [Name](StringRef Path) {
857bdd1243dSDimitry Andric     if (Thin && !sys::path::is_absolute(Path)) {
858bdd1243dSDimitry Andric       Expected<std::string> PathOrErr =
859bdd1243dSDimitry Andric           computeArchiveRelativePath(ArchiveName, Path);
860bdd1243dSDimitry Andric       return comparePaths(Name, PathOrErr ? *PathOrErr : Path);
861bdd1243dSDimitry Andric     } else {
862bdd1243dSDimitry Andric       return comparePaths(Name, Path);
863bdd1243dSDimitry Andric     }
864bdd1243dSDimitry Andric   });
8650b57cec5SDimitry Andric 
8660b57cec5SDimitry Andric   if (MI == Members.end())
8670b57cec5SDimitry Andric     return IA_AddOldMember;
8680b57cec5SDimitry Andric 
8690b57cec5SDimitry Andric   Pos = MI;
8700b57cec5SDimitry Andric 
8710b57cec5SDimitry Andric   if (Operation == Delete) {
8720b57cec5SDimitry Andric     if (CountParam && ++MemberCount[Name] != CountParam)
8730b57cec5SDimitry Andric       return IA_AddOldMember;
8740b57cec5SDimitry Andric     return IA_Delete;
8750b57cec5SDimitry Andric   }
8760b57cec5SDimitry Andric 
8770b57cec5SDimitry Andric   if (Operation == Move)
8780b57cec5SDimitry Andric     return IA_MoveOldMember;
8790b57cec5SDimitry Andric 
8800b57cec5SDimitry Andric   if (Operation == ReplaceOrInsert) {
8810b57cec5SDimitry Andric     if (!OnlyUpdate) {
8828bcb0991SDimitry Andric       if (RelPos.empty())
8830b57cec5SDimitry Andric         return IA_AddNewMember;
8840b57cec5SDimitry Andric       return IA_MoveNewMember;
8850b57cec5SDimitry Andric     }
8860b57cec5SDimitry Andric 
8870b57cec5SDimitry Andric     // We could try to optimize this to a fstat, but it is not a common
8880b57cec5SDimitry Andric     // operation.
8890b57cec5SDimitry Andric     sys::fs::file_status Status;
8900b57cec5SDimitry Andric     failIfError(sys::fs::status(*MI, Status), *MI);
8910b57cec5SDimitry Andric     auto ModTimeOrErr = Member.getLastModified();
8920b57cec5SDimitry Andric     failIfError(ModTimeOrErr.takeError());
8930b57cec5SDimitry Andric     if (Status.getLastModificationTime() < ModTimeOrErr.get()) {
8948bcb0991SDimitry Andric       if (RelPos.empty())
8950b57cec5SDimitry Andric         return IA_AddOldMember;
8960b57cec5SDimitry Andric       return IA_MoveOldMember;
8970b57cec5SDimitry Andric     }
8980b57cec5SDimitry Andric 
8998bcb0991SDimitry Andric     if (RelPos.empty())
9000b57cec5SDimitry Andric       return IA_AddNewMember;
9010b57cec5SDimitry Andric     return IA_MoveNewMember;
9020b57cec5SDimitry Andric   }
9030b57cec5SDimitry Andric   llvm_unreachable("No such operation");
9040b57cec5SDimitry Andric }
9050b57cec5SDimitry Andric 
9060b57cec5SDimitry Andric // We have to walk this twice and computing it is not trivial, so creating an
9070b57cec5SDimitry Andric // explicit std::vector is actually fairly efficient.
9080b57cec5SDimitry Andric static std::vector<NewArchiveMember>
9090b57cec5SDimitry Andric computeNewArchiveMembers(ArchiveOperation Operation,
9100b57cec5SDimitry Andric                          object::Archive *OldArchive) {
9110b57cec5SDimitry Andric   std::vector<NewArchiveMember> Ret;
9120b57cec5SDimitry Andric   std::vector<NewArchiveMember> Moved;
9130b57cec5SDimitry Andric   int InsertPos = -1;
9140b57cec5SDimitry Andric   if (OldArchive) {
9150b57cec5SDimitry Andric     Error Err = Error::success();
9160b57cec5SDimitry Andric     StringMap<int> MemberCount;
9170b57cec5SDimitry Andric     for (auto &Child : OldArchive->children(Err)) {
9180b57cec5SDimitry Andric       int Pos = Ret.size();
9190b57cec5SDimitry Andric       Expected<StringRef> NameOrErr = Child.getName();
9200b57cec5SDimitry Andric       failIfError(NameOrErr.takeError());
9215ffd83dbSDimitry Andric       std::string Name = std::string(NameOrErr.get());
922fcaf7f86SDimitry Andric       if (comparePaths(Name, RelPos) && isValidInBitMode(Child)) {
9230b57cec5SDimitry Andric         assert(AddAfter || AddBefore);
9240b57cec5SDimitry Andric         if (AddBefore)
9250b57cec5SDimitry Andric           InsertPos = Pos;
9260b57cec5SDimitry Andric         else
9270b57cec5SDimitry Andric           InsertPos = Pos + 1;
9280b57cec5SDimitry Andric       }
9290b57cec5SDimitry Andric 
9300b57cec5SDimitry Andric       std::vector<StringRef>::iterator MemberI = Members.end();
9310b57cec5SDimitry Andric       InsertAction Action =
9320b57cec5SDimitry Andric           computeInsertAction(Operation, Child, Name, MemberI, MemberCount);
933fcaf7f86SDimitry Andric 
934fcaf7f86SDimitry Andric       auto HandleNewMember = [](auto Member, auto &Members, auto &Child) {
935fcaf7f86SDimitry Andric         NewArchiveMember NM = getArchiveMember(*Member);
936fcaf7f86SDimitry Andric         if (isValidInBitMode(NM))
937fcaf7f86SDimitry Andric           addMember(Members, NM);
938fcaf7f86SDimitry Andric         else {
939fcaf7f86SDimitry Andric           // If a new member is not a valid object for the bit mode, add
940fcaf7f86SDimitry Andric           // the old member back.
941fcaf7f86SDimitry Andric           warnInvalidObjectForFileMode(*Member);
942fcaf7f86SDimitry Andric           addChildMember(Members, Child, /*FlattenArchive=*/Thin);
943fcaf7f86SDimitry Andric         }
944fcaf7f86SDimitry Andric       };
945fcaf7f86SDimitry Andric 
9460b57cec5SDimitry Andric       switch (Action) {
9470b57cec5SDimitry Andric       case IA_AddOldMember:
9480b57cec5SDimitry Andric         addChildMember(Ret, Child, /*FlattenArchive=*/Thin);
9490b57cec5SDimitry Andric         break;
9500b57cec5SDimitry Andric       case IA_AddNewMember:
951fcaf7f86SDimitry Andric         HandleNewMember(MemberI, Ret, Child);
9520b57cec5SDimitry Andric         break;
9530b57cec5SDimitry Andric       case IA_Delete:
9540b57cec5SDimitry Andric         break;
9550b57cec5SDimitry Andric       case IA_MoveOldMember:
9560b57cec5SDimitry Andric         addChildMember(Moved, Child, /*FlattenArchive=*/Thin);
9570b57cec5SDimitry Andric         break;
9580b57cec5SDimitry Andric       case IA_MoveNewMember:
959fcaf7f86SDimitry Andric         HandleNewMember(MemberI, Moved, Child);
9600b57cec5SDimitry Andric         break;
9610b57cec5SDimitry Andric       }
9620b57cec5SDimitry Andric       // When processing elements with the count param, we need to preserve the
9630b57cec5SDimitry Andric       // full members list when iterating over all archive members. For
9640b57cec5SDimitry Andric       // instance, "llvm-ar dN 2 archive.a member.o" should delete the second
9650b57cec5SDimitry Andric       // file named member.o it sees; we are not done with member.o the first
9660b57cec5SDimitry Andric       // time we see it in the archive.
9670b57cec5SDimitry Andric       if (MemberI != Members.end() && !CountParam)
9680b57cec5SDimitry Andric         Members.erase(MemberI);
9690b57cec5SDimitry Andric     }
9700b57cec5SDimitry Andric     failIfError(std::move(Err));
9710b57cec5SDimitry Andric   }
9720b57cec5SDimitry Andric 
9730b57cec5SDimitry Andric   if (Operation == Delete)
9740b57cec5SDimitry Andric     return Ret;
9750b57cec5SDimitry Andric 
9760b57cec5SDimitry Andric   if (!RelPos.empty() && InsertPos == -1)
9778bcb0991SDimitry Andric     fail("insertion point not found");
9780b57cec5SDimitry Andric 
9790b57cec5SDimitry Andric   if (RelPos.empty())
9800b57cec5SDimitry Andric     InsertPos = Ret.size();
9810b57cec5SDimitry Andric 
9820b57cec5SDimitry Andric   assert(unsigned(InsertPos) <= Ret.size());
9830b57cec5SDimitry Andric   int Pos = InsertPos;
9840b57cec5SDimitry Andric   for (auto &M : Moved) {
9850b57cec5SDimitry Andric     Ret.insert(Ret.begin() + Pos, std::move(M));
9860b57cec5SDimitry Andric     ++Pos;
9870b57cec5SDimitry Andric   }
9880b57cec5SDimitry Andric 
9890b57cec5SDimitry Andric   if (AddLibrary) {
9900b57cec5SDimitry Andric     assert(Operation == QuickAppend);
9910b57cec5SDimitry Andric     for (auto &Member : Members)
9920b57cec5SDimitry Andric       addMember(Ret, Member, /*FlattenArchive=*/true);
9930b57cec5SDimitry Andric     return Ret;
9940b57cec5SDimitry Andric   }
9950b57cec5SDimitry Andric 
9960b57cec5SDimitry Andric   std::vector<NewArchiveMember> NewMembers;
9970b57cec5SDimitry Andric   for (auto &Member : Members)
9980b57cec5SDimitry Andric     addMember(NewMembers, Member, /*FlattenArchive=*/Thin);
9990b57cec5SDimitry Andric   Ret.reserve(Ret.size() + NewMembers.size());
10000b57cec5SDimitry Andric   std::move(NewMembers.begin(), NewMembers.end(),
10010b57cec5SDimitry Andric             std::inserter(Ret, std::next(Ret.begin(), InsertPos)));
10020b57cec5SDimitry Andric 
10030b57cec5SDimitry Andric   return Ret;
10040b57cec5SDimitry Andric }
10050b57cec5SDimitry Andric 
10060b57cec5SDimitry Andric static void performWriteOperation(ArchiveOperation Operation,
10070b57cec5SDimitry Andric                                   object::Archive *OldArchive,
10080b57cec5SDimitry Andric                                   std::unique_ptr<MemoryBuffer> OldArchiveBuf,
10090b57cec5SDimitry Andric                                   std::vector<NewArchiveMember> *NewMembersP) {
101081ad6265SDimitry Andric   if (OldArchive) {
101181ad6265SDimitry Andric     if (Thin && !OldArchive->isThin())
101281ad6265SDimitry Andric       fail("cannot convert a regular archive to a thin one");
101381ad6265SDimitry Andric 
101481ad6265SDimitry Andric     if (OldArchive->isThin())
101581ad6265SDimitry Andric       Thin = true;
101681ad6265SDimitry Andric   }
101781ad6265SDimitry Andric 
10180b57cec5SDimitry Andric   std::vector<NewArchiveMember> NewMembers;
10190b57cec5SDimitry Andric   if (!NewMembersP)
10200b57cec5SDimitry Andric     NewMembers = computeNewArchiveMembers(Operation, OldArchive);
10210b57cec5SDimitry Andric 
10220b57cec5SDimitry Andric   object::Archive::Kind Kind;
10230b57cec5SDimitry Andric   switch (FormatType) {
10240b57cec5SDimitry Andric   case Default:
10250b57cec5SDimitry Andric     if (Thin)
10260b57cec5SDimitry Andric       Kind = object::Archive::K_GNU;
102781ad6265SDimitry Andric     else if (OldArchive) {
10280b57cec5SDimitry Andric       Kind = OldArchive->kind();
1029*0fca6ea1SDimitry Andric       std::optional<object::Archive::Kind> AltKind;
1030*0fca6ea1SDimitry Andric       if (Kind == object::Archive::K_BSD)
1031*0fca6ea1SDimitry Andric         AltKind = object::Archive::K_DARWIN;
1032*0fca6ea1SDimitry Andric       else if (Kind == object::Archive::K_GNU && !OldArchive->hasSymbolTable())
1033*0fca6ea1SDimitry Andric         // If there is no symbol table, we can't tell GNU from COFF format
1034*0fca6ea1SDimitry Andric         // from the old archive type.
1035*0fca6ea1SDimitry Andric         AltKind = object::Archive::K_COFF;
1036*0fca6ea1SDimitry Andric       if (AltKind) {
1037*0fca6ea1SDimitry Andric         auto InferredKind = Kind;
103881ad6265SDimitry Andric         if (NewMembersP && !NewMembersP->empty())
103981ad6265SDimitry Andric           InferredKind = NewMembersP->front().detectKindFromObject();
104081ad6265SDimitry Andric         else if (!NewMembers.empty())
104181ad6265SDimitry Andric           InferredKind = NewMembers.front().detectKindFromObject();
1042*0fca6ea1SDimitry Andric         if (InferredKind == AltKind)
1043*0fca6ea1SDimitry Andric           Kind = *AltKind;
104481ad6265SDimitry Andric       }
104581ad6265SDimitry Andric     } else if (NewMembersP)
104681ad6265SDimitry Andric       Kind = !NewMembersP->empty() ? NewMembersP->front().detectKindFromObject()
1047*0fca6ea1SDimitry Andric                                    : object::Archive::getDefaultKind();
10480b57cec5SDimitry Andric     else
104981ad6265SDimitry Andric       Kind = !NewMembers.empty() ? NewMembers.front().detectKindFromObject()
1050*0fca6ea1SDimitry Andric                                  : object::Archive::getDefaultKind();
10510b57cec5SDimitry Andric     break;
10520b57cec5SDimitry Andric   case GNU:
10530b57cec5SDimitry Andric     Kind = object::Archive::K_GNU;
10540b57cec5SDimitry Andric     break;
1055*0fca6ea1SDimitry Andric   case COFF:
1056*0fca6ea1SDimitry Andric     Kind = object::Archive::K_COFF;
1057*0fca6ea1SDimitry Andric     break;
10580b57cec5SDimitry Andric   case BSD:
10590b57cec5SDimitry Andric     if (Thin)
10608bcb0991SDimitry Andric       fail("only the gnu format has a thin mode");
10610b57cec5SDimitry Andric     Kind = object::Archive::K_BSD;
10620b57cec5SDimitry Andric     break;
10630b57cec5SDimitry Andric   case DARWIN:
10640b57cec5SDimitry Andric     if (Thin)
10658bcb0991SDimitry Andric       fail("only the gnu format has a thin mode");
10660b57cec5SDimitry Andric     Kind = object::Archive::K_DARWIN;
10670b57cec5SDimitry Andric     break;
106881ad6265SDimitry Andric   case BIGARCHIVE:
106981ad6265SDimitry Andric     if (Thin)
107081ad6265SDimitry Andric       fail("only the gnu format has a thin mode");
107181ad6265SDimitry Andric     Kind = object::Archive::K_AIXBIG;
107281ad6265SDimitry Andric     break;
10730b57cec5SDimitry Andric   case Unknown:
10740b57cec5SDimitry Andric     llvm_unreachable("");
10750b57cec5SDimitry Andric   }
10760b57cec5SDimitry Andric 
10770b57cec5SDimitry Andric   Error E =
10780b57cec5SDimitry Andric       writeArchive(ArchiveName, NewMembersP ? *NewMembersP : NewMembers, Symtab,
10790b57cec5SDimitry Andric                    Kind, Deterministic, Thin, std::move(OldArchiveBuf));
10800b57cec5SDimitry Andric   failIfError(std::move(E), ArchiveName);
10810b57cec5SDimitry Andric }
10820b57cec5SDimitry Andric 
10830b57cec5SDimitry Andric static void createSymbolTable(object::Archive *OldArchive) {
10840b57cec5SDimitry Andric   // When an archive is created or modified, if the s option is given, the
10850b57cec5SDimitry Andric   // resulting archive will have a current symbol table. If the S option
10860b57cec5SDimitry Andric   // is given, it will have no symbol table.
10870b57cec5SDimitry Andric   // In summary, we only need to update the symbol table if we have none.
10880b57cec5SDimitry Andric   // This is actually very common because of broken build systems that think
10890b57cec5SDimitry Andric   // they have to run ranlib.
10905f757f3fSDimitry Andric   if (OldArchive->hasSymbolTable()) {
10915f757f3fSDimitry Andric     if (OldArchive->kind() != object::Archive::K_AIXBIG)
10920b57cec5SDimitry Andric       return;
10930b57cec5SDimitry Andric 
10945f757f3fSDimitry Andric     // For archives in the Big Archive format, the bit mode option specifies
10955f757f3fSDimitry Andric     // which symbol table to generate. The presence of a symbol table that does
10965f757f3fSDimitry Andric     // not match the specified bit mode does not prevent creation of the symbol
10975f757f3fSDimitry Andric     // table that has been requested.
10985f757f3fSDimitry Andric     if (OldArchive->kind() == object::Archive::K_AIXBIG) {
10995f757f3fSDimitry Andric       BigArchive *BigArc = dyn_cast<BigArchive>(OldArchive);
11005f757f3fSDimitry Andric       if (BigArc->has32BitGlobalSymtab() &&
11015f757f3fSDimitry Andric           Symtab == SymtabWritingMode::BigArchive32)
11025f757f3fSDimitry Andric         return;
11035f757f3fSDimitry Andric 
11045f757f3fSDimitry Andric       if (BigArc->has64BitGlobalSymtab() &&
11055f757f3fSDimitry Andric           Symtab == SymtabWritingMode::BigArchive64)
11065f757f3fSDimitry Andric         return;
11075f757f3fSDimitry Andric 
11085f757f3fSDimitry Andric       if (BigArc->has32BitGlobalSymtab() && BigArc->has64BitGlobalSymtab() &&
11095f757f3fSDimitry Andric           Symtab == SymtabWritingMode::NormalSymtab)
11105f757f3fSDimitry Andric         return;
11115f757f3fSDimitry Andric 
11125f757f3fSDimitry Andric       Symtab = SymtabWritingMode::NormalSymtab;
11135f757f3fSDimitry Andric     }
11145f757f3fSDimitry Andric   }
11151fd87a68SDimitry Andric   if (OldArchive->isThin())
11161fd87a68SDimitry Andric     Thin = true;
11170b57cec5SDimitry Andric   performWriteOperation(CreateSymTab, OldArchive, nullptr, nullptr);
11180b57cec5SDimitry Andric }
11190b57cec5SDimitry Andric 
11200b57cec5SDimitry Andric static void performOperation(ArchiveOperation Operation,
11210b57cec5SDimitry Andric                              object::Archive *OldArchive,
11220b57cec5SDimitry Andric                              std::unique_ptr<MemoryBuffer> OldArchiveBuf,
11230b57cec5SDimitry Andric                              std::vector<NewArchiveMember> *NewMembers) {
11240b57cec5SDimitry Andric   switch (Operation) {
11250b57cec5SDimitry Andric   case Print:
11260b57cec5SDimitry Andric   case DisplayTable:
11270b57cec5SDimitry Andric   case Extract:
11280b57cec5SDimitry Andric     performReadOperation(Operation, OldArchive);
11290b57cec5SDimitry Andric     return;
11300b57cec5SDimitry Andric 
11310b57cec5SDimitry Andric   case Delete:
11320b57cec5SDimitry Andric   case Move:
11330b57cec5SDimitry Andric   case QuickAppend:
11340b57cec5SDimitry Andric   case ReplaceOrInsert:
11350b57cec5SDimitry Andric     performWriteOperation(Operation, OldArchive, std::move(OldArchiveBuf),
11360b57cec5SDimitry Andric                           NewMembers);
11370b57cec5SDimitry Andric     return;
11380b57cec5SDimitry Andric   case CreateSymTab:
11390b57cec5SDimitry Andric     createSymbolTable(OldArchive);
11400b57cec5SDimitry Andric     return;
11410b57cec5SDimitry Andric   }
11420b57cec5SDimitry Andric   llvm_unreachable("Unknown operation.");
11430b57cec5SDimitry Andric }
11440b57cec5SDimitry Andric 
114561cfbce3SDimitry Andric static int performOperation(ArchiveOperation Operation) {
11460b57cec5SDimitry Andric   // Create or open the archive object.
1147fe6060f1SDimitry Andric   ErrorOr<std::unique_ptr<MemoryBuffer>> Buf = MemoryBuffer::getFile(
1148fe6060f1SDimitry Andric       ArchiveName, /*IsText=*/false, /*RequiresNullTerminator=*/false);
11490b57cec5SDimitry Andric   std::error_code EC = Buf.getError();
11500b57cec5SDimitry Andric   if (EC && EC != errc::no_such_file_or_directory)
11515ffd83dbSDimitry Andric     fail("unable to open '" + ArchiveName + "': " + EC.message());
11520b57cec5SDimitry Andric 
11530b57cec5SDimitry Andric   if (!EC) {
115404eeddc0SDimitry Andric     Expected<std::unique_ptr<object::Archive>> ArchiveOrError =
115504eeddc0SDimitry Andric         object::Archive::create(Buf.get()->getMemBufferRef());
115604eeddc0SDimitry Andric     if (!ArchiveOrError)
115704eeddc0SDimitry Andric       failIfError(ArchiveOrError.takeError(),
115804eeddc0SDimitry Andric                   "unable to load '" + ArchiveName + "'");
115904eeddc0SDimitry Andric 
116004eeddc0SDimitry Andric     std::unique_ptr<object::Archive> Archive = std::move(ArchiveOrError.get());
116104eeddc0SDimitry Andric     if (Archive->isThin())
11620b57cec5SDimitry Andric       CompareFullPath = true;
116304eeddc0SDimitry Andric     performOperation(Operation, Archive.get(), std::move(Buf.get()),
116461cfbce3SDimitry Andric                      /*NewMembers=*/nullptr);
11650b57cec5SDimitry Andric     return 0;
11660b57cec5SDimitry Andric   }
11670b57cec5SDimitry Andric 
11680b57cec5SDimitry Andric   assert(EC == errc::no_such_file_or_directory);
11690b57cec5SDimitry Andric 
11700b57cec5SDimitry Andric   if (!shouldCreateArchive(Operation)) {
11715ffd83dbSDimitry Andric     failIfError(EC, Twine("unable to load '") + ArchiveName + "'");
11720b57cec5SDimitry Andric   } else {
11730b57cec5SDimitry Andric     if (!Create) {
11740b57cec5SDimitry Andric       // Produce a warning if we should and we're creating the archive
1175fcaf7f86SDimitry Andric       warn("creating " + ArchiveName);
11760b57cec5SDimitry Andric     }
11770b57cec5SDimitry Andric   }
11780b57cec5SDimitry Andric 
117961cfbce3SDimitry Andric   performOperation(Operation, nullptr, nullptr, /*NewMembers=*/nullptr);
11800b57cec5SDimitry Andric   return 0;
11810b57cec5SDimitry Andric }
11820b57cec5SDimitry Andric 
11830b57cec5SDimitry Andric static void runMRIScript() {
11840b57cec5SDimitry Andric   enum class MRICommand { AddLib, AddMod, Create, CreateThin, Delete, Save, End, Invalid };
11850b57cec5SDimitry Andric 
11860b57cec5SDimitry Andric   ErrorOr<std::unique_ptr<MemoryBuffer>> Buf = MemoryBuffer::getSTDIN();
11870b57cec5SDimitry Andric   failIfError(Buf.getError());
11880b57cec5SDimitry Andric   const MemoryBuffer &Ref = *Buf.get();
11890b57cec5SDimitry Andric   bool Saved = false;
11900b57cec5SDimitry Andric   std::vector<NewArchiveMember> NewMembers;
11918bcb0991SDimitry Andric   ParsingMRIScript = true;
11920b57cec5SDimitry Andric 
11930b57cec5SDimitry Andric   for (line_iterator I(Ref, /*SkipBlanks*/ false), E; I != E; ++I) {
11948bcb0991SDimitry Andric     ++MRILineNumber;
11950b57cec5SDimitry Andric     StringRef Line = *I;
11960b57cec5SDimitry Andric     Line = Line.split(';').first;
11970b57cec5SDimitry Andric     Line = Line.split('*').first;
11980b57cec5SDimitry Andric     Line = Line.trim();
11990b57cec5SDimitry Andric     if (Line.empty())
12000b57cec5SDimitry Andric       continue;
12010b57cec5SDimitry Andric     StringRef CommandStr, Rest;
12020b57cec5SDimitry Andric     std::tie(CommandStr, Rest) = Line.split(' ');
12030b57cec5SDimitry Andric     Rest = Rest.trim();
12040b57cec5SDimitry Andric     if (!Rest.empty() && Rest.front() == '"' && Rest.back() == '"')
12050b57cec5SDimitry Andric       Rest = Rest.drop_front().drop_back();
12060b57cec5SDimitry Andric     auto Command = StringSwitch<MRICommand>(CommandStr.lower())
12070b57cec5SDimitry Andric                        .Case("addlib", MRICommand::AddLib)
12080b57cec5SDimitry Andric                        .Case("addmod", MRICommand::AddMod)
12090b57cec5SDimitry Andric                        .Case("create", MRICommand::Create)
12100b57cec5SDimitry Andric                        .Case("createthin", MRICommand::CreateThin)
12110b57cec5SDimitry Andric                        .Case("delete", MRICommand::Delete)
12120b57cec5SDimitry Andric                        .Case("save", MRICommand::Save)
12130b57cec5SDimitry Andric                        .Case("end", MRICommand::End)
12140b57cec5SDimitry Andric                        .Default(MRICommand::Invalid);
12150b57cec5SDimitry Andric 
12160b57cec5SDimitry Andric     switch (Command) {
12170b57cec5SDimitry Andric     case MRICommand::AddLib: {
121881ad6265SDimitry Andric       if (!Create)
121981ad6265SDimitry Andric         fail("no output archive has been opened");
12200b57cec5SDimitry Andric       object::Archive &Lib = readLibrary(Rest);
12210b57cec5SDimitry Andric       {
122281ad6265SDimitry Andric         if (Thin && !Lib.isThin())
122381ad6265SDimitry Andric           fail("cannot add a regular archive's contents to a thin archive");
12240b57cec5SDimitry Andric         Error Err = Error::success();
12250b57cec5SDimitry Andric         for (auto &Member : Lib.children(Err))
12260b57cec5SDimitry Andric           addChildMember(NewMembers, Member, /*FlattenArchive=*/Thin);
12270b57cec5SDimitry Andric         failIfError(std::move(Err));
12280b57cec5SDimitry Andric       }
12290b57cec5SDimitry Andric       break;
12300b57cec5SDimitry Andric     }
12310b57cec5SDimitry Andric     case MRICommand::AddMod:
123281ad6265SDimitry Andric       if (!Create)
123381ad6265SDimitry Andric         fail("no output archive has been opened");
12340b57cec5SDimitry Andric       addMember(NewMembers, Rest);
12350b57cec5SDimitry Andric       break;
12360b57cec5SDimitry Andric     case MRICommand::CreateThin:
12370b57cec5SDimitry Andric       Thin = true;
1238bdd1243dSDimitry Andric       [[fallthrough]];
12390b57cec5SDimitry Andric     case MRICommand::Create:
12400b57cec5SDimitry Andric       Create = true;
12410b57cec5SDimitry Andric       if (!ArchiveName.empty())
12428bcb0991SDimitry Andric         fail("editing multiple archives not supported");
12430b57cec5SDimitry Andric       if (Saved)
12448bcb0991SDimitry Andric         fail("file already saved");
12455ffd83dbSDimitry Andric       ArchiveName = std::string(Rest);
124681ad6265SDimitry Andric       if (ArchiveName.empty())
124781ad6265SDimitry Andric         fail("missing archive name");
12480b57cec5SDimitry Andric       break;
12490b57cec5SDimitry Andric     case MRICommand::Delete: {
12508bcb0991SDimitry Andric       llvm::erase_if(NewMembers, [=](NewArchiveMember &M) {
12518bcb0991SDimitry Andric         return comparePaths(M.MemberName, Rest);
12528bcb0991SDimitry Andric       });
12530b57cec5SDimitry Andric       break;
12540b57cec5SDimitry Andric     }
12550b57cec5SDimitry Andric     case MRICommand::Save:
12560b57cec5SDimitry Andric       Saved = true;
12570b57cec5SDimitry Andric       break;
12580b57cec5SDimitry Andric     case MRICommand::End:
12590b57cec5SDimitry Andric       break;
12600b57cec5SDimitry Andric     case MRICommand::Invalid:
12618bcb0991SDimitry Andric       fail("unknown command: " + CommandStr);
12620b57cec5SDimitry Andric     }
12630b57cec5SDimitry Andric   }
12640b57cec5SDimitry Andric 
12658bcb0991SDimitry Andric   ParsingMRIScript = false;
12668bcb0991SDimitry Andric 
12670b57cec5SDimitry Andric   // Nothing to do if not saved.
12680b57cec5SDimitry Andric   if (Saved)
126981ad6265SDimitry Andric     performOperation(ReplaceOrInsert, /*OldArchive=*/nullptr,
127081ad6265SDimitry Andric                      /*OldArchiveBuf=*/nullptr, &NewMembers);
12710b57cec5SDimitry Andric   exit(0);
12720b57cec5SDimitry Andric }
12730b57cec5SDimitry Andric 
12740b57cec5SDimitry Andric static bool handleGenericOption(StringRef arg) {
127504eeddc0SDimitry Andric   if (arg == "--help" || arg == "-h") {
12760b57cec5SDimitry Andric     printHelpMessage();
12770b57cec5SDimitry Andric     return true;
12780b57cec5SDimitry Andric   }
127904eeddc0SDimitry Andric   if (arg == "--version") {
12800b57cec5SDimitry Andric     cl::PrintVersionMessage();
12810b57cec5SDimitry Andric     return true;
12820b57cec5SDimitry Andric   }
12830b57cec5SDimitry Andric   return false;
12840b57cec5SDimitry Andric }
12850b57cec5SDimitry Andric 
1286fcaf7f86SDimitry Andric static BitModeTy getBitMode(const char *RawBitMode) {
1287fcaf7f86SDimitry Andric   return StringSwitch<BitModeTy>(RawBitMode)
1288fcaf7f86SDimitry Andric       .Case("32", BitModeTy::Bit32)
1289fcaf7f86SDimitry Andric       .Case("64", BitModeTy::Bit64)
1290fcaf7f86SDimitry Andric       .Case("32_64", BitModeTy::Bit32_64)
1291fcaf7f86SDimitry Andric       .Case("any", BitModeTy::Any)
1292fcaf7f86SDimitry Andric       .Default(BitModeTy::Unknown);
1293fcaf7f86SDimitry Andric }
1294fcaf7f86SDimitry Andric 
12955ffd83dbSDimitry Andric static const char *matchFlagWithArg(StringRef Expected,
12965ffd83dbSDimitry Andric                                     ArrayRef<const char *>::iterator &ArgIt,
12975ffd83dbSDimitry Andric                                     ArrayRef<const char *> Args) {
12985ffd83dbSDimitry Andric   StringRef Arg = *ArgIt;
12995ffd83dbSDimitry Andric 
1300647cbc5dSDimitry Andric   Arg.consume_front("--");
13015ffd83dbSDimitry Andric 
13025ffd83dbSDimitry Andric   size_t len = Expected.size();
13035ffd83dbSDimitry Andric   if (Arg == Expected) {
13045ffd83dbSDimitry Andric     if (++ArgIt == Args.end())
13055ffd83dbSDimitry Andric       fail(std::string(Expected) + " requires an argument");
13065ffd83dbSDimitry Andric 
13075ffd83dbSDimitry Andric     return *ArgIt;
13085ffd83dbSDimitry Andric   }
13095f757f3fSDimitry Andric   if (Arg.starts_with(Expected) && Arg.size() > len && Arg[len] == '=')
13105ffd83dbSDimitry Andric     return Arg.data() + len + 1;
13115ffd83dbSDimitry Andric 
13125ffd83dbSDimitry Andric   return nullptr;
13135ffd83dbSDimitry Andric }
13145ffd83dbSDimitry Andric 
13155ffd83dbSDimitry Andric static cl::TokenizerCallback getRspQuoting(ArrayRef<const char *> ArgsArr) {
13165ffd83dbSDimitry Andric   cl::TokenizerCallback Ret =
13175ffd83dbSDimitry Andric       Triple(sys::getProcessTriple()).getOS() == Triple::Win32
13185ffd83dbSDimitry Andric           ? cl::TokenizeWindowsCommandLine
13195ffd83dbSDimitry Andric           : cl::TokenizeGNUCommandLine;
13205ffd83dbSDimitry Andric 
13215ffd83dbSDimitry Andric   for (ArrayRef<const char *>::iterator ArgIt = ArgsArr.begin();
13225ffd83dbSDimitry Andric        ArgIt != ArgsArr.end(); ++ArgIt) {
13235ffd83dbSDimitry Andric     if (const char *Match = matchFlagWithArg("rsp-quoting", ArgIt, ArgsArr)) {
13245ffd83dbSDimitry Andric       StringRef MatchRef = Match;
13255ffd83dbSDimitry Andric       if (MatchRef == "posix")
13265ffd83dbSDimitry Andric         Ret = cl::TokenizeGNUCommandLine;
13275ffd83dbSDimitry Andric       else if (MatchRef == "windows")
13285ffd83dbSDimitry Andric         Ret = cl::TokenizeWindowsCommandLine;
13295ffd83dbSDimitry Andric       else
13305ffd83dbSDimitry Andric         fail(std::string("Invalid response file quoting style ") + Match);
13315ffd83dbSDimitry Andric     }
13325ffd83dbSDimitry Andric   }
13335ffd83dbSDimitry Andric 
13345ffd83dbSDimitry Andric   return Ret;
13355ffd83dbSDimitry Andric }
13365ffd83dbSDimitry Andric 
13370b57cec5SDimitry Andric static int ar_main(int argc, char **argv) {
13385ffd83dbSDimitry Andric   SmallVector<const char *, 0> Argv(argv + 1, argv + argc);
13390b57cec5SDimitry Andric   StringSaver Saver(Alloc);
13405ffd83dbSDimitry Andric 
1341bdd1243dSDimitry Andric   cl::ExpandResponseFiles(Saver, getRspQuoting(ArrayRef(argv, argc)), Argv);
13425ffd83dbSDimitry Andric 
1343fcaf7f86SDimitry Andric   // Get BitMode from enviorment variable "OBJECT_MODE" for AIX OS, if
1344fcaf7f86SDimitry Andric   // specified.
1345*0fca6ea1SDimitry Andric   if (object::Archive::getDefaultKind() == object::Archive::K_AIXBIG) {
1346fcaf7f86SDimitry Andric     BitMode = getBitMode(getenv("OBJECT_MODE"));
1347fcaf7f86SDimitry Andric     if (BitMode == BitModeTy::Unknown)
1348fcaf7f86SDimitry Andric       BitMode = BitModeTy::Bit32;
1349fcaf7f86SDimitry Andric   }
1350fcaf7f86SDimitry Andric 
13515ffd83dbSDimitry Andric   for (ArrayRef<const char *>::iterator ArgIt = Argv.begin();
13525ffd83dbSDimitry Andric        ArgIt != Argv.end(); ++ArgIt) {
13535ffd83dbSDimitry Andric     const char *Match = nullptr;
13545ffd83dbSDimitry Andric 
13555ffd83dbSDimitry Andric     if (handleGenericOption(*ArgIt))
13560b57cec5SDimitry Andric       return 0;
13575ffd83dbSDimitry Andric     if (strcmp(*ArgIt, "--") == 0) {
13585ffd83dbSDimitry Andric       ++ArgIt;
13595ffd83dbSDimitry Andric       for (; ArgIt != Argv.end(); ++ArgIt)
13605ffd83dbSDimitry Andric         PositionalArgs.push_back(*ArgIt);
13610b57cec5SDimitry Andric       break;
13620b57cec5SDimitry Andric     }
13635ffd83dbSDimitry Andric 
13645ffd83dbSDimitry Andric     if (*ArgIt[0] != '-') {
13655ffd83dbSDimitry Andric       if (Options.empty())
13665ffd83dbSDimitry Andric         Options += *ArgIt;
13670b57cec5SDimitry Andric       else
13685ffd83dbSDimitry Andric         PositionalArgs.push_back(*ArgIt);
13695ffd83dbSDimitry Andric       continue;
13705ffd83dbSDimitry Andric     }
13715ffd83dbSDimitry Andric 
13725ffd83dbSDimitry Andric     if (strcmp(*ArgIt, "-M") == 0) {
13730b57cec5SDimitry Andric       MRI = true;
13745ffd83dbSDimitry Andric       continue;
13755ffd83dbSDimitry Andric     }
13765ffd83dbSDimitry Andric 
13771fd87a68SDimitry Andric     if (strcmp(*ArgIt, "--thin") == 0) {
13781fd87a68SDimitry Andric       Thin = true;
13791fd87a68SDimitry Andric       continue;
13801fd87a68SDimitry Andric     }
13811fd87a68SDimitry Andric 
13825ffd83dbSDimitry Andric     Match = matchFlagWithArg("format", ArgIt, Argv);
13835ffd83dbSDimitry Andric     if (Match) {
13845ffd83dbSDimitry Andric       FormatType = StringSwitch<Format>(Match)
13850b57cec5SDimitry Andric                        .Case("default", Default)
13860b57cec5SDimitry Andric                        .Case("gnu", GNU)
13870b57cec5SDimitry Andric                        .Case("darwin", DARWIN)
13880b57cec5SDimitry Andric                        .Case("bsd", BSD)
138981ad6265SDimitry Andric                        .Case("bigarchive", BIGARCHIVE)
1390*0fca6ea1SDimitry Andric                        .Case("coff", COFF)
13910b57cec5SDimitry Andric                        .Default(Unknown);
13920b57cec5SDimitry Andric       if (FormatType == Unknown)
13935ffd83dbSDimitry Andric         fail(std::string("Invalid format ") + Match);
13945ffd83dbSDimitry Andric       continue;
13950b57cec5SDimitry Andric     }
13965ffd83dbSDimitry Andric 
139781ad6265SDimitry Andric     if ((Match = matchFlagWithArg("output", ArgIt, Argv))) {
139881ad6265SDimitry Andric       OutputDir = Match;
139981ad6265SDimitry Andric       continue;
140081ad6265SDimitry Andric     }
140181ad6265SDimitry Andric 
14025ffd83dbSDimitry Andric     if (matchFlagWithArg("plugin", ArgIt, Argv) ||
14035ffd83dbSDimitry Andric         matchFlagWithArg("rsp-quoting", ArgIt, Argv))
14045ffd83dbSDimitry Andric       continue;
14055ffd83dbSDimitry Andric 
1406fcaf7f86SDimitry Andric     if (strncmp(*ArgIt, "-X", 2) == 0) {
1407*0fca6ea1SDimitry Andric       if (object::Archive::getDefaultKind() == object::Archive::K_AIXBIG) {
1408fcaf7f86SDimitry Andric         Match = *(*ArgIt + 2) != '\0' ? *ArgIt + 2 : *(++ArgIt);
1409fcaf7f86SDimitry Andric         BitMode = getBitMode(Match);
1410fcaf7f86SDimitry Andric         if (BitMode == BitModeTy::Unknown)
1411fcaf7f86SDimitry Andric           fail(Twine("invalid bit mode: ") + Match);
1412fcaf7f86SDimitry Andric         continue;
1413fcaf7f86SDimitry Andric       } else {
1414fcaf7f86SDimitry Andric         fail(Twine(*ArgIt) + " option not supported on non AIX OS");
1415fcaf7f86SDimitry Andric       }
1416fcaf7f86SDimitry Andric     }
1417fcaf7f86SDimitry Andric 
14185ffd83dbSDimitry Andric     Options += *ArgIt + 1;
14190b57cec5SDimitry Andric   }
14205ffd83dbSDimitry Andric 
142161cfbce3SDimitry Andric   return performOperation(parseCommandLine());
14220b57cec5SDimitry Andric }
14230b57cec5SDimitry Andric 
14240b57cec5SDimitry Andric static int ranlib_main(int argc, char **argv) {
142561cfbce3SDimitry Andric   std::vector<StringRef> Archives;
14265f757f3fSDimitry Andric   bool HasAIXXOption = false;
14275f757f3fSDimitry Andric 
14280b57cec5SDimitry Andric   for (int i = 1; i < argc; ++i) {
1429480093f4SDimitry Andric     StringRef arg(argv[i]);
1430480093f4SDimitry Andric     if (handleGenericOption(arg)) {
14310b57cec5SDimitry Andric       return 0;
1432480093f4SDimitry Andric     } else if (arg.consume_front("-")) {
1433480093f4SDimitry Andric       // Handle the -D/-U flag
1434480093f4SDimitry Andric       while (!arg.empty()) {
1435480093f4SDimitry Andric         if (arg.front() == 'D') {
1436480093f4SDimitry Andric           Deterministic = true;
1437480093f4SDimitry Andric         } else if (arg.front() == 'U') {
1438480093f4SDimitry Andric           Deterministic = false;
1439480093f4SDimitry Andric         } else if (arg.front() == 'h') {
1440480093f4SDimitry Andric           printHelpMessage();
1441480093f4SDimitry Andric           return 0;
1442*0fca6ea1SDimitry Andric         } else if (arg.front() == 'V') {
1443480093f4SDimitry Andric           cl::PrintVersionMessage();
1444480093f4SDimitry Andric           return 0;
14455f757f3fSDimitry Andric         } else if (arg.front() == 'X') {
1446*0fca6ea1SDimitry Andric           if (object::Archive::getDefaultKind() == object::Archive::K_AIXBIG) {
14475f757f3fSDimitry Andric             HasAIXXOption = true;
14485f757f3fSDimitry Andric             arg.consume_front("X");
14495f757f3fSDimitry Andric             const char *Xarg = arg.data();
14505f757f3fSDimitry Andric             if (Xarg[0] == '\0') {
14515f757f3fSDimitry Andric               if (argv[i + 1][0] != '-')
14525f757f3fSDimitry Andric                 BitMode = getBitMode(argv[++i]);
14535f757f3fSDimitry Andric               else
14545f757f3fSDimitry Andric                 BitMode = BitModeTy::Unknown;
14555f757f3fSDimitry Andric             } else
14565f757f3fSDimitry Andric               BitMode = getBitMode(arg.data());
14575f757f3fSDimitry Andric 
14585f757f3fSDimitry Andric             if (BitMode == BitModeTy::Unknown)
14595f757f3fSDimitry Andric               fail("the specified object mode is not valid. Specify -X32, "
14605f757f3fSDimitry Andric                    "-X64, -X32_64, or -Xany");
14615f757f3fSDimitry Andric           } else {
14625f757f3fSDimitry Andric             fail(Twine("-") + Twine(arg) +
14635f757f3fSDimitry Andric                  " option not supported on non AIX OS");
14645f757f3fSDimitry Andric           }
14655f757f3fSDimitry Andric           break;
1466480093f4SDimitry Andric         } else {
1467480093f4SDimitry Andric           // TODO: GNU ranlib also supports a -t flag
1468480093f4SDimitry Andric           fail("Invalid option: '-" + arg + "'");
1469480093f4SDimitry Andric         }
1470480093f4SDimitry Andric         arg = arg.drop_front(1);
1471480093f4SDimitry Andric       }
14720b57cec5SDimitry Andric     } else {
147361cfbce3SDimitry Andric       Archives.push_back(arg);
14740b57cec5SDimitry Andric     }
14750b57cec5SDimitry Andric   }
147661cfbce3SDimitry Andric 
1477*0fca6ea1SDimitry Andric   if (object::Archive::getDefaultKind() == object::Archive::K_AIXBIG) {
14785f757f3fSDimitry Andric     // If not specify -X option, get BitMode from enviorment variable
14795f757f3fSDimitry Andric     // "OBJECT_MODE" for AIX OS if specify.
14805f757f3fSDimitry Andric     if (!HasAIXXOption) {
14815f757f3fSDimitry Andric       if (char *EnvObjectMode = getenv("OBJECT_MODE")) {
14825f757f3fSDimitry Andric         BitMode = getBitMode(EnvObjectMode);
14835f757f3fSDimitry Andric         if (BitMode == BitModeTy::Unknown)
14845f757f3fSDimitry Andric           fail("the OBJECT_MODE environment variable has an invalid value. "
14855f757f3fSDimitry Andric                "OBJECT_MODE must be 32, 64, 32_64, or any");
14865f757f3fSDimitry Andric       }
14875f757f3fSDimitry Andric     }
14885f757f3fSDimitry Andric 
14895f757f3fSDimitry Andric     switch (BitMode) {
14905f757f3fSDimitry Andric     case BitModeTy::Bit32:
14915f757f3fSDimitry Andric       Symtab = SymtabWritingMode::BigArchive32;
14925f757f3fSDimitry Andric       break;
14935f757f3fSDimitry Andric     case BitModeTy::Bit64:
14945f757f3fSDimitry Andric       Symtab = SymtabWritingMode::BigArchive64;
14955f757f3fSDimitry Andric       break;
14965f757f3fSDimitry Andric     default:
14975f757f3fSDimitry Andric       Symtab = SymtabWritingMode::NormalSymtab;
14985f757f3fSDimitry Andric       break;
14995f757f3fSDimitry Andric     }
15005f757f3fSDimitry Andric   }
15015f757f3fSDimitry Andric 
150261cfbce3SDimitry Andric   for (StringRef Archive : Archives) {
150361cfbce3SDimitry Andric     ArchiveName = Archive.str();
150461cfbce3SDimitry Andric     performOperation(CreateSymTab);
150561cfbce3SDimitry Andric   }
150661cfbce3SDimitry Andric   if (Archives.empty())
1507480093f4SDimitry Andric     badUsage("an archive name must be specified");
150861cfbce3SDimitry Andric   return 0;
15090b57cec5SDimitry Andric }
15100b57cec5SDimitry Andric 
151106c3fb27SDimitry Andric int llvm_ar_main(int argc, char **argv, const llvm::ToolContext &) {
15120b57cec5SDimitry Andric   ToolName = argv[0];
15130b57cec5SDimitry Andric 
15140b57cec5SDimitry Andric   llvm::InitializeAllTargetInfos();
15150b57cec5SDimitry Andric   llvm::InitializeAllTargetMCs();
15160b57cec5SDimitry Andric   llvm::InitializeAllAsmParsers();
15170b57cec5SDimitry Andric 
15180b57cec5SDimitry Andric   Stem = sys::path::stem(ToolName);
1519480093f4SDimitry Andric   auto Is = [](StringRef Tool) {
1520480093f4SDimitry Andric     // We need to recognize the following filenames.
1521480093f4SDimitry Andric     //
1522480093f4SDimitry Andric     // Lib.exe -> lib (see D44808, MSBuild runs Lib.exe)
1523480093f4SDimitry Andric     // dlltool.exe -> dlltool
1524480093f4SDimitry Andric     // arm-pokymllib32-linux-gnueabi-llvm-ar-10 -> ar
1525fe6060f1SDimitry Andric     auto I = Stem.rfind_insensitive(Tool);
1526480093f4SDimitry Andric     return I != StringRef::npos &&
1527480093f4SDimitry Andric            (I + Tool.size() == Stem.size() || !isAlnum(Stem[I + Tool.size()]));
1528480093f4SDimitry Andric   };
1529480093f4SDimitry Andric 
1530480093f4SDimitry Andric   if (Is("dlltool"))
1531bdd1243dSDimitry Andric     return dlltoolDriverMain(ArrayRef(argv, argc));
1532480093f4SDimitry Andric   if (Is("ranlib"))
15330b57cec5SDimitry Andric     return ranlib_main(argc, argv);
1534480093f4SDimitry Andric   if (Is("lib"))
1535bdd1243dSDimitry Andric     return libDriverMain(ArrayRef(argv, argc));
1536480093f4SDimitry Andric   if (Is("ar"))
15370b57cec5SDimitry Andric     return ar_main(argc, argv);
1538480093f4SDimitry Andric 
15398bcb0991SDimitry Andric   fail("not ranlib, ar, lib or dlltool");
15400b57cec5SDimitry Andric }
1541