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
This commit is contained in:
Rafael Espindola 2014-10-10 18:33:51 +00:00
parent b144f27c8f
commit f02687d9eb
6 changed files with 82 additions and 2 deletions

6
test/Object/mri1.test Normal file
View File

@ -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

7
test/Object/mri2.test Normal file
View File

@ -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

6
test/Object/mri3.test Normal file
View File

@ -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.

4
test/Object/mri4.test Normal file
View File

@ -0,0 +1,4 @@
; RUN: echo abc > %t.mri
; RUN: not llvm-ar -M < %t.mri 2>&1 | FileCheck %s
; CHECK: Unknown command: abc.

2
test/Object/mri5.test Normal file
View File

@ -0,0 +1,2 @@
; RUN: not llvm-ar -M t < %s 2>&1 | FileCheck %s
; CHECK: Cannot mix -M and other options.

View 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