Index: COFF/Driver.h =================================================================== --- COFF/Driver.h +++ COFF/Driver.h @@ -110,11 +110,11 @@ void invokeMSVC(llvm::opt::InputArgList &Args); MemoryBufferRef takeBuffer(std::unique_ptr MB); - void addBuffer(std::unique_ptr MB); + void addBuffer(std::unique_ptr MB, bool WholeArchive); void addArchiveBuffer(MemoryBufferRef MBRef, StringRef SymName, StringRef ParentName); - void enqueuePath(StringRef Path); + void enqueuePath(StringRef Path, bool WholeArchive); void enqueueTask(std::function Task); bool run(); Index: COFF/Driver.cpp =================================================================== --- COFF/Driver.cpp +++ COFF/Driver.cpp @@ -110,7 +110,8 @@ return MBRef; } -void LinkerDriver::addBuffer(std::unique_ptr MB) { +void LinkerDriver::addBuffer(std::unique_ptr MB, + bool WholeArchive) { MemoryBufferRef MBRef = takeBuffer(std::move(MB)); // File type is detected by contents, not by file extension. @@ -121,10 +122,24 @@ } FilePaths.push_back(MBRef.getBufferIdentifier()); - if (Magic == file_magic::archive) - return Symtab->addFile(make(MBRef)); - if (Magic == file_magic::bitcode) - return Symtab->addFile(make(MBRef)); + if (Magic == file_magic::archive) { + if (WholeArchive) { + std::unique_ptr File = + check(Archive::create(MBRef), + MBRef.getBufferIdentifier() + ": failed to parse archive"); + + for (MemoryBufferRef Member : getArchiveMembers(File.get())) + addArchiveBuffer(Member, "*", MBRef.getBufferIdentifier()); + return; + } + Symtab->addFile(make(MBRef)); + return; + } + + if (Magic == file_magic::bitcode) { + Symtab->addFile(make(MBRef)); + return; + } if (Magic == file_magic::coff_cl_gl_object) error(MBRef.getBufferIdentifier() + ": is not a native COFF file. " @@ -133,7 +148,7 @@ Symtab->addFile(make(MBRef)); } -void LinkerDriver::enqueuePath(StringRef Path) { +void LinkerDriver::enqueuePath(StringRef Path, bool WholeArchive) { auto Future = std::make_shared>(createFutureForFile(Path)); std::string PathStr = Path; @@ -142,7 +157,7 @@ if (MBOrErr.second) error("could not open " + PathStr + ": " + MBOrErr.second.message()); else - Driver->addBuffer(std::move(MBOrErr.first)); + Driver->addBuffer(std::move(MBOrErr.first), WholeArchive); }); } @@ -215,7 +230,7 @@ break; case OPT_defaultlib: if (Optional Path = findLib(Arg->getValue())) - enqueuePath(*Path); + enqueuePath(*Path, false); break; case OPT_export: { Export E = parseExport(Arg->getValue()); @@ -956,16 +971,25 @@ // Create a list of input files. Files can be given as arguments // for /defaultlib option. std::vector MBs; - for (auto *Arg : Args.filtered(OPT_INPUT)) - if (Optional Path = findFile(Arg->getValue())) - enqueuePath(*Path); + for (auto *Arg : Args.filtered(OPT_INPUT, OPT_wholearchive_file)) { + switch (Arg->getOption().getID()) { + case OPT_INPUT: + if (Optional Path = findFile(Arg->getValue())) + enqueuePath(*Path, Args.hasArg(OPT_wholearchive_flag)); + break; + case OPT_wholearchive_file: + if (Optional Path = findFile(Arg->getValue())) + enqueuePath(*Path, true); + break; + } + } for (auto *Arg : Args.filtered(OPT_defaultlib)) if (Optional Path = findLib(Arg->getValue())) - enqueuePath(*Path); + enqueuePath(*Path, Args.hasArg(OPT_wholearchive_flag)); // Windows specific -- Create a resource file containing a manifest file. if (Config->Manifest == Configuration::Embed) - addBuffer(createManifestRes()); + addBuffer(createManifestRes(), false); // Read all input files given via the command line. run(); @@ -981,7 +1005,7 @@ // WindowsResource to convert resource files to a regular COFF file, // then link the resulting file normally. if (!Resources.empty()) - addBuffer(convertResToCOFF(Resources)); + addBuffer(convertResToCOFF(Resources), false); if (Tar) Tar->append("response.txt", Index: COFF/Options.td =================================================================== --- COFF/Options.td +++ COFF/Options.td @@ -47,6 +47,7 @@ def stub : P<"stub", "Specify DOS stub file">; def subsystem : P<"subsystem", "Specify subsystem">; def version : P<"version", "Specify a version number in the PE header">; +def wholearchive_file : P<"wholearchive", "Include all object files from this archive">; def disallowlib : Joined<["/", "-", "-?"], "disallowlib:">, Alias; @@ -78,6 +79,7 @@ def swaprun_cd : F<"swaprun:cd">; def swaprun_net : F<"swaprun:net">; def verbose : F<"verbose">; +def wholearchive_flag : F<"wholearchive">; def force : F<"force">, HelpText<"Allow undefined symbols when creating executables">; Index: test/COFF/wholearchive.s =================================================================== --- /dev/null +++ test/COFF/wholearchive.s @@ -0,0 +1,19 @@ +# REQEUIRES: x86 + +# RUN: yaml2obj < %p/Inputs/export.yaml > %t.archive.obj +# RUN: llvm-ar rcs %t.archive.lib %t.archive.obj +# RUN: llvm-mc -triple=x86_64-windows-msvc %s -filetype=obj -o %t.main.obj + +# RUN: lld-link -dll -out:%t.dll -entry:main %t.main.obj -wholearchive:%t.archive.lib -implib:%t.lib +# RUN: llvm-readobj %t.lib | FileCheck %s -check-prefix CHECK-IMPLIB + +# RUN: lld-link -dll -out:%t.dll -entry:main %t.main.obj -wholearchive %t.archive.lib -implib:%t.lib +# RUN: llvm-readobj %t.lib | FileCheck %s -check-prefix CHECK-IMPLIB + +# CHECK-IMPLIB: Symbol: __imp_exportfn3 +# CHECK-IMPLIB: Symbol: exportfn3 + +.global main +.text +main: + ret