Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 0f3ba5a

Browse files
authored
[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
1 parent 476ad9f commit 0f3ba5a

5 files changed

Lines changed: 105 additions & 13 deletions

File tree

lld/COFF/Driver.cpp

Lines changed: 46 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,26 @@ void LinkerDriver::addBuffer(std::unique_ptr<MemoryBuffer> mb,
340340
}
341341
}
342342

343-
void LinkerDriver::enqueuePath(StringRef path, bool wholeArchive, bool lazy) {
343+
void LinkerDriver::handleReproFile(StringRef path, InputOpt inputOpt) {
344+
if (!reproFile)
345+
return;
346+
347+
*reproFile << '"';
348+
if (inputOpt == InputOpt::DefaultLib)
349+
*reproFile << "/defaultlib:";
350+
else if (inputOpt == InputOpt::WholeArchive)
351+
*reproFile << "/wholearchive:";
352+
353+
SmallString<128> absPath = path;
354+
std::error_code ec = sys::fs::make_absolute(absPath);
355+
if (ec)
356+
Err(ctx) << "cannot find absolute path for reproFile for " << absPath
357+
<< ": " << ec.message();
358+
sys::path::remove_dots(absPath, true);
359+
*reproFile << absPath << "\"\n";
360+
}
361+
362+
void LinkerDriver::enqueuePath(StringRef path, bool lazy, InputOpt inputOpt) {
344363
auto future = std::make_shared<std::future<MBErrPair>>(
345364
createFutureForFile(std::string(path)));
346365
std::string pathStr = std::string(path);
@@ -378,8 +397,11 @@ void LinkerDriver::enqueuePath(StringRef path, bool wholeArchive, bool lazy) {
378397
Err(ctx) << msg;
379398
else
380399
Err(ctx) << msg << "; did you mean '" << nearest << "'";
381-
} else
382-
ctx.driver.addBuffer(std::move(mb), wholeArchive, lazy);
400+
} else {
401+
handleReproFile(pathStr, inputOpt);
402+
ctx.driver.addBuffer(std::move(mb), inputOpt == InputOpt::WholeArchive,
403+
lazy);
404+
}
383405
});
384406
}
385407

@@ -428,10 +450,9 @@ void LinkerDriver::enqueueArchiveMember(const Archive::Child &c,
428450
StringRef parentName) {
429451

430452
auto reportBufferError = [=](Error &&e) {
431-
StringRef childName =
432-
CHECK(c.getName(),
433-
"could not get child name for archive " + parentName +
434-
" while loading symbol " + toCOFFString(ctx, sym));
453+
StringRef childName = CHECK(
454+
c.getName(), "could not get child name for archive " + parentName +
455+
" while loading symbol " + toCOFFString(ctx, sym));
435456
Fatal(ctx) << "could not get the buffer for the member defining symbol "
436457
<< &sym << ": " << parentName << "(" << childName
437458
<< "): " << std::move(e);
@@ -537,7 +558,7 @@ void LinkerDriver::parseDirectives(InputFile *file) {
537558
break;
538559
case OPT_defaultlib:
539560
if (std::optional<StringRef> path = findLibIfNew(arg->getValue()))
540-
enqueuePath(*path, false, false);
561+
enqueuePath(*path, false, InputOpt::DefaultLib);
541562
break;
542563
case OPT_entry:
543564
if (!arg->getValue()[0])
@@ -1638,6 +1659,15 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
16381659
}
16391660
}
16401661
}
1662+
// Handle /linkreprofullpathrsp
1663+
if (auto *arg = args.getLastArg(OPT_linkreprofullpathrsp)) {
1664+
std::error_code ec;
1665+
reproFile = std::make_unique<raw_fd_ostream>(arg->getValue(), ec);
1666+
if (ec) {
1667+
Err(ctx) << "cannot open " << arg->getValue() << ": " << ec.message();
1668+
reproFile.reset();
1669+
}
1670+
}
16411671

16421672
if (!args.hasArg(OPT_INPUT, OPT_wholearchive_file)) {
16431673
if (args.hasArg(OPT_deffile))
@@ -2280,11 +2310,13 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
22802310
break;
22812311
case OPT_wholearchive_file:
22822312
if (std::optional<StringRef> path = findFileIfNew(arg->getValue()))
2283-
enqueuePath(*path, true, inLib);
2313+
enqueuePath(*path, inLib, InputOpt::WholeArchive);
22842314
break;
22852315
case OPT_INPUT:
22862316
if (std::optional<StringRef> path = findFileIfNew(arg->getValue()))
2287-
enqueuePath(*path, isWholeArchive(*path), inLib);
2317+
enqueuePath(*path, inLib,
2318+
isWholeArchive(*path) ? InputOpt::WholeArchive
2319+
: InputOpt::None);
22882320
break;
22892321
default:
22902322
// Ignore other options.
@@ -2324,7 +2356,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
23242356
// addWinSysRootLibSearchPaths(), which is why they are in a separate loop.
23252357
for (auto *arg : args.filtered(OPT_defaultlib))
23262358
if (std::optional<StringRef> path = findLibIfNew(arg->getValue()))
2327-
enqueuePath(*path, false, false);
2359+
enqueuePath(*path, false, InputOpt::DefaultLib);
23282360
run();
23292361
if (errorCount())
23302362
return;
@@ -2890,6 +2922,9 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
28902922
if (config->showTiming)
28912923
ctx.rootTimer.print();
28922924

2925+
// Clean up /linkreprofullpathrsp file
2926+
reproFile.reset();
2927+
28932928
if (config->timeTraceEnabled) {
28942929
// Manually stop the topmost "COFF link" scope, since we're shutting down.
28952930
timeTraceProfilerEnd();

lld/COFF/Driver.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,11 +88,13 @@ 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+
enum class InputOpt { None, DefaultLib, WholeArchive };
92+
void enqueuePDB(StringRef Path) { enqueuePath(Path, false); }
9293

9394
MemoryBufferRef takeBuffer(std::unique_ptr<MemoryBuffer> mb);
9495

95-
void enqueuePath(StringRef path, bool wholeArchive, bool lazy);
96+
void enqueuePath(StringRef path, bool lazy,
97+
InputOpt inputOpt = InputOpt::None);
9698

9799
// Returns a list of chunks of selected symbols.
98100
std::vector<Chunk *> getChunks() const;
@@ -138,6 +140,10 @@ class LinkerDriver {
138140
//
139141
std::string getImportName(bool asLib);
140142

143+
// Write fullly resolved path to repro file if /linkreprofullpathrsp
144+
// is specified.
145+
void handleReproFile(StringRef path, InputOpt inputOpt);
146+
141147
void createImportLibrary(bool asLib);
142148

143149
// Used by the resolver to parse .drectve section contents.
@@ -193,6 +199,9 @@ class LinkerDriver {
193199
int sdkMajor = 0;
194200
llvm::SmallString<128> windowsSdkLibPath;
195201

202+
// For linkreprofullpathrsp
203+
std::unique_ptr<llvm::raw_fd_ostream> reproFile;
204+
196205
// Functions below this line are defined in DriverUtils.cpp.
197206

198207
void printHelp(const char *argv0);

lld/COFF/Options.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ def link : F<"link">, HelpText<"Ignored for compatibility">;
7575
def linkrepro : Joined<["/", "-", "/?", "-?"], "linkrepro:">,
7676
MetaVarName<"directory">,
7777
HelpText<"Write repro.tar containing inputs and command to reproduce link">;
78+
def linkreprofullpathrsp : Joined<["/", "-", "/?", "-?"], "linkreprofullpathrsp:">,
79+
MetaVarName<"directory">,
80+
HelpText<"Write .rsp file containing inputs used to link with full paths">;
7881
def lldignoreenv : F<"lldignoreenv">,
7982
HelpText<"Ignore environment variables like %LIB%">;
8083
def lldltocache : P<"lldltocache",

lld/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ COFF Improvements
4040

4141
* ``/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.
4242
(`#165529 <https://github.com/llvm/llvm-project/pull/165529>`_)
43+
* ``/linkreprofullpathrsp`` prints the full path to each object passed to the link line to a file.
44+
(`#174971 <https://github.com/llvm/llvm-project/pull/165449>`_)
4345

4446
MinGW Improvements
4547
------------------
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# REQUIRES: x86
2+
3+
# RUN: rm -rf %t.dir %t.obj
4+
# RUN: yaml2obj %p/Inputs/hello32.yaml -o %t.obj
5+
# RUN: yaml2obj %p/Inputs/empty.yaml -o %t.archive.obj
6+
# RUN: rm -f %t.archive.lib
7+
# RUN: llvm-ar rcs %t.archive.lib %t.archive.obj
8+
# RUN: llvm-pdbutil yaml2pdb %S/Inputs/pdb-type-server-simple-ts.yaml -pdb %t.pdb
9+
10+
11+
Test link.exe-style /linkreprofullpathrsp: flag.
12+
# RUN: mkdir -p %t.dir/build1
13+
# RUN: cd %t.dir/build1
14+
# RUN: lld-link /subsystem:console %t.obj %p/Inputs/std32.lib /defaultlib:%p/Inputs/library.lib \
15+
# RUN: /libpath:%p/Inputs /defaultlib:std64.lib ret42.lib /entry:main@0 /linkreprofullpathrsp:%t.rsp \
16+
# RUN: %t.pdb /wholearchive:%t.archive.lib /out:%t.exe /timestamp:0
17+
# # RUN: FileCheck %s --check-prefix=RSP -DT=%t -DP=%p < %t.rsp
18+
19+
# RUN: lld-link /subsystem:console @%t.rsp /out:%t2.exe /entry:main@0 /timestamp:0
20+
# RUN: diff %t.exe %t2.exe
21+
22+
# RSP: "[[T]].obj"
23+
# RSP-NEXT: "[[P]]{{[/\\]}}Inputs{{[/\\]}}std32.lib"
24+
# RSP-NEXT: "[[P]]{{[/\\]}}Inputs{{[/\\]}}ret42.lib"
25+
# RSP-NEXT: "[[T]].pdb"
26+
# RSP-NEXT: "/wholearchive:[[T]].archive.lib"
27+
# RSP-NEXT: "/defaultlib:[[P]]{{[/\\]}}Inputs{{[/\\]}}library.lib"
28+
# RSP-NEXT: "/defaultlib:[[P]]{{[/\\]}}Inputs{{[/\\]}}std64.lib"
29+
30+
#--- drectve.s
31+
.section .drectve, "yn"
32+
.ascii "/defaultlib:std32"
33+
34+
#--- archive.s
35+
.text
36+
.intel_syntax noprefix
37+
.globl exportfn3
38+
.p2align 4
39+
exportfn3:
40+
ret
41+
42+
.section .drectve,"yni"
43+
.ascii " /EXPORT:exportfn3"

0 commit comments

Comments
 (0)