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