Skip to content

Commit 4039db5

Browse files
authored
Merge pull request #16362 from dabelknap/frontend_responsefile (#17409)
Wrap Command Line Arguments in a Response File if System Limits are Exceeded https://bugs.swift.org/browse/SR-4517 (cherry picked from commit 7d8e40b)
1 parent 5511c09 commit 4039db5

File tree

8 files changed

+186
-79
lines changed

8 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
@@ -120,6 +120,12 @@ class ToolChain {
120120
std::vector<std::pair<const char *, const char *>> ExtraEnvironment;
121121
std::vector<FilelistInfo> FilelistInfos;
122122

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

lib/Driver/Compilation.cpp

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

300300
/// 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
@@ -118,11 +118,22 @@ ToolChain::constructJob(const JobAction &JA,
118118
}
119119
}
120120

121+
const char *responseFilePath = nullptr;
122+
const char *responseFileArg = nullptr;
123+
if (invocationInfo.allowsResponseFiles &&
124+
!llvm::sys::commandLineFitsWithinSystemLimits(
125+
executablePath, invocationInfo.Arguments)) {
126+
responseFilePath = context.getTemporaryFilePath("arguments", "resp");
127+
responseFileArg = C.getArgs().MakeArgString(Twine("@") + responseFilePath);
128+
}
129+
121130
return llvm::make_unique<Job>(JA, std::move(inputs), std::move(output),
122131
executablePath,
123132
std::move(invocationInfo.Arguments),
124133
std::move(invocationInfo.ExtraEnvironment),
125-
std::move(invocationInfo.FilelistInfos));
134+
std::move(invocationInfo.FilelistInfos),
135+
responseFilePath,
136+
responseFileArg);
126137
}
127138

128139
std::string

lib/Driver/ToolChains.cpp

Lines changed: 9 additions & 2 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

@@ -1670,7 +1671,10 @@ toolchains::Windows::constructInvocation(const LinkJobAction &job,
16701671
Arguments.push_back(
16711672
context.Args.MakeArgString(context.Output.getPrimaryOutputFilename()));
16721673

1673-
return {Clang, Arguments};
1674+
InvocationInfo II{Clang, Arguments};
1675+
II.allowsResponseFiles = true;
1676+
1677+
return II;
16741678
}
16751679

16761680
ToolChain::InvocationInfo
@@ -1934,7 +1938,10 @@ toolchains::GenericUnix::constructInvocation(const LinkJobAction &job,
19341938
Arguments.push_back(context.Args.MakeArgString(
19351939
context.Output.getPrimaryOutputFilename()));
19361940

1937-
return {Clang, Arguments};
1941+
InvocationInfo II{Clang, Arguments};
1942+
II.allowsResponseFiles = true;
1943+
1944+
return II;
19381945
}
19391946

19401947
std::string

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)