diff options
| -rw-r--r-- | llvm/tools/llvm-ar/llvm-ar.cpp | 94 |
1 files changed, 76 insertions, 18 deletions
diff --git a/llvm/tools/llvm-ar/llvm-ar.cpp b/llvm/tools/llvm-ar/llvm-ar.cpp index 01c8b804a73..0078bda4db4 100644 --- a/llvm/tools/llvm-ar/llvm-ar.cpp +++ b/llvm/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" @@ -575,21 +576,86 @@ 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 NewArchiveIterator &Member) { + if (Member.isNewMember()) { + object::Archive::Kind Kind = getDefaultForHost(); + + sys::fs::file_status Status; + if (auto OptionalFD = Member.getFD(Status)) { + auto OptionalMB = MemoryBuffer::getOpenFile(*OptionalFD, Member.getName(), + Status.getSize(), false); + if (OptionalMB) { + MemoryBufferRef MemoryBuffer = (*OptionalMB)->getMemBufferRef(); + + Expected<std::unique_ptr<object::ObjectFile>> OptionalObject = + object::ObjectFile::createObjectFile(MemoryBuffer); + + if (OptionalObject) + Kind = 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()); + } + + if (close(*OptionalFD) != 0) + failIfError(std::error_code(errno, std::generic_category()), + "failed to close file"); + } + + return Kind; + } else { + const object::Archive::Child &OldMember = Member.getOld(); + if (OldMember.getParent()->isThin()) + return object::Archive::Kind::K_GNU; + + auto OptionalMB = OldMember.getMemoryBufferRef(); + failIfError(OptionalMB.getError()); + + Expected<std::unique_ptr<object::ObjectFile>> OptionalObject = + object::ObjectFile::createObjectFile(*OptionalMB); + + if (OptionalObject) + return isa<object::MachOObjectFile>(*OptionalObject->get()) + ? 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::unique_ptr<MemoryBuffer> OldArchiveBuf, std::vector<NewArchiveIterator> *NewMembersP) { + std::vector<NewArchiveIterator> NewMembers; + if (!NewMembersP) + NewMembers = computeNewArchiveMembers(Operation, OldArchive); + object::Archive::Kind Kind; switch (FormatOpt) { - case Default: { - Triple T(sys::getProcessTriple()); - if (T.isOSDarwin() && !Thin) - 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; @@ -599,18 +665,10 @@ performWriteOperation(ArchiveOperation Operation, Kind = object::Archive::K_BSD; break; } - if (NewMembersP) { - std::pair<StringRef, std::error_code> Result = writeArchive( - ArchiveName, *NewMembersP, Symtab, Kind, Deterministic, Thin, - std::move(OldArchiveBuf)); - failIfError(Result.second, Result.first); - return; - } - std::vector<NewArchiveIterator> NewMembers = - computeNewArchiveMembers(Operation, OldArchive); - auto Result = - writeArchive(ArchiveName, NewMembers, Symtab, Kind, Deterministic, Thin, - std::move(OldArchiveBuf)); + + std::pair<StringRef, std::error_code> Result = + writeArchive(ArchiveName, NewMembersP ? *NewMembersP : NewMembers, Symtab, + Kind, Deterministic, Thin, std::move(OldArchiveBuf)); failIfError(Result.second, Result.first); } |

