Index: lld/COFF/Driver.h =================================================================== --- lld/COFF/Driver.h +++ lld/COFF/Driver.h @@ -21,6 +21,7 @@ #include "llvm/Object/COFF.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/TarWriter.h" #include #include @@ -94,7 +95,11 @@ // Library search path. The first element is always "" (current directory). std::vector SearchPaths; - std::set VisitedFiles; + + // We don't want to add the same file more than once. + // Files are uniquified by their filesystem and file number. + std::set VisitedFiles; + std::set VisitedLibs; Symbol *addUndefined(StringRef Sym); Index: lld/COFF/Driver.cpp =================================================================== --- lld/COFF/Driver.cpp +++ lld/COFF/Driver.cpp @@ -332,13 +332,24 @@ return Filename; } +static Optional getUniqueID(StringRef Path) { + sys::fs::UniqueID Ret; + if (sys::fs::getUniqueID(Path, Ret)) + return None; + return Ret; +} + // Resolves a file path. This never returns the same path // (in that case, it returns None). Optional LinkerDriver::findFile(StringRef Filename) { StringRef Path = doFindFile(Filename); - bool Seen = !VisitedFiles.insert(Path.lower()).second; - if (Seen) - return None; + + if (Optional ID = getUniqueID(Path)) { + bool Seen = !VisitedFiles.insert(*ID).second; + if (Seen) + return None; + } + if (Path.endswith_lower(".lib")) VisitedLibs.insert(sys::path::filename(Path)); return Path; @@ -361,11 +372,14 @@ return None; if (!VisitedLibs.insert(Filename.lower()).second) return None; + StringRef Path = doFindLib(Filename); if (Config->NoDefaultLibs.count(Path)) return None; - if (!VisitedFiles.insert(Path.lower()).second) - return None; + + if (Optional ID = getUniqueID(Path)) + if (!VisitedFiles.insert(*ID).second) + return None; return Path; } @@ -1231,22 +1245,29 @@ if (errorCount()) return; - bool WholeArchiveFlag = Args.hasArg(OPT_wholearchive_flag); + // A predicate returning true if a given path is an argument for + // /wholearchive:, or /wholearchive is enabled globally. + // This function is a bit tricky because "foo.obj /wholearchive:././foo.obj" + // needs to be handled as "/wholearchive:foo.obj foo.obj". + std::set WholeArchives; + for (auto *Arg : Args.filtered(OPT_wholearchive_file)) + if (Optional ID = getUniqueID(Arg->getValue())) + WholeArchives.insert(*ID); + + auto IsWholeArchive = [&](StringRef Path) -> bool { + if (Args.hasArg(OPT_wholearchive_flag)) + return true; + if (Optional ID = getUniqueID(Path)) + return WholeArchives.count(*ID); + return false; + }; + // 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, OPT_wholearchive_file)) { - switch (Arg->getOption().getID()) { - case OPT_INPUT: - if (Optional Path = findFile(Arg->getValue())) - enqueuePath(*Path, WholeArchiveFlag); - break; - case OPT_wholearchive_file: - if (Optional Path = findFile(Arg->getValue())) - enqueuePath(*Path, true); - break; - } - } + for (auto *Arg : Args.filtered(OPT_INPUT, OPT_wholearchive_file)) + if (Optional Path = findFile(Arg->getValue())) + enqueuePath(*Path, IsWholeArchive(Arg->getValue())); + for (auto *Arg : Args.filtered(OPT_defaultlib)) if (Optional Path = findLib(Arg->getValue())) enqueuePath(*Path, false); Index: lld/test/COFF/wholearchive.s =================================================================== --- lld/test/COFF/wholearchive.s +++ lld/test/COFF/wholearchive.s @@ -10,6 +10,14 @@ # 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 %t.archive.lib -wholearchive:%t.archive.lib -implib:%t.lib +# RUN: llvm-readobj %t.lib | FileCheck %s -check-prefix CHECK-IMPLIB + +# RUN: mkdir -p %t.dir +# RUN: cp %t.archive.lib %t.dir/foo.lib +# RUN: lld-link -dll -out:%t.dll -entry:main %t.main.obj %t.dir/./foo.lib -wholearchive:%t.dir/foo.lib -implib:%t.lib +# RUN: llvm-readobj %t.lib | FileCheck %s -check-prefix CHECK-IMPLIB + # CHECK-IMPLIB: Symbol: __imp_exportfn3 # CHECK-IMPLIB: Symbol: exportfn3