This update refactors the new code in Job.cpp to use streams, no longer
building and managing its own char buffers. Thanks to Sean’s suggestion, the
code now is much more simple. However, I wanted to build a stream that could
directly write to the response file with the correct encoding, but
raw_fd_ostream lacks the capability to write files with different encodings.
Therefore, I added this capability to raw_fd_ostream with a small modification
and introduced a new constructor variant that creates buffers that, when
flushed to a file, is written in a different encoding. If you think it is
inadequate to have such a feature in raw_fd_ostream, I can work on creating my
own stream class to do so.
I also refactored part of the write function in raw_fd_ostream out of this
class, to avoid duplicating code in this implementation. Then, I changed by
writeFileWithEncoding() function to write in a given file descriptor, which is
assumed to be opened, rather than opening the file by my own and then closing
it. This enabled me to make raw_fd_ostream work with different encodings with
little extra code.
http://reviews.llvm.org/D4897
Files:
include/clang/Driver/Compilation.h
include/clang/Driver/Job.h
include/clang/Driver/Tool.h
lib/Driver/Compilation.cpp
lib/Driver/Job.cpp
lib/Driver/Tools.cpp
lib/Driver/Tools.h
test/Driver/response-file.c
Index: include/clang/Driver/Compilation.h
===================================================================
--- include/clang/Driver/Compilation.h
+++ include/clang/Driver/Compilation.h
@@ -94,7 +94,7 @@
JobList &getJobs() { return Jobs; }
const JobList &getJobs() const { return Jobs; }
- void addCommand(Command *C) { Jobs.addJob(C); }
+ void addCommand(Command *C);
const llvm::opt::ArgStringList &getTempFiles() const { return TempFiles; }
Index: include/clang/Driver/Job.h
===================================================================
--- include/clang/Driver/Job.h
+++ include/clang/Driver/Job.h
@@ -72,13 +72,27 @@
/// argument, which will be the executable).
llvm::opt::ArgStringList Arguments;
+ /// Whether this job will need to write its arguments to a disk file
+ const bool NeedsResponseFile;
+
+ /// Response file name
+ StringRef ResponseFile;
+
+ /// The input file list in case we need to emit a file list instead of a
+ /// proper response file
+ llvm::opt::ArgStringList InputFileList;
+
public:
Command(const Action &_Source, const Tool &_Creator, const char *_Executable,
const llvm::opt::ArgStringList &_Arguments);
void Print(llvm::raw_ostream &OS, const char *Terminator, bool Quote,
bool CrashReport = false) const override;
+ /// Checks whether the given command line arguments fit within system
+ /// limits (the maximum command line length).
+ bool needsResponseFile() const { return NeedsResponseFile; }
+
virtual int Execute(const StringRef **Redirects, std::string *ErrMsg,
bool *ExecutionFailed) const;
@@ -88,6 +102,9 @@
/// getCreator - Return the Tool which caused the creation of this job.
const Tool &getCreator() const { return Creator; }
+ void setResponseFile(StringRef FileName) { ResponseFile = FileName; }
+ void setInputFileList(llvm::opt::ArgStringList List) { InputFileList = List; }
+
const char *getExecutable() const { return Executable; }
const llvm::opt::ArgStringList &getArguments() const { return Arguments; }
Index: include/clang/Driver/Tool.h
===================================================================
--- include/clang/Driver/Tool.h
+++ include/clang/Driver/Tool.h
@@ -11,6 +11,7 @@
#define LLVM_CLANG_DRIVER_TOOL_H
#include "clang/Basic/LLVM.h"
+#include "llvm/Support/FileSystem.h"
namespace llvm {
namespace opt {
@@ -31,6 +32,24 @@
/// Tool - Information on a specific compilation tool.
class Tool {
+public:
+ // Documents the level of support for response files in this tool.
+ // Response files are necessary if the command line gets too large,
+ // requiring the arguments to be transfered to a file.
+ enum ResponseFileSupport {
+ // Provides full support for response files, which means we can transfer
+ // all tool input arguments to a file. E.g.: clang, gcc, binutils and MSVC
+ // tools.
+ RF_Full,
+ // Input file names can live in a file, but flags can't. E.g.: ld64 (Mac
+ // OS X linker).
+ RF_FileList,
+ // Does not support response files: all arguments must be passed via
+ // command line.
+ RF_None
+ };
+
+private:
/// The tool name (for debugging).
const char *Name;
@@ -57,6 +76,29 @@
virtual bool hasIntegratedCPP() const = 0;
virtual bool isLinkJob() const { return false; }
virtual bool isDsymutilJob() const { return false; }
+ /// \brief Returns the level of support for response files of this tool,
+ /// whether it accepts arguments to be passed via a file on disk.
+ virtual ResponseFileSupport getResponseFilesSupport() const {
+ return RF_None;
+ }
+ /// \brief Returns which encoding the response file should use. This is only
+ /// relevant on Windows platforms where there are different encodings being
+ /// accepted for different tools. On UNIX, UTF8 is universal.
+ ///
+ /// Windows use cases: - GCC and Binutils on mingw only accept ANSI response
+ /// files encoded with the system current code page.
+ /// - MSVC's CL.exe and LINK.exe accept UTF16 on Windows.
+ /// - Clang accepts both UTF8 and UTF16.
+ ///
+ /// FIXME: When GNU tools learn how to parse UTF16 on Windows, we should
+ /// always use UTF16 for Windows, which is the Windows official encoding for
+ /// international characters.
+ virtual llvm::sys::fs::WindowsEncodingMethod getResponseFileEncoding() const {
+ return llvm::sys::fs::WEM_UTF8;
+ }
+ /// \brief Returns which prefix to use when passing the name of a response
+ /// file as a parameter to this tool.
+ virtual const char *getResponseFileFlag() const { return "@"; }
/// \brief Does this tool have "good" standardized diagnostics, or should the
/// driver add an additional "command failed" diagnostic on failures.
Index: lib/Driver/Compilation.cpp
===================================================================
--- lib/Driver/Compilation.cpp
+++ lib/Driver/Compilation.cpp
@@ -52,6 +52,15 @@
}
}
+void Compilation::addCommand(Command *C) {
+ Jobs.addJob(C);
+ // Verify if we need a response file
+ if (C->needsResponseFile()) {
+ std::string TmpName = TheDriver.GetTemporaryPath("response", "txt");
+ C->setResponseFile(addTempFile(getArgs().MakeArgString(TmpName.c_str())));
+ }
+}
+
const DerivedArgList &Compilation::getArgsForToolChain(const ToolChain *TC,
const char *BoundArch) {
if (!TC)
@@ -88,7 +97,7 @@
// Failure is only failure if the file exists and is "regular". We checked
// for it being regular before, and llvm::sys::fs::remove ignores ENOENT,
// so we don't need to check again.
-
+
if (IssueErrors)
getDriver().Diag(clang::diag::err_drv_unable_to_remove_file)
<< EC.message();
Index: lib/Driver/Job.cpp
===================================================================
--- lib/Driver/Job.cpp
+++ lib/Driver/Job.cpp
@@ -12,6 +12,7 @@
#include "clang/Driver/Job.h"
#include "clang/Driver/Tool.h"
#include "clang/Driver/ToolChain.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
@@ -21,14 +22,19 @@
using namespace clang::driver;
using llvm::raw_ostream;
using llvm::StringRef;
+using llvm::ArrayRef;
Job::~Job() {}
Command::Command(const Action &_Source, const Tool &_Creator,
const char *_Executable,
const ArgStringList &_Arguments)
: Job(CommandClass), Source(_Source), Creator(_Creator),
- Executable(_Executable), Arguments(_Arguments) {}
+ Executable(_Executable), Arguments(_Arguments),
+ NeedsResponseFile(
+ !llvm::sys::argumentsFitWithinSystemLimits(_Arguments) &&
+ Creator.getResponseFilesSupport() != Tool::RF_None),
+ ResponseFile() {}
static int skipArgs(const char *Flag) {
// These flags are all of the form -Flag <Arg> and are treated as two
@@ -93,14 +99,122 @@
OS << '"';
}
+/// ArgNeedsQuotes - Check whether argument needs to be quoted when serializing
+/// it to a response file.
+static bool ArgNeedsQuotes(const char *Str) {
+ return Str[0] == '\0' || strpbrk(Str, "\t \"&\'()*<>\\`^|") != 0;
+}
+
+/// Encodes the array of C strings into a single string separated by whitespace.
+/// This function will also put in quotes arguments that have whitespaces and
+/// will escape the regular backslashes (used in Windows paths) and quotes.
+/// The results are the contents of a response file, written into a raw_ostream.
+static void writeSerializedArgs(raw_ostream &OS, ArrayRef<const char *> Args) {
+ for (auto Arg : Args) {
+ bool NeedsQuoting = ArgNeedsQuotes(Arg);
+ if (NeedsQuoting)
+ OS << '"';
+
+ while (*Arg != '\0') {
+ if (*Arg == '\"' || *Arg == '\\') {
+ OS << '\\';
+ }
+ OS << *Arg++;
+ }
+
+ if (NeedsQuoting) {
+ OS << '"';
+ }
+ OS << ' ';
+ }
+}
+
+/// Check if string \p Arg is present in the list of inputs.
+static bool isInInputList(const llvm::SmallVectorImpl<const char *> &Inputs,
+ const char *Arg) {
+ for (auto InputName : Inputs) {
+ if (strcmp(Arg, InputName) == 0)
+ return true;
+ }
+ return false;
+}
+
+/// Build the argument vector with a single argument to supply the response
+/// file.
+static llvm::SmallVector<const char *, 128>
+buildArgvForResponseFile(const char *ResponseFlag, const char *Executable) {
+ llvm::SmallVector<const char *, 128> Argv;
+ Argv.push_back(Executable);
+ Argv.push_back(ResponseFlag);
+ return Argv;
+}
+
+/// Read the list of input files in Inputs and the list of arguments, building
+/// Argv accordingly (ignoring the elements from Arguments that also appear in
+/// Inputs, since they will be passed via a response file). This function will
+/// also insert the response file flag in Argv to indicate that a file list with
+/// extra arguments is available.
+///
+/// \p Inputs - List of file names that will be written into a file list
+/// \p ResponseFlag - Prefix used to pass a response file to the tool
+/// \p ResponseFile - Response file name
+/// \p Executable - Name of the tool
+/// \p Arguments - Original arguments when calling the tool
+static llvm::SmallVector<const char *, 128>
+buildArgvForFileList(const llvm::SmallVectorImpl<const char *> &Inputs,
+ const char *ResponseFlag, const char *ResponseFile,
+ const char *Executable, ArrayRef<const char *> Arguments) {
+ llvm::SmallVector<const char *, 128> Argv;
+ Argv.push_back(Executable);
+ // Build args vector, ignoring parameters that will go in a response file
+ bool FirstInput = true;
+ for (auto Arg : Arguments) {
+ if (!isInInputList(Inputs, Arg)) {
+ Argv.push_back(Arg);
+ } else if (FirstInput) {
+ FirstInput = false;
+ Argv.push_back(ResponseFlag);
+ Argv.push_back(ResponseFile);
+ }
+ }
+ return Argv;
+}
+
+/// Writes the file list contents into a raw_ostream.
+static void
+writeFileList(raw_ostream &OS,
+ const llvm::SmallVectorImpl<const char *> &Inputs) {
+ for (auto Arg : Inputs) {
+ OS << Arg;
+ OS << '\n';
+ }
+}
+
void Command::Print(raw_ostream &OS, const char *Terminator, bool Quote,
bool CrashReport) const {
// Always quote the exe.
OS << ' ';
PrintArg(OS, Executable, /*Quote=*/true);
- for (size_t i = 0, e = Arguments.size(); i < e; ++i) {
- const char *const Arg = Arguments[i];
+ llvm::ArrayRef<const char *> Args = Arguments;
+ llvm::SmallVector<const char *, 128> ArgsRespFile;
+ Tool::ResponseFileSupport RespFileSup = Creator.getResponseFilesSupport();
+ std::string ResponseFlag;
+ if (NeedsResponseFile && ResponseFile.data() != nullptr) {
+ ResponseFlag = Creator.getResponseFileFlag();
+ ResponseFlag += ResponseFile.data();
+ if (RespFileSup == Tool::RF_FileList)
+ ArgsRespFile = buildArgvForFileList(
+ InputFileList, Creator.getResponseFileFlag(), ResponseFile.data(),
+ Executable, Arguments);
+ else
+ ArgsRespFile = buildArgvForResponseFile(ResponseFlag.c_str(), Executable);
+
+ Args = ArrayRef<const char *>(ArgsRespFile).slice(1); // no executable name
+ }
+
+ for (size_t i = 0, e = Args.size(); i < e; ++i) {
+ const char *const Arg = Args[i];
if (CrashReport) {
if (int Skip = skipArgs(Arg)) {
@@ -114,19 +228,79 @@
if (CrashReport && quoteNextArg(Arg) && i + 1 < e) {
OS << ' ';
- PrintArg(OS, Arguments[++i], true);
+ PrintArg(OS, Args[++i], true);
}
}
+
+ if (NeedsResponseFile && ResponseFile.data() != nullptr) {
+ OS << "\n Arguments passed via response file:\n";
+ if (RespFileSup == Tool::RF_FileList)
+ writeFileList(OS, InputFileList);
+ else
+ writeSerializedArgs(OS, Arguments);
+ // Avoiding duplicated newline terminator, since FileLists are
+ // newline-separated.
+ if (RespFileSup != Tool::RF_FileList)
+ OS << "\n";
+ OS << " (end of response file)";
+ }
+
OS << Terminator;
}
int Command::Execute(const StringRef **Redirects, std::string *ErrMsg,
bool *ExecutionFailed) const {
SmallVector<const char*, 128> Argv;
- Argv.push_back(Executable);
- for (size_t i = 0, e = Arguments.size(); i != e; ++i)
- Argv.push_back(Arguments[i]);
- Argv.push_back(nullptr);
+
+ if (ResponseFile.data() == nullptr || !NeedsResponseFile) {
+ Argv.push_back(Executable);
+ for (size_t i = 0, e = Arguments.size(); i != e; ++i)
+ Argv.push_back(Arguments[i]);
+ Argv.push_back(nullptr);
+
+ return llvm::sys::ExecuteAndWait(Executable, Argv.data(), /*env*/ nullptr,
+ Redirects, /*secondsToWait*/ 0,
+ /*memoryLimit*/ 0, ErrMsg,
+ ExecutionFailed);
+ }
+
+ // We need to put arguments in a response file (command is too large)
+ // Open stream to write the response file
+ std::error_code EC;
+ llvm::raw_fd_ostream ROS(ResponseFile, EC, llvm::sys::fs::OpenFlags::F_Text,
+ Creator.getResponseFileEncoding());
+ if (EC) {
+ if (ErrMsg)
+ *ErrMsg = EC.message();
+ if (ExecutionFailed)
+ *ExecutionFailed = true;
+ return -1;
+ }
+
+ // String storage to hold this new argument
+ std::string ResponseFlag = Creator.getResponseFileFlag();
+ ResponseFlag += ResponseFile.data();
+ // Write file contents and build the Argv vector
+ if (Creator.getResponseFilesSupport() == Tool::RF_FileList) {
+ writeFileList(ROS, InputFileList);
+ Argv = buildArgvForFileList(InputFileList, Creator.getResponseFileFlag(),
+ ResponseFile.data(), Executable, Arguments);
+ Argv.push_back(nullptr);
+ } else {
+ writeSerializedArgs(ROS, Arguments);
+ Argv = buildArgvForResponseFile(ResponseFlag.c_str(), Executable);
+ Argv.push_back(nullptr);
+ }
+ // Flush and close file
+ ROS.close();
+
+ if (ROS.has_error()) {
+ if (ErrMsg)
+ *ErrMsg = "IO failure on output stream.";
+ if (ExecutionFailed)
+ *ExecutionFailed = true;
+ return -1;
+ }
return llvm::sys::ExecuteAndWait(Executable, Argv.data(), /*env*/ nullptr,
Redirects, /*secondsToWait*/ 0,
Index: lib/Driver/Tools.cpp
===================================================================
--- lib/Driver/Tools.cpp
+++ lib/Driver/Tools.cpp
@@ -506,7 +506,7 @@
} else
D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
}
-
+
// Handle -mfpu=.
//
// FIXME: Centralize feature selection, defaulting shouldn't be also in the
@@ -2506,7 +2506,7 @@
// Select the appropriate action.
RewriteKind rewriteKind = RK_None;
-
+
if (isa<AnalyzeJobAction>(JA)) {
assert(JA.getType() == types::TY_Plist && "Invalid output type.");
CmdArgs.push_back("-analyze");
@@ -2844,7 +2844,7 @@
// This alias option is being used to simplify the getLastArg logic.
OptSpecifier FastMathAliasOption = OFastEnabled ? options::OPT_Ofast :
options::OPT_ffast_math;
-
+
// Handle various floating point optimization flags, mapping them to the
// appropriate LLVM code generation flags. The pattern for all of these is to
// default off the codegen optimizations, and if any flag enables them and no
@@ -4043,12 +4043,12 @@
objcRuntime.getKind() == ObjCRuntime::FragileMacOSX &&
objcRuntime.isNeXTFamily())
CmdArgs.push_back("-fobjc-subscripting-legacy-runtime");
-
+
// -fencode-extended-block-signature=1 is default.
if (getToolChain().IsEncodeExtendedBlockSignatureDefault()) {
CmdArgs.push_back("-fencode-extended-block-signature");
}
-
+
// Allow -fno-objc-arr to trump -fobjc-arr/-fobjc-arc.
// NOTE: This logic is duplicated in ToolChains.cpp.
bool ARC = isObjCAutoRefCount(Args);
@@ -4383,7 +4383,7 @@
Args.AddLastArg(CmdArgs, options::OPT_dM);
Args.AddLastArg(CmdArgs, options::OPT_dD);
-
+
// Handle serialized diagnostics.
if (Arg *A = Args.getLastArg(options::OPT__serialize_diags)) {
CmdArgs.push_back("-serialize-diagnostic-file");
@@ -5779,6 +5779,12 @@
const char *LinkingOutput) const {
assert(Output.getType() == types::TY_Image && "Invalid linker output type.");
+ // If the number of arguments surpasses the system limits, we will encode the
+ // input files in a separate file, shortening the command line. To this end,
+ // build a list of input file names that can be passed via a file with the
+ // -filelist linker option.
+ llvm::opt::ArgStringList InputFileList;
+
// The logic here is derived from gcc's behavior; most of which
// comes from specs (starting with link_command). Consult gcc for
// more information.
@@ -5847,7 +5853,21 @@
}
AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs);
-
+ // Build the input file for -filelist (list of linker input files) in case we
+ // need it later
+ for (const auto &II : Inputs) {
+ if (II.isFilename()) {
+ InputFileList.push_back(II.getFilename());
+ continue;
+ }
+
+ // This is a linker input argument.
+ // We cannot mix input arguments and file names in a -filelist input, thus
+ // we prematurely stop our list (remaining files shall be passed as
+ // arguments).
+ break;
+ }
+
if (isObjCRuntimeLinked(Args) &&
!Args.hasArg(options::OPT_nostdlib) &&
!Args.hasArg(options::OPT_nodefaultlibs)) {
@@ -5890,7 +5910,10 @@
const char *Exec =
Args.MakeArgString(getToolChain().GetLinkerPath());
- C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+ Command *Cmd = new Command(JA, *this, Exec, CmdArgs);
+ if (Cmd->needsResponseFile())
+ Cmd->setInputFileList(InputFileList);
+ C.addCommand(Cmd);
}
void darwin::Lipo::ConstructJob(Compilation &C, const JobAction &JA,
Index: lib/Driver/Tools.h
===================================================================
--- lib/Driver/Tools.h
+++ lib/Driver/Tools.h
@@ -95,6 +95,9 @@
bool hasGoodDiagnostics() const override { return true; }
bool hasIntegratedAssembler() const override { return true; }
bool hasIntegratedCPP() const override { return true; }
+ ResponseFileSupport getResponseFilesSupport() const override {
+ return RF_Full;
+ }
void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output, const InputInfoList &Inputs,
@@ -111,6 +114,9 @@
bool hasGoodDiagnostics() const override { return true; }
bool hasIntegratedAssembler() const override { return false; }
bool hasIntegratedCPP() const override { return false; }
+ ResponseFileSupport getResponseFilesSupport() const override {
+ return RF_Full;
+ }
void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output, const InputInfoList &Inputs,
@@ -130,6 +136,13 @@
const InputInfoList &Inputs,
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
+ ResponseFileSupport getResponseFilesSupport() const override {
+ return RF_Full;
+ }
+ llvm::sys::fs::WindowsEncodingMethod
+ getResponseFileEncoding() const override {
+ return llvm::sys::fs::WEM_CurrentCodePage;
+ }
/// RenderExtraToolArgs - Render any arguments necessary to force
/// the particular tool mode.
@@ -191,6 +204,13 @@
const InputInfo &Output, const InputInfoList &Inputs,
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
+ ResponseFileSupport getResponseFilesSupport() const override {
+ return RF_Full;
+ }
+ llvm::sys::fs::WindowsEncodingMethod
+ getResponseFileEncoding() const override {
+ return llvm::sys::fs::WEM_CurrentCodePage;
+ }
};
class LLVM_LIBRARY_VISIBILITY Link : public Tool {
@@ -207,6 +227,13 @@
const InputInfo &Output, const InputInfoList &Inputs,
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
+ ResponseFileSupport getResponseFilesSupport() const override {
+ return RF_Full;
+ }
+ llvm::sys::fs::WindowsEncodingMethod
+ getResponseFileEncoding() const override {
+ return llvm::sys::fs::WEM_CurrentCodePage;
+ }
};
} // end namespace hexagon.
@@ -276,6 +303,12 @@
bool hasIntegratedCPP() const override { return false; }
bool isLinkJob() const override { return true; }
+ ResponseFileSupport getResponseFilesSupport() const override {
+ return RF_FileList;
+ }
+ virtual const char *getResponseFileFlag() const override {
+ return "-filelist";
+ }
void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output, const InputInfoList &Inputs,
@@ -339,6 +372,14 @@
const InputInfoList &Inputs,
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
+
+ ResponseFileSupport getResponseFilesSupport() const override {
+ return RF_Full;
+ }
+ llvm::sys::fs::WindowsEncodingMethod
+ getResponseFileEncoding() const override {
+ return llvm::sys::fs::WEM_CurrentCodePage;
+ }
};
class LLVM_LIBRARY_VISIBILITY Link : public Tool {
public:
@@ -351,6 +392,14 @@
const InputInfo &Output, const InputInfoList &Inputs,
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
+
+ ResponseFileSupport getResponseFilesSupport() const override {
+ return RF_Full;
+ }
+ llvm::sys::fs::WindowsEncodingMethod
+ getResponseFileEncoding() const override {
+ return llvm::sys::fs::WEM_CurrentCodePage;
+ }
};
} // end namespace openbsd
@@ -367,6 +416,14 @@
const InputInfo &Output, const InputInfoList &Inputs,
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
+
+ ResponseFileSupport getResponseFilesSupport() const override {
+ return RF_Full;
+ }
+ llvm::sys::fs::WindowsEncodingMethod
+ getResponseFileEncoding() const override {
+ return llvm::sys::fs::WEM_CurrentCodePage;
+ }
};
class LLVM_LIBRARY_VISIBILITY Link : public Tool {
public:
@@ -379,6 +436,14 @@
const InputInfo &Output, const InputInfoList &Inputs,
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
+
+ ResponseFileSupport getResponseFilesSupport() const override {
+ return RF_Full;
+ }
+ llvm::sys::fs::WindowsEncodingMethod
+ getResponseFileEncoding() const override {
+ return llvm::sys::fs::WEM_CurrentCodePage;
+ }
};
} // end namespace bitrig
@@ -395,6 +460,14 @@
const InputInfo &Output, const InputInfoList &Inputs,
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
+
+ ResponseFileSupport getResponseFilesSupport() const override {
+ return RF_Full;
+ }
+ llvm::sys::fs::WindowsEncodingMethod
+ getResponseFileEncoding() const override {
+ return llvm::sys::fs::WEM_CurrentCodePage;
+ }
};
class LLVM_LIBRARY_VISIBILITY Link : public Tool {
public:
@@ -407,6 +480,14 @@
const InputInfo &Output, const InputInfoList &Inputs,
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
+
+ ResponseFileSupport getResponseFilesSupport() const override {
+ return RF_Full;
+ }
+ llvm::sys::fs::WindowsEncodingMethod
+ getResponseFileEncoding() const override {
+ return llvm::sys::fs::WEM_CurrentCodePage;
+ }
};
} // end namespace freebsd
@@ -424,6 +505,14 @@
const InputInfo &Output, const InputInfoList &Inputs,
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
+
+ ResponseFileSupport getResponseFilesSupport() const override {
+ return RF_Full;
+ }
+ llvm::sys::fs::WindowsEncodingMethod
+ getResponseFileEncoding() const override {
+ return llvm::sys::fs::WEM_CurrentCodePage;
+ }
};
class LLVM_LIBRARY_VISIBILITY Link : public Tool {
@@ -438,6 +527,14 @@
const InputInfo &Output, const InputInfoList &Inputs,
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
+
+ ResponseFileSupport getResponseFilesSupport() const override {
+ return RF_Full;
+ }
+ llvm::sys::fs::WindowsEncodingMethod
+ getResponseFileEncoding() const override {
+ return llvm::sys::fs::WEM_CurrentCodePage;
+ }
};
} // end namespace netbsd
@@ -454,13 +551,28 @@
const InputInfoList &Inputs,
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
+
+ ResponseFileSupport getResponseFilesSupport() const override {
+ return RF_Full;
+ }
+ llvm::sys::fs::WindowsEncodingMethod
+ getResponseFileEncoding() const override {
+ return llvm::sys::fs::WEM_CurrentCodePage;
+ }
};
class LLVM_LIBRARY_VISIBILITY Link : public Tool {
public:
Link(const ToolChain &TC) : Tool("GNU::Link", "linker", TC) {}
bool hasIntegratedCPP() const override { return false; }
bool isLinkJob() const override { return true; }
+ ResponseFileSupport getResponseFilesSupport() const override {
+ return RF_Full;
+ }
+ llvm::sys::fs::WindowsEncodingMethod
+ getResponseFileEncoding() const override {
+ return llvm::sys::fs::WEM_CurrentCodePage;
+ }
void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
@@ -483,6 +595,14 @@
const InputInfoList &Inputs,
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
+
+ ResponseFileSupport getResponseFilesSupport() const override {
+ return RF_Full;
+ }
+ llvm::sys::fs::WindowsEncodingMethod
+ getResponseFileEncoding() const override {
+ return llvm::sys::fs::WEM_CurrentCodePage;
+ }
};
class LLVM_LIBRARY_VISIBILITY Link : public Tool {
public:
@@ -496,6 +616,14 @@
const InputInfoList &Inputs,
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
+
+ ResponseFileSupport getResponseFilesSupport() const override {
+ return RF_Full;
+ }
+ llvm::sys::fs::WindowsEncodingMethod
+ getResponseFileEncoding() const override {
+ return llvm::sys::fs::WEM_CurrentCodePage;
+ }
};
} // end namespace minix
@@ -540,6 +668,14 @@
const InputInfo &Output, const InputInfoList &Inputs,
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
+
+ ResponseFileSupport getResponseFilesSupport() const override {
+ return RF_Full;
+ }
+ llvm::sys::fs::WindowsEncodingMethod
+ getResponseFileEncoding() const override {
+ return llvm::sys::fs::WEM_CurrentCodePage;
+ }
};
class LLVM_LIBRARY_VISIBILITY Link : public Tool {
public:
@@ -553,6 +689,14 @@
const InputInfoList &Inputs,
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
+
+ ResponseFileSupport getResponseFilesSupport() const override {
+ return RF_Full;
+ }
+ llvm::sys::fs::WindowsEncodingMethod
+ getResponseFileEncoding() const override {
+ return llvm::sys::fs::WEM_CurrentCodePage;
+ }
};
} // end namespace dragonfly
@@ -564,6 +708,13 @@
bool hasIntegratedCPP() const override { return false; }
bool isLinkJob() const override { return true; }
+ ResponseFileSupport getResponseFilesSupport() const override {
+ return RF_Full;
+ }
+ llvm::sys::fs::WindowsEncodingMethod
+ getResponseFileEncoding() const override {
+ return llvm::sys::fs::WEM_UTF16;
+ }
void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output, const InputInfoList &Inputs,
@@ -578,6 +729,13 @@
bool hasIntegratedAssembler() const override { return true; }
bool hasIntegratedCPP() const override { return true; }
bool isLinkJob() const override { return false; }
+ ResponseFileSupport getResponseFilesSupport() const override {
+ return RF_Full;
+ }
+ llvm::sys::fs::WindowsEncodingMethod
+ getResponseFileEncoding() const override {
+ return llvm::sys::fs::WEM_UTF16;
+ }
void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output, const InputInfoList &Inputs,
Index: test/Driver/response-file.c
===================================================================
--- /dev/null
+++ test/Driver/response-file.c
@@ -0,0 +1,26 @@
+// REQUIRES: long_tests
+
+// Check that clang is able to process short response files
+// Since this is a short response file, clang must not use a response file
+// to pass its parameters to other tools. This is only necessary for a large
+// number of parameters.
+// RUN: echo "-DTEST" >> %t.0.txt
+// RUN: %clang -E @%t.0.txt %s -v 2>&1 | FileCheck %s -check-prefix=SHORT
+// SHORT-NOT: Arguments passed via response file
+// SHORT: -D TEST
+// SHORT: extern int it_works;
+
+// Check that clang is able to process long response files, routing a long
+// sequence of arguments to other tools by using response files as well.
+// We generate a 2MB response file to be big enough to surpass any system
+// limit.
+// RUN: awk "BEGIN { while (count++<300000) string=string \"-DTEST \";\
+// RUN: print string }" > %t.1.txt
+// RUN: %clang -E @%t.1.txt %s -v 2>&1 | FileCheck %s -check-prefix=LONG
+// LONG: Arguments passed via response file
+// LONG: -D TEST
+// LONG: extern int it_works;
+
+#ifdef TEST
+extern int it_works;
+#endif
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits