diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp index 0e528de9c3652..c26955fbbfe5b 100644 --- a/lld/COFF/Driver.cpp +++ b/lld/COFF/Driver.cpp @@ -318,7 +318,22 @@ void LinkerDriver::addBuffer(std::unique_ptr mb, } } -void LinkerDriver::enqueuePath(StringRef path, bool wholeArchive, bool lazy) { +static void handleReproFile(COFFLinkerContext &ctx, raw_ostream &reproFile, + StringRef path, bool defaultlib) { + reproFile << '"'; + if (defaultlib) + reproFile << "/defaultlib:"; + SmallString<128> absPath = path; + std::error_code ec = sys::fs::make_absolute(absPath); + if (ec) + Err(ctx) << "cannot find absolute path for reproFile for " << absPath + << ": " << ec.message(); + sys::path::remove_dots(absPath, true); + reproFile << absPath << "\"\n"; +} + +void LinkerDriver::enqueuePath(StringRef path, bool wholeArchive, bool lazy, + llvm::raw_ostream *reproFile, bool defaultlib) { auto future = std::make_shared>( createFutureForFile(std::string(path))); std::string pathStr = std::string(path); @@ -356,8 +371,14 @@ void LinkerDriver::enqueuePath(StringRef path, bool wholeArchive, bool lazy) { Err(ctx) << msg; else Err(ctx) << msg << "; did you mean '" << nearest << "'"; - } else + } else { + // Write full path to library to repro file if /linkreprofullpathrsp + // is specified. + if (reproFile) + handleReproFile(ctx, *reproFile, pathStr, defaultlib); + ctx.driver.addBuffer(std::move(mb), wholeArchive, lazy); + } }); } @@ -514,7 +535,7 @@ void LinkerDriver::parseDirectives(InputFile *file) { break; case OPT_defaultlib: if (std::optional path = findLibIfNew(arg->getValue())) - enqueuePath(*path, false, false); + enqueuePath(*path, false, false, nullptr); break; case OPT_entry: if (!arg->getValue()[0]) @@ -2204,6 +2225,17 @@ void LinkerDriver::linkerMain(ArrayRef argsArr) { config->incremental = false; } + // Handle /linkreprofullpathrsp. + std::unique_ptr reproFile; + if (auto *arg = args.getLastArg(OPT_linkreprofullpathrsp)) { + std::error_code ec; + reproFile = std::make_unique(arg->getValue(), ec); + if (ec) { + Err(ctx) << "cannot open " << arg->getValue() << ": " << ec.message(); + reproFile.reset(); + } + } + if (errCount(ctx)) return; @@ -2245,11 +2277,11 @@ void LinkerDriver::linkerMain(ArrayRef argsArr) { break; case OPT_wholearchive_file: if (std::optional path = findFileIfNew(arg->getValue())) - enqueuePath(*path, true, inLib); + enqueuePath(*path, true, inLib, reproFile.get()); break; case OPT_INPUT: if (std::optional path = findFileIfNew(arg->getValue())) - enqueuePath(*path, isWholeArchive(*path), inLib); + enqueuePath(*path, isWholeArchive(*path), inLib, reproFile.get()); break; default: // Ignore other options. @@ -2289,7 +2321,7 @@ void LinkerDriver::linkerMain(ArrayRef argsArr) { // addWinSysRootLibSearchPaths(), which is why they are in a separate loop. for (auto *arg : args.filtered(OPT_defaultlib)) if (std::optional path = findLibIfNew(arg->getValue())) - enqueuePath(*path, false, false); + enqueuePath(*path, false, false, reproFile.get(), true); run(); if (errorCount()) return; diff --git a/lld/COFF/Driver.h b/lld/COFF/Driver.h index 14710d5853bcf..f4b72a317d077 100644 --- a/lld/COFF/Driver.h +++ b/lld/COFF/Driver.h @@ -88,11 +88,12 @@ class LinkerDriver { void enqueueArchiveMember(const Archive::Child &c, const Archive::Symbol &sym, StringRef parentName); - void enqueuePDB(StringRef Path) { enqueuePath(Path, false, false); } + void enqueuePDB(StringRef Path) { enqueuePath(Path, false, false, nullptr); } MemoryBufferRef takeBuffer(std::unique_ptr mb); - void enqueuePath(StringRef path, bool wholeArchive, bool lazy); + void enqueuePath(StringRef path, bool wholeArchive, bool lazy, + raw_ostream *reproFile, bool defaultlib = false); // Returns a list of chunks of selected symbols. std::vector getChunks() const; diff --git a/lld/COFF/Options.td b/lld/COFF/Options.td index d77478fc9c987..dca8a721dc4fd 100644 --- a/lld/COFF/Options.td +++ b/lld/COFF/Options.td @@ -74,6 +74,9 @@ def libpath : P<"libpath", "Additional library search path">; def linkrepro : Joined<["/", "-", "/?", "-?"], "linkrepro:">, MetaVarName<"directory">, HelpText<"Write repro.tar containing inputs and command to reproduce link">; +def linkreprofullpathrsp : Joined<["/", "-", "/?", "-?"], "linkreprofullpathrsp:">, + MetaVarName<"directory">, + HelpText<"Write .rsp file containing inputs used to link with full paths">; def lldignoreenv : F<"lldignoreenv">, HelpText<"Ignore environment variables like %LIB%">; def lldltocache : P<"lldltocache", diff --git a/lld/test/COFF/linkreprofullpathrsp.test b/lld/test/COFF/linkreprofullpathrsp.test new file mode 100644 index 0000000000000..b099d4f217913 --- /dev/null +++ b/lld/test/COFF/linkreprofullpathrsp.test @@ -0,0 +1,35 @@ +# REQUIRES: x86 +# Unsupported on Windows due to maximum path length limitations. +# UNSUPPORTED: system-windows + +# RUN: rm -rf %t.dir %t.obj +# RUN: yaml2obj %p/Inputs/hello32.yaml -o %t.obj + +Test link.exe-style /linkreprofullpathrsp: flag. +# RUN: mkdir -p %t.dir/build1 +# RUN: cd %t.dir/build1 +# RUN: lld-link %t.obj %p/Inputs/std32.lib /subsystem:console /defaultlib:%p/Inputs/library.lib \ +# RUN: /libpath:%p/Inputs /defaultlib:std64.lib ret42.lib /entry:main@0 /linkreprofullpathrsp:%t.rsp \ +# RUN: /out:%t.exe +# RUN: FileCheck %s --check-prefix=RSP -DT=%t -DP=%p < %t.rsp + +# RSP: [[T]].obj +# RSP-NEXT: "[[P]]/Inputs/std32.lib" +# RSP-NEXT: "[[P]]/Inputs/ret42.lib" +# RSP-NEXT: "/defaultlib:[[P]]/Inputs/library.lib" +# RSP-NEXT: "/defaultlib:[[P]]/Inputs/std64.lib" + +#--- drectve.s + .section .drectve, "yn" + .ascii "/defaultlib:std32" + +#--- archive.s + .text + .intel_syntax noprefix + .globl exportfn3 + .p2align 4 +exportfn3: + ret + + .section .drectve,"yni" + .ascii " /EXPORT:exportfn3"