Index: llvm/test/tools/llvm-link/Inputs/f.ll =================================================================== --- /dev/null +++ llvm/test/tools/llvm-link/Inputs/f.ll @@ -0,0 +1,6 @@ +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + +define void @f() { +entry: + ret void +} Index: llvm/test/tools/llvm-link/Inputs/g.ll =================================================================== --- /dev/null +++ llvm/test/tools/llvm-link/Inputs/g.ll @@ -0,0 +1,6 @@ +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + +define void @g() { +entry: + ret void +} Index: llvm/test/tools/llvm-link/Inputs/h.ll =================================================================== --- /dev/null +++ llvm/test/tools/llvm-link/Inputs/h.ll @@ -0,0 +1,6 @@ +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + +define void @h() { +entry: + ret void +} Index: llvm/test/tools/llvm-link/archive.ll =================================================================== --- /dev/null +++ llvm/test/tools/llvm-link/archive.ll @@ -0,0 +1,17 @@ +# RUN: llvm-as %S/Inputs/f.ll -o %t.f.bc +# RUN: llvm-as %S/Inputs/g.ll -o %t.g.bc +# RUN: llvm-ar cr %t.fg.a %t.f.bc %t.g.bc +# RUN: llvm-ar cr %t.empty.a +# RUN: llvm-link %S/Inputs/h.ll %t.fg.a %t.empty.a -o %t.linked.bc + +# RUN: llvm-nm %t.linked.bc | FileCheck %s + +# RUN: rm -f %t.f.bc +# RUN: rm -f %t.g.bc +# RUN: rm -f %t.fg.a +# RUN: rm -f %t.empty.a +# RUN: rm -f %t.linked.bc + +# CHECK: -------- T f +# CHECK: -------- T g +# CHECK: -------- T h Index: llvm/tools/llvm-link/llvm-link.cpp =================================================================== --- llvm/tools/llvm-link/llvm-link.cpp +++ llvm/tools/llvm-link/llvm-link.cpp @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// +#include "llvm//Object/Archive.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Bitcode/BitcodeReader.h" #include "llvm/Bitcode/BitcodeWriter.h" @@ -139,6 +140,62 @@ return Result; } +static std::unique_ptr loadArFile(const char *argv0, + const std::string ArchiveName, + LLVMContext &Context, Linker &L, + unsigned OrigFlags, + unsigned ApplicableFlags) { + std::unique_ptr Result(new Module("ArchiveModule", Context)); + if (Verbose) + errs() << "Reading library archive file '" << ArchiveName + << "' to memory\n"; + auto Buf = MemoryBuffer::getFile(ArchiveName, -1, false); + ExitOnErr(errorCodeToError(Buf.getError())); + auto Err = Error::success(); + object::Archive Archive(Buf.get()->getMemBufferRef(), Err); + ExitOnErr(std::move(Err)); + for (auto &C : Archive.children(Err)) { + auto Ename = C.getName(); + if (auto E = Ename.takeError()) { + errs() << argv0 << ": "; + WithColor::error() + << " could not get member name of archive library failed'" + << ArchiveName << "'\n"; + return nullptr; + }; + auto ChildName = Ename.get().str(); + if (Verbose) + errs() << "Parsing member '" << ChildName + << "' of archive library to module.\n"; + SMDiagnostic ParseErr; + auto MemBuf = C.getMemoryBufferRef(); + if (auto E = MemBuf.takeError()) { + errs() << argv0 << ": "; + WithColor::error() << " loading memory for member '" << ChildName + << "' of archive library failed'" << ArchiveName + << "'\n"; + return nullptr; + }; + + auto M = parseIR(MemBuf.get(), ParseErr, Context); + if (!M.get()) { + errs() << argv0 << ": "; + WithColor::error() << " parsing member '" << ChildName + << "' of archive library failed'" << ArchiveName + << "'\n"; + return nullptr; + } + if (Verbose) + errs() << "Linking member '" << ChildName << "' of archive library.\n"; + auto Err = L.linkModules(*Result, std::move(M), ApplicableFlags); + if (Err) + return nullptr; + ApplicableFlags = OrigFlags; + } // end for each child + ExitOnErr(std::move(Err)); + return Result; +} + namespace { /// Helper to load on demand a Module from file and cache it for subsequent @@ -281,7 +338,10 @@ // Similar to some flags, internalization doesn't apply to the first file. bool InternalizeLinkedSymbols = false; for (const auto &File : Files) { - std::unique_ptr M = loadFile(argv0, File, Context); + std::unique_ptr M = + (llvm::sys::path::extension(File) == ".a") + ? loadArFile(argv0, File, Context, L, Flags, ApplicableFlags) + : loadFile(argv0, File, Context); if (!M.get()) { errs() << argv0 << ": "; WithColor::error() << " loading file '" << File << "'\n";