diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp --- a/lld/COFF/Driver.cpp +++ b/lld/COFF/Driver.cpp @@ -247,10 +247,25 @@ createFutureForFile(std::string(path))); std::string pathStr = std::string(path); enqueueTask([=]() { - auto mbOrErr = future->get(); - if (mbOrErr.second) { - std::string msg = - "could not open '" + pathStr + "': " + mbOrErr.second.message(); + auto [mb, ec] = future->get(); + if (ec) { + // Retry reading the file (synchronously) now that we may have added + // winsysroot search paths from SymbolTable::addFile(). + // Retrying synchronously is important for keeping the order of inputs + // consistent. + // This makes it so that if the user passes something in the winsysroot + // before something we can find with an architecture, we won't find the + // winsysroot file. + if (std::optional retryPath = findFile(pathStr)) { + auto retryMb = MemoryBuffer::getFile(*retryPath, /*IsText=*/false, + /*RequiresNullTerminator=*/false); + ec = retryMb.getError(); + if (!ec) + mb = std::move(*retryMb); + } + } + if (ec) { + std::string msg = "could not open '" + pathStr + "': " + ec.message(); // Check if the filename is a typo for an option flag. OptTable thinks // that all args that are not known options and that start with / are // filenames, but e.g. `/nodefaultlibs` is more likely a typo for @@ -262,7 +277,7 @@ else error(msg + "; did you mean '" + nearest + "'"); } else - ctx.driver.addBuffer(std::move(mbOrErr.first), wholeArchive, lazy); + ctx.driver.addBuffer(std::move(mb), wholeArchive, lazy); }); } diff --git a/lld/test/COFF/winsysroot.test b/lld/test/COFF/winsysroot.test --- a/lld/test/COFF/winsysroot.test +++ b/lld/test/COFF/winsysroot.test @@ -12,6 +12,31 @@ # RUN: lld-link %p/Inputs/hello64.obj /winsysroot:%t.dir/sysroot \ # RUN: /defaultlib:std64 /entry:main +Check directly passed lib with /machine: +# RUN: lld-link %p/Inputs/hello64.obj /winsysroot:%t.dir/sysroot /machine:x64 \ +# RUN: std64.lib /entry:main + +# RUN: lld-link %t.obj /winsysroot:%t.dir/sysroot /machine:x86 \ +# RUN: std32.lib /entry:main + +Check directly passed lib without /machine: (should infer from obj arch) +# RUN: lld-link %p/Inputs/hello64.obj /winsysroot:%t.dir/sysroot \ +# RUN: std64.lib /entry:main + +# RUN: lld-link %t.obj /winsysroot:%t.dir/sysroot \ +# RUN: std32.lib /entry:main + +If winsysroot lib appears before we can detect arch we don't find it +# RUN: not lld-link std64.lib %p/Inputs/hello64.obj /winsysroot:%t.dir/sysroot \ +# RUN: /entry:main + +Check we don't choose the wrong arch +# RUN: not lld-link %t.obj /winsysroot:%t.dir/sysroot \ +# RUN: std64.lib /entry:main + +# RUN: not lld-link %p/Inputs/hello64.obj /winsysroot:%t.dir/sysroot \ +# RUN: std32.lib /entry:main + Check that when /winsysroot is specified, %LIB% is ignored. # RUN: env LIB=foo.dir/sysroot/VC/Tools/MSVC/1.1.1.1/lib/x86 not lld-link %t.obj /winsysroot:%t.dir/doesnotexist /defaultlib:std32 2>&1 | FileCheck -check-prefix=LIBIGNORED %s LIBIGNORED: could not open 'std32.lib'