Job.cpp revision 263508
1//===--- Job.cpp - Command to Execute -------------------------------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9 10#include "clang/Driver/Job.h" 11#include "llvm/ADT/STLExtras.h" 12#include "llvm/ADT/StringRef.h" 13#include "llvm/ADT/StringSwitch.h" 14#include "llvm/Support/Program.h" 15#include "llvm/Support/raw_ostream.h" 16#include <cassert> 17using namespace clang::driver; 18using llvm::raw_ostream; 19using llvm::StringRef; 20 21Job::~Job() {} 22 23Command::Command(const Action &_Source, const Tool &_Creator, 24 const char *_Executable, 25 const ArgStringList &_Arguments) 26 : Job(CommandClass), Source(_Source), Creator(_Creator), 27 Executable(_Executable), Arguments(_Arguments) {} 28 29static int skipArgs(const char *Flag) { 30 // These flags are all of the form -Flag <Arg> and are treated as two 31 // arguments. Therefore, we need to skip the flag and the next argument. 32 bool Res = llvm::StringSwitch<bool>(Flag) 33 .Cases("-I", "-MF", "-MT", "-MQ", true) 34 .Cases("-o", "-coverage-file", "-dependency-file", true) 35 .Cases("-fdebug-compilation-dir", "-idirafter", true) 36 .Cases("-include", "-include-pch", "-internal-isystem", true) 37 .Cases("-internal-externc-isystem", "-iprefix", "-iwithprefix", true) 38 .Cases("-iwithprefixbefore", "-isysroot", "-isystem", "-iquote", true) 39 .Cases("-resource-dir", "-serialize-diagnostic-file", true) 40 .Case("-dwarf-debug-flags", true) 41 .Default(false); 42 43 // Match found. 44 if (Res) 45 return 2; 46 47 // The remaining flags are treated as a single argument. 48 49 // These flags are all of the form -Flag and have no second argument. 50 Res = llvm::StringSwitch<bool>(Flag) 51 .Cases("-M", "-MM", "-MG", "-MP", "-MD", true) 52 .Case("-MMD", true) 53 .Default(false); 54 55 // Match found. 56 if (Res) 57 return 1; 58 59 // These flags are treated as a single argument (e.g., -F<Dir>). 60 StringRef FlagRef(Flag); 61 if (FlagRef.startswith("-F") || FlagRef.startswith("-I")) 62 return 1; 63 64 return 0; 65} 66 67static bool quoteNextArg(const char *flag) { 68 return llvm::StringSwitch<bool>(flag) 69 .Case("-D", true) 70 .Default(false); 71} 72 73static void PrintArg(raw_ostream &OS, const char *Arg, bool Quote) { 74 const bool Escape = std::strpbrk(Arg, "\"\\$"); 75 76 if (!Quote && !Escape) { 77 OS << Arg; 78 return; 79 } 80 81 // Quote and escape. This isn't really complete, but good enough. 82 OS << '"'; 83 while (const char c = *Arg++) { 84 if (c == '"' || c == '\\' || c == '$') 85 OS << '\\'; 86 OS << c; 87 } 88 OS << '"'; 89} 90 91void Command::Print(raw_ostream &OS, const char *Terminator, bool Quote, 92 bool CrashReport) const { 93 OS << " \"" << Executable << '"'; 94 95 for (size_t i = 0, e = Arguments.size(); i < e; ++i) { 96 const char *const Arg = Arguments[i]; 97 98 if (CrashReport) { 99 if (int Skip = skipArgs(Arg)) { 100 i += Skip - 1; 101 continue; 102 } 103 } 104 105 OS << ' '; 106 PrintArg(OS, Arg, Quote); 107 108 if (CrashReport && quoteNextArg(Arg) && i + 1 < e) { 109 OS << ' '; 110 PrintArg(OS, Arguments[++i], true); 111 } 112 } 113 OS << Terminator; 114} 115 116int Command::Execute(const StringRef **Redirects, std::string *ErrMsg, 117 bool *ExecutionFailed) const { 118 SmallVector<const char*, 128> Argv; 119 Argv.push_back(Executable); 120 for (size_t i = 0, e = Arguments.size(); i != e; ++i) 121 Argv.push_back(Arguments[i]); 122 Argv.push_back(0); 123 124 return llvm::sys::ExecuteAndWait(Executable, Argv.data(), /*env*/ 0, 125 Redirects, /*secondsToWait*/ 0, 126 /*memoryLimit*/ 0, ErrMsg, ExecutionFailed); 127} 128 129FallbackCommand::FallbackCommand(const Action &Source_, const Tool &Creator_, 130 const char *Executable_, 131 const ArgStringList &Arguments_, 132 Command *Fallback_) 133 : Command(Source_, Creator_, Executable_, Arguments_), Fallback(Fallback_) { 134} 135 136void FallbackCommand::Print(raw_ostream &OS, const char *Terminator, 137 bool Quote, bool CrashReport) const { 138 Command::Print(OS, "", Quote, CrashReport); 139 OS << " ||"; 140 Fallback->Print(OS, Terminator, Quote, CrashReport); 141} 142 143static bool ShouldFallback(int ExitCode) { 144 // FIXME: We really just want to fall back for internal errors, such 145 // as when some symbol cannot be mangled, when we should be able to 146 // parse something but can't, etc. 147 return ExitCode != 0; 148} 149 150int FallbackCommand::Execute(const StringRef **Redirects, std::string *ErrMsg, 151 bool *ExecutionFailed) const { 152 int PrimaryStatus = Command::Execute(Redirects, ErrMsg, ExecutionFailed); 153 if (!ShouldFallback(PrimaryStatus)) 154 return PrimaryStatus; 155 156 // Clear ExecutionFailed and ErrMsg before falling back. 157 if (ErrMsg) 158 ErrMsg->clear(); 159 if (ExecutionFailed) 160 *ExecutionFailed = false; 161 162 int SecondaryStatus = Fallback->Execute(Redirects, ErrMsg, ExecutionFailed); 163 return SecondaryStatus; 164} 165 166JobList::JobList() : Job(JobListClass) {} 167 168JobList::~JobList() { 169 for (iterator it = begin(), ie = end(); it != ie; ++it) 170 delete *it; 171} 172 173void JobList::Print(raw_ostream &OS, const char *Terminator, bool Quote, 174 bool CrashReport) const { 175 for (const_iterator it = begin(), ie = end(); it != ie; ++it) 176 (*it)->Print(OS, Terminator, Quote, CrashReport); 177} 178 179void JobList::clear() { 180 DeleteContainerPointers(Jobs); 181} 182