Index: ELF/InputFiles.h =================================================================== --- ELF/InputFiles.h +++ ELF/InputFiles.h @@ -240,6 +240,7 @@ public: explicit ArchiveFile(MemoryBufferRef M) : InputFile(ArchiveKind, M) {} static bool classof(const InputFile *F) { return F->kind() == ArchiveKind; } + static bool archiveWithoutSymbolsSeen() { return ArchiveWithoutSymbolsSeen; } template void parse(); // Returns a memory buffer for a given symbol and the offset in the archive @@ -249,6 +250,7 @@ std::pair getMember(const Archive::Symbol *Sym); private: + static bool ArchiveWithoutSymbolsSeen; std::unique_ptr File; llvm::DenseSet Seen; }; Index: ELF/InputFiles.cpp =================================================================== --- ELF/InputFiles.cpp +++ ELF/InputFiles.cpp @@ -55,6 +55,8 @@ }; } +bool ArchiveFile::ArchiveWithoutSymbolsSeen = false; + Optional elf::readFile(StringRef Path) { log(Path); auto MBOrErr = MemoryBuffer::getFile(Path); @@ -556,8 +558,13 @@ MB.getBufferIdentifier() + ": failed to parse archive"); // Read the symbol table to construct Lazy objects. - for (const Archive::Symbol &Sym : File->symbols()) + bool NoSymbols = true; + for (const Archive::Symbol &Sym : File->symbols()) { Symtab::X->addLazyArchive(this, Sym); + NoSymbols = false; + } + + if (NoSymbols) ArchiveWithoutSymbolsSeen = true; } // Returns a buffer pointing to a member file containing a given symbol. Index: ELF/Relocations.cpp =================================================================== --- ELF/Relocations.cpp +++ ELF/Relocations.cpp @@ -611,10 +611,18 @@ toString(Sym) + "'"; if (Config->UnresolvedSymbols == UnresolvedPolicy::WarnAll || - (Config->UnresolvedSymbols == UnresolvedPolicy::Warn && CanBeExternal)) + (Config->UnresolvedSymbols == UnresolvedPolicy::Warn && CanBeExternal)) { warn(Msg); - else + } else { error(Msg); + if (ArchiveFile::archiveWithoutSymbolsSeen()) + message("At least one archive listed no symbols in its index." + " This can happen when creating archives with a version" + " of ar that does not understand the object files in" + " the archive. For example, if you are using LLVM" + " bitcode objects (such as created by -flto), you may " + " need to use llvm-ar or GNU ar with a plugin.\n"); + } } template Index: test/ELF/lto/archive-no-index.ll =================================================================== --- /dev/null +++ test/ELF/lto/archive-no-index.ll @@ -0,0 +1,39 @@ +; REQUIRES: x86 +; Tests that we suggest that LTO symbols missing from an archive index +; may be the cause of undefined references, but only if we both +; encountered an empty archive index and undefined references (to prevent +; noisy false alarms). + +; RUN: rm -fr %T/archive-no-index +; RUN: mkdir %T/archive-no-index +; RUN: llvm-as %S/Inputs/archive.ll -o %T/archive-no-index/f.o +; RUN: llvm-ar cr %T/archive-no-index/libf.a +; RUN: llvm-ar qS %T/archive-no-index/libf.a %T/archive-no-index/f.o +; RUN: llvm-as %s -o %t.o +; RUN: not ld.lld -emain -m elf_x86_64 %t.o -o %t %T/archive-no-index/libf.a \ +; RUN: 2>&1 | FileCheck --check-prefix=NOTE %s + +; RUN: llvm-ar crs %T/archive-no-index/libfs.a %T/archive-no-index/f.o +; RUN: ld.lld -emain -m elf_x86_64 %t.o -o %t %T/archive-no-index/libf.a \ +; RUN: %T/archive-no-index/libfs.a + +; RUN: llvm-as %S/Inputs/archive-3.ll -o %T/archive-no-index/foo.o +; RUN: llvm-ar crs %T/archive-no-index/libfoo.a %T/archive-no-index/foo.o +; RUN: not ld.lld -emain -m elf_x86_64 %t.o -o %t %T/archive-no-index/libfoo.a \ +; RUN: 2>&1 | FileCheck --check-prefix=NO-NOTE %s + +; NOTE: undefined symbol 'f' +; NOTE: archive listed no symbols + +; NO-NOTE: undefined symbol 'f' +; NO-NOTE-NOT: archive listed no symbols + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +declare void @f() + +define i32 @main() { + call void @f() + ret i32 0 +}