diff --git a/llvm/include/llvm/ADT/Triple.h b/llvm/include/llvm/ADT/Triple.h --- a/llvm/include/llvm/ADT/Triple.h +++ b/llvm/include/llvm/ADT/Triple.h @@ -503,6 +503,10 @@ return getOS() == Triple::FreeBSD; } + bool isOSBSDLike() const { + return isOSNetBSD() || isOSOpenBSD() || isOSFreeBSD(); + } + bool isOSFuchsia() const { return getOS() == Triple::Fuchsia; } diff --git a/llvm/test/tools/llvm-ar/lto-kind-from-triple.test b/llvm/test/tools/llvm-ar/lto-kind-from-triple.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-ar/lto-kind-from-triple.test @@ -0,0 +1,30 @@ +Ensure that we generate a GNU style archive if the first input is a bitcode +file with a GNU target triple (absence of __.SYMDEF in the archive). + +RUN: echo -e "target triple = \"x86_64-unknown-linux-gnu\" \n define void @_Z3foov() { ret void }" > %t.gnu.ll +RUN: llvm-as -o %t.o %t.gnu.ll + +RUN: rm -f %t.ar +RUN: llvm-ar crs %t.ar %t.o +RUN: not grep -q __.SYMDEF %t.ar + +Ensure that we generate a MachO style archive if the first input is a bitcode +file with a MachO target triple (presence of __.SYMDEF in the archive). + +RUN: echo -e "target triple = \"x86_64-apple-macosx10.9\" \n define void @_Z3foov() { ret void }" > %t.macho.ll +RUN: llvm-as -o %t.o %t.macho.ll + +RUN: rm -f %t.ar +RUN: llvm-ar crs %t.ar %t.o +RUN: grep -q __.SYMDEF %t.ar + +Ensure that we generate a BSD style archive if the first input is a bitcode +file with a BSD target triple (presence of __.SYMDEF in the archive). + +RUN: echo -e "target triple = \"x86_64-unknown-freebsd\" \n define void @_Z3foov() { ret void }" > %t.bsd.ll +RUN: llvm-as -o %t.o %t.bsd.ll + +RUN: rm -f %t.ar +RUN: llvm-ar crs %t.ar %t.o +RUN: grep -q __.SYMDEF %t.ar + 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 @@ -14,11 +14,14 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Triple.h" +#include "llvm/BinaryFormat/Magic.h" #include "llvm/IR/LLVMContext.h" #include "llvm/Object/Archive.h" #include "llvm/Object/ArchiveWriter.h" +#include "llvm/Object/IRObjectFile.h" #include "llvm/Object/MachO.h" #include "llvm/Object/ObjectFile.h" +#include "llvm/Object/SymbolicFile.h" #include "llvm/Support/Chrono.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ConvertUTF.h" @@ -875,8 +878,9 @@ } static object::Archive::Kind getKindFromMember(const NewArchiveMember &Member) { + auto MemBufferRef = Member.Buf->getMemBufferRef(); Expected> OptionalObject = - object::ObjectFile::createObjectFile(Member.Buf->getMemBufferRef()); + object::ObjectFile::createObjectFile(MemBufferRef); if (OptionalObject) return isa(**OptionalObject) @@ -885,6 +889,27 @@ // 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) { + auto ObjOrErr = object::SymbolicFile::createSymbolicFile( + MemBufferRef, file_magic::bitcode, &Context); + if (ObjOrErr) { + auto &IRObject = cast(**ObjOrErr); + Triple TargetTriple(IRObject.getTargetTriple()); + if (TargetTriple.isOSBinFormatMachO()) + return object::Archive::K_DARWIN; + else if (TargetTriple.isOSBinFormatELF()) { + return TargetTriple.isOSBSDLike() ? object::Archive::K_BSD + : object::Archive::K_GNU; + } + } + // squelch the error in case this was not a SymbolicFile. + consumeError(ObjOrErr.takeError()); + } + return getDefaultForHost(); }