Index: llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp =================================================================== --- llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp +++ llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp @@ -96,6 +96,47 @@ return ""; } +static void fatalOpenError(llvm::Error E, Twine File) { + if (!E) + return; + handleAllErrors(std::move(E), [&](const llvm::ErrorInfoBase &EIB) { + llvm::errs() << "error opening '" << File << "': " << EIB.message() << '\n'; + exit(1); + }); +} + +static void doList(opt::InputArgList& Args) { + // lib.exe prints the contents of the first archive file. + std::unique_ptr B; + for (auto *Arg : Args.filtered(OPT_INPUT)) { + // Create or open the archive object. + ErrorOr> MaybeBuf = + MemoryBuffer::getFile(Arg->getValue(), -1, false); + fatalOpenError(errorCodeToError(MaybeBuf.getError()), Arg->getValue()); + + if (identify_magic(MaybeBuf.get()->getBuffer()) == file_magic::archive) { + B = std::move(MaybeBuf.get()); + break; + } + } + + // lib.exe doesn't print an error if no .lib files are passed. + if (!B) + return; + + Error Err = Error::success(); + object::Archive Archive(B.get()->getMemBufferRef(), Err); + fatalOpenError(std::move(Err), B->getBufferIdentifier()); + + for (auto &C : Archive.children(Err)) { + Expected NameOrErr = C.getName(); + fatalOpenError(NameOrErr.takeError(), B->getBufferIdentifier()); + StringRef Name = NameOrErr.get(); + llvm::outs() << Name << '\n'; + } + fatalOpenError(std::move(Err), B->getBufferIdentifier()); +} + int llvm::libDriverMain(ArrayRef ArgsArr) { BumpPtrAllocator Alloc; StringSaver Saver(Alloc); @@ -130,6 +171,11 @@ if (!Args.hasArgNoClaim(OPT_INPUT)) return 0; + if (Args.hasArg(OPT_lst)) { + doList(Args); + return 0; + } + std::vector SearchPaths = getSearchPaths(&Args, Saver); // Create a NewArchiveMember for each input file. Index: llvm/lib/ToolDrivers/llvm-lib/Options.td =================================================================== --- llvm/lib/ToolDrivers/llvm-lib/Options.td +++ llvm/lib/ToolDrivers/llvm-lib/Options.td @@ -10,6 +10,9 @@ Joined<["/", "-", "-?"], name#":">, HelpText; def libpath: P<"libpath", "Object file search path">; + +// Can't be called "list" since that's a keyword. +def lst : F<"list">, HelpText<"List contents of .lib file on stdout">; def out : P<"out", "Path to file to write output">; def llvmlibthin : F<"llvmlibthin">, Index: llvm/test/tools/llvm-lib/list.test =================================================================== --- /dev/null +++ llvm/test/tools/llvm-lib/list.test @@ -0,0 +1,14 @@ +RUN: rm -rf %t && mkdir -p %t +RUN: llvm-mc -triple=x86_64-pc-windows-msvc -filetype=obj -o %t/a.obj %S/Inputs/a.s +RUN: llvm-mc -triple=x86_64-pc-windows-msvc -filetype=obj -o %t/b.obj %S/Inputs/b.s + +RUN: rm -f %t/l.lib +RUN: llvm-lib /out:%t/foo.lib %t/a.obj %t/b.obj + +# This should ignore the two .obj files, then print the first .lib file, +# then ignore the 2nd one. +RUN: llvm-lib /list %t/a.obj %t/b.obj %t/foo.lib %t/foo.lib | FileCheck %s + +CHECK: a.obj +CHECK: b.obj +CHECK-NOT: a.obj