diff options
Diffstat (limited to 'lib/Driver/Job.cpp')
-rw-r--r-- | lib/Driver/Job.cpp | 187 |
1 files changed, 151 insertions, 36 deletions
diff --git a/lib/Driver/Job.cpp b/lib/Driver/Job.cpp index 42cc1bc..c5b3f5a 100644 --- a/lib/Driver/Job.cpp +++ b/lib/Driver/Job.cpp @@ -12,8 +12,10 @@ #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/StringSet.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/Program.h" #include "llvm/Support/raw_ostream.h" @@ -21,6 +23,7 @@ using namespace clang::driver; using llvm::raw_ostream; using llvm::StringRef; +using llvm::ArrayRef; Job::~Job() {} @@ -28,7 +31,8 @@ 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), + ResponseFile(nullptr) {} static int skipArgs(const char *Flag) { // These flags are all of the form -Flag <Arg> and are treated as two @@ -69,12 +73,6 @@ static int skipArgs(const char *Flag) { return 0; } -static bool quoteNextArg(const char *flag) { - return llvm::StringSwitch<bool>(flag) - .Case("-D", true) - .Default(false); -} - static void PrintArg(raw_ostream &OS, const char *Arg, bool Quote) { const bool Escape = std::strpbrk(Arg, "\"\\$"); @@ -93,38 +91,162 @@ static void PrintArg(raw_ostream &OS, const char *Arg, bool Quote) { OS << '"'; } +void Command::writeResponseFile(raw_ostream &OS) const { + // In a file list, we only write the set of inputs to the response file + if (Creator.getResponseFilesSupport() == Tool::RF_FileList) { + for (const char *Arg : InputFileList) { + OS << Arg << '\n'; + } + return; + } + + // In regular response files, we send all arguments to the response file + for (const char *Arg : Arguments) { + OS << '"'; + + for (; *Arg != '\0'; Arg++) { + if (*Arg == '\"' || *Arg == '\\') { + OS << '\\'; + } + OS << *Arg; + } + + OS << "\" "; + } +} + +void Command::buildArgvForResponseFile( + llvm::SmallVectorImpl<const char *> &Out) const { + // When not a file list, all arguments are sent to the response file. + // This leaves us to set the argv to a single parameter, requesting the tool + // to read the response file. + if (Creator.getResponseFilesSupport() != Tool::RF_FileList) { + Out.push_back(Executable); + Out.push_back(ResponseFileFlag.c_str()); + return; + } + + llvm::StringSet<> Inputs; + for (const char *InputName : InputFileList) + Inputs.insert(InputName); + Out.push_back(Executable); + // In a file list, build args vector ignoring parameters that will go in the + // response file (elements of the InputFileList vector) + bool FirstInput = true; + for (const char *Arg : Arguments) { + if (Inputs.count(Arg) == 0) { + Out.push_back(Arg); + } else if (FirstInput) { + FirstInput = false; + Out.push_back(Creator.getResponseFileFlag()); + Out.push_back(ResponseFile); + } + } +} + void Command::Print(raw_ostream &OS, const char *Terminator, bool Quote, - bool CrashReport) const { - OS << " \"" << Executable << '"'; + CrashReportInfo *CrashInfo) const { + // Always quote the exe. + OS << ' '; + PrintArg(OS, Executable, /*Quote=*/true); + + llvm::ArrayRef<const char *> Args = Arguments; + llvm::SmallVector<const char *, 128> ArgsRespFile; + if (ResponseFile != nullptr) { + buildArgvForResponseFile(ArgsRespFile); + Args = ArrayRef<const char *>(ArgsRespFile).slice(1); // no executable name + } - for (size_t i = 0, e = Arguments.size(); i < e; ++i) { - const char *const Arg = Arguments[i]; + StringRef MainFilename; + // We'll need the argument to -main-file-name to find the input file name. + if (CrashInfo) + for (size_t I = 0, E = Args.size(); I + 1 < E; ++I) + if (StringRef(Args[I]).equals("-main-file-name")) + MainFilename = Args[I + 1]; - if (CrashReport) { + for (size_t i = 0, e = Args.size(); i < e; ++i) { + const char *const Arg = Args[i]; + + if (CrashInfo) { if (int Skip = skipArgs(Arg)) { i += Skip - 1; continue; + } else if (llvm::sys::path::filename(Arg) == MainFilename && + (i == 0 || StringRef(Args[i - 1]) != "-main-file-name")) { + // Replace the input file name with the crashinfo's file name. + OS << ' '; + StringRef ShortName = llvm::sys::path::filename(CrashInfo->Filename); + PrintArg(OS, ShortName.str().c_str(), Quote); + continue; } } OS << ' '; PrintArg(OS, Arg, Quote); + } - if (CrashReport && quoteNextArg(Arg) && i + 1 < e) { - OS << ' '; - PrintArg(OS, Arguments[++i], true); - } + if (CrashInfo && !CrashInfo->VFSPath.empty()) { + OS << ' '; + PrintArg(OS, "-ivfsoverlay", Quote); + OS << ' '; + PrintArg(OS, CrashInfo->VFSPath.str().c_str(), Quote); } + + if (ResponseFile != nullptr) { + OS << "\n Arguments passed via response file:\n"; + writeResponseFile(OS); + // Avoiding duplicated newline terminator, since FileLists are + // newline-separated. + if (Creator.getResponseFilesSupport() != Tool::RF_FileList) + OS << "\n"; + OS << " (end of response file)"; + } + OS << Terminator; } +void Command::setResponseFile(const char *FileName) { + ResponseFile = FileName; + ResponseFileFlag = Creator.getResponseFileFlag(); + ResponseFileFlag += FileName; +} + 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]); + + if (ResponseFile == nullptr) { + 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 store the response file contents + std::string RespContents; + llvm::raw_string_ostream SS(RespContents); + + // Write file contents and build the Argv vector + writeResponseFile(SS); + buildArgvForResponseFile(Argv); Argv.push_back(nullptr); + SS.flush(); + + // Save the response file in the appropriate encoding + if (std::error_code EC = writeFileWithEncoding( + ResponseFile, RespContents, Creator.getResponseFileEncoding())) { + if (ErrMsg) + *ErrMsg = EC.message(); + if (ExecutionFailed) + *ExecutionFailed = true; + return -1; + } return llvm::sys::ExecuteAndWait(Executable, Argv.data(), /*env*/ nullptr, Redirects, /*secondsToWait*/ 0, @@ -134,15 +256,15 @@ int Command::Execute(const StringRef **Redirects, std::string *ErrMsg, FallbackCommand::FallbackCommand(const Action &Source_, const Tool &Creator_, const char *Executable_, const ArgStringList &Arguments_, - Command *Fallback_) - : Command(Source_, Creator_, Executable_, Arguments_), Fallback(Fallback_) { -} + std::unique_ptr<Command> Fallback_) + : Command(Source_, Creator_, Executable_, Arguments_), + Fallback(std::move(Fallback_)) {} void FallbackCommand::Print(raw_ostream &OS, const char *Terminator, - bool Quote, bool CrashReport) const { - Command::Print(OS, "", Quote, CrashReport); + bool Quote, CrashReportInfo *CrashInfo) const { + Command::Print(OS, "", Quote, CrashInfo); OS << " ||"; - Fallback->Print(OS, Terminator, Quote, CrashReport); + Fallback->Print(OS, Terminator, Quote, CrashInfo); } static bool ShouldFallback(int ExitCode) { @@ -173,17 +295,10 @@ int FallbackCommand::Execute(const StringRef **Redirects, std::string *ErrMsg, JobList::JobList() : Job(JobListClass) {} -JobList::~JobList() { - for (iterator it = begin(), ie = end(); it != ie; ++it) - delete *it; -} - void JobList::Print(raw_ostream &OS, const char *Terminator, bool Quote, - bool CrashReport) const { - for (const_iterator it = begin(), ie = end(); it != ie; ++it) - (*it)->Print(OS, Terminator, Quote, CrashReport); + CrashReportInfo *CrashInfo) const { + for (const auto &Job : *this) + Job.Print(OS, Terminator, Quote, CrashInfo); } -void JobList::clear() { - DeleteContainerPointers(Jobs); -} +void JobList::clear() { Jobs.clear(); } |