diff options
Diffstat (limited to 'gnu/llvm/tools/llvm-ar/llvm-ar.cpp')
| -rw-r--r-- | gnu/llvm/tools/llvm-ar/llvm-ar.cpp | 296 |
1 files changed, 185 insertions, 111 deletions
diff --git a/gnu/llvm/tools/llvm-ar/llvm-ar.cpp b/gnu/llvm/tools/llvm-ar/llvm-ar.cpp index ae7d1a7f1b7..64be08ff946 100644 --- a/gnu/llvm/tools/llvm-ar/llvm-ar.cpp +++ b/gnu/llvm/tools/llvm-ar/llvm-ar.cpp @@ -15,8 +15,6 @@ #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Triple.h" #include "llvm/IR/LLVMContext.h" -#include "llvm/ToolDrivers/llvm-dlltool/DlltoolDriver.h" -#include "llvm/ToolDrivers/llvm-lib/LibDriver.h" #include "llvm/Object/Archive.h" #include "llvm/Object/ArchiveWriter.h" #include "llvm/Object/MachO.h" @@ -26,15 +24,17 @@ #include "llvm/Support/Errc.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Format.h" +#include "llvm/Support/InitLLVM.h" #include "llvm/Support/LineIterator.h" -#include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" -#include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/Signals.h" +#include "llvm/Support/Process.h" +#include "llvm/Support/StringSaver.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/ToolOutputFile.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/ToolDrivers/llvm-dlltool/DlltoolDriver.h" +#include "llvm/ToolDrivers/llvm-lib/LibDriver.h" #if !defined(_MSC_VER) && !defined(__MINGW32__) #include <unistd.h> @@ -47,10 +47,74 @@ using namespace llvm; // The name this program was invoked as. static StringRef ToolName; +// The basename of this program. +static StringRef Stem; + +const char RanlibHelp[] = R"( +OVERVIEW: LLVM Ranlib (llvm-ranlib) + + This program generates an index to speed access to archives + +USAGE: llvm-ranlib <archive-file> + +OPTIONS: + -help - Display available options + -version - Display the version of this program +)"; + +const char ArHelp[] = R"( +OVERVIEW: LLVM Archiver + +USAGE: llvm-ar [options] [-]<operation>[modifiers] [relpos] <archive> [files] + llvm-ar -M [<mri-script] + +OPTIONS: + --format - Archive format to create + =default - default + =gnu - gnu + =darwin - darwin + =bsd - bsd + --plugin=<string> - Ignored for compatibility + --help - Display available options + --version - Display the version of this program + +OPERATIONS: + d - delete [files] from the archive + m - move [files] in the archive + p - print [files] found in the archive + q - quick append [files] to the archive + r - replace or insert [files] into the archive + s - act as ranlib + t - display contents of archive + x - extract [files] from the archive + +MODIFIERS: + [a] - put [files] after [relpos] + [b] - put [files] before [relpos] (same as [i]) + [c] - do not warn if archive had to be created + [D] - use zero for timestamps and uids/gids (default) + [i] - put [files] before [relpos] (same as [b]) + [l] - ignored for compatibility + [o] - preserve original dates + [s] - create an archive index (cf. ranlib) + [S] - do not build a symbol table + [T] - create a thin archive + [u] - update only [files] newer than archive contents + [U] - use actual timestamps and uids/gids + [v] - be verbose about actions taken +)"; + +void printHelpMessage() { + if (Stem.contains_lower("ranlib")) + outs() << RanlibHelp; + else if (Stem.contains_lower("ar")) + outs() << ArHelp; +} + // Show the error message and exit. LLVM_ATTRIBUTE_NORETURN static void fail(Twine Error) { errs() << ToolName << ": " << Error << ".\n"; - cl::PrintHelpMessage(); + printHelpMessage(); exit(1); } @@ -76,55 +140,18 @@ static void failIfError(Error E, Twine Context = "") { }); } -// llvm-ar/llvm-ranlib remaining positional arguments. -static cl::list<std::string> - RestOfArgs(cl::Positional, cl::ZeroOrMore, - cl::desc("[relpos] [count] <archive-file> [members]...")); +static SmallVector<const char *, 256> PositionalArgs; -static cl::opt<bool> MRI("M", cl::desc("")); -static cl::opt<std::string> Plugin("plugin", cl::desc("plugin (ignored for compatibility")); +static bool MRI; namespace { -enum Format { Default, GNU, BSD, DARWIN }; +enum Format { Default, GNU, BSD, DARWIN, Unknown }; } -static cl::opt<Format> - FormatOpt("format", cl::desc("Archive format to create"), - cl::values(clEnumValN(Default, "default", "default"), - clEnumValN(GNU, "gnu", "gnu"), - clEnumValN(DARWIN, "darwin", "darwin"), - clEnumValN(BSD, "bsd", "bsd"))); +static Format FormatType = Default; static std::string Options; -// Provide additional help output explaining the operations and modifiers of -// llvm-ar. This object instructs the CommandLine library to print the text of -// the constructor when the --help option is given. -static cl::extrahelp MoreHelp( - "\nOPERATIONS:\n" - " d[NsS] - delete file(s) from the archive\n" - " m[abiSs] - move file(s) in the archive\n" - " p[kN] - print file(s) found in the archive\n" - " q[ufsS] - quick append file(s) to the archive\n" - " r[abfiuRsS] - replace or insert file(s) into the archive\n" - " t - display contents of archive\n" - " x[No] - extract file(s) from the archive\n" - "\nMODIFIERS (operation specific):\n" - " [a] - put file(s) after [relpos]\n" - " [b] - put file(s) before [relpos] (same as [i])\n" - " [i] - put file(s) before [relpos] (same as [b])\n" - " [o] - preserve original dates\n" - " [s] - create an archive index (cf. ranlib)\n" - " [S] - do not build a symbol table\n" - " [T] - create a thin archive\n" - " [u] - update only files newer than archive contents\n" - "\nMODIFIERS (generic):\n" - " [c] - do not warn if the library had to be created\n" - " [v] - be verbose about actions taken\n" -); - -static const char OptionChars[] = "dmpqrtxabiosSTucv"; - // This enumeration delineates the kinds of operations on an archive // that are permitted. enum ArchiveOperation { @@ -166,30 +193,23 @@ static std::vector<StringRef> Members; // Extract the member filename from the command line for the [relpos] argument // associated with a, b, and i modifiers static void getRelPos() { - if(RestOfArgs.size() == 0) + if (PositionalArgs.size() == 0) fail("Expected [relpos] for a, b, or i modifier"); - RelPos = RestOfArgs[0]; - RestOfArgs.erase(RestOfArgs.begin()); -} - -static void getOptions() { - if(RestOfArgs.size() == 0) - fail("Expected options"); - Options = RestOfArgs[0]; - RestOfArgs.erase(RestOfArgs.begin()); + RelPos = PositionalArgs[0]; + PositionalArgs.erase(PositionalArgs.begin()); } // Get the archive file name from the command line static void getArchive() { - if(RestOfArgs.size() == 0) + if (PositionalArgs.size() == 0) fail("An archive name must be specified"); - ArchiveName = RestOfArgs[0]; - RestOfArgs.erase(RestOfArgs.begin()); + ArchiveName = PositionalArgs[0]; + PositionalArgs.erase(PositionalArgs.begin()); } -// Copy over remaining items in RestOfArgs to our Members vector +// Copy over remaining items in PositionalArgs to our Members vector static void getMembers() { - for (auto &Arg : RestOfArgs) + for (auto &Arg : PositionalArgs) Members.push_back(Arg); } @@ -200,13 +220,11 @@ static void runMRIScript(); // modifier/operation pairs have not been violated. static ArchiveOperation parseCommandLine() { if (MRI) { - if (!RestOfArgs.empty()) + if (!PositionalArgs.empty() || !Options.empty()) fail("Cannot mix -M and other options"); runMRIScript(); } - getOptions(); - // Keep track of number of operations. We can only specify one // per execution. unsigned NumOperations = 0; @@ -370,6 +388,7 @@ static void doExtract(StringRef Name, const object::Archive::Child &C) { int FD; failIfError(sys::fs::openFileForWrite(sys::path::filename(Name), FD, + sys::fs::CD_CreateAlways, sys::fs::F_None, Mode), Name); @@ -651,7 +670,7 @@ performWriteOperation(ArchiveOperation Operation, NewMembers = computeNewArchiveMembers(Operation, OldArchive); object::Archive::Kind Kind; - switch (FormatOpt) { + switch (FormatType) { case Default: if (Thin) Kind = object::Archive::K_GNU; @@ -677,6 +696,8 @@ performWriteOperation(ArchiveOperation Operation, fail("Only the gnu format has a thin mode"); Kind = object::Archive::K_DARWIN; break; + case Unknown: + llvm_unreachable(""); } Error E = @@ -758,7 +779,7 @@ static int performOperation(ArchiveOperation Operation, } static void runMRIScript() { - enum class MRICommand { AddLib, AddMod, Create, Save, End, Invalid }; + enum class MRICommand { AddLib, AddMod, Create, Delete, Save, End, Invalid }; ErrorOr<std::unique_ptr<MemoryBuffer>> Buf = MemoryBuffer::getSTDIN(); failIfError(Buf.getError()); @@ -779,6 +800,7 @@ static void runMRIScript() { .Case("addlib", MRICommand::AddLib) .Case("addmod", MRICommand::AddMod) .Case("create", MRICommand::Create) + .Case("delete", MRICommand::Delete) .Case("save", MRICommand::Save) .Case("end", MRICommand::End) .Default(MRICommand::Invalid); @@ -813,6 +835,12 @@ static void runMRIScript() { fail("File already saved"); ArchiveName = Rest; break; + case MRICommand::Delete: { + StringRef Name = sys::path::filename(Rest); + llvm::erase_if(NewMembers, + [=](NewArchiveMember &M) { return M.MemberName == Name; }); + break; + } case MRICommand::Save: Saved = true; break; @@ -829,67 +857,113 @@ static void runMRIScript() { exit(0); } -static int ar_main() { - // Do our own parsing of the command line because the CommandLine utility - // can't handle the grouped positional parameters without a dash. +static bool handleGenericOption(StringRef arg) { + if (arg == "-help" || arg == "--help") { + printHelpMessage(); + return true; + } + if (arg == "-version" || arg == "--version") { + cl::PrintVersionMessage(); + return true; + } + return false; +} + +static int ar_main(int argc, char **argv) { + SmallVector<const char *, 0> Argv(argv, argv + argc); + BumpPtrAllocator Alloc; + StringSaver Saver(Alloc); + cl::ExpandResponseFiles(Saver, cl::TokenizeGNUCommandLine, Argv); + for(size_t i = 1; i < Argv.size(); ++i) { + StringRef Arg = Argv[i]; + const char *match; + auto MatchFlagWithArg = [&](const char *expected) { + size_t len = strlen(expected); + if (Arg == expected) { + if (++i >= Argv.size()) + fail(std::string(expected) + " requires an argument"); + match = Argv[i]; + return true; + } + if (Arg.startswith(expected) && Arg.size() > len && + Arg[len] == '=') { + match = Arg.data() + len + 1; + return true; + } + return false; + }; + if (handleGenericOption(Argv[i])) + return 0; + if (Arg == "--") { + for(; i < Argv.size(); ++i) + PositionalArgs.push_back(Argv[i]); + break; + } + if (Arg[0] == '-') { + if (Arg.startswith("--")) + Arg = Argv[i] + 2; + else + Arg = Argv[i] + 1; + if (Arg == "M") { + MRI = true; + } else if (MatchFlagWithArg("format")) { + FormatType = StringSwitch<Format>(match) + .Case("default", Default) + .Case("gnu", GNU) + .Case("darwin", DARWIN) + .Case("bsd", BSD) + .Default(Unknown); + if (FormatType == Unknown) + fail(std::string("Invalid format ") + match); + } else if (MatchFlagWithArg("plugin")) { + // Ignored. + } else { + Options += Argv[i] + 1; + } + } else if (Options.empty()) { + Options += Argv[i]; + } else { + PositionalArgs.push_back(Argv[i]); + } + } ArchiveOperation Operation = parseCommandLine(); return performOperation(Operation, nullptr); } -static int ranlib_main() { - if (RestOfArgs.size() != 1) - fail(ToolName + " takes just one archive as an argument"); - ArchiveName = RestOfArgs[0]; +static int ranlib_main(int argc, char **argv) { + bool ArchiveSpecified = false; + for(int i = 1; i < argc; ++i) { + if (handleGenericOption(argv[i])) { + return 0; + } else { + if (ArchiveSpecified) + fail("Exactly one archive should be specified"); + ArchiveSpecified = true; + ArchiveName = argv[i]; + } + } return performOperation(CreateSymTab, nullptr); } int main(int argc, char **argv) { + InitLLVM X(argc, argv); ToolName = argv[0]; - // Print a stack trace if we signal out. - sys::PrintStackTraceOnErrorSignal(argv[0]); - PrettyStackTraceProgram X(argc, argv); - llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. llvm::InitializeAllTargetInfos(); llvm::InitializeAllTargetMCs(); llvm::InitializeAllAsmParsers(); - StringRef Stem = sys::path::stem(ToolName); - if (Stem.find("dlltool") != StringRef::npos) + Stem = sys::path::stem(ToolName); + if (Stem.contains_lower("dlltool")) return dlltoolDriverMain(makeArrayRef(argv, argc)); - if (Stem.find("ranlib") == StringRef::npos && - Stem.find("lib") != StringRef::npos) - return libDriverMain(makeArrayRef(argv, argc)); + if (Stem.contains_lower("ranlib")) + return ranlib_main(argc, argv); - for (int i = 1; i < argc; i++) { - // If an argument starts with a dash and only contains chars - // that belong to the options chars set, remove the dash. - // We can't handle it after the command line options parsing - // is done, since it will error out on an unrecognized string - // starting with a dash. - // Make sure this doesn't match the actual llvm-ar specific options - // that start with a dash. - StringRef S = argv[i]; - if (S.startswith("-") && - S.find_first_not_of(OptionChars, 1) == StringRef::npos) { - argv[i]++; - break; - } - if (S == "--") - break; - } + if (Stem.contains_lower("lib")) + return libDriverMain(makeArrayRef(argv, argc)); - // Have the command line options parsed and handle things - // like --help and --version. - cl::ParseCommandLineOptions(argc, argv, - "LLVM Archiver (llvm-ar)\n\n" - " This program archives bitcode files into single libraries\n" - ); - - if (Stem.find("ranlib") != StringRef::npos) - return ranlib_main(); - if (Stem.find("ar") != StringRef::npos) - return ar_main(); + if (Stem.contains_lower("ar")) + return ar_main(argc, argv); fail("Not ranlib, ar, lib or dlltool!"); } |
