summaryrefslogtreecommitdiff
path: root/tools/llvm-ar/llvm-ar.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/llvm-ar/llvm-ar.cpp')
-rw-r--r--tools/llvm-ar/llvm-ar.cpp224
1 files changed, 137 insertions, 87 deletions
diff --git a/tools/llvm-ar/llvm-ar.cpp b/tools/llvm-ar/llvm-ar.cpp
index ef5fab68b9479..865152b6af831 100644
--- a/tools/llvm-ar/llvm-ar.cpp
+++ b/tools/llvm-ar/llvm-ar.cpp
@@ -19,6 +19,7 @@
#include "llvm/LibDriver/LibDriver.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/ArchiveWriter.h"
+#include "llvm/Object/MachO.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Errc.h"
@@ -64,12 +65,25 @@ static void failIfError(std::error_code EC, Twine Context = "") {
fail(Context + ": " + EC.message());
}
+static void failIfError(Error E, Twine Context = "") {
+ if (!E)
+ return;
+
+ handleAllErrors(std::move(E), [&](const llvm::ErrorInfoBase &EIB) {
+ std::string ContextStr = Context.str();
+ if (ContextStr == "")
+ fail(EIB.message());
+ fail(Context + ": " + EIB.message());
+ });
+}
+
// 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 cl::opt<bool> MRI("M", cl::desc(""));
+static cl::opt<std::string> Plugin("plugin", cl::desc("plugin (ignored for compatibility"));
namespace {
enum Format { Default, GNU, BSD };
@@ -77,7 +91,7 @@ enum Format { Default, GNU, BSD };
static cl::opt<Format>
FormatOpt("format", cl::desc("Archive format to create"),
- cl::values(clEnumValN(Default, "defalut", "default"),
+ cl::values(clEnumValN(Default, "default", "default"),
clEnumValN(GNU, "gnu", "gnu"),
clEnumValN(BSD, "bsd", "bsd"), clEnumValEnd));
@@ -343,12 +357,9 @@ static void doDisplayTable(StringRef Name, const object::Archive::Child &C) {
static void doExtract(StringRef Name, const object::Archive::Child &C) {
// Retain the original mode.
sys::fs::perms Mode = C.getAccessMode();
- SmallString<128> Storage = Name;
int FD;
- failIfError(
- sys::fs::openFileForWrite(Storage.c_str(), FD, sys::fs::F_None, Mode),
- Storage.c_str());
+ failIfError(sys::fs::openFileForWrite(Name, FD, sys::fs::F_None, Mode), Name);
{
raw_fd_ostream file(FD, false);
@@ -394,35 +405,37 @@ static void performReadOperation(ArchiveOperation Operation,
fail("extracting from a thin archive is not supported");
bool Filter = !Members.empty();
- for (auto &ChildOrErr : OldArchive->children()) {
- failIfError(ChildOrErr.getError());
- const object::Archive::Child &C = *ChildOrErr;
-
- ErrorOr<StringRef> NameOrErr = C.getName();
- failIfError(NameOrErr.getError());
- StringRef Name = NameOrErr.get();
-
- if (Filter) {
- auto I = std::find(Members.begin(), Members.end(), Name);
- if (I == Members.end())
- continue;
- Members.erase(I);
- }
+ {
+ Error Err;
+ for (auto &C : OldArchive->children(Err)) {
+ ErrorOr<StringRef> NameOrErr = C.getName();
+ failIfError(NameOrErr.getError());
+ StringRef Name = NameOrErr.get();
- switch (Operation) {
- default:
- llvm_unreachable("Not a read operation");
- case Print:
- doPrint(Name, C);
- break;
- case DisplayTable:
- doDisplayTable(Name, C);
- break;
- case Extract:
- doExtract(Name, C);
- break;
+ if (Filter) {
+ auto I = std::find(Members.begin(), Members.end(), Name);
+ if (I == Members.end())
+ continue;
+ Members.erase(I);
+ }
+
+ switch (Operation) {
+ default:
+ llvm_unreachable("Not a read operation");
+ case Print:
+ doPrint(Name, C);
+ break;
+ case DisplayTable:
+ doDisplayTable(Name, C);
+ break;
+ case Extract:
+ doExtract(Name, C);
+ break;
+ }
}
+ failIfError(std::move(Err));
}
+
if (Members.empty())
return;
for (StringRef Name : Members)
@@ -430,25 +443,28 @@ static void performReadOperation(ArchiveOperation Operation,
std::exit(1);
}
-static void addMember(std::vector<NewArchiveIterator> &Members,
+static void addMember(std::vector<NewArchiveMember> &Members,
StringRef FileName, int Pos = -1) {
- NewArchiveIterator NI(FileName);
+ Expected<NewArchiveMember> NMOrErr =
+ NewArchiveMember::getFile(FileName, Deterministic);
+ failIfError(NMOrErr.takeError(), FileName);
if (Pos == -1)
- Members.push_back(NI);
+ Members.push_back(std::move(*NMOrErr));
else
- Members[Pos] = NI;
+ Members[Pos] = std::move(*NMOrErr);
}
-static void addMember(std::vector<NewArchiveIterator> &Members,
- const object::Archive::Child &M, StringRef Name,
- int Pos = -1) {
+static void addMember(std::vector<NewArchiveMember> &Members,
+ const object::Archive::Child &M, int Pos = -1) {
if (Thin && !M.getParent()->isThin())
fail("Cannot convert a regular archive to a thin one");
- NewArchiveIterator NI(M, Name);
+ Expected<NewArchiveMember> NMOrErr =
+ NewArchiveMember::getOldMember(M, Deterministic);
+ failIfError(NMOrErr.takeError());
if (Pos == -1)
- Members.push_back(NI);
+ Members.push_back(std::move(*NMOrErr));
else
- Members[Pos] = NI;
+ Members[Pos] = std::move(*NMOrErr);
}
enum InsertAction {
@@ -509,17 +525,16 @@ static InsertAction computeInsertAction(ArchiveOperation Operation,
// We have to walk this twice and computing it is not trivial, so creating an
// explicit std::vector is actually fairly efficient.
-static std::vector<NewArchiveIterator>
+static std::vector<NewArchiveMember>
computeNewArchiveMembers(ArchiveOperation Operation,
object::Archive *OldArchive) {
- std::vector<NewArchiveIterator> Ret;
- std::vector<NewArchiveIterator> Moved;
+ std::vector<NewArchiveMember> Ret;
+ std::vector<NewArchiveMember> Moved;
int InsertPos = -1;
StringRef PosName = sys::path::filename(RelPos);
if (OldArchive) {
- for (auto &ChildOrErr : OldArchive->children()) {
- failIfError(ChildOrErr.getError());
- auto &Child = ChildOrErr.get();
+ Error Err;
+ for (auto &Child : OldArchive->children(Err)) {
int Pos = Ret.size();
ErrorOr<StringRef> NameOrErr = Child.getName();
failIfError(NameOrErr.getError());
@@ -537,7 +552,7 @@ computeNewArchiveMembers(ArchiveOperation Operation,
computeInsertAction(Operation, Child, Name, MemberI);
switch (Action) {
case IA_AddOldMember:
- addMember(Ret, Child, Name);
+ addMember(Ret, Child);
break;
case IA_AddNewMeber:
addMember(Ret, *MemberI);
@@ -545,7 +560,7 @@ computeNewArchiveMembers(ArchiveOperation Operation,
case IA_Delete:
break;
case IA_MoveOldMember:
- addMember(Moved, Child, Name);
+ addMember(Moved, Child);
break;
case IA_MoveNewMember:
addMember(Moved, *MemberI);
@@ -554,6 +569,7 @@ computeNewArchiveMembers(ArchiveOperation Operation,
if (MemberI != Members.end())
Members.erase(MemberI);
}
+ failIfError(std::move(Err));
}
if (Operation == Delete)
@@ -566,10 +582,15 @@ computeNewArchiveMembers(ArchiveOperation Operation,
InsertPos = Ret.size();
assert(unsigned(InsertPos) <= Ret.size());
- Ret.insert(Ret.begin() + InsertPos, Moved.begin(), Moved.end());
-
- Ret.insert(Ret.begin() + InsertPos, Members.size(), NewArchiveIterator(""));
int Pos = InsertPos;
+ for (auto &M : Moved) {
+ Ret.insert(Ret.begin() + Pos, std::move(M));
+ ++Pos;
+ }
+
+ for (unsigned I = 0; I != Members.size(); ++I)
+ Ret.insert(Ret.begin() + InsertPos, NewArchiveMember());
+ Pos = InsertPos;
for (auto &Member : Members) {
addMember(Ret, Member, Pos);
++Pos;
@@ -578,36 +599,61 @@ computeNewArchiveMembers(ArchiveOperation Operation,
return Ret;
}
+static object::Archive::Kind getDefaultForHost() {
+ return Triple(sys::getProcessTriple()).isOSDarwin() ? object::Archive::K_BSD
+ : object::Archive::K_GNU;
+}
+
+static object::Archive::Kind getKindFromMember(const NewArchiveMember &Member) {
+ Expected<std::unique_ptr<object::ObjectFile>> OptionalObject =
+ object::ObjectFile::createObjectFile(Member.Buf->getMemBufferRef());
+
+ if (OptionalObject)
+ return isa<object::MachOObjectFile>(**OptionalObject)
+ ? object::Archive::K_BSD
+ : object::Archive::K_GNU;
+
+ // squelch the error in case we had a non-object file
+ consumeError(OptionalObject.takeError());
+ return getDefaultForHost();
+}
+
static void
-performWriteOperation(ArchiveOperation Operation, object::Archive *OldArchive,
- std::vector<NewArchiveIterator> *NewMembersP) {
+performWriteOperation(ArchiveOperation Operation,
+ object::Archive *OldArchive,
+ std::unique_ptr<MemoryBuffer> OldArchiveBuf,
+ std::vector<NewArchiveMember> *NewMembersP) {
+ std::vector<NewArchiveMember> NewMembers;
+ if (!NewMembersP)
+ NewMembers = computeNewArchiveMembers(Operation, OldArchive);
+
object::Archive::Kind Kind;
switch (FormatOpt) {
- case Default: {
- Triple T(sys::getProcessTriple());
- if (T.isOSDarwin())
- Kind = object::Archive::K_BSD;
- else
+ case Default:
+ if (Thin)
Kind = object::Archive::K_GNU;
+ else if (OldArchive)
+ Kind = OldArchive->kind();
+ else if (NewMembersP)
+ Kind = NewMembersP->size() ? getKindFromMember(NewMembersP->front())
+ : getDefaultForHost();
+ else
+ Kind = NewMembers.size() ? getKindFromMember(NewMembers.front())
+ : getDefaultForHost();
break;
- }
case GNU:
Kind = object::Archive::K_GNU;
break;
case BSD:
+ if (Thin)
+ fail("Only the gnu format has a thin mode");
Kind = object::Archive::K_BSD;
break;
}
- if (NewMembersP) {
- std::pair<StringRef, std::error_code> Result = writeArchive(
- ArchiveName, *NewMembersP, Symtab, Kind, Deterministic, Thin);
- failIfError(Result.second, Result.first);
- return;
- }
- std::vector<NewArchiveIterator> NewMembers =
- computeNewArchiveMembers(Operation, OldArchive);
- auto Result =
- writeArchive(ArchiveName, NewMembers, Symtab, Kind, Deterministic, Thin);
+
+ std::pair<StringRef, std::error_code> Result =
+ writeArchive(ArchiveName, NewMembersP ? *NewMembersP : NewMembers, Symtab,
+ Kind, Deterministic, Thin, std::move(OldArchiveBuf));
failIfError(Result.second, Result.first);
}
@@ -621,12 +667,13 @@ static void createSymbolTable(object::Archive *OldArchive) {
if (OldArchive->hasSymbolTable())
return;
- performWriteOperation(CreateSymTab, OldArchive, nullptr);
+ performWriteOperation(CreateSymTab, OldArchive, nullptr, nullptr);
}
static void performOperation(ArchiveOperation Operation,
object::Archive *OldArchive,
- std::vector<NewArchiveIterator> *NewMembers) {
+ std::unique_ptr<MemoryBuffer> OldArchiveBuf,
+ std::vector<NewArchiveMember> *NewMembers) {
switch (Operation) {
case Print:
case DisplayTable:
@@ -638,7 +685,8 @@ static void performOperation(ArchiveOperation Operation,
case Move:
case QuickAppend:
case ReplaceOrInsert:
- performWriteOperation(Operation, OldArchive, NewMembers);
+ performWriteOperation(Operation, OldArchive, std::move(OldArchiveBuf),
+ NewMembers);
return;
case CreateSymTab:
createSymbolTable(OldArchive);
@@ -648,7 +696,7 @@ static void performOperation(ArchiveOperation Operation,
}
static int performOperation(ArchiveOperation Operation,
- std::vector<NewArchiveIterator> *NewMembers) {
+ std::vector<NewArchiveMember> *NewMembers) {
// Create or open the archive object.
ErrorOr<std::unique_ptr<MemoryBuffer>> Buf =
MemoryBuffer::getFile(ArchiveName, -1, false);
@@ -657,10 +705,12 @@ static int performOperation(ArchiveOperation Operation,
fail("error opening '" + ArchiveName + "': " + EC.message() + "!");
if (!EC) {
- object::Archive Archive(Buf.get()->getMemBufferRef(), EC);
+ Error Err;
+ object::Archive Archive(Buf.get()->getMemBufferRef(), Err);
+ EC = errorToErrorCode(std::move(Err));
failIfError(EC,
"error loading '" + ArchiveName + "': " + EC.message() + "!");
- performOperation(Operation, &Archive, NewMembers);
+ performOperation(Operation, &Archive, std::move(Buf.get()), NewMembers);
return 0;
}
@@ -675,7 +725,7 @@ static int performOperation(ArchiveOperation Operation,
}
}
- performOperation(Operation, nullptr, NewMembers);
+ performOperation(Operation, nullptr, nullptr, NewMembers);
return 0;
}
@@ -686,7 +736,7 @@ static void runMRIScript() {
failIfError(Buf.getError());
const MemoryBuffer &Ref = *Buf.get();
bool Saved = false;
- std::vector<NewArchiveIterator> NewMembers;
+ std::vector<NewArchiveMember> NewMembers;
std::vector<std::unique_ptr<MemoryBuffer>> ArchiveBuffers;
std::vector<std::unique_ptr<object::Archive>> Archives;
@@ -712,15 +762,15 @@ static void runMRIScript() {
ArchiveBuffers.push_back(std::move(*BufOrErr));
auto LibOrErr =
object::Archive::create(ArchiveBuffers.back()->getMemBufferRef());
- failIfError(LibOrErr.getError(), "Could not parse library");
+ failIfError(errorToErrorCode(LibOrErr.takeError()),
+ "Could not parse library");
Archives.push_back(std::move(*LibOrErr));
object::Archive &Lib = *Archives.back();
- for (auto &MemberOrErr : Lib.children()) {
- failIfError(MemberOrErr.getError());
- auto &Member = MemberOrErr.get();
- ErrorOr<StringRef> NameOrErr = Member.getName();
- failIfError(NameOrErr.getError());
- addMember(NewMembers, Member, *NameOrErr);
+ {
+ Error Err;
+ for (auto &Member : Lib.children(Err))
+ addMember(NewMembers, Member);
+ failIfError(std::move(Err));
}
break;
}
@@ -760,7 +810,7 @@ static int ar_main() {
static int ranlib_main() {
if (RestOfArgs.size() != 1)
- fail(ToolName + "takes just one archive as argument");
+ fail(ToolName + " takes just one archive as an argument");
ArchiveName = RestOfArgs[0];
return performOperation(CreateSymTab, nullptr);
}
@@ -768,7 +818,7 @@ static int ranlib_main() {
int main(int argc, char **argv) {
ToolName = argv[0];
// Print a stack trace if we signal out.
- sys::PrintStackTraceOnErrorSignal();
+ sys::PrintStackTraceOnErrorSignal(argv[0]);
PrettyStackTraceProgram X(argc, argv);
llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.