Hi rafael, asl,
This patch addresses PR15171 and teaches Clang how to call other tools with
response files, when the command line exceeds system limits. This is a problem
for Windows systems, whose maximum command-line length is 32kb.
I introduce the concept of "response file support" for each Tool object. A
given Tool may have full support for response files (e.g. MSVC's link.exe) or
only support file names inside response files, but no flags (e.g. Apple's ld64,
as commented in PR15171), or no support at all (the default case). Therefore,
if you implement a toolchain in the clang driver and you want clang to be able
to use response files in your tools, you must override a method
(getReponseFileSupport()) to tell so.
I designed it to support different kinds of tools and internationalisation
needs:
- VS response files ( UTF-16 )
- GNU tools ( uses system's current code page, windows' legacy intl. support,
with escaped backslashes. On unix, fallback to UTF-8 )
- Clang itself ( UTF-16 on windows, UTF-8 on unix )
- ld64 response files ( only a limited file list, UTF-8 on unix )
With this design, I was able to test input file names with spaces and
international characters for Windows. When the linker input is large enough, it
creates a response file with the correct encoding. On a Mac, to test ld64, I
temporarily changed Clang's behavior to always use response files regardless of
the command size limit (avoiding using huge command line inputs). I tested
clang with the LLVM test suite (compiling benchmarks) and it did fine.
Note: It depends on http://reviews.llvm.org/D4896 landing in the LLVM tree.
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,33 @@
/// 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
+ const char *ResponseFile;
+
+ /// The input file list in case we need to emit a file list instead of a
+ /// proper response file
+ llvm::opt::ArgStringList InputFileList;
+
+ /// Helps Command::Print to precisely describe the contents of a reponse
+ /// file, when it is used.
+ void PrintArgsWithRespFile(llvm::raw_ostream &OS,
+ const char *Terminator, bool Quote,
+ bool CrashReport) const;
+
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 +108,9 @@
/// getCreator - Return the Tool which caused the creation of this job.
const Tool &getCreator() const { return Creator; }
+ void setResponseFile(const char *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
@@ -31,6 +31,28 @@
/// 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. The response files should
+ // be encoded in UTF8 in Unix systems or in the current code page in
+ // Windows systems (e.g. gcc.exe)
+ FullWithoutUTF16,
+ // Provides full support for response files. The response files should
+ // be encoded in UTF16 (e.g. link.exe, clang.exe). This is only relevant
+ // for Windows toolchains, while in Unix systems we will always fallback
+ // to UTF8.
+ FullWithUTF16,
+ // Input file names can live in a file, but flags can't (e.g. ld64)
+ FileList,
+ // Does not support response files: all arguments must be passed via
+ // command line
+ None
+ };
+
+private:
/// The tool name (for debugging).
const char *Name;
@@ -57,6 +79,10 @@
virtual bool hasIntegratedCPP() const = 0;
virtual bool isLinkJob() const { return false; }
virtual bool isDsymutilJob() const { return false; }
+ virtual ResponseFileSupport getResponseFilesSupport() const {
+ return ResponseFileSupport::None;
+ }
+ 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
@@ -28,7 +28,12 @@
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::ResponseFileSupport::None),
+ ResponseFile(nullptr) {}
static int skipArgs(const char *Flag) {
// These flags are all of the form -Flag <Arg> and are treated as two
@@ -93,12 +98,185 @@
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;
+}
+
+/// Returns the number of backslashes and quotes in this string. These
+/// characters need to be escaped in the response files of some tools, but
+/// others do not care. Thus, we escape for all response files.
+static unsigned int CountBackslashesAndQuotes(const char *Start) {
+ unsigned int Count = 0;
+ while (*Start != '\0') {
+ if (*Start == '\\' || *Start == '\"')
+ ++Count;
+ ++Start;
+ }
+ return Count;
+}
+
+/// 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.
+static std::unique_ptr<char[]> FlattenArgs(const char **args) {
+ // First, determine the length of the command line.
+ unsigned len = 0;
+ for (unsigned i = 0; args[i]; i++) {
+ bool Quoted = ArgNeedsQuotes(args[i]);
+ len += Quoted ? 2 : 0;
+ len += CountBackslashesAndQuotes(args[i]) + strlen(args[i]) + 1;
+ }
+
+ // Now build the command line.
+ std::unique_ptr<char[]> command(new char[len + 1]);
+ char *p = command.get();
+
+ for (unsigned i = 0; args[i]; i++) {
+ const char *arg = args[i];
+
+ bool needsQuoting = ArgNeedsQuotes(arg);
+ if (needsQuoting)
+ *p++ = '"';
+
+ while (*arg != '\0') {
+ if (*arg == '\"' || *arg == '\\') {
+ *p++ = '\\';
+ }
+ *p++ = *arg++;
+ }
+
+ if (needsQuoting) {
+ *p++ = '"';
+ }
+ *p++ = ' ';
+ }
+
+ *p = 0;
+ return command;
+}
+
+/// Read the list of input files in Inputs and adjusts Argv accordingly,
+/// removing the elements of Inputs from Argv (since they will be passed via a
+/// response file). This function will also Insert the response file name in
+/// argv. Finally, it returns a C string with the contents of the response
+/// file (the input file list separated by newlines).
+static std::unique_ptr<char[]>
+FlattenFileList(const llvm::SmallVectorImpl<const char *> &Inputs,
+ llvm::SmallVectorImpl<const char *> &Argv,
+ const char *ResponseFlag, const char *ResponseFile) {
+ llvm::SmallVector<const char *, 128> NewArgv;
+ unsigned len = 0;
+ for (auto Input : Inputs) {
+ len += strlen(Input) + 1;
+ }
+ bool FirstInput = true;
+ for (auto Arg : Argv) {
+ if (Arg == nullptr) {
+ NewArgv.push_back(Arg);
+ break;
+ }
+ bool found = false;
+ for (auto InputName : Inputs) {
+ if (strcmp(Arg, InputName) == 0) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ NewArgv.push_back(Arg);
+ } else if (FirstInput) {
+ FirstInput = false;
+ NewArgv.push_back(ResponseFlag);
+ NewArgv.push_back(ResponseFile);
+ }
+ }
+ Argv = NewArgv;
+ // Now build the file list.
+ std::unique_ptr<char[]> command(new char[len + 1]);
+ char *p = command.get();
+ for (auto Arg : Inputs) {
+ const char *src = Arg;
+ while (*src != '\0')
+ *p++ = *src++;
+ *p++ = '\n';
+ }
+ *p = 0;
+ return command;
+}
+
+void Command::PrintArgsWithRespFile(raw_ostream &OS,
+ const char *Terminator, bool Quote,
+ bool CrashReport) const {
+ std::string ResponseFlag = Creator.getResponseFileFlag();
+ ResponseFlag += ResponseFile;
+ OS << ' ';
+
+ llvm::opt::ArgStringList Argv = Arguments;
+ Argv.push_back(nullptr);
+ std::unique_ptr<char[]> FlattenedArgs;
+ Tool::ResponseFileSupport RespFileSup = Creator.getResponseFilesSupport();
+ if (RespFileSup == Tool::ResponseFileSupport::FileList) {
+ FlattenedArgs = FlattenFileList(InputFileList, Argv,
+ Creator.getResponseFileFlag(),
+ ResponseFile);
+ } else {
+ FlattenedArgs = FlattenArgs(Argv.data());
+ Argv.clear();
+ }
+
+ // Print args that are not in the FileList (if it is a proper response file
+ // rather than a file list, all arguments go into the response file and Argv
+ // is empty).
+ for (size_t i = 0, e = Argv.size(); i < e; ++i) {
+ const char *const Arg = Argv[i];
+ if (Arg == nullptr)
+ break;
+
+ if (CrashReport) {
+ if (int Skip = skipArgs(Arg)) {
+ i += Skip - 1;
+ continue;
+ }
+ }
+
+ OS << ' ';
+ PrintArg(OS, Arg, Quote);
+
+ if (CrashReport && quoteNextArg(Arg) && i + 1 < e) {
+ OS << ' ';
+ PrintArg(OS, Arguments[++i], true);
+ }
+ }
+ // Now print our response file flag and print the contents that we will put in
+ // a response file. If it is a FileList, FlattenFileList() already put the
+ // flag in Argv and there is no need to print it again.
+ if (RespFileSup != Tool::ResponseFileSupport::FileList) {
+ PrintArg(OS, ResponseFlag.c_str(), Quote);
+ }
+ OS << "\n Arguments passed via response file:\n";
+ OS << FlattenedArgs.get();
+ // Avoiding duplicated newline terminator, since FileLists are
+ // newline-separated.
+ if (RespFileSup != Tool::ResponseFileSupport::FileList) {
+ OS << "\n";
+ }
+ OS << " (end of response file)";
+ OS << Terminator;
+}
+
void Command::Print(raw_ostream &OS, const char *Terminator, bool Quote,
bool CrashReport) const {
// Always quote the exe.
OS << ' ';
PrintArg(OS, Executable, /*Quote=*/true);
+ if (needsResponseFile && ResponseFile != nullptr) {
+ PrintArgsWithRespFile(OS, Terminator, Quote, CrashReport);
+ return;
+ }
+
for (size_t i = 0, e = Arguments.size(); i < e; ++i) {
const char *const Arg = Arguments[i];
@@ -128,6 +306,44 @@
Argv.push_back(Arguments[i]);
Argv.push_back(nullptr);
+ if (ResponseFile == nullptr || !needsResponseFile) {
+ 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)
+ std::string ResponseFlag;
+ std::unique_ptr<char[]> FlattenedArgs;
+ Tool::ResponseFileSupport RespFileSup = Creator.getResponseFilesSupport();
+ ResponseFlag = Creator.getResponseFileFlag();
+ ResponseFlag += ResponseFile;
+ if (RespFileSup == Tool::ResponseFileSupport::FileList)
+ FlattenedArgs = FlattenFileList(InputFileList, Argv,
+ Creator.getResponseFileFlag(),
+ ResponseFile);
+ else
+ FlattenedArgs = FlattenArgs(Argv.data() + 1 /* Skip exec name */);
+
+ bool useUTF16 = RespFileSup == Tool::ResponseFileSupport::FullWithUTF16;
+ if (!llvm::sys::writeFileWithSystemEncoding(ResponseFile, FlattenedArgs.get(),
+ ErrMsg, useUTF16)) {
+ if (ExecutionFailed)
+ *ExecutionFailed = true;
+ return -1;
+ }
+
+ // Substitute the argument vector with a single argument to supply the
+ // response file. In case of a FileList, FlattenFileList() already prepared
+ // Argv with the correct arguments.
+ if (RespFileSup != Tool::ResponseFileSupport::FileList) {
+ Argv.clear();
+ Argv.push_back(Executable);
+ Argv.push_back(ResponseFlag.c_str());
+ Argv.push_back(nullptr);
+ }
+
return llvm::sys::ExecuteAndWait(Executable, Argv.data(), /*env*/ nullptr,
Redirects, /*secondsToWait*/ 0,
/*memoryLimit*/ 0, ErrMsg, ExecutionFailed);
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
@@ -815,7 +815,7 @@
}
}
- // Setting -mno-global-merge disables the codegen global merge pass. Setting
+ // Setting -mno-global-merge disables the codegen global merge pass. Setting
// -mglobal-merge has no effect as the pass is enabled by default.
if (Arg *A = Args.getLastArg(options::OPT_mglobal_merge,
options::OPT_mno_global_merge)) {
@@ -2499,7 +2499,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");
@@ -2601,18 +2601,18 @@
if (getToolChain().getTriple().getVendor() == llvm::Triple::Apple)
CmdArgs.push_back("-analyzer-checker=osx");
-
+
CmdArgs.push_back("-analyzer-checker=deadcode");
-
+
if (types::isCXX(Inputs[0].getType()))
CmdArgs.push_back("-analyzer-checker=cplusplus");
// Enable the following experimental checkers for testing.
CmdArgs.push_back(
"-analyzer-checker=security.insecureAPI.UncheckedReturn");
CmdArgs.push_back("-analyzer-checker=security.insecureAPI.getpw");
CmdArgs.push_back("-analyzer-checker=security.insecureAPI.gets");
- CmdArgs.push_back("-analyzer-checker=security.insecureAPI.mktemp");
+ CmdArgs.push_back("-analyzer-checker=security.insecureAPI.mktemp");
CmdArgs.push_back("-analyzer-checker=security.insecureAPI.mkstemp");
CmdArgs.push_back("-analyzer-checker=security.insecureAPI.vfork");
}
@@ -2837,7 +2837,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
@@ -2936,7 +2936,7 @@
CmdArgs.push_back("-menable-unsafe-fp-math");
- // Validate and pass through -fp-contract option.
+ // Validate and pass through -fp-contract option.
if (Arg *A = Args.getLastArg(options::OPT_ffast_math, FastMathAliasOption,
options::OPT_fno_fast_math,
options::OPT_ffp_contract)) {
@@ -3582,7 +3582,7 @@
Args.AddLastArg(CmdArgs, options::OPT_fno_standalone_debug);
Args.AddLastArg(CmdArgs, options::OPT_fno_operator_names);
// AltiVec language extensions aren't relevant for assembling.
- if (!isa<PreprocessJobAction>(JA) ||
+ if (!isa<PreprocessJobAction>(JA) ||
Output.getType() != types::TY_PP_Asm)
Args.AddLastArg(CmdArgs, options::OPT_faltivec);
Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_show_template_tree);
@@ -3768,7 +3768,7 @@
!Args.hasArg(options::OPT_fno_blocks))) {
CmdArgs.push_back("-fblocks");
- if (!Args.hasArg(options::OPT_fgnu_runtime) &&
+ if (!Args.hasArg(options::OPT_fgnu_runtime) &&
!getToolChain().hasBlocksRuntime())
CmdArgs.push_back("-fblocks-runtime-optional");
}
@@ -3778,8 +3778,8 @@
// modules implementation is solid for C++/Objective-C++ programs as well.
bool HaveModules = false;
if (Args.hasFlag(options::OPT_fmodules, options::OPT_fno_modules, false)) {
- bool AllowedInCXX = Args.hasFlag(options::OPT_fcxx_modules,
- options::OPT_fno_cxx_modules,
+ bool AllowedInCXX = Args.hasFlag(options::OPT_fcxx_modules,
+ options::OPT_fno_cxx_modules,
false);
if (AllowedInCXX || !types::isCXX(InputType)) {
CmdArgs.push_back("-fmodules");
@@ -3949,7 +3949,7 @@
CmdArgs.push_back("-fms-extensions");
// -fms-compatibility=0 is default.
- if (Args.hasFlag(options::OPT_fms_compatibility,
+ if (Args.hasFlag(options::OPT_fms_compatibility,
options::OPT_fno_ms_compatibility,
(IsWindowsMSVC && Args.hasFlag(options::OPT_fms_extensions,
options::OPT_fno_ms_extensions,
@@ -4036,12 +4036,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);
@@ -4335,7 +4335,7 @@
options::OPT_fno_apple_pragma_pack, false))
CmdArgs.push_back("-fapple-pragma-pack");
- // le32-specific flags:
+ // le32-specific flags:
// -fno-math-builtin: clang should not convert math builtins to intrinsics
// by default.
if (getToolChain().getArch() == llvm::Triple::le32) {
@@ -4376,7 +4376,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");
@@ -4542,8 +4542,8 @@
<< value;
} else {
// Otherwise, determine if we are using the non-fragile ABI.
- bool nonFragileABIIsDefault =
- (rewriteKind == RK_NonFragile ||
+ bool nonFragileABIIsDefault =
+ (rewriteKind == RK_NonFragile ||
(rewriteKind == RK_None &&
getToolChain().IsObjCNonFragileABIDefault()));
if (args.hasFlag(options::OPT_fobjc_nonfragile_abi,
@@ -4796,7 +4796,7 @@
// Add the "effective" target triple.
CmdArgs.push_back("-triple");
- std::string TripleStr =
+ std::string TripleStr =
getToolChain().ComputeEffectiveClangTriple(Args, Input.getType());
CmdArgs.push_back(Args.MakeArgString(TripleStr));
@@ -5772,6 +5772,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.
@@ -5840,7 +5846,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)) {
@@ -5883,7 +5903,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,
@@ -6309,7 +6332,7 @@
if (!Args.hasArg(options::OPT_nostdlib) &&
!Args.hasArg(options::OPT_nostartfiles)) {
if (!Args.hasArg(options::OPT_shared)) {
- if (Args.hasArg(options::OPT_pg))
+ if (Args.hasArg(options::OPT_pg))
CmdArgs.push_back(Args.MakeArgString(
getToolChain().GetFilePath("gcrt0.o")));
else
@@ -6343,7 +6366,7 @@
!Args.hasArg(options::OPT_nodefaultlibs)) {
if (D.CCCIsCXX()) {
getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
- if (Args.hasArg(options::OPT_pg))
+ if (Args.hasArg(options::OPT_pg))
CmdArgs.push_back("-lm_p");
else
CmdArgs.push_back("-lm");
@@ -6608,7 +6631,7 @@
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
- const toolchains::FreeBSD& ToolChain =
+ const toolchains::FreeBSD& ToolChain =
static_cast<const toolchains::FreeBSD&>(getToolChain());
const Driver &D = ToolChain.getDriver();
const bool IsPIE =
@@ -6844,7 +6867,7 @@
break;
default:
- break;
+ break;
}
Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA,
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 ResponseFileSupport::FullWithUTF16;
+ }
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 ResponseFileSupport::FullWithUTF16;
+ }
void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output, const InputInfoList &Inputs,
@@ -130,6 +136,9 @@
const InputInfoList &Inputs,
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
+ ResponseFileSupport getResponseFilesSupport() const override {
+ return ResponseFileSupport::FullWithoutUTF16;
+ }
/// RenderExtraToolArgs - Render any arguments necessary to force
/// the particular tool mode.
@@ -191,6 +200,9 @@
const InputInfo &Output, const InputInfoList &Inputs,
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
+ ResponseFileSupport getResponseFilesSupport() const override {
+ return ResponseFileSupport::FullWithoutUTF16;
+ }
};
class LLVM_LIBRARY_VISIBILITY Link : public Tool {
@@ -207,6 +219,9 @@
const InputInfo &Output, const InputInfoList &Inputs,
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
+ ResponseFileSupport getResponseFilesSupport() const override {
+ return ResponseFileSupport::FullWithoutUTF16;
+ }
};
} // end namespace hexagon.
@@ -276,6 +291,12 @@
bool hasIntegratedCPP() const override { return false; }
bool isLinkJob() const override { return true; }
+ ResponseFileSupport getResponseFilesSupport() const override {
+ return ResponseFileSupport::FileList;
+ }
+ virtual const char *getResponseFileFlag() const override {
+ return "-filelist";
+ }
void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output, const InputInfoList &Inputs,
@@ -339,6 +360,10 @@
const InputInfoList &Inputs,
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
+
+ ResponseFileSupport getResponseFilesSupport() const override {
+ return ResponseFileSupport::FullWithoutUTF16;
+ }
};
class LLVM_LIBRARY_VISIBILITY Link : public Tool {
public:
@@ -351,6 +376,10 @@
const InputInfo &Output, const InputInfoList &Inputs,
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
+
+ ResponseFileSupport getResponseFilesSupport() const override {
+ return ResponseFileSupport::FullWithoutUTF16;
+ }
};
} // end namespace openbsd
@@ -367,6 +396,10 @@
const InputInfo &Output, const InputInfoList &Inputs,
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
+
+ ResponseFileSupport getResponseFilesSupport() const override {
+ return ResponseFileSupport::FullWithoutUTF16;
+ }
};
class LLVM_LIBRARY_VISIBILITY Link : public Tool {
public:
@@ -379,6 +412,10 @@
const InputInfo &Output, const InputInfoList &Inputs,
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
+
+ ResponseFileSupport getResponseFilesSupport() const override {
+ return ResponseFileSupport::FullWithoutUTF16;
+ }
};
} // end namespace bitrig
@@ -395,6 +432,10 @@
const InputInfo &Output, const InputInfoList &Inputs,
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
+
+ ResponseFileSupport getResponseFilesSupport() const override {
+ return ResponseFileSupport::FullWithoutUTF16;
+ }
};
class LLVM_LIBRARY_VISIBILITY Link : public Tool {
public:
@@ -407,6 +448,10 @@
const InputInfo &Output, const InputInfoList &Inputs,
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
+
+ ResponseFileSupport getResponseFilesSupport() const override {
+ return ResponseFileSupport::FullWithoutUTF16;
+ }
};
} // end namespace freebsd
@@ -424,6 +469,10 @@
const InputInfo &Output, const InputInfoList &Inputs,
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
+
+ ResponseFileSupport getResponseFilesSupport() const override {
+ return ResponseFileSupport::FullWithoutUTF16;
+ }
};
class LLVM_LIBRARY_VISIBILITY Link : public Tool {
@@ -438,6 +487,10 @@
const InputInfo &Output, const InputInfoList &Inputs,
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
+
+ ResponseFileSupport getResponseFilesSupport() const override {
+ return ResponseFileSupport::FullWithoutUTF16;
+ }
};
} // end namespace netbsd
@@ -454,13 +507,20 @@
const InputInfoList &Inputs,
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
+
+ ResponseFileSupport getResponseFilesSupport() const override {
+ return ResponseFileSupport::FullWithoutUTF16;
+ }
};
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 ResponseFileSupport::FullWithoutUTF16;
+ }
void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
@@ -483,6 +543,10 @@
const InputInfoList &Inputs,
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
+
+ ResponseFileSupport getResponseFilesSupport() const override {
+ return ResponseFileSupport::FullWithoutUTF16;
+ }
};
class LLVM_LIBRARY_VISIBILITY Link : public Tool {
public:
@@ -496,6 +560,10 @@
const InputInfoList &Inputs,
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
+
+ ResponseFileSupport getResponseFilesSupport() const override {
+ return ResponseFileSupport::FullWithoutUTF16;
+ }
};
} // end namespace minix
@@ -540,13 +608,20 @@
const InputInfo &Output, const InputInfoList &Inputs,
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
+
+ ResponseFileSupport getResponseFilesSupport() const override {
+ return ResponseFileSupport::FullWithoutUTF16;
+ }
};
class LLVM_LIBRARY_VISIBILITY Link : public Tool {
public:
Link(const ToolChain &TC) : Tool("auroraux::Link", "linker", TC) {}
bool hasIntegratedCPP() const override { return false; }
bool isLinkJob() const override { return true; }
+ ResponseFileSupport getResponseFilesSupport() const override {
+ return ResponseFileSupport::FullWithoutUTF16;
+ }
void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output, const InputInfoList &Inputs,
@@ -568,6 +643,10 @@
const InputInfo &Output, const InputInfoList &Inputs,
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
+
+ ResponseFileSupport getResponseFilesSupport() const override {
+ return ResponseFileSupport::FullWithoutUTF16;
+ }
};
class LLVM_LIBRARY_VISIBILITY Link : public Tool {
public:
@@ -581,6 +660,10 @@
const InputInfoList &Inputs,
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
+
+ ResponseFileSupport getResponseFilesSupport() const override {
+ return ResponseFileSupport::FullWithoutUTF16;
+ }
};
} // end namespace dragonfly
@@ -592,6 +675,9 @@
bool hasIntegratedCPP() const override { return false; }
bool isLinkJob() const override { return true; }
+ ResponseFileSupport getResponseFilesSupport() const override {
+ return ResponseFileSupport::FullWithUTF16;
+ }
void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output, const InputInfoList &Inputs,
@@ -606,6 +692,9 @@
bool hasIntegratedAssembler() const override { return true; }
bool hasIntegratedCPP() const override { return true; }
bool isLinkJob() const override { return false; }
+ ResponseFileSupport getResponseFilesSupport() const override {
+ return ResponseFileSupport::FullWithUTF16;
+ }
void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output, const InputInfoList &Inputs,
Index: test/Driver/response-file.c
===================================================================
--- test/Driver/response-file.c
+++ 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