llvm-ar: Start adding support for mri scripts.
authorRafael Espindola <rafael.espindola@gmail.com>
Fri, 10 Oct 2014 18:33:51 +0000 (18:33 +0000)
committerRafael Espindola <rafael.espindola@gmail.com>
Fri, 10 Oct 2014 18:33:51 +0000 (18:33 +0000)
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 [new file with mode: 0644]
test/Object/mri2.test [new file with mode: 0644]
test/Object/mri3.test [new file with mode: 0644]
test/Object/mri4.test [new file with mode: 0644]
test/Object/mri5.test [new file with mode: 0644]
tools/llvm-ar/llvm-ar.cpp

diff --git a/test/Object/mri1.test b/test/Object/mri1.test
new file mode 100644 (file)
index 0000000..3d27db7
--- /dev/null
@@ -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 (file)
index 0000000..0c24179
--- /dev/null
@@ -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 (file)
index 0000000..bdc5399
--- /dev/null
@@ -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 (file)
index 0000000..a24c14d
--- /dev/null
@@ -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 (file)
index 0000000..9811424
--- /dev/null
@@ -0,0 +1,2 @@
+; RUN: not llvm-ar -M t < %s 2>&1 | FileCheck %s
+; CHECK: Cannot mix -M and other options.
index 2b32098a4900f83f67a63cff4ce3338fe7c9cae8..fa0842992ec506a0bb8d1cc97df2d00147fb5dec 100644 (file)
@@ -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<std::string>
-RestOfArgs(cl::Positional, cl::OneOrMore,
-    cl::desc("[relpos] [count] <archive-file> [members]..."));
+    RestOfArgs(cl::Positional, cl::ZeroOrMore,
+               cl::desc("[relpos] [count] <archive-file> [members]..."));
+
+static cl::opt<bool> MRI("M", cl::desc(""));
 
 std::string Options;
 
@@ -173,10 +177,61 @@ static void getMembers() {
     Members = std::vector<std::string>(RestOfArgs);
 }
 
+namespace {
+enum class MRICommand { Create, Save, End, Invalid };
+}
+
+static ArchiveOperation parseMRIScript() {
+  ErrorOr<std::unique_ptr<MemoryBuffer>> 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<MRICommand>(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