diff --git a/llvm/include/llvm/Object/Archive.h b/llvm/include/llvm/Object/Archive.h --- a/llvm/include/llvm/Object/Archive.h +++ b/llvm/include/llvm/Object/Archive.h @@ -340,6 +340,7 @@ Kind kind() const { return (Kind)Format; } bool isThin() const { return IsThin; } + static object::Archive::Kind getDefaultKindForHost(); child_iterator child_begin(Error &Err, bool SkipInternal = true) const; child_iterator child_end() const; diff --git a/llvm/include/llvm/Object/ArchiveWriter.h b/llvm/include/llvm/Object/ArchiveWriter.h --- a/llvm/include/llvm/Object/ArchiveWriter.h +++ b/llvm/include/llvm/Object/ArchiveWriter.h @@ -26,6 +26,8 @@ NewArchiveMember() = default; NewArchiveMember(MemoryBufferRef BufRef); + object::Archive::Kind getKind() const; + static Expected getOldMember(const object::Archive::Child &OldMember, bool Deterministic); diff --git a/llvm/lib/ObjCopy/Archive.cpp b/llvm/lib/ObjCopy/Archive.cpp --- a/llvm/lib/ObjCopy/Archive.cpp +++ b/llvm/lib/ObjCopy/Archive.cpp @@ -11,6 +11,7 @@ #include "llvm/ObjCopy/MultiFormatConfig.h" #include "llvm/ObjCopy/ObjCopy.h" #include "llvm/Object/Error.h" +#include "llvm/Object/MachO.h" #include "llvm/Support/FileOutputBuffer.h" #include "llvm/Support/SmallVectorMemoryBuffer.h" @@ -61,6 +62,10 @@ ArrayRef NewMembers, bool WriteSymtab, object::Archive::Kind Kind, bool Deterministic, bool Thin) { + if (Kind == object::Archive::K_BSD && !NewMembers.empty() && + NewMembers.front().getKind() == object::Archive::K_DARWIN) + Kind = object::Archive::K_DARWIN; + if (Error E = writeArchive(ArcName, NewMembers, WriteSymtab, Kind, Deterministic, Thin)) return createFileError(ArcName, std::move(E)); diff --git a/llvm/lib/ObjCopy/MachO/MachOObjcopy.cpp b/llvm/lib/ObjCopy/MachO/MachOObjcopy.cpp --- a/llvm/lib/ObjCopy/MachO/MachOObjcopy.cpp +++ b/llvm/lib/ObjCopy/MachO/MachOObjcopy.cpp @@ -484,9 +484,12 @@ createNewArchiveMembers(Config, **ArOrErr); if (!NewArchiveMembersOrErr) return NewArchiveMembersOrErr.takeError(); + auto Kind = (*ArOrErr)->kind(); + if (Kind == object::Archive::K_BSD) + Kind = object::Archive::K_DARWIN; Expected> OutputBufferOrErr = writeArchiveToBuffer(*NewArchiveMembersOrErr, - (*ArOrErr)->hasSymbolTable(), (*ArOrErr)->kind(), + (*ArOrErr)->hasSymbolTable(), Kind, Config.getCommonConfig().DeterministicArchives, (*ArOrErr)->isThin()); if (!OutputBufferOrErr) diff --git a/llvm/lib/Object/Archive.cpp b/llvm/lib/Object/Archive.cpp --- a/llvm/lib/Object/Archive.cpp +++ b/llvm/lib/Object/Archive.cpp @@ -22,6 +22,7 @@ #include "llvm/Support/Error.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/Host.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" @@ -925,6 +926,14 @@ Err = Error::success(); } +object::Archive::Kind Archive::getDefaultKindForHost() { + Triple HostTriple(sys::getProcessTriple()); + return HostTriple.isOSDarwin() + ? object::Archive::K_DARWIN + : (HostTriple.isOSAIX() ? object::Archive::K_AIXBIG + : object::Archive::K_GNU); +} + Archive::child_iterator Archive::child_begin(Error &Err, bool SkipInternal) const { if (isEmpty()) diff --git a/llvm/lib/Object/ArchiveWriter.cpp b/llvm/lib/Object/ArchiveWriter.cpp --- a/llvm/lib/Object/ArchiveWriter.cpp +++ b/llvm/lib/Object/ArchiveWriter.cpp @@ -18,8 +18,11 @@ #include "llvm/IR/LLVMContext.h" #include "llvm/Object/Archive.h" #include "llvm/Object/Error.h" +#include "llvm/Object/IRObjectFile.h" +#include "llvm/Object/MachO.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Object/SymbolicFile.h" +#include "llvm/Object/XCOFFObjectFile.h" #include "llvm/Support/Alignment.h" #include "llvm/Support/EndianStream.h" #include "llvm/Support/Errc.h" @@ -43,6 +46,40 @@ : Buf(MemoryBuffer::getMemBuffer(BufRef, false)), MemberName(BufRef.getBufferIdentifier()) {} +object::Archive::Kind NewArchiveMember::getKind() const { + auto MemBufferRef = this->Buf->getMemBufferRef(); + Expected> OptionalObject = + object::ObjectFile::createObjectFile(MemBufferRef); + + if (OptionalObject) + return isa(**OptionalObject) + ? object::Archive::K_DARWIN + : (isa(**OptionalObject) + ? object::Archive::K_AIXBIG + : object::Archive::K_GNU); + + // squelch the error in case we had a non-object file + consumeError(OptionalObject.takeError()); + + // If we're adding a bitcode file to the archive, detect the Archive kind + // based on the target triple. + LLVMContext Context; + if (identify_magic(MemBufferRef.getBuffer()) == file_magic::bitcode) { + if (auto ObjOrErr = object::SymbolicFile::createSymbolicFile( + MemBufferRef, file_magic::bitcode, &Context)) { + auto &IRObject = cast(**ObjOrErr); + return Triple(IRObject.getTargetTriple()).isOSDarwin() + ? object::Archive::K_DARWIN + : object::Archive::K_GNU; + } else { + // Squelch the error in case this was not a SymbolicFile. + consumeError(ObjOrErr.takeError()); + } + } + + return object::Archive::getDefaultKindForHost(); +} + Expected NewArchiveMember::getOldMember(const object::Archive::Child &OldMember, bool Deterministic) { diff --git a/llvm/test/tools/llvm-ar/macho-edit.test b/llvm/test/tools/llvm-ar/macho-edit.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-ar/macho-edit.test @@ -0,0 +1,16 @@ +## Make sure the darwin format specifics are preserved when updating archives. + +# RUN: rm -rf %t && mkdir -p %t +# RUN: yaml2obj %p/Inputs/macho.yaml > %t/dup.o + +## Create the archive with a duplicate object to ensure that darwin specific +## incrementing timestamps are used. +# RUN: llvm-ar --format=darwin crD %t/lib.a %t/dup.o %t/dup.o +# RUN: cp %t/lib.a %t/lib.copy.a + +## Replace an object file in the archive to force a re-write. +# RUN: llvm-ar crD %t/lib.a %t/dup.o +# RUN: obj2yaml %t/lib.a | FileCheck --implicit-check-not=LastModified %s + +# CHECK: LastModified: '1' +# CHECK: LastModified: '2' diff --git a/llvm/test/tools/llvm-objcopy/MachO/archive-format.test b/llvm/test/tools/llvm-objcopy/MachO/archive-format.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/MachO/archive-format.test @@ -0,0 +1,12 @@ +# REQUIRES: x86-registered-target + +## Make sure the darwin format specifics are preserved when updating archives. + +# RUN: rm -rf %t && mkdir -p %t +# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %p/Inputs/macho.64.s -o %t/dup.o +# RUN: llvm-ar --format=darwin crD %t/lib.a %t/dup.o %t/dup.o +# RUN: llvm-objcopy %t/lib.a %t/lib.copy.a +# RUN: obj2yaml %t/lib.copy.a | FileCheck --implicit-check-not=LastModified %s + +# CHECK: LastModified: '1' +# CHECK: LastModified: '2' diff --git a/llvm/test/tools/llvm-objcopy/MachO/universal-object.test b/llvm/test/tools/llvm-objcopy/MachO/universal-object.test --- a/llvm/test/tools/llvm-objcopy/MachO/universal-object.test +++ b/llvm/test/tools/llvm-objcopy/MachO/universal-object.test @@ -12,9 +12,9 @@ # RUN: cmp %t.i386 %t.i386.copy # RUN: cmp %t.x86_64 %t.x86_64.copy -## Case 2: copy a universal object file containing an archive. +## Case 2: copy a universal object file containing an archive with darwin specific timestamps. # RUN: rm -f %t.archive.i386 -# RUN: llvm-ar --format=gnu cr %t.archive.i386 %t.i386 +# RUN: llvm-ar --format=darwin cr %t.archive.i386 %t.i386 %t.i386 # RUN: llvm-lipo %t.archive.i386 %t.x86_64 -create -output %t.universal.containing.archive # RUN: llvm-objcopy %t.universal.containing.archive %t.universal.containing.archive.copy # RUN: llvm-lipo %t.universal.containing.archive.copy -archs | FileCheck --check-prefix=VERIFY_ARCHS %s diff --git a/llvm/tools/llvm-ar/llvm-ar.cpp b/llvm/tools/llvm-ar/llvm-ar.cpp --- a/llvm/tools/llvm-ar/llvm-ar.cpp +++ b/llvm/tools/llvm-ar/llvm-ar.cpp @@ -879,48 +879,6 @@ return Ret; } -static object::Archive::Kind getDefaultForHost() { - Triple HostTriple(sys::getProcessTriple()); - return HostTriple.isOSDarwin() - ? object::Archive::K_DARWIN - : (HostTriple.isOSAIX() ? object::Archive::K_AIXBIG - : object::Archive::K_GNU); -} - -static object::Archive::Kind getKindFromMember(const NewArchiveMember &Member) { - auto MemBufferRef = Member.Buf->getMemBufferRef(); - Expected> OptionalObject = - object::ObjectFile::createObjectFile(MemBufferRef); - - if (OptionalObject) - return isa(**OptionalObject) - ? object::Archive::K_DARWIN - : (isa(**OptionalObject) - ? object::Archive::K_AIXBIG - : object::Archive::K_GNU); - - // squelch the error in case we had a non-object file - consumeError(OptionalObject.takeError()); - - // If we're adding a bitcode file to the archive, detect the Archive kind - // based on the target triple. - LLVMContext Context; - if (identify_magic(MemBufferRef.getBuffer()) == file_magic::bitcode) { - if (auto ObjOrErr = object::SymbolicFile::createSymbolicFile( - MemBufferRef, file_magic::bitcode, &Context)) { - auto &IRObject = cast(**ObjOrErr); - return Triple(IRObject.getTargetTriple()).isOSDarwin() - ? object::Archive::K_DARWIN - : object::Archive::K_GNU; - } else { - // Squelch the error in case this was not a SymbolicFile. - consumeError(ObjOrErr.takeError()); - } - } - - return getDefaultForHost(); -} - static void performWriteOperation(ArchiveOperation Operation, object::Archive *OldArchive, std::unique_ptr OldArchiveBuf, @@ -942,14 +900,23 @@ case Default: if (Thin) Kind = object::Archive::K_GNU; - else if (OldArchive) + else if (OldArchive) { Kind = OldArchive->kind(); - else if (NewMembersP) - Kind = !NewMembersP->empty() ? getKindFromMember(NewMembersP->front()) - : getDefaultForHost(); + if (Kind == object::Archive::K_BSD) { + auto InferredKind = object::Archive::K_BSD; + if (NewMembersP && !NewMembersP->empty()) + InferredKind = NewMembersP->front().getKind(); + else if (!NewMembers.empty()) + InferredKind = NewMembers.front().getKind(); + if (InferredKind == object::Archive::K_DARWIN) + Kind = object::Archive::K_DARWIN; + } + } else if (NewMembersP) + Kind = !NewMembersP->empty() ? NewMembersP->front().getKind() + : object::Archive::getDefaultKindForHost(); else - Kind = !NewMembers.empty() ? getKindFromMember(NewMembers.front()) - : getDefaultForHost(); + Kind = !NewMembers.empty() ? NewMembers.front().getKind() + : object::Archive::getDefaultKindForHost(); if (Kind == object::Archive::K_AIXBIG) fail("big archive writer operation on AIX not yet supported"); break;