Skip to content

Commit 7d8e40b

Browse files
authored
Merge pull request #16362 from dabelknap/frontend_responsefile
Wrap Command Line Arguments in a Response File if System Limits are Exceeded https://bugs.swift.org/browse/SR-4517
2 parents 6b3a739 + be229fc commit 7d8e40b

File tree

10 files changed

+186
-79
lines changed

10 files changed

+186
-79
lines changed

include/swift/Driver/Job.h

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,14 @@ class Job {
271271
/// Whether the job wants a list of input or output files created.
272272
std::vector<FilelistInfo> FilelistFileInfos;
273273

274+
/// Response file path
275+
const char *ResponseFilePath;
276+
277+
/// This contains a single argument pointing to the response file path with
278+
/// the '@' prefix.
279+
/// The argument string must be kept alive as long as the Job is alive.
280+
const char *ResponseFileArg;
281+
274282
/// The modification time of the main input file, if any.
275283
llvm::sys::TimePoint<> InputModTime = llvm::sys::TimePoint<>::max();
276284

@@ -281,12 +289,16 @@ class Job {
281289
const char *Executable,
282290
llvm::opt::ArgStringList Arguments,
283291
EnvironmentVector ExtraEnvironment = {},
284-
std::vector<FilelistInfo> Infos = {})
292+
std::vector<FilelistInfo> Infos = {},
293+
const char *ResponseFilePath = nullptr,
294+
const char *ResponseFileArg = nullptr)
285295
: SourceAndCondition(&Source, Condition::Always),
286296
Inputs(std::move(Inputs)), Output(std::move(Output)),
287297
Executable(Executable), Arguments(std::move(Arguments)),
288298
ExtraEnvironment(std::move(ExtraEnvironment)),
289-
FilelistFileInfos(std::move(Infos)) {}
299+
FilelistFileInfos(std::move(Infos)),
300+
ResponseFilePath(ResponseFilePath),
301+
ResponseFileArg(ResponseFileArg) {}
290302

291303
virtual ~Job();
292304

@@ -296,7 +308,9 @@ class Job {
296308

297309
const char *getExecutable() const { return Executable; }
298310
const llvm::opt::ArgStringList &getArguments() const { return Arguments; }
311+
ArrayRef<const char *> getResponseFileArg() const { return ResponseFileArg; }
299312
ArrayRef<FilelistInfo> getFilelistInfos() const { return FilelistFileInfos; }
313+
ArrayRef<const char *> getArgumentsForTaskExecution() const;
300314

301315
ArrayRef<const Job *> getInputs() const { return Inputs; }
302316
const CommandOutput &getOutput() const { return *Output; }
@@ -347,6 +361,10 @@ class Job {
347361

348362
static void printArguments(raw_ostream &Stream,
349363
const llvm::opt::ArgStringList &Args);
364+
365+
bool hasResponseFile() const { return ResponseFilePath != nullptr; }
366+
367+
bool writeArgsToResponseFile() const;
350368
};
351369

352370
/// A BatchJob comprises a _set_ of jobs, each of which is sufficiently similar

include/swift/Driver/ToolChain.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,12 @@ class ToolChain {
122122
std::vector<std::pair<const char *, const char *>> ExtraEnvironment;
123123
std::vector<FilelistInfo> FilelistInfos;
124124

125+
// Not all platforms and jobs support the use of response files, so assume
126+
// "false" by default. If the executable specified in the InvocationInfo
127+
// constructor supports response files, this can be overridden and set to
128+
// "true".
129+
bool allowsResponseFiles = false;
130+
125131
InvocationInfo(const char *name, llvm::opt::ArgStringList args = {},
126132
decltype(ExtraEnvironment) extraEnv = {})
127133
: ExecutableName(name), Arguments(std::move(args)),

lib/Driver/Compilation.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -291,8 +291,8 @@ namespace driver {
291291
"not implemented for compilations with multiple jobs");
292292
if (Comp.ShowJobLifecycle)
293293
llvm::outs() << "Added to TaskQueue: " << LogJob(Cmd) << "\n";
294-
TQ->addTask(Cmd->getExecutable(), Cmd->getArguments(), llvm::None,
295-
(void *)Cmd);
294+
TQ->addTask(Cmd->getExecutable(), Cmd->getArgumentsForTaskExecution(),
295+
llvm::None, (void *)Cmd);
296296
}
297297

298298
/// When a task finishes, check other Jobs that may be blocked.

lib/Driver/Job.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "llvm/ADT/STLExtras.h"
1717
#include "llvm/Option/Arg.h"
1818
#include "llvm/Support/Compiler.h"
19+
#include "llvm/Support/FileSystem.h"
1920
#include "llvm/Support/Path.h"
2021
#include "llvm/Support/Program.h"
2122
#include "llvm/Support/raw_ostream.h"
@@ -337,6 +338,15 @@ void Job::dump() const {
337338
printCommandLineAndEnvironment(llvm::errs());
338339
}
339340

341+
ArrayRef<const char *> Job::getArgumentsForTaskExecution() const {
342+
if (hasResponseFile()) {
343+
writeArgsToResponseFile();
344+
return getResponseFileArg();
345+
} else {
346+
return getArguments();
347+
}
348+
}
349+
340350
void Job::printCommandLineAndEnvironment(raw_ostream &Stream,
341351
StringRef Terminator) const {
342352
printCommandLine(Stream, /*Terminator=*/"");
@@ -352,7 +362,12 @@ void Job::printCommandLineAndEnvironment(raw_ostream &Stream,
352362
void Job::printCommandLine(raw_ostream &os, StringRef Terminator) const {
353363
escapeAndPrintString(os, Executable);
354364
os << ' ';
365+
if (hasResponseFile()) {
366+
printArguments(os, {ResponseFileArg});
367+
os << " # ";
368+
}
355369
printArguments(os, Arguments);
370+
356371
os << Terminator;
357372
}
358373

@@ -403,6 +418,21 @@ void Job::printSummary(raw_ostream &os) const {
403418
os << "}";
404419
}
405420

421+
bool Job::writeArgsToResponseFile() const {
422+
std::error_code EC;
423+
llvm::raw_fd_ostream OS(ResponseFilePath, EC, llvm::sys::fs::F_None);
424+
if (EC) {
425+
return true;
426+
}
427+
for (const char *arg : Arguments) {
428+
OS << "\"";
429+
escapeAndPrintString(OS, arg);
430+
OS << "\" ";
431+
}
432+
OS.flush();
433+
return false;
434+
}
435+
406436
BatchJob::BatchJob(const JobAction &Source,
407437
SmallVectorImpl<const Job *> &&Inputs,
408438
std::unique_ptr<CommandOutput> Output,

lib/Driver/ToolChain.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,11 +114,22 @@ std::unique_ptr<Job> ToolChain::constructJob(
114114
}
115115
}
116116

117+
const char *responseFilePath = nullptr;
118+
const char *responseFileArg = nullptr;
119+
if (invocationInfo.allowsResponseFiles &&
120+
!llvm::sys::commandLineFitsWithinSystemLimits(
121+
executablePath, invocationInfo.Arguments)) {
122+
responseFilePath = context.getTemporaryFilePath("arguments", "resp");
123+
responseFileArg = C.getArgs().MakeArgString(Twine("@") + responseFilePath);
124+
}
125+
117126
return llvm::make_unique<Job>(JA, std::move(inputs), std::move(output),
118127
executablePath,
119128
std::move(invocationInfo.Arguments),
120129
std::move(invocationInfo.ExtraEnvironment),
121-
std::move(invocationInfo.FilelistInfos));
130+
std::move(invocationInfo.FilelistInfos),
131+
responseFilePath,
132+
responseFileArg);
122133
}
123134

124135
std::string

lib/Driver/ToolChains.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@ ToolChain::constructInvocation(const CompileJobAction &job,
248248
const JobContext &context) const {
249249
InvocationInfo II{SWIFT_EXECUTABLE_NAME};
250250
ArgStringList &Arguments = II.Arguments;
251+
II.allowsResponseFiles = true;
251252

252253
Arguments.push_back("-frontend");
253254

lib/Driver/UnixToolChains.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,10 @@ toolchains::GenericUnix::constructInvocation(const LinkJobAction &job,
325325
Arguments.push_back(
326326
context.Args.MakeArgString(context.Output.getPrimaryOutputFilename()));
327327

328-
return {Clang, Arguments};
328+
InvocationInfo II{Clang, Arguments};
329+
II.allowsResponseFiles = true;
330+
331+
return II;
329332
}
330333

331334
std::string toolchains::Android::getTargetForLinker() const {

lib/Driver/WindowsToolChains.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,5 +171,8 @@ toolchains::Windows::constructInvocation(const LinkJobAction &job,
171171
Arguments.push_back(
172172
context.Args.MakeArgString(context.Output.getPrimaryOutputFilename()));
173173

174-
return {Clang, Arguments};
174+
InvocationInfo II{Clang, Arguments};
175+
II.allowsResponseFiles = true;
176+
177+
return II;
175178
}

test/Driver/response-file.swift

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,35 @@
66
// RUN: %target-build-swift -typecheck @%t.1.resp %s 2>&1 | %FileCheck %s -check-prefix=MULTIPLE
77
// MULTIPLE: warning: result of call to 'abs' is unused
88

9-
// RUN: echo "-DTEST2A -DTEST2B" > %t.2.resp
10-
// RUN: echo "-DTEST2C -DTEST2D" > %t.3.resp
11-
// RUN: %target-build-swift -typecheck @%t.2.resp %s @%t.3.resp 2>&1 | %FileCheck %s -check-prefix=MIXED
9+
// RUN: echo "-DTEST2A -DTEST2B" > %t.2A.resp
10+
// RUN: echo "-DTEST2C -DTEST2D" > %t.2B.resp
11+
// RUN: %target-build-swift -typecheck @%t.2A.resp %s @%t.2B.resp 2>&1 | %FileCheck %s -check-prefix=MIXED
1212
// MIXED: warning: result of call to 'abs' is unused
1313

14-
// RUN: echo "-DTEST3A" > %t.4.resp
15-
// RUN: echo "%s" >> %t.4.resp
16-
// RUN: echo "-DTEST3B" >> %t.4.resp
17-
// RUN: %target-build-swift -typecheck @%t.4.resp 2>&1 | %FileCheck %s -check-prefix=RESPONLY
14+
// RUN: echo "-DTEST3A" > %t.3.resp
15+
// RUN: echo "%s" >> %t.3.resp
16+
// RUN: echo "-DTEST3B" >> %t.3.resp
17+
// RUN: %target-build-swift -typecheck @%t.3.resp 2>&1 | %FileCheck %s -check-prefix=RESPONLY
1818
// RESPONLY: warning: result of call to 'abs' is unused
1919

20-
// RUN: echo "-DTEST4A" > %t.5.resp
21-
// RUN: echo "%s" >> %t.5.resp
22-
// RUN: echo "@%t.5.resp" > %t.6.resp
23-
// RUN: echo "-DTEST4B" >> %t.6.resp
24-
// RUN: %target-build-swift -typecheck @%t.6.resp 2>&1 | %FileCheck %s -check-prefix=RECURSIVE
20+
// RUN: echo "-DTEST4A" > %t.4A.resp
21+
// RUN: echo "%s" >> %t.4A.resp
22+
// RUN: echo "@%t.4A.resp" > %t.4B.resp
23+
// RUN: echo "-DTEST4B" >> %t.4B.resp
24+
// RUN: %target-build-swift -typecheck @%t.4B.resp 2>&1 | %FileCheck %s -check-prefix=RECURSIVE
2525
// RECURSIVE: warning: result of call to 'abs' is unused
2626

27+
// RUN: python -c 'for i in range(500001): print "-DTEST5_" + str(i)' > %t.5.resp
28+
// RUN: %target-build-swift -typecheck @%t.5.resp %s 2>&1 | %FileCheck %s -check-prefix=LONG
29+
// LONG: warning: result of call to 'abs' is unused
30+
// RUN: %empty-directory(%t/tmp)
31+
// RUN: env TMPDIR=%t/tmp/ %target-swiftc_driver %s @%t.5.resp -save-temps 2>&1
32+
// RUN: ls %t/tmp/arguments-*.resp
33+
// RUN: %target-build-swift -v @%t.5.resp %s 2>&1 | %FileCheck %s -check-prefix=VERBOSE
34+
// VERBOSE: @{{[^ ]*}}arguments-{{[0-9a-zA-Z]+}}.resp # -frontend -c -primary-file
35+
// RUN: not %target-swiftc_driver %s @%t.5.resp -Xfrontend -debug-crash-immediately 2>&1 | %FileCheck %s -check-prefix=CRASH
36+
// CRASH: Program arguments: {{[^ ]*}}swift -frontend -c -primary-file
37+
2738
#if TEST0
2839
abs(-5)
2940
#endif
@@ -43,3 +54,7 @@ abs(-5)
4354
#if TEST4A && TEST4B
4455
abs(-5)
4556
#endif
57+
58+
#if TEST5_0 && TEST5_10 && TEST5_100 && TEST5_1000 && TEST5_10000 && TEST5_100000 && TEST5_500000
59+
abs(-5)
60+
#endif

0 commit comments

Comments
 (0)