From f02687d9eb9dca1890ada305c609daf21e8cd846 Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Fri, 10 Oct 2014 18:33:51 +0000 Subject: [PATCH] llvm-ar: Start adding support for mri scripts. I was quiet surprised to find this feature being used. Fortunately the uses I found look fairly simple. In fact, they are just a very verbose version of the regular ar commands. Start implementing it then by parsing the script and setting the command variables as if we had a regular command line. This patch adds just enough support to create an empty archive and do a bit of error checking. In followup patches I will implement at least addmod and addlib. From the description in the manual, even the more general case should not be too hard to implement if needed. The features that don't map 1:1 to the simple command line are * Reading from multiple archives. * Creating multiple archives. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@219521 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/Object/mri1.test | 6 ++++ test/Object/mri2.test | 7 +++++ test/Object/mri3.test | 6 ++++ test/Object/mri4.test | 4 +++ test/Object/mri5.test | 2 ++ tools/llvm-ar/llvm-ar.cpp | 59 +++++++++++++++++++++++++++++++++++++-- 6 files changed, 82 insertions(+), 2 deletions(-) create mode 100644 test/Object/mri1.test create mode 100644 test/Object/mri2.test create mode 100644 test/Object/mri3.test create mode 100644 test/Object/mri4.test create mode 100644 test/Object/mri5.test diff --git a/test/Object/mri1.test b/test/Object/mri1.test new file mode 100644 index 00000000000..3d27db7996a --- /dev/null +++ b/test/Object/mri1.test @@ -0,0 +1,6 @@ +; RUN: echo create %t.a > %t.mri +; RUN: echo save >> %t.mri +; RUN: echo end >> %t.mri + +; RUN: llvm-ar -M < %t.mri +; RUN: llvm-ar t %t.a diff --git a/test/Object/mri2.test b/test/Object/mri2.test new file mode 100644 index 00000000000..0c241793417 --- /dev/null +++ b/test/Object/mri2.test @@ -0,0 +1,7 @@ +; RUN: echo create %t.a > %t.mri +; RUN: echo create %t.a >> %t.mri +; RUN: echo save >> %t.mri +; RUN: echo end >> %t.mri + +; RUN: not llvm-ar -M < %t.mri 2>&1 | FileCheck %s +; CHECK: Editing multiple archives not supported diff --git a/test/Object/mri3.test b/test/Object/mri3.test new file mode 100644 index 00000000000..bdc53991510 --- /dev/null +++ b/test/Object/mri3.test @@ -0,0 +1,6 @@ +; RUN: echo save > %t.mri +; RUN: echo create %t.a >> %t.mri +; RUN: echo end >> %t.mri + +; RUN: not llvm-ar -M < %t.mri 2>&1 | FileCheck %s +; CHECK: File already saved. diff --git a/test/Object/mri4.test b/test/Object/mri4.test new file mode 100644 index 00000000000..a24c14d7d28 --- /dev/null +++ b/test/Object/mri4.test @@ -0,0 +1,4 @@ +; RUN: echo abc > %t.mri + +; RUN: not llvm-ar -M < %t.mri 2>&1 | FileCheck %s +; CHECK: Unknown command: abc. diff --git a/test/Object/mri5.test b/test/Object/mri5.test new file mode 100644 index 00000000000..98114248b69 --- /dev/null +++ b/test/Object/mri5.test @@ -0,0 +1,2 @@ +; RUN: not llvm-ar -M t < %s 2>&1 | FileCheck %s +; CHECK: Cannot mix -M and other options. diff --git a/tools/llvm-ar/llvm-ar.cpp b/tools/llvm-ar/llvm-ar.cpp index 2b32098a490..fa0842992ec 100644 --- a/tools/llvm-ar/llvm-ar.cpp +++ b/tools/llvm-ar/llvm-ar.cpp @@ -12,6 +12,7 @@ // //===----------------------------------------------------------------------===// +#include "llvm/ADT/StringSwitch.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/Object/Archive.h" @@ -20,6 +21,7 @@ #include "llvm/Support/Errc.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Format.h" +#include "llvm/Support/LineIterator.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/PrettyStackTrace.h" @@ -67,8 +69,10 @@ static void failIfError(std::error_code EC, Twine Context = "") { // llvm-ar/llvm-ranlib remaining positional arguments. static cl::list -RestOfArgs(cl::Positional, cl::OneOrMore, - cl::desc("[relpos] [count] [members]...")); + RestOfArgs(cl::Positional, cl::ZeroOrMore, + cl::desc("[relpos] [count] [members]...")); + +static cl::opt MRI("M", cl::desc("")); std::string Options; @@ -173,10 +177,61 @@ static void getMembers() { Members = std::vector(RestOfArgs); } +namespace { +enum class MRICommand { Create, Save, End, Invalid }; +} + +static ArchiveOperation parseMRIScript() { + ErrorOr> Buf = MemoryBuffer::getSTDIN(); + failIfError(Buf.getError()); + const MemoryBuffer &Ref = *Buf.get(); + bool Saved = false; + + for (line_iterator I(Ref, /*SkipBlanks*/ true, ';'), E; I != E; ++I) { + StringRef Line = *I; + StringRef CommandStr, Rest; + std::tie(CommandStr, Rest) = Line.split(' '); + auto Command = StringSwitch(CommandStr.lower()) + .Case("create", MRICommand::Create) + .Case("save", MRICommand::Save) + .Case("end", MRICommand::End) + .Default(MRICommand::Invalid); + + switch (Command) { + case MRICommand::Create: + Create = true; + if (!ArchiveName.empty()) + fail("Editing multiple archives not supported"); + if (Saved) + fail("File already saved"); + ArchiveName = Rest; + break; + case MRICommand::Save: + Saved = true; + break; + case MRICommand::End: + break; + case MRICommand::Invalid: + fail("Unknown command: " + CommandStr); + } + } + + // Nothing to do if not saved. + if (!Saved) + exit(0); + return ReplaceOrInsert; +} + // parseCommandLine - Parse the command line options as presented and return the // operation specified. Process all modifiers and check to make sure that // constraints on modifier/operation pairs have not been violated. static ArchiveOperation parseCommandLine() { + if (MRI) { + if (!RestOfArgs.empty()) + fail("Cannot mix -M and other options"); + return parseMRIScript(); + } + getOptions(); // Keep track of number of operations. We can only specify one -- 2.34.1