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