Skip to content

Commit e49faac

Browse files
committed
[lld][COFF] Add /linkreprofullpathrsp flag
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.
1 parent 0621fd0 commit e49faac

File tree

4 files changed

+71
-8
lines changed

4 files changed

+71
-8
lines changed

lld/COFF/Driver.cpp

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,8 @@ void LinkerDriver::addBuffer(std::unique_ptr<MemoryBuffer> mb,
318318
}
319319
}
320320

321-
void LinkerDriver::enqueuePath(StringRef path, bool wholeArchive, bool lazy) {
321+
void LinkerDriver::enqueuePath(StringRef path, bool wholeArchive, bool lazy,
322+
llvm::raw_ostream *reproFile, bool defaultlib) {
322323
auto future = std::make_shared<std::future<MBErrPair>>(
323324
createFutureForFile(std::string(path)));
324325
std::string pathStr = std::string(path);
@@ -356,8 +357,17 @@ void LinkerDriver::enqueuePath(StringRef path, bool wholeArchive, bool lazy) {
356357
Err(ctx) << msg;
357358
else
358359
Err(ctx) << msg << "; did you mean '" << nearest << "'";
359-
} else
360+
} else {
361+
// Write full path to library to repro file if /linkreprofullpathrsp
362+
// is specified.
363+
if (reproFile) {
364+
*reproFile << '"';
365+
if (defaultlib)
366+
*reproFile << "/defaultlib:";
367+
*reproFile << pathStr << "\"\n";
368+
}
360369
ctx.driver.addBuffer(std::move(mb), wholeArchive, lazy);
370+
}
361371
});
362372
}
363373

@@ -514,7 +524,7 @@ void LinkerDriver::parseDirectives(InputFile *file) {
514524
break;
515525
case OPT_defaultlib:
516526
if (std::optional<StringRef> path = findLibIfNew(arg->getValue()))
517-
enqueuePath(*path, false, false);
527+
enqueuePath(*path, false, false, nullptr);
518528
break;
519529
case OPT_entry:
520530
if (!arg->getValue()[0])
@@ -2204,6 +2214,17 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
22042214
config->incremental = false;
22052215
}
22062216

2217+
// Handle /linkreprofullpathrsp.
2218+
std::unique_ptr<llvm::raw_ostream> reproFile;
2219+
if (auto *arg = args.getLastArg(OPT_linkreprofullpathrsp)) {
2220+
std::error_code ec;
2221+
reproFile = std::make_unique<llvm::raw_fd_ostream>(arg->getValue(), ec);
2222+
if (ec) {
2223+
Err(ctx) << "cannot open " << arg->getValue() << ": " << ec.message();
2224+
reproFile.reset();
2225+
}
2226+
}
2227+
22072228
if (errCount(ctx))
22082229
return;
22092230

@@ -2245,11 +2266,11 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
22452266
break;
22462267
case OPT_wholearchive_file:
22472268
if (std::optional<StringRef> path = findFileIfNew(arg->getValue()))
2248-
enqueuePath(*path, true, inLib);
2269+
enqueuePath(*path, true, inLib, reproFile.get());
22492270
break;
22502271
case OPT_INPUT:
22512272
if (std::optional<StringRef> path = findFileIfNew(arg->getValue()))
2252-
enqueuePath(*path, isWholeArchive(*path), inLib);
2273+
enqueuePath(*path, isWholeArchive(*path), inLib, reproFile.get());
22532274
break;
22542275
default:
22552276
// Ignore other options.
@@ -2289,7 +2310,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
22892310
// addWinSysRootLibSearchPaths(), which is why they are in a separate loop.
22902311
for (auto *arg : args.filtered(OPT_defaultlib))
22912312
if (std::optional<StringRef> path = findLibIfNew(arg->getValue()))
2292-
enqueuePath(*path, false, false);
2313+
enqueuePath(*path, false, false, reproFile.get(), true);
22932314
run();
22942315
if (errorCount())
22952316
return;

lld/COFF/Driver.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,11 +88,12 @@ class LinkerDriver {
8888
void enqueueArchiveMember(const Archive::Child &c, const Archive::Symbol &sym,
8989
StringRef parentName);
9090

91-
void enqueuePDB(StringRef Path) { enqueuePath(Path, false, false); }
91+
void enqueuePDB(StringRef Path) { enqueuePath(Path, false, false, nullptr); }
9292

9393
MemoryBufferRef takeBuffer(std::unique_ptr<MemoryBuffer> mb);
9494

95-
void enqueuePath(StringRef path, bool wholeArchive, bool lazy);
95+
void enqueuePath(StringRef path, bool wholeArchive, bool lazy,
96+
raw_ostream *reproFile, bool defaultlib = false);
9697

9798
// Returns a list of chunks of selected symbols.
9899
std::vector<Chunk *> getChunks() const;

lld/COFF/Options.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@ def libpath : P<"libpath", "Additional library search path">;
7474
def linkrepro : Joined<["/", "-", "/?", "-?"], "linkrepro:">,
7575
MetaVarName<"directory">,
7676
HelpText<"Write repro.tar containing inputs and command to reproduce link">;
77+
def linkreprofullpathrsp : Joined<["/", "-", "/?", "-?"], "linkreprofullpathrsp:">,
78+
MetaVarName<"directory">,
79+
HelpText<"Write .rsp file containing inputs used to link with full paths">;
7780
def lldignoreenv : F<"lldignoreenv">,
7881
HelpText<"Ignore environment variables like %LIB%">;
7982
def lldltocache : P<"lldltocache",
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# REQUIRES: x86
2+
# Unsupported on Windows due to maximum path length limitations.
3+
4+
# RUN: rm -rf %t.dir
5+
# RUN: split-file %s %t.dir
6+
# RUN: yaml2obj %p/Inputs/hello32.yaml -o %t.obj
7+
# RUN: llvm-mc -filetype=obj -triple=i386-windows %t.dir/drectve.s -o %t.dir/drectve.obj
8+
# RUN: echo '_main@0' > %t.order
9+
# RUN: touch %t.def
10+
# RUN: touch %t.cg
11+
12+
13+
14+
Test link.exe-style /linkreprofullpathrsp: flag.
15+
# RUN: mkdir -p %t.dir/build1
16+
# RUN: cd %t.dir/build1
17+
# RUN: lld-link %t.obj %p/Inputs/std32.lib /subsystem:console /defaultlib:%p/Inputs/library.lib \
18+
# RUN: /entry:main@0 /linkreprofullpathrsp:%t.rsp /out:%t.exe
19+
# RUN: FileCheck %s --check-prefix=RSP -DT=%t -DP=%p < %t.rsp
20+
21+
# RSP: [[T]].obj
22+
# RSP-NEXT: "[[P]]/Inputs/std32.lib"
23+
# RSP-NEXT: "/defaultlib:[[P]]/Inputs/library.lib"
24+
25+
#--- drectve.s
26+
.section .drectve, "yn"
27+
.ascii "/defaultlib:std32"
28+
29+
#--- archive.s
30+
.text
31+
.intel_syntax noprefix
32+
.globl exportfn3
33+
.p2align 4
34+
exportfn3:
35+
ret
36+
37+
.section .drectve,"yni"
38+
.ascii " /EXPORT:exportfn3"

0 commit comments

Comments
 (0)