[llvm] r328716 - [llvm-ar] Support multiple dashed options
Peter Collingbourne via llvm-commits
llvm-commits at lists.llvm.org
Wed Mar 28 10:21:15 PDT 2018
Author: pcc
Date: Wed Mar 28 10:21:14 2018
New Revision: 328716
URL: http://llvm.org/viewvc/llvm-project?rev=328716&view=rev
Log:
[llvm-ar] Support multiple dashed options
This allows syntax like:
$ llvm-ar -c -r -u file.a file.o
This is in addition to the other formats that are already supported:
$ llvm-ar cru file.a file.o
$ llvm-ar -cru file.a file.o
Patch by Tom Anderson!
Differential Revision: https://reviews.llvm.org/D44452
Modified:
llvm/trunk/lib/Object/ArchiveWriter.cpp
llvm/trunk/test/Object/archive-GNU64-write.test
llvm/trunk/test/tools/llvm-ar/default-add.test
llvm/trunk/tools/llvm-ar/llvm-ar.cpp
Modified: llvm/trunk/lib/Object/ArchiveWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Object/ArchiveWriter.cpp?rev=328716&r1=328715&r2=328716&view=diff
==============================================================================
--- llvm/trunk/lib/Object/ArchiveWriter.cpp (original)
+++ llvm/trunk/lib/Object/ArchiveWriter.cpp Wed Mar 28 10:21:14 2018
@@ -35,15 +35,6 @@
using namespace llvm;
-// The SYM64 format is used when an archive's member offsets are larger than
-// 32-bits can hold. The need for this shift in format is detected by
-// writeArchive. To test this we need to generate a file with a member that has
-// an offset larger than 32-bits but this demands a very slow test. To speed
-// the test up we use this flag to pretend like the cutoff happens before
-// 32-bits and instead happens at some much smaller value.
-static cl::opt<int> Sym64Threshold("sym64-threshold", cl::Hidden,
- cl::init(32));
-
NewArchiveMember::NewArchiveMember(MemoryBufferRef BufRef)
: Buf(MemoryBuffer::getMemBuffer(BufRef, false)),
MemberName(BufRef.getBufferIdentifier()) {}
@@ -490,6 +481,19 @@ Error llvm::writeArchive(StringRef ArcNa
// We assume 32-bit symbols to see if 32-bit symbols are possible or not.
MaxOffset += M.Symbols.size() * 4;
}
+
+ // The SYM64 format is used when an archive's member offsets are larger than
+ // 32-bits can hold. The need for this shift in format is detected by
+ // writeArchive. To test this we need to generate a file with a member that
+ // has an offset larger than 32-bits but this demands a very slow test. To
+ // speed the test up we use this environment variable to pretend like the
+ // cutoff happens before 32-bits and instead happens at some much smaller
+ // value.
+ const char *Sym64Env = std::getenv("SYM64_THRESHOLD");
+ int Sym64Threshold = 32;
+ if (Sym64Env)
+ StringRef(Sym64Env).getAsInteger(10, Sym64Threshold);
+
// If LastOffset isn't going to fit in a 32-bit varible we need to switch
// to 64-bit. Note that the file can be larger than 4GB as long as the last
// member starts before the 4GB offset.
Modified: llvm/trunk/test/Object/archive-GNU64-write.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Object/archive-GNU64-write.test?rev=328716&r1=328715&r2=328716&view=diff
==============================================================================
--- llvm/trunk/test/Object/archive-GNU64-write.test (original)
+++ llvm/trunk/test/Object/archive-GNU64-write.test Wed Mar 28 10:21:14 2018
@@ -5,7 +5,7 @@
# RUN: dd if=%t of=%t bs=1 count=0 seek=1M
# RUN: rm -f %t.lib
# RUN: cp %t %t2
-# RUN: llvm-ar -sym64-threshold=19 cr %t.lib %t %t2 %p/Inputs/trivial-object-test.elf-x86-64
+# RUN: SYM64_THRESHOLD=19 llvm-ar cr %t.lib %t %t2 %p/Inputs/trivial-object-test.elf-x86-64
# RUN: llvm-nm --print-armap %t.lib | FileCheck %s
# RUN: grep SYM64 %t.lib
Modified: llvm/trunk/test/tools/llvm-ar/default-add.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-ar/default-add.test?rev=328716&r1=328715&r2=328716&view=diff
==============================================================================
--- llvm/trunk/test/tools/llvm-ar/default-add.test (original)
+++ llvm/trunk/test/tools/llvm-ar/default-add.test Wed Mar 28 10:21:14 2018
@@ -14,5 +14,21 @@ RUN: not grep -q __.SYMDEF %t.ar
RUN: llvm-ar crs %t.ar %t-macho.o
RUN: not grep -q __.SYMDEF %t.ar
+RUN: rm -f %t.ar
+Test that multiple dashed options works.
+RUN: llvm-ar -c -r -s %t.ar %t-macho.o
+RUN: grep -q __.SYMDEF %t.ar
+Test with duplicated options.
+RUN: llvm-ar -c -r -s -c -s %t.ar %t-coff.o
+RUN: grep -q __.SYMDEF %t.ar
+
+RUN: rm -f %t.ar
+Test with the options in a different order.
+RUN: llvm-ar rsc %t.ar %t-macho.o
+RUN: grep -q __.SYMDEF %t.ar
+Test with options everywhere.
+RUN: llvm-ar rsc -cs -sc %t.ar %t-coff.o -cs -sc
+RUN: grep -q __.SYMDEF %t.ar
+
Ensure that we select the existing format when updating.
Modified: llvm/trunk/tools/llvm-ar/llvm-ar.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-ar/llvm-ar.cpp?rev=328716&r1=328715&r2=328716&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-ar/llvm-ar.cpp (original)
+++ llvm/trunk/tools/llvm-ar/llvm-ar.cpp Wed Mar 28 10:21:14 2018
@@ -33,6 +33,7 @@
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/Signals.h"
+#include "llvm/Support/StringSaver.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/ToolOutputFile.h"
#include "llvm/Support/raw_ostream.h"
@@ -48,10 +49,76 @@ 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 (llvm-ar)
+
+ This program archives bitcode files into single libraries
+
+USAGE: llvm-ar [options] [relpos] [count] <archive-file> [members]...
+
+OPTIONS:
+ -M -
+ -format - Archive format to create
+ =default - default
+ =gnu - gnu
+ =darwin - darwin
+ =bsd - bsd
+ -plugin=<string> - plugin (ignored for compatibility
+ -help - Display available options
+ -version - Display the version of this program
+
+OPERATIONS:
+ d[NsS] - delete file(s) from the archive
+ m[abiSs] - move file(s) in the archive
+ p[kN] - print file(s) found in the archive
+ q[ufsS] - quick append file(s) to the archive
+ r[abfiuRsS] - replace or insert file(s) into the archive
+ t - display contents of archive
+ x[No] - extract file(s) from the archive
+
+MODIFIERS (operation specific):
+ [a] - put file(s) after [relpos]
+ [b] - put file(s) before [relpos] (same as [i])
+ [D] - use zero for timestamps and uids/gids (default)
+ [i] - put file(s) before [relpos] (same as [b])
+ [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
+
+MODIFIERS (generic):
+ [c] - do not warn if the library had to be created
+ [v] - be verbose about actions taken
+)";
+
+void printHelpMessage() {
+ if (Stem.find("ranlib") != StringRef::npos)
+ outs() << RanlibHelp;
+ else if (Stem.find("ar") != StringRef::npos)
+ 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);
}
@@ -77,55 +144,18 @@ static void failIfError(Error E, Twine C
});
}
-// llvm-ar/llvm-ranlib remaining positional arguments.
-static cl::list<std::string>
- RestOfArgs(cl::Positional, cl::ZeroOrMore,
- cl::desc("[relpos] [count] <archive-file> [members]..."));
+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 {
@@ -167,30 +197,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);
}
@@ -201,13 +224,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;
@@ -652,7 +673,7 @@ performWriteOperation(ArchiveOperation O
NewMembers = computeNewArchiveMembers(Operation, OldArchive);
object::Archive::Kind Kind;
- switch (FormatOpt) {
+ switch (FormatType) {
case Default:
if (Thin)
Kind = object::Archive::K_GNU;
@@ -678,6 +699,8 @@ performWriteOperation(ArchiveOperation O
fail("Only the gnu format has a thin mode");
Kind = object::Archive::K_DARWIN;
break;
+ case Unknown:
+ llvm_unreachable("");
}
Error E =
@@ -837,17 +860,91 @@ 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);
}
@@ -862,47 +959,17 @@ int main(int argc, char **argv) {
llvm::InitializeAllTargetMCs();
llvm::InitializeAllAsmParsers();
- StringRef Stem = sys::path::stem(ToolName);
+ Stem = sys::path::stem(ToolName);
if (Stem.find("dlltool") != StringRef::npos)
return dlltoolDriverMain(makeArrayRef(argv, argc));
- if (Stem.find("ranlib") == StringRef::npos &&
- Stem.find("lib") != StringRef::npos)
- return libDriverMain(makeArrayRef(argv, argc));
-
- SmallVector<const char *, 256> Argv;
- SpecificBumpPtrAllocator<char> ArgAllocator;
- failIfError(errorCodeToError(sys::Process::GetArgumentVector(
- Argv, makeArrayRef(argv, argc), ArgAllocator)));
-
- for (unsigned i = 1; i < Argv.size(); 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.find("ranlib") != StringRef::npos)
+ return ranlib_main(argc, argv);
- // Have the command line options parsed and handle things
- // like --help and --version.
- cl::ParseCommandLineOptions(Argv.size(), Argv.data(),
- "LLVM Archiver (llvm-ar)\n\n"
- " This program archives bitcode files into single libraries\n"
- );
+ if (Stem.find("lib") != StringRef::npos)
+ return libDriverMain(makeArrayRef(argv, argc));
- if (Stem.find("ranlib") != StringRef::npos)
- return ranlib_main();
if (Stem.find("ar") != StringRef::npos)
- return ar_main();
+ return ar_main(argc, argv);
fail("Not ranlib, ar, lib or dlltool!");
}
More information about the llvm-commits
mailing list