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 .Cases("-dwarf-debug-flags", "-ivfsoverlay", 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 FlagRef.startswith("-fmodules-cache-path=")) 67 return 1; 68 69 return 0; 70 } 71 72 static bool quoteNextArg(const char *flag) { 73 return llvm::StringSwitch<bool>(flag) 74 .Case("-D", true) 75 .Default(false); 76 } 77 78 static void PrintArg(raw_ostream &OS, const char *Arg, bool Quote) { 79 const bool Escape = std::strpbrk(Arg, "\"\\$"); 80 81 if (!Quote && !Escape) { 82 OS << Arg; 83 return; 84 } 85 86 // Quote and escape. This isn't really complete, but good enough. 87 OS << '"'; 88 while (const char c = *Arg++) { 89 if (c == '"' || c == '\\' || c == '$') 90 OS << '\\'; 91 OS << c; 92 } 93 OS << '"'; 94 } 95 96 void Command::Print(raw_ostream &OS, const char *Terminator, bool Quote, 97 bool CrashReport) const { 98 // Always quote the exe. 99 OS << ' '; 100 PrintArg(OS, Executable, /*Quote=*/true); 101 102 for (size_t i = 0, e = Arguments.size(); i < e; ++i) { 103 const char *const Arg = Arguments[i]; 104 105 if (CrashReport) { 106 if (int Skip = skipArgs(Arg)) { 107 i += Skip - 1; 108 continue; 109 } 110 } 111 112 OS << ' '; 113 PrintArg(OS, Arg, Quote); 114 115 if (CrashReport && quoteNextArg(Arg) && i + 1 < e) { 116 OS << ' '; 117 PrintArg(OS, Arguments[++i], true); 118 } 119 } 120 OS << Terminator; 121 } 122 123 int Command::Execute(const StringRef **Redirects, std::string *ErrMsg, 124 bool *ExecutionFailed) const { 125 SmallVector<const char*, 128> Argv; 126 Argv.push_back(Executable); 127 for (size_t i = 0, e = Arguments.size(); i != e; ++i) 128 Argv.push_back(Arguments[i]); 129 Argv.push_back(nullptr); 130 131 return llvm::sys::ExecuteAndWait(Executable, Argv.data(), /*env*/ nullptr, 132 Redirects, /*secondsToWait*/ 0, 133 /*memoryLimit*/ 0, ErrMsg, ExecutionFailed); 134 } 135 136 FallbackCommand::FallbackCommand(const Action &Source_, const Tool &Creator_, 137 const char *Executable_, 138 const ArgStringList &Arguments_, 139 Command *Fallback_) 140 : Command(Source_, Creator_, Executable_, Arguments_), Fallback(Fallback_) { 141 } 142 143 void FallbackCommand::Print(raw_ostream &OS, const char *Terminator, 144 bool Quote, bool CrashReport) const { 145 Command::Print(OS, "", Quote, CrashReport); 146 OS << " ||"; 147 Fallback->Print(OS, Terminator, Quote, CrashReport); 148 } 149 150 static bool ShouldFallback(int ExitCode) { 151 // FIXME: We really just want to fall back for internal errors, such 152 // as when some symbol cannot be mangled, when we should be able to 153 // parse something but can't, etc. 154 return ExitCode != 0; 155 } 156 157 int FallbackCommand::Execute(const StringRef **Redirects, std::string *ErrMsg, 158 bool *ExecutionFailed) const { 159 int PrimaryStatus = Command::Execute(Redirects, ErrMsg, ExecutionFailed); 160 if (!ShouldFallback(PrimaryStatus)) 161 return PrimaryStatus; 162 163 // Clear ExecutionFailed and ErrMsg before falling back. 164 if (ErrMsg) 165 ErrMsg->clear(); 166 if (ExecutionFailed) 167 *ExecutionFailed = false; 168 169 const Driver &D = getCreator().getToolChain().getDriver(); 170 D.Diag(diag::warn_drv_invoking_fallback) << Fallback->getExecutable(); 171 172 int SecondaryStatus = Fallback->Execute(Redirects, ErrMsg, ExecutionFailed); 173 return SecondaryStatus; 174 } 175 176 JobList::JobList() : Job(JobListClass) {} 177 178 JobList::~JobList() { 179 for (iterator it = begin(), ie = end(); it != ie; ++it) 180 delete *it; 181 } 182 183 void JobList::Print(raw_ostream &OS, const char *Terminator, bool Quote, 184 bool CrashReport) const { 185 for (const_iterator it = begin(), ie = end(); it != ie; ++it) 186 (*it)->Print(OS, Terminator, Quote, CrashReport); 187 } 188 189 void JobList::clear() { 190 DeleteContainerPointers(Jobs); 191 } 192