Skip to content

Commit 4772b99

Browse files
committed
Clang Driver: refactor support for writing response files to be
specified at Command creation, rather than as part of the Tool. This resolves the hack I just added to allow Darwin toolchain to vary its level of support based on `-mlinker-version=`. The change preserves the _current_ settings for response-file support. Some tools look likely to be declaring that they don't support response files in error, however I kept them as-is in order for this change to be a simple refactoring. Differential Revision: https://reviews.llvm.org/D82782
1 parent 381df16 commit 4772b99

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+349
-299
lines changed

clang/include/clang/Driver/Job.h

Lines changed: 80 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "llvm/ADT/StringRef.h"
1717
#include "llvm/ADT/iterator.h"
1818
#include "llvm/Option/Option.h"
19+
#include "llvm/Support/Program.h"
1920
#include <memory>
2021
#include <string>
2122
#include <utility>
@@ -36,6 +37,69 @@ struct CrashReportInfo {
3637
: Filename(Filename), VFSPath(VFSPath) {}
3738
};
3839

40+
// Encodes the kind of response file supported for a command invocation.
41+
// Response files are necessary if the command line gets too large, requiring
42+
// the arguments to be transferred to a file.
43+
struct ResponseFileSupport {
44+
enum ResponseFileKind {
45+
// Provides full support for response files, which means we can transfer
46+
// all tool input arguments to a file.
47+
RF_Full,
48+
// Input file names can live in a file, but flags can't. This is a special
49+
// case for old versions of Apple's ld64.
50+
RF_FileList,
51+
// Does not support response files: all arguments must be passed via
52+
// command line.
53+
RF_None
54+
};
55+
/// The level of support for response files.
56+
ResponseFileKind ResponseKind;
57+
58+
/// The encoding to use when writing response files on Windows. Ignored on
59+
/// other host OSes.
60+
///
61+
/// Windows use cases: - GCC and Binutils on mingw only accept ANSI response
62+
/// files encoded with the system current code page.
63+
/// - MSVC's CL.exe and LINK.exe accept UTF16 on Windows.
64+
/// - Clang accepts both UTF8 and UTF16.
65+
///
66+
/// FIXME: When GNU tools learn how to parse UTF16 on Windows, we should
67+
/// always use UTF16 for Windows, which is the Windows official encoding for
68+
/// international characters.
69+
llvm::sys::WindowsEncodingMethod ResponseEncoding;
70+
71+
/// What prefix to use for the command-line argument when passing a response
72+
/// file.
73+
const char *ResponseFlag;
74+
75+
/// Returns a ResponseFileSupport indicating that response files are not
76+
/// supported.
77+
static constexpr ResponseFileSupport None() {
78+
return {RF_None, llvm::sys::WEM_UTF8, nullptr};
79+
}
80+
81+
/// Returns a ResponseFileSupport indicating that response files are
82+
/// supported, using the @file syntax. On windows, the file is written in the
83+
/// UTF8 encoding. On other OSes, no re-encoding occurs.
84+
static constexpr ResponseFileSupport AtFileUTF8() {
85+
return {RF_Full, llvm::sys::WEM_UTF8, "@"};
86+
}
87+
88+
/// Returns a ResponseFileSupport indicating that response files are
89+
/// supported, using the @file syntax. On windows, the file is written in the
90+
/// current ANSI code-page encoding. On other OSes, no re-encoding occurs.
91+
static constexpr ResponseFileSupport AtFileCurCP() {
92+
return {RF_Full, llvm::sys::WEM_CurrentCodePage, "@"};
93+
}
94+
95+
/// Returns a ResponseFileSupport indicating that response files are
96+
/// supported, using the @file syntax. On windows, the file is written in the
97+
/// UTF-16 encoding. On other OSes, no re-encoding occurs.
98+
static constexpr ResponseFileSupport AtFileUTF16() {
99+
return {RF_Full, llvm::sys::WEM_UTF16, "@"};
100+
}
101+
};
102+
39103
/// Command - An executable path/name and argument vector to
40104
/// execute.
41105
class Command {
@@ -45,6 +109,9 @@ class Command {
45109
/// Tool - The tool which caused the creation of this job.
46110
const Tool &Creator;
47111

112+
/// Whether and how to generate response files if the arguments are too long.
113+
ResponseFileSupport ResponseSupport;
114+
48115
/// The executable to run.
49116
const char *Executable;
50117

@@ -89,7 +156,8 @@ class Command {
89156
/// Whether the command will be executed in this process or not.
90157
bool InProcess = false;
91158

92-
Command(const Action &Source, const Tool &Creator, const char *Executable,
159+
Command(const Action &Source, const Tool &Creator,
160+
ResponseFileSupport ResponseSupport, const char *Executable,
93161
const llvm::opt::ArgStringList &Arguments,
94162
ArrayRef<InputInfo> Inputs);
95163
// FIXME: This really shouldn't be copyable, but is currently copied in some
@@ -109,11 +177,16 @@ class Command {
109177
/// getCreator - Return the Tool which caused the creation of this job.
110178
const Tool &getCreator() const { return Creator; }
111179

180+
/// Returns the kind of response file supported by the current invocation.
181+
const ResponseFileSupport &getResponseFileSupport() {
182+
return ResponseSupport;
183+
}
184+
112185
/// Set to pass arguments via a response file when launching the command
113186
void setResponseFile(const char *FileName);
114187

115-
/// Set an input file list, necessary if we need to use a response file but
116-
/// the tool being called only supports input files lists.
188+
/// Set an input file list, necessary if you specified an RF_FileList response
189+
/// file support.
117190
void setInputFileList(llvm::opt::ArgStringList List) {
118191
InputFileList = std::move(List);
119192
}
@@ -136,7 +209,8 @@ class Command {
136209
/// Use the CC1 tool callback when available, to avoid creating a new process
137210
class CC1Command : public Command {
138211
public:
139-
CC1Command(const Action &Source, const Tool &Creator, const char *Executable,
212+
CC1Command(const Action &Source, const Tool &Creator,
213+
ResponseFileSupport ResponseSupport, const char *Executable,
140214
const llvm::opt::ArgStringList &Arguments,
141215
ArrayRef<InputInfo> Inputs);
142216

@@ -154,7 +228,7 @@ class CC1Command : public Command {
154228
class FallbackCommand : public Command {
155229
public:
156230
FallbackCommand(const Action &Source_, const Tool &Creator_,
157-
const char *Executable_,
231+
ResponseFileSupport ResponseSupport, const char *Executable_,
158232
const llvm::opt::ArgStringList &Arguments_,
159233
ArrayRef<InputInfo> Inputs,
160234
std::unique_ptr<Command> Fallback_);
@@ -173,6 +247,7 @@ class FallbackCommand : public Command {
173247
class ForceSuccessCommand : public Command {
174248
public:
175249
ForceSuccessCommand(const Action &Source_, const Tool &Creator_,
250+
ResponseFileSupport ResponseSupport,
176251
const char *Executable_,
177252
const llvm::opt::ArgStringList &Arguments_,
178253
ArrayRef<InputInfo> Inputs);

clang/include/clang/Driver/Tool.h

Lines changed: 1 addition & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
#define LLVM_CLANG_DRIVER_TOOL_H
1111

1212
#include "clang/Basic/LLVM.h"
13-
#include "llvm/Support/Program.h"
1413

1514
namespace llvm {
1615
namespace opt {
@@ -31,24 +30,6 @@ namespace driver {
3130

3231
/// Tool - Information on a specific compilation tool.
3332
class Tool {
34-
public:
35-
// Documents the level of support for response files in this tool.
36-
// Response files are necessary if the command line gets too large,
37-
// requiring the arguments to be transferred to a file.
38-
enum ResponseFileSupport {
39-
// Provides full support for response files, which means we can transfer
40-
// all tool input arguments to a file. E.g.: clang, gcc, binutils and MSVC
41-
// tools.
42-
RF_Full,
43-
// Input file names can live in a file, but flags can't. E.g.: ld64 (Mac
44-
// OS X linker).
45-
RF_FileList,
46-
// Does not support response files: all arguments must be passed via
47-
// command line.
48-
RF_None
49-
};
50-
51-
private:
5233
/// The tool name (for debugging).
5334
const char *Name;
5435

@@ -58,20 +39,8 @@ class Tool {
5839
/// The tool chain this tool is a part of.
5940
const ToolChain &TheToolChain;
6041

61-
/// The level of support for response files seen in this tool
62-
const ResponseFileSupport ResponseSupport;
63-
64-
/// The encoding to use when writing response files for this tool on Windows
65-
const llvm::sys::WindowsEncodingMethod ResponseEncoding;
66-
67-
/// The flag used to pass a response file via command line to this tool
68-
const char *const ResponseFlag;
69-
7042
public:
71-
Tool(const char *Name, const char *ShortName, const ToolChain &TC,
72-
ResponseFileSupport ResponseSupport = RF_None,
73-
llvm::sys::WindowsEncodingMethod ResponseEncoding = llvm::sys::WEM_UTF8,
74-
const char *ResponseFlag = "@");
43+
Tool(const char *Name, const char *ShortName, const ToolChain &TC);
7544

7645
public:
7746
virtual ~Tool();
@@ -87,29 +56,6 @@ class Tool {
8756
virtual bool hasIntegratedCPP() const = 0;
8857
virtual bool isLinkJob() const { return false; }
8958
virtual bool isDsymutilJob() const { return false; }
90-
/// Returns the level of support for response files of this tool,
91-
/// whether it accepts arguments to be passed via a file on disk.
92-
ResponseFileSupport getResponseFilesSupport() const {
93-
return ResponseSupport;
94-
}
95-
/// Returns which encoding the response file should use. This is only
96-
/// relevant on Windows platforms where there are different encodings being
97-
/// accepted for different tools. On UNIX, UTF8 is universal.
98-
///
99-
/// Windows use cases: - GCC and Binutils on mingw only accept ANSI response
100-
/// files encoded with the system current code page.
101-
/// - MSVC's CL.exe and LINK.exe accept UTF16 on Windows.
102-
/// - Clang accepts both UTF8 and UTF16.
103-
///
104-
/// FIXME: When GNU tools learn how to parse UTF16 on Windows, we should
105-
/// always use UTF16 for Windows, which is the Windows official encoding for
106-
/// international characters.
107-
llvm::sys::WindowsEncodingMethod getResponseFileEncoding() const {
108-
return ResponseEncoding;
109-
}
110-
/// Returns which prefix to use when passing the name of a response
111-
/// file as a parameter to this tool.
112-
const char *getResponseFileFlag() const { return ResponseFlag; }
11359

11460
/// Does this tool have "good" standardized diagnostics, or should the
11561
/// driver add an additional "command failed" diagnostic on failures.

clang/include/clang/Driver/ToolChain.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -201,9 +201,6 @@ class ToolChain {
201201

202202
// Accessors
203203

204-
/// Temporary for Darwin::Linker
205-
const llvm::opt::ArgList &getArgs_DO_NOT_USE() const { return Args; }
206-
207204
const Driver &getDriver() const { return D; }
208205
llvm::vfs::FileSystem &getVFS() const;
209206
const llvm::Triple &getTriple() const { return Triple; }

clang/lib/Driver/Driver.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1456,7 +1456,8 @@ void Driver::setUpResponseFiles(Compilation &C, Command &Cmd) {
14561456
// capacity if the tool does not support response files, there is a chance/
14571457
// that things will just work without a response file, so we silently just
14581458
// skip it.
1459-
if (Cmd.getCreator().getResponseFilesSupport() == Tool::RF_None ||
1459+
if (Cmd.getResponseFileSupport().ResponseKind ==
1460+
ResponseFileSupport::RF_None ||
14601461
llvm::sys::commandLineFitsWithinSystemLimits(Cmd.getExecutable(),
14611462
Cmd.getArguments()))
14621463
return;

clang/lib/Driver/Job.cpp

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,11 @@ using namespace clang;
3636
using namespace driver;
3737

3838
Command::Command(const Action &Source, const Tool &Creator,
39-
const char *Executable,
39+
ResponseFileSupport ResponseSupport, const char *Executable,
4040
const llvm::opt::ArgStringList &Arguments,
4141
ArrayRef<InputInfo> Inputs)
42-
: Source(Source), Creator(Creator), Executable(Executable),
43-
Arguments(Arguments) {
42+
: Source(Source), Creator(Creator), ResponseSupport(ResponseSupport),
43+
Executable(Executable), Arguments(Arguments) {
4444
for (const auto &II : Inputs)
4545
if (II.isFilename())
4646
InputFilenames.push_back(II.getFilename());
@@ -102,7 +102,7 @@ static bool skipArgs(const char *Flag, bool HaveCrashVFS, int &SkipNum,
102102

103103
void Command::writeResponseFile(raw_ostream &OS) const {
104104
// In a file list, we only write the set of inputs to the response file
105-
if (Creator.getResponseFilesSupport() == Tool::RF_FileList) {
105+
if (ResponseSupport.ResponseKind == ResponseFileSupport::RF_FileList) {
106106
for (const auto *Arg : InputFileList) {
107107
OS << Arg << '\n';
108108
}
@@ -131,7 +131,7 @@ void Command::buildArgvForResponseFile(
131131
// When not a file list, all arguments are sent to the response file.
132132
// This leaves us to set the argv to a single parameter, requesting the tool
133133
// to read the response file.
134-
if (Creator.getResponseFilesSupport() != Tool::RF_FileList) {
134+
if (ResponseSupport.ResponseKind != ResponseFileSupport::RF_FileList) {
135135
Out.push_back(Executable);
136136
Out.push_back(ResponseFileFlag.c_str());
137137
return;
@@ -149,7 +149,7 @@ void Command::buildArgvForResponseFile(
149149
Out.push_back(Arg);
150150
} else if (FirstInput) {
151151
FirstInput = false;
152-
Out.push_back(Creator.getResponseFileFlag());
152+
Out.push_back(ResponseSupport.ResponseFlag);
153153
Out.push_back(ResponseFile);
154154
}
155155
}
@@ -277,7 +277,7 @@ void Command::Print(raw_ostream &OS, const char *Terminator, bool Quote,
277277
writeResponseFile(OS);
278278
// Avoiding duplicated newline terminator, since FileLists are
279279
// newline-separated.
280-
if (Creator.getResponseFilesSupport() != Tool::RF_FileList)
280+
if (ResponseSupport.ResponseKind != ResponseFileSupport::RF_FileList)
281281
OS << "\n";
282282
OS << " (end of response file)";
283283
}
@@ -287,7 +287,7 @@ void Command::Print(raw_ostream &OS, const char *Terminator, bool Quote,
287287

288288
void Command::setResponseFile(const char *FileName) {
289289
ResponseFile = FileName;
290-
ResponseFileFlag = Creator.getResponseFileFlag();
290+
ResponseFileFlag = ResponseSupport.ResponseFlag;
291291
ResponseFileFlag += FileName;
292292
}
293293

@@ -327,7 +327,7 @@ int Command::Execute(ArrayRef<llvm::Optional<StringRef>> Redirects,
327327

328328
// Save the response file in the appropriate encoding
329329
if (std::error_code EC = writeFileWithEncoding(
330-
ResponseFile, RespContents, Creator.getResponseFileEncoding())) {
330+
ResponseFile, RespContents, ResponseSupport.ResponseEncoding)) {
331331
if (ErrMsg)
332332
*ErrMsg = EC.message();
333333
if (ExecutionFailed)
@@ -354,10 +354,11 @@ int Command::Execute(ArrayRef<llvm::Optional<StringRef>> Redirects,
354354
}
355355

356356
CC1Command::CC1Command(const Action &Source, const Tool &Creator,
357+
ResponseFileSupport ResponseSupport,
357358
const char *Executable,
358359
const llvm::opt::ArgStringList &Arguments,
359360
ArrayRef<InputInfo> Inputs)
360-
: Command(Source, Creator, Executable, Arguments, Inputs) {
361+
: Command(Source, Creator, ResponseSupport, Executable, Arguments, Inputs) {
361362
InProcess = true;
362363
}
363364

@@ -410,11 +411,13 @@ void CC1Command::setEnvironment(llvm::ArrayRef<const char *> NewEnvironment) {
410411
}
411412

412413
FallbackCommand::FallbackCommand(const Action &Source_, const Tool &Creator_,
414+
ResponseFileSupport ResponseSupport,
413415
const char *Executable_,
414416
const llvm::opt::ArgStringList &Arguments_,
415417
ArrayRef<InputInfo> Inputs,
416418
std::unique_ptr<Command> Fallback_)
417-
: Command(Source_, Creator_, Executable_, Arguments_, Inputs),
419+
: Command(Source_, Creator_, ResponseSupport, Executable_, Arguments_,
420+
Inputs),
418421
Fallback(std::move(Fallback_)) {}
419422

420423
void FallbackCommand::Print(raw_ostream &OS, const char *Terminator,
@@ -451,9 +454,11 @@ int FallbackCommand::Execute(ArrayRef<llvm::Optional<StringRef>> Redirects,
451454
}
452455

453456
ForceSuccessCommand::ForceSuccessCommand(
454-
const Action &Source_, const Tool &Creator_, const char *Executable_,
457+
const Action &Source_, const Tool &Creator_,
458+
ResponseFileSupport ResponseSupport, const char *Executable_,
455459
const llvm::opt::ArgStringList &Arguments_, ArrayRef<InputInfo> Inputs)
456-
: Command(Source_, Creator_, Executable_, Arguments_, Inputs) {}
460+
: Command(Source_, Creator_, ResponseSupport, Executable_, Arguments_,
461+
Inputs) {}
457462

458463
void ForceSuccessCommand::Print(raw_ostream &OS, const char *Terminator,
459464
bool Quote, CrashReportInfo *CrashInfo) const {

clang/lib/Driver/Tool.cpp

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,8 @@
1111

1212
using namespace clang::driver;
1313

14-
Tool::Tool(const char *_Name, const char *_ShortName, const ToolChain &TC,
15-
ResponseFileSupport _ResponseSupport,
16-
llvm::sys::WindowsEncodingMethod _ResponseEncoding,
17-
const char *_ResponseFlag)
18-
: Name(_Name), ShortName(_ShortName), TheToolChain(TC),
19-
ResponseSupport(_ResponseSupport), ResponseEncoding(_ResponseEncoding),
20-
ResponseFlag(_ResponseFlag) {}
14+
Tool::Tool(const char *_Name, const char *_ShortName, const ToolChain &TC)
15+
: Name(_Name), ShortName(_ShortName), TheToolChain(TC) {}
2116

2217
Tool::~Tool() {
2318
}

clang/lib/Driver/ToolChains/AIX.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@ void aix::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
7373
CmdArgs.push_back(II.getFilename());
7474

7575
const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
76-
C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
76+
C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
77+
Exec, CmdArgs, Inputs));
7778
}
7879

7980
void aix::Linker::ConstructJob(Compilation &C, const JobAction &JA,
@@ -152,7 +153,8 @@ void aix::Linker::ConstructJob(Compilation &C, const JobAction &JA,
152153
}
153154

154155
const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
155-
C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
156+
C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
157+
Exec, CmdArgs, Inputs));
156158
}
157159

158160
/// AIX - AIX tool chain which can call as(1) and ld(1) directly.

0 commit comments

Comments
 (0)