[lld][COFF] Add /linkreprofullpathrsp flag (#174971)
This patch adds the /linkreprofullpathrsp flag with the same behaviour as link.exe. This flag emits a file containing the full paths to each object passed to the link line. This is used in particular when linking Arm64X binaries, as you need the full path to all the Arm64 objects that were used in a standard Arm64 build. See: https://learn.microsoft.com/en-us/cpp/build/reference/link-repro-full-path-rsp for the Microsoft documentation of the flag. Relands #165449
This commit is contained in:
parent
476ad9f03c
commit
0f3ba5a208
@ -340,7 +340,26 @@ void LinkerDriver::addBuffer(std::unique_ptr<MemoryBuffer> mb,
|
||||
}
|
||||
}
|
||||
|
||||
void LinkerDriver::enqueuePath(StringRef path, bool wholeArchive, bool lazy) {
|
||||
void LinkerDriver::handleReproFile(StringRef path, InputOpt inputOpt) {
|
||||
if (!reproFile)
|
||||
return;
|
||||
|
||||
*reproFile << '"';
|
||||
if (inputOpt == InputOpt::DefaultLib)
|
||||
*reproFile << "/defaultlib:";
|
||||
else if (inputOpt == InputOpt::WholeArchive)
|
||||
*reproFile << "/wholearchive:";
|
||||
|
||||
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 lazy, InputOpt inputOpt) {
|
||||
auto future = std::make_shared<std::future<MBErrPair>>(
|
||||
createFutureForFile(std::string(path)));
|
||||
std::string pathStr = std::string(path);
|
||||
@ -378,8 +397,11 @@ void LinkerDriver::enqueuePath(StringRef path, bool wholeArchive, bool lazy) {
|
||||
Err(ctx) << msg;
|
||||
else
|
||||
Err(ctx) << msg << "; did you mean '" << nearest << "'";
|
||||
} else
|
||||
ctx.driver.addBuffer(std::move(mb), wholeArchive, lazy);
|
||||
} else {
|
||||
handleReproFile(pathStr, inputOpt);
|
||||
ctx.driver.addBuffer(std::move(mb), inputOpt == InputOpt::WholeArchive,
|
||||
lazy);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -428,10 +450,9 @@ void LinkerDriver::enqueueArchiveMember(const Archive::Child &c,
|
||||
StringRef parentName) {
|
||||
|
||||
auto reportBufferError = [=](Error &&e) {
|
||||
StringRef childName =
|
||||
CHECK(c.getName(),
|
||||
"could not get child name for archive " + parentName +
|
||||
" while loading symbol " + toCOFFString(ctx, sym));
|
||||
StringRef childName = CHECK(
|
||||
c.getName(), "could not get child name for archive " + parentName +
|
||||
" while loading symbol " + toCOFFString(ctx, sym));
|
||||
Fatal(ctx) << "could not get the buffer for the member defining symbol "
|
||||
<< &sym << ": " << parentName << "(" << childName
|
||||
<< "): " << std::move(e);
|
||||
@ -537,7 +558,7 @@ void LinkerDriver::parseDirectives(InputFile *file) {
|
||||
break;
|
||||
case OPT_defaultlib:
|
||||
if (std::optional<StringRef> path = findLibIfNew(arg->getValue()))
|
||||
enqueuePath(*path, false, false);
|
||||
enqueuePath(*path, false, InputOpt::DefaultLib);
|
||||
break;
|
||||
case OPT_entry:
|
||||
if (!arg->getValue()[0])
|
||||
@ -1638,6 +1659,15 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Handle /linkreprofullpathrsp
|
||||
if (auto *arg = args.getLastArg(OPT_linkreprofullpathrsp)) {
|
||||
std::error_code ec;
|
||||
reproFile = std::make_unique<raw_fd_ostream>(arg->getValue(), ec);
|
||||
if (ec) {
|
||||
Err(ctx) << "cannot open " << arg->getValue() << ": " << ec.message();
|
||||
reproFile.reset();
|
||||
}
|
||||
}
|
||||
|
||||
if (!args.hasArg(OPT_INPUT, OPT_wholearchive_file)) {
|
||||
if (args.hasArg(OPT_deffile))
|
||||
@ -2280,11 +2310,13 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
|
||||
break;
|
||||
case OPT_wholearchive_file:
|
||||
if (std::optional<StringRef> path = findFileIfNew(arg->getValue()))
|
||||
enqueuePath(*path, true, inLib);
|
||||
enqueuePath(*path, inLib, InputOpt::WholeArchive);
|
||||
break;
|
||||
case OPT_INPUT:
|
||||
if (std::optional<StringRef> path = findFileIfNew(arg->getValue()))
|
||||
enqueuePath(*path, isWholeArchive(*path), inLib);
|
||||
enqueuePath(*path, inLib,
|
||||
isWholeArchive(*path) ? InputOpt::WholeArchive
|
||||
: InputOpt::None);
|
||||
break;
|
||||
default:
|
||||
// Ignore other options.
|
||||
@ -2324,7 +2356,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
|
||||
// addWinSysRootLibSearchPaths(), which is why they are in a separate loop.
|
||||
for (auto *arg : args.filtered(OPT_defaultlib))
|
||||
if (std::optional<StringRef> path = findLibIfNew(arg->getValue()))
|
||||
enqueuePath(*path, false, false);
|
||||
enqueuePath(*path, false, InputOpt::DefaultLib);
|
||||
run();
|
||||
if (errorCount())
|
||||
return;
|
||||
@ -2890,6 +2922,9 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
|
||||
if (config->showTiming)
|
||||
ctx.rootTimer.print();
|
||||
|
||||
// Clean up /linkreprofullpathrsp file
|
||||
reproFile.reset();
|
||||
|
||||
if (config->timeTraceEnabled) {
|
||||
// Manually stop the topmost "COFF link" scope, since we're shutting down.
|
||||
timeTraceProfilerEnd();
|
||||
|
||||
@ -88,11 +88,13 @@ public:
|
||||
void enqueueArchiveMember(const Archive::Child &c, const Archive::Symbol &sym,
|
||||
StringRef parentName);
|
||||
|
||||
void enqueuePDB(StringRef Path) { enqueuePath(Path, false, false); }
|
||||
enum class InputOpt { None, DefaultLib, WholeArchive };
|
||||
void enqueuePDB(StringRef Path) { enqueuePath(Path, false); }
|
||||
|
||||
MemoryBufferRef takeBuffer(std::unique_ptr<MemoryBuffer> mb);
|
||||
|
||||
void enqueuePath(StringRef path, bool wholeArchive, bool lazy);
|
||||
void enqueuePath(StringRef path, bool lazy,
|
||||
InputOpt inputOpt = InputOpt::None);
|
||||
|
||||
// Returns a list of chunks of selected symbols.
|
||||
std::vector<Chunk *> getChunks() const;
|
||||
@ -138,6 +140,10 @@ private:
|
||||
//
|
||||
std::string getImportName(bool asLib);
|
||||
|
||||
// Write fullly resolved path to repro file if /linkreprofullpathrsp
|
||||
// is specified.
|
||||
void handleReproFile(StringRef path, InputOpt inputOpt);
|
||||
|
||||
void createImportLibrary(bool asLib);
|
||||
|
||||
// Used by the resolver to parse .drectve section contents.
|
||||
@ -193,6 +199,9 @@ private:
|
||||
int sdkMajor = 0;
|
||||
llvm::SmallString<128> windowsSdkLibPath;
|
||||
|
||||
// For linkreprofullpathrsp
|
||||
std::unique_ptr<llvm::raw_fd_ostream> reproFile;
|
||||
|
||||
// Functions below this line are defined in DriverUtils.cpp.
|
||||
|
||||
void printHelp(const char *argv0);
|
||||
|
||||
@ -75,6 +75,9 @@ def link : F<"link">, HelpText<"Ignored for compatibility">;
|
||||
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",
|
||||
|
||||
@ -40,6 +40,8 @@ COFF Improvements
|
||||
|
||||
* ``/fat-lto-objects`` addded to support FatLTO. Without ``/fat-lto-objects`` or with ``/fat-lto-objects:no``, LLD will link LLVM FatLTO objects using the relocatable object file.
|
||||
(`#165529 <https://github.com/llvm/llvm-project/pull/165529>`_)
|
||||
* ``/linkreprofullpathrsp`` prints the full path to each object passed to the link line to a file.
|
||||
(`#174971 <https://github.com/llvm/llvm-project/pull/165449>`_)
|
||||
|
||||
MinGW Improvements
|
||||
------------------
|
||||
|
||||
43
lld/test/COFF/linkreprofullpathrsp.test
Normal file
43
lld/test/COFF/linkreprofullpathrsp.test
Normal file
@ -0,0 +1,43 @@
|
||||
# REQUIRES: x86
|
||||
|
||||
# RUN: rm -rf %t.dir %t.obj
|
||||
# RUN: yaml2obj %p/Inputs/hello32.yaml -o %t.obj
|
||||
# RUN: yaml2obj %p/Inputs/empty.yaml -o %t.archive.obj
|
||||
# RUN: rm -f %t.archive.lib
|
||||
# RUN: llvm-ar rcs %t.archive.lib %t.archive.obj
|
||||
# RUN: llvm-pdbutil yaml2pdb %S/Inputs/pdb-type-server-simple-ts.yaml -pdb %t.pdb
|
||||
|
||||
|
||||
Test link.exe-style /linkreprofullpathrsp: flag.
|
||||
# RUN: mkdir -p %t.dir/build1
|
||||
# RUN: cd %t.dir/build1
|
||||
# RUN: lld-link /subsystem:console %t.obj %p/Inputs/std32.lib /defaultlib:%p/Inputs/library.lib \
|
||||
# RUN: /libpath:%p/Inputs /defaultlib:std64.lib ret42.lib /entry:main@0 /linkreprofullpathrsp:%t.rsp \
|
||||
# RUN: %t.pdb /wholearchive:%t.archive.lib /out:%t.exe /timestamp:0
|
||||
# # RUN: FileCheck %s --check-prefix=RSP -DT=%t -DP=%p < %t.rsp
|
||||
|
||||
# RUN: lld-link /subsystem:console @%t.rsp /out:%t2.exe /entry:main@0 /timestamp:0
|
||||
# RUN: diff %t.exe %t2.exe
|
||||
|
||||
# RSP: "[[T]].obj"
|
||||
# RSP-NEXT: "[[P]]{{[/\\]}}Inputs{{[/\\]}}std32.lib"
|
||||
# RSP-NEXT: "[[P]]{{[/\\]}}Inputs{{[/\\]}}ret42.lib"
|
||||
# RSP-NEXT: "[[T]].pdb"
|
||||
# RSP-NEXT: "/wholearchive:[[T]].archive.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"
|
||||
Loading…
x
Reference in New Issue
Block a user