Job.cpp 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  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. #include "clang/Driver/Driver.h"
  10. #include "clang/Driver/DriverDiagnostic.h"
  11. #include "clang/Driver/Job.h"
  12. #include "clang/Driver/Tool.h"
  13. #include "clang/Driver/ToolChain.h"
  14. #include "llvm/ADT/ArrayRef.h"
  15. #include "llvm/ADT/STLExtras.h"
  16. #include "llvm/ADT/StringRef.h"
  17. #include "llvm/ADT/StringSet.h"
  18. #include "llvm/ADT/StringSwitch.h"
  19. #include "llvm/Support/Program.h"
  20. #include "llvm/Support/raw_ostream.h"
  21. #include <cassert>
  22. using namespace clang::driver;
  23. using llvm::raw_ostream;
  24. using llvm::StringRef;
  25. using llvm::ArrayRef;
  26. Command::Command(const Action &Source, const Tool &Creator,
  27. const char *Executable, const ArgStringList &Arguments)
  28. : Source(Source), Creator(Creator), Executable(Executable),
  29. Arguments(Arguments), ResponseFile(nullptr) {}
  30. static int skipArgs(const char *Flag, bool HaveCrashVFS) {
  31. // These flags are all of the form -Flag <Arg> and are treated as two
  32. // arguments. Therefore, we need to skip the flag and the next argument.
  33. bool Res = llvm::StringSwitch<bool>(Flag)
  34. .Cases("-I", "-MF", "-MT", "-MQ", true)
  35. .Cases("-o", "-coverage-file", "-dependency-file", true)
  36. .Cases("-fdebug-compilation-dir", "-idirafter", true)
  37. .Cases("-include", "-include-pch", "-internal-isystem", true)
  38. .Cases("-internal-externc-isystem", "-iprefix", "-iwithprefix", true)
  39. .Cases("-iwithprefixbefore", "-isystem", "-iquote", true)
  40. .Cases("-resource-dir", "-serialize-diagnostic-file", true)
  41. .Cases("-dwarf-debug-flags", "-ivfsoverlay", true)
  42. // Some include flags shouldn't be skipped if we have a crash VFS
  43. .Case("-isysroot", !HaveCrashVFS)
  44. .Default(false);
  45. // Match found.
  46. if (Res)
  47. return 2;
  48. // The remaining flags are treated as a single argument.
  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. // Match found.
  55. if (Res)
  56. return 1;
  57. // These flags are treated as a single argument (e.g., -F<Dir>).
  58. StringRef FlagRef(Flag);
  59. if (FlagRef.startswith("-F") || FlagRef.startswith("-I") ||
  60. FlagRef.startswith("-fmodules-cache-path="))
  61. return 1;
  62. return 0;
  63. }
  64. void Command::printArg(raw_ostream &OS, const char *Arg, bool Quote) {
  65. const bool Escape = std::strpbrk(Arg, "\"\\$");
  66. if (!Quote && !Escape) {
  67. OS << Arg;
  68. return;
  69. }
  70. // Quote and escape. This isn't really complete, but good enough.
  71. OS << '"';
  72. while (const char c = *Arg++) {
  73. if (c == '"' || c == '\\' || c == '$')
  74. OS << '\\';
  75. OS << c;
  76. }
  77. OS << '"';
  78. }
  79. void Command::writeResponseFile(raw_ostream &OS) const {
  80. // In a file list, we only write the set of inputs to the response file
  81. if (Creator.getResponseFilesSupport() == Tool::RF_FileList) {
  82. for (const char *Arg : InputFileList) {
  83. OS << Arg << '\n';
  84. }
  85. return;
  86. }
  87. // In regular response files, we send all arguments to the response file
  88. for (const char *Arg : Arguments) {
  89. OS << '"';
  90. for (; *Arg != '\0'; Arg++) {
  91. if (*Arg == '\"' || *Arg == '\\') {
  92. OS << '\\';
  93. }
  94. OS << *Arg;
  95. }
  96. OS << "\" ";
  97. }
  98. }
  99. void Command::buildArgvForResponseFile(
  100. llvm::SmallVectorImpl<const char *> &Out) const {
  101. // When not a file list, all arguments are sent to the response file.
  102. // This leaves us to set the argv to a single parameter, requesting the tool
  103. // to read the response file.
  104. if (Creator.getResponseFilesSupport() != Tool::RF_FileList) {
  105. Out.push_back(Executable);
  106. Out.push_back(ResponseFileFlag.c_str());
  107. return;
  108. }
  109. llvm::StringSet<> Inputs;
  110. for (const char *InputName : InputFileList)
  111. Inputs.insert(InputName);
  112. Out.push_back(Executable);
  113. // In a file list, build args vector ignoring parameters that will go in the
  114. // response file (elements of the InputFileList vector)
  115. bool FirstInput = true;
  116. for (const char *Arg : Arguments) {
  117. if (Inputs.count(Arg) == 0) {
  118. Out.push_back(Arg);
  119. } else if (FirstInput) {
  120. FirstInput = false;
  121. Out.push_back(Creator.getResponseFileFlag());
  122. Out.push_back(ResponseFile);
  123. }
  124. }
  125. }
  126. void Command::Print(raw_ostream &OS, const char *Terminator, bool Quote,
  127. CrashReportInfo *CrashInfo) const {
  128. // Always quote the exe.
  129. OS << ' ';
  130. printArg(OS, Executable, /*Quote=*/true);
  131. llvm::ArrayRef<const char *> Args = Arguments;
  132. llvm::SmallVector<const char *, 128> ArgsRespFile;
  133. if (ResponseFile != nullptr) {
  134. buildArgvForResponseFile(ArgsRespFile);
  135. Args = ArrayRef<const char *>(ArgsRespFile).slice(1); // no executable name
  136. }
  137. StringRef MainFilename;
  138. // We'll need the argument to -main-file-name to find the input file name.
  139. if (CrashInfo)
  140. for (size_t I = 0, E = Args.size(); I + 1 < E; ++I)
  141. if (StringRef(Args[I]).equals("-main-file-name"))
  142. MainFilename = Args[I + 1];
  143. bool HaveCrashVFS = CrashInfo && !CrashInfo->VFSPath.empty();
  144. for (size_t i = 0, e = Args.size(); i < e; ++i) {
  145. const char *const Arg = Args[i];
  146. if (CrashInfo) {
  147. if (int Skip = skipArgs(Arg, HaveCrashVFS)) {
  148. i += Skip - 1;
  149. continue;
  150. } else if (llvm::sys::path::filename(Arg) == MainFilename &&
  151. (i == 0 || StringRef(Args[i - 1]) != "-main-file-name")) {
  152. // Replace the input file name with the crashinfo's file name.
  153. OS << ' ';
  154. StringRef ShortName = llvm::sys::path::filename(CrashInfo->Filename);
  155. printArg(OS, ShortName.str().c_str(), Quote);
  156. continue;
  157. }
  158. }
  159. OS << ' ';
  160. printArg(OS, Arg, Quote);
  161. }
  162. if (CrashInfo && HaveCrashVFS) {
  163. OS << ' ';
  164. printArg(OS, "-ivfsoverlay", Quote);
  165. OS << ' ';
  166. printArg(OS, CrashInfo->VFSPath.str().c_str(), Quote);
  167. }
  168. if (ResponseFile != nullptr) {
  169. OS << "\n Arguments passed via response file:\n";
  170. writeResponseFile(OS);
  171. // Avoiding duplicated newline terminator, since FileLists are
  172. // newline-separated.
  173. if (Creator.getResponseFilesSupport() != Tool::RF_FileList)
  174. OS << "\n";
  175. OS << " (end of response file)";
  176. }
  177. OS << Terminator;
  178. }
  179. void Command::setResponseFile(const char *FileName) {
  180. ResponseFile = FileName;
  181. ResponseFileFlag = Creator.getResponseFileFlag();
  182. ResponseFileFlag += FileName;
  183. }
  184. int Command::Execute(const StringRef **Redirects, std::string *ErrMsg,
  185. bool *ExecutionFailed) const {
  186. #ifdef MSFT_SUPPORTS_CHILD_PROCESSES
  187. SmallVector<const char*, 128> Argv;
  188. if (ResponseFile == nullptr) {
  189. Argv.push_back(Executable);
  190. Argv.append(Arguments.begin(), Arguments.end());
  191. Argv.push_back(nullptr);
  192. return llvm::sys::ExecuteAndWait(Executable, Argv.data(), /*env*/ nullptr,
  193. Redirects, /*secondsToWait*/ 0,
  194. /*memoryLimit*/ 0, ErrMsg,
  195. ExecutionFailed);
  196. }
  197. // We need to put arguments in a response file (command is too large)
  198. // Open stream to store the response file contents
  199. std::string RespContents;
  200. llvm::raw_string_ostream SS(RespContents);
  201. // Write file contents and build the Argv vector
  202. writeResponseFile(SS);
  203. buildArgvForResponseFile(Argv);
  204. Argv.push_back(nullptr);
  205. SS.flush();
  206. // Save the response file in the appropriate encoding
  207. if (std::error_code EC = writeFileWithEncoding(
  208. ResponseFile, RespContents, Creator.getResponseFileEncoding())) {
  209. if (ErrMsg)
  210. *ErrMsg = EC.message();
  211. if (ExecutionFailed)
  212. *ExecutionFailed = true;
  213. return -1;
  214. }
  215. return llvm::sys::ExecuteAndWait(Executable, Argv.data(), /*env*/ nullptr,
  216. Redirects, /*secondsToWait*/ 0,
  217. /*memoryLimit*/ 0, ErrMsg, ExecutionFailed);
  218. #else
  219. assert(false && "support for spawning processes should be removed from public paths");
  220. return 1;
  221. #endif
  222. }
  223. FallbackCommand::FallbackCommand(const Action &Source_, const Tool &Creator_,
  224. const char *Executable_,
  225. const ArgStringList &Arguments_,
  226. std::unique_ptr<Command> Fallback_)
  227. : Command(Source_, Creator_, Executable_, Arguments_),
  228. Fallback(std::move(Fallback_)) {}
  229. void FallbackCommand::Print(raw_ostream &OS, const char *Terminator,
  230. bool Quote, CrashReportInfo *CrashInfo) const {
  231. Command::Print(OS, "", Quote, CrashInfo);
  232. OS << " ||";
  233. Fallback->Print(OS, Terminator, Quote, CrashInfo);
  234. }
  235. static bool ShouldFallback(int ExitCode) {
  236. // FIXME: We really just want to fall back for internal errors, such
  237. // as when some symbol cannot be mangled, when we should be able to
  238. // parse something but can't, etc.
  239. return ExitCode != 0;
  240. }
  241. int FallbackCommand::Execute(const StringRef **Redirects, std::string *ErrMsg,
  242. bool *ExecutionFailed) const {
  243. int PrimaryStatus = Command::Execute(Redirects, ErrMsg, ExecutionFailed);
  244. if (!ShouldFallback(PrimaryStatus))
  245. return PrimaryStatus;
  246. // Clear ExecutionFailed and ErrMsg before falling back.
  247. if (ErrMsg)
  248. ErrMsg->clear();
  249. if (ExecutionFailed)
  250. *ExecutionFailed = false;
  251. const Driver &D = getCreator().getToolChain().getDriver();
  252. D.Diag(diag::warn_drv_invoking_fallback) << Fallback->getExecutable();
  253. int SecondaryStatus = Fallback->Execute(Redirects, ErrMsg, ExecutionFailed);
  254. return SecondaryStatus;
  255. }
  256. void JobList::Print(raw_ostream &OS, const char *Terminator, bool Quote,
  257. CrashReportInfo *CrashInfo) const {
  258. for (const auto &Job : *this)
  259. Job.Print(OS, Terminator, Quote, CrashInfo);
  260. }
  261. void JobList::clear() { Jobs.clear(); }