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,8 +122,18 @@ } FilePaths.push_back(MBRef.getBufferIdentifier()); - if (Magic == file_magic::archive) + 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; + } return Symtab->addFile(make(MBRef)); + } if (Magic == file_magic::bitcode) return Symtab->addFile(make(MBRef)); @@ -133,7 +144,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 +153,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 +226,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()); @@ -955,17 +966,27 @@ // Create a list of input files. Files can be given as arguments // for /defaultlib option. + bool WholeArchive = Args.hasArg(OPT_wholearchive_flag); 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, WholeArchive); + 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, WholeArchive); // 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 +1002,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: MinGW/Driver.cpp =================================================================== --- MinGW/Driver.cpp +++ MinGW/Driver.cpp @@ -172,11 +172,23 @@ for (auto *A : Args.filtered(OPT_L)) SearchPaths.push_back(A->getValue()); - for (auto *A : Args.filtered(OPT_INPUT, OPT_l)) { - if (A->getOption().getUnaliasedOption().getID() == OPT_INPUT) - Add(A->getValue()); - else - Add(searchLibrary(A->getValue(), SearchPaths, Args.hasArg(OPT_Bstatic))); + StringRef WholeArchivePrefix = ""; + for (auto *A : Args.filtered(OPT_INPUT, OPT_l, OPT_whole_archive, + OPT_no_whole_archive)) { + switch (A->getOption().getID()) { + case OPT_INPUT: + Add(WholeArchivePrefix + StringRef(A->getValue())); + break; + case OPT_l: + Add(WholeArchivePrefix + searchLibrary(A->getValue(), SearchPaths, Args.hasArg(OPT_Bstatic))); + break; + case OPT_whole_archive: + WholeArchivePrefix = "-wholearchive:"; + break; + case OPT_no_whole_archive: + WholeArchivePrefix = ""; + break; + } } if (Args.hasArg(OPT_verbose)) Index: MinGW/Options.td =================================================================== --- MinGW/Options.td +++ MinGW/Options.td @@ -12,12 +12,16 @@ HelpText<"Root name of library to use">; def m: JoinedOrSeparate<["-"], "m">, HelpText<"Set target emulation">; def mllvm: S<"mllvm">; +def no_whole_archive: F<"no-whole-archive">, + HelpText<"No longer include all object files for following archives">; def o: JoinedOrSeparate<["-"], "o">, MetaVarName<"">, HelpText<"Path to file to write output">; def out_implib: Separate<["--"], "out-implib">, HelpText<"Import library name">; def shared: F<"shared">, HelpText<"Build a shared object">; def subs: Separate<["--"], "subsystem">, HelpText<"Specify subsystem">; def stack: Separate<["--"], "stack">; +def whole_archive: F<"whole-archive">, + HelpText<"Include all object files for following archives">; def verbose: F<"verbose">, HelpText<"Verbose mode">; // LLD specific options 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 Index: test/MinGW/driver.test =================================================================== --- test/MinGW/driver.test +++ test/MinGW/driver.test @@ -47,3 +47,6 @@ RUN: ld.lld -### -shared -m i386pe -e _DllMainCRTStartup@12 foo.o | FileCheck -check-prefix I386-ENTRY %s I386-ENTRY: -entry:DllMainCRTStartup@12 + +RUN: ld.lld -### -shared -m i386pep foo.o --whole-archive bar.a --no-whole-archive baz.a | FileCheck -check-prefix WHOLE-ARCHIVE %s +WHOLE-ARCHIVE: foo.o -wholearchive:bar.a baz.a