clang  3.9.0
Job.cpp
Go to the documentation of this file.
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 "InputInfo.h"
11 #include "clang/Driver/Driver.h"
13 #include "clang/Driver/Job.h"
14 #include "clang/Driver/Tool.h"
15 #include "clang/Driver/ToolChain.h"
16 #include "llvm/ADT/ArrayRef.h"
17 #include "llvm/ADT/STLExtras.h"
18 #include "llvm/ADT/StringRef.h"
19 #include "llvm/ADT/StringSet.h"
20 #include "llvm/ADT/StringSwitch.h"
21 #include "llvm/Support/FileSystem.h"
22 #include "llvm/Support/Program.h"
23 #include "llvm/Support/raw_ostream.h"
24 #include <cassert>
25 using namespace clang::driver;
26 using llvm::raw_ostream;
27 using llvm::StringRef;
28 using llvm::ArrayRef;
29 
30 Command::Command(const Action &Source, const Tool &Creator,
31  const char *Executable, const ArgStringList &Arguments,
32  ArrayRef<InputInfo> Inputs)
33  : Source(Source), Creator(Creator), Executable(Executable),
34  Arguments(Arguments), ResponseFile(nullptr) {
35  for (const auto &II : Inputs)
36  if (II.isFilename())
37  InputFilenames.push_back(II.getFilename());
38 }
39 
40 static int skipArgs(const char *Flag, bool HaveCrashVFS) {
41  // These flags are all of the form -Flag <Arg> and are treated as two
42  // arguments. Therefore, we need to skip the flag and the next argument.
43  bool Res = llvm::StringSwitch<bool>(Flag)
44  .Cases("-MF", "-MT", "-MQ", "-serialize-diagnostic-file", true)
45  .Cases("-o", "-coverage-file", "-dependency-file", true)
46  .Cases("-fdebug-compilation-dir", "-idirafter", true)
47  .Cases("-include", "-include-pch", "-internal-isystem", true)
48  .Cases("-internal-externc-isystem", "-iprefix", "-iwithprefix", true)
49  .Cases("-iwithprefixbefore", "-isystem", "-iquote", true)
50  .Cases("-dwarf-debug-flags", "-ivfsoverlay", true)
51  .Cases("-header-include-file", "-diagnostic-log-file", true)
52  // Some include flags shouldn't be skipped if we have a crash VFS
53  .Cases("-isysroot", "-I", "-F", "-resource-dir", !HaveCrashVFS)
54  .Default(false);
55 
56  // Match found.
57  if (Res)
58  return 2;
59 
60  // The remaining flags are treated as a single argument.
61 
62  // These flags are all of the form -Flag and have no second argument.
63  Res = llvm::StringSwitch<bool>(Flag)
64  .Cases("-M", "-MM", "-MG", "-MP", "-MD", true)
65  .Case("-MMD", true)
66  .Default(false);
67 
68  // Match found.
69  if (Res)
70  return 1;
71 
72  // These flags are treated as a single argument (e.g., -F<Dir>).
73  StringRef FlagRef(Flag);
74  if ((!HaveCrashVFS &&
75  (FlagRef.startswith("-F") || FlagRef.startswith("-I"))) ||
76  FlagRef.startswith("-fmodules-cache-path="))
77  return 1;
78 
79  return 0;
80 }
81 
82 void Command::printArg(raw_ostream &OS, const char *Arg, bool Quote) {
83  const bool Escape = std::strpbrk(Arg, "\"\\$");
84 
85  if (!Quote && !Escape) {
86  OS << Arg;
87  return;
88  }
89 
90  // Quote and escape. This isn't really complete, but good enough.
91  OS << '"';
92  while (const char c = *Arg++) {
93  if (c == '"' || c == '\\' || c == '$')
94  OS << '\\';
95  OS << c;
96  }
97  OS << '"';
98 }
99 
100 void Command::writeResponseFile(raw_ostream &OS) const {
101  // In a file list, we only write the set of inputs to the response file
102  if (Creator.getResponseFilesSupport() == Tool::RF_FileList) {
103  for (const char *Arg : InputFileList) {
104  OS << Arg << '\n';
105  }
106  return;
107  }
108 
109  // In regular response files, we send all arguments to the response file.
110  // Wrapping all arguments in double quotes ensures that both Unix tools and
111  // Windows tools understand the response file.
112  for (const char *Arg : Arguments) {
113  OS << '"';
114 
115  for (; *Arg != '\0'; Arg++) {
116  if (*Arg == '\"' || *Arg == '\\') {
117  OS << '\\';
118  }
119  OS << *Arg;
120  }
121 
122  OS << "\" ";
123  }
124 }
125 
126 void Command::buildArgvForResponseFile(
128  // When not a file list, all arguments are sent to the response file.
129  // This leaves us to set the argv to a single parameter, requesting the tool
130  // to read the response file.
131  if (Creator.getResponseFilesSupport() != Tool::RF_FileList) {
132  Out.push_back(Executable);
133  Out.push_back(ResponseFileFlag.c_str());
134  return;
135  }
136 
137  llvm::StringSet<> Inputs;
138  for (const char *InputName : InputFileList)
139  Inputs.insert(InputName);
140  Out.push_back(Executable);
141  // In a file list, build args vector ignoring parameters that will go in the
142  // response file (elements of the InputFileList vector)
143  bool FirstInput = true;
144  for (const char *Arg : Arguments) {
145  if (Inputs.count(Arg) == 0) {
146  Out.push_back(Arg);
147  } else if (FirstInput) {
148  FirstInput = false;
149  Out.push_back(Creator.getResponseFileFlag());
150  Out.push_back(ResponseFile);
151  }
152  }
153 }
154 
155 void Command::Print(raw_ostream &OS, const char *Terminator, bool Quote,
156  CrashReportInfo *CrashInfo) const {
157  // Always quote the exe.
158  OS << ' ';
159  printArg(OS, Executable, /*Quote=*/true);
160 
161  llvm::ArrayRef<const char *> Args = Arguments;
163  if (ResponseFile != nullptr) {
164  buildArgvForResponseFile(ArgsRespFile);
165  Args = ArrayRef<const char *>(ArgsRespFile).slice(1); // no executable name
166  }
167 
168  bool HaveCrashVFS = CrashInfo && !CrashInfo->VFSPath.empty();
169  for (size_t i = 0, e = Args.size(); i < e; ++i) {
170  const char *const Arg = Args[i];
171 
172  if (CrashInfo) {
173  if (int Skip = skipArgs(Arg, HaveCrashVFS)) {
174  i += Skip - 1;
175  continue;
176  }
177  auto Found = std::find_if(InputFilenames.begin(), InputFilenames.end(),
178  [&Arg](StringRef IF) { return IF == Arg; });
179  if (Found != InputFilenames.end() &&
180  (i == 0 || StringRef(Args[i - 1]) != "-main-file-name")) {
181  // Replace the input file name with the crashinfo's file name.
182  OS << ' ';
183  StringRef ShortName = llvm::sys::path::filename(CrashInfo->Filename);
184  printArg(OS, ShortName.str().c_str(), Quote);
185  continue;
186  }
187  }
188 
189  OS << ' ';
190  printArg(OS, Arg, Quote);
191  }
192 
193  if (CrashInfo && HaveCrashVFS) {
194  OS << ' ';
195  printArg(OS, "-ivfsoverlay", Quote);
196  OS << ' ';
197  printArg(OS, CrashInfo->VFSPath.str().c_str(), Quote);
198 
199  // Insert -fmodules-cache-path and use the relative module directory
200  // <name>.cache/vfs/modules where we already dumped the modules.
201  SmallString<128> RelModCacheDir = llvm::sys::path::parent_path(
202  llvm::sys::path::parent_path(CrashInfo->VFSPath));
203  llvm::sys::path::append(RelModCacheDir, "modules");
204 
205  std::string ModCachePath = "-fmodules-cache-path=";
206  ModCachePath.append(RelModCacheDir.c_str());
207 
208  OS << ' ';
209  printArg(OS, ModCachePath.c_str(), Quote);
210  }
211 
212  if (ResponseFile != nullptr) {
213  OS << "\n Arguments passed via response file:\n";
214  writeResponseFile(OS);
215  // Avoiding duplicated newline terminator, since FileLists are
216  // newline-separated.
218  OS << "\n";
219  OS << " (end of response file)";
220  }
221 
222  OS << Terminator;
223 }
224 
226  ResponseFile = FileName;
227  ResponseFileFlag = Creator.getResponseFileFlag();
228  ResponseFileFlag += FileName;
229 }
230 
231 int Command::Execute(const StringRef **Redirects, std::string *ErrMsg,
232  bool *ExecutionFailed) const {
234 
235  if (ResponseFile == nullptr) {
236  Argv.push_back(Executable);
237  Argv.append(Arguments.begin(), Arguments.end());
238  Argv.push_back(nullptr);
239 
240  return llvm::sys::ExecuteAndWait(Executable, Argv.data(), /*env*/ nullptr,
241  Redirects, /*secondsToWait*/ 0,
242  /*memoryLimit*/ 0, ErrMsg,
243  ExecutionFailed);
244  }
245 
246  // We need to put arguments in a response file (command is too large)
247  // Open stream to store the response file contents
248  std::string RespContents;
249  llvm::raw_string_ostream SS(RespContents);
250 
251  // Write file contents and build the Argv vector
252  writeResponseFile(SS);
253  buildArgvForResponseFile(Argv);
254  Argv.push_back(nullptr);
255  SS.flush();
256 
257  // Save the response file in the appropriate encoding
258  if (std::error_code EC = writeFileWithEncoding(
259  ResponseFile, RespContents, Creator.getResponseFileEncoding())) {
260  if (ErrMsg)
261  *ErrMsg = EC.message();
262  if (ExecutionFailed)
263  *ExecutionFailed = true;
264  return -1;
265  }
266 
267  return llvm::sys::ExecuteAndWait(Executable, Argv.data(), /*env*/ nullptr,
268  Redirects, /*secondsToWait*/ 0,
269  /*memoryLimit*/ 0, ErrMsg, ExecutionFailed);
270 }
271 
272 FallbackCommand::FallbackCommand(const Action &Source_, const Tool &Creator_,
273  const char *Executable_,
274  const ArgStringList &Arguments_,
275  ArrayRef<InputInfo> Inputs,
276  std::unique_ptr<Command> Fallback_)
277  : Command(Source_, Creator_, Executable_, Arguments_, Inputs),
278  Fallback(std::move(Fallback_)) {}
279 
280 void FallbackCommand::Print(raw_ostream &OS, const char *Terminator,
281  bool Quote, CrashReportInfo *CrashInfo) const {
282  Command::Print(OS, "", Quote, CrashInfo);
283  OS << " ||";
284  Fallback->Print(OS, Terminator, Quote, CrashInfo);
285 }
286 
287 static bool ShouldFallback(int ExitCode) {
288  // FIXME: We really just want to fall back for internal errors, such
289  // as when some symbol cannot be mangled, when we should be able to
290  // parse something but can't, etc.
291  return ExitCode != 0;
292 }
293 
294 int FallbackCommand::Execute(const StringRef **Redirects, std::string *ErrMsg,
295  bool *ExecutionFailed) const {
296  int PrimaryStatus = Command::Execute(Redirects, ErrMsg, ExecutionFailed);
297  if (!ShouldFallback(PrimaryStatus))
298  return PrimaryStatus;
299 
300  // Clear ExecutionFailed and ErrMsg before falling back.
301  if (ErrMsg)
302  ErrMsg->clear();
303  if (ExecutionFailed)
304  *ExecutionFailed = false;
305 
306  const Driver &D = getCreator().getToolChain().getDriver();
307  D.Diag(diag::warn_drv_invoking_fallback) << Fallback->getExecutable();
308 
309  int SecondaryStatus = Fallback->Execute(Redirects, ErrMsg, ExecutionFailed);
310  return SecondaryStatus;
311 }
312 
314  const Tool &Creator_,
315  const char *Executable_,
316  const ArgStringList &Arguments_,
317  ArrayRef<InputInfo> Inputs)
318  : Command(Source_, Creator_, Executable_, Arguments_, Inputs) {}
319 
320 void ForceSuccessCommand::Print(raw_ostream &OS, const char *Terminator,
321  bool Quote, CrashReportInfo *CrashInfo) const {
322  Command::Print(OS, "", Quote, CrashInfo);
323  OS << " || (exit 0)" << Terminator;
324 }
325 
326 int ForceSuccessCommand::Execute(const StringRef **Redirects,
327  std::string *ErrMsg,
328  bool *ExecutionFailed) const {
329  int Status = Command::Execute(Redirects, ErrMsg, ExecutionFailed);
330  (void)Status;
331  if (ExecutionFailed)
332  *ExecutionFailed = false;
333  return 0;
334 }
335 
336 void JobList::Print(raw_ostream &OS, const char *Terminator, bool Quote,
337  CrashReportInfo *CrashInfo) const {
338  for (const auto &Job : *this)
339  Job.Print(OS, Terminator, Quote, CrashInfo);
340 }
341 
342 void JobList::clear() { Jobs.clear(); }
void setResponseFile(const char *FileName)
Set to pass arguments via a response file when launching the command.
Definition: Job.cpp:225
int Execute(const StringRef **Redirects, std::string *ErrMsg, bool *ExecutionFailed) const override
Definition: Job.cpp:294
DiagnosticBuilder Diag(unsigned DiagID) const
Definition: Driver.h:97
const Tool & getCreator() const
getCreator - Return the Tool which caused the creation of this job.
Definition: Job.h:103
virtual void Print(llvm::raw_ostream &OS, const char *Terminator, bool Quote, CrashReportInfo *CrashInfo=nullptr) const
Definition: Job.cpp:155
Action - Represent an abstract compilation step to perform.
Definition: Action.h:45
Driver - Encapsulate logic for constructing compilation processes from a set of gcc-driver-like comma...
Definition: Driver.h:66
const Driver & getDriver() const
Definition: ToolChain.h:128
const ToolChain & getToolChain() const
Definition: Tool.h:84
virtual int Execute(const StringRef **Redirects, std::string *ErrMsg, bool *ExecutionFailed) const
Definition: Job.cpp:231
static int skipArgs(const char *Flag, bool HaveCrashVFS)
Definition: Job.cpp:40
static bool ShouldFallback(int ExitCode)
Definition: Job.cpp:287
const char * getResponseFileFlag() const
Returns which prefix to use when passing the name of a response file as a parameter to this tool...
Definition: Tool.h:113
StringRef FileName
Definition: Format.cpp:1313
void clear()
Clear the job list.
Definition: Job.cpp:342
Command(const Action &Source, const Tool &Creator, const char *Executable, const llvm::opt::ArgStringList &Arguments, ArrayRef< InputInfo > Inputs)
Command - An executable path/name and argument vector to execute.
Definition: Job.h:43
void Print(llvm::raw_ostream &OS, const char *Terminator, bool Quote, CrashReportInfo *CrashInfo=nullptr) const override
Definition: Job.cpp:280
ResponseFileSupport getResponseFilesSupport() const
Returns the level of support for response files of this tool, whether it accepts arguments to be pass...
Definition: Tool.h:93
void Print(llvm::raw_ostream &OS, const char *Terminator, bool Quote, CrashReportInfo *CrashInfo=nullptr) const override
Definition: Job.cpp:320
llvm::sys::WindowsEncodingMethod getResponseFileEncoding() const
Returns which encoding the response file should use.
Definition: Tool.h:108
Tool - Information on a specific compilation tool.
Definition: Tool.h:34
static void printArg(llvm::raw_ostream &OS, const char *Arg, bool Quote)
Print a command argument, and optionally quote it.
Definition: Job.cpp:82
void Print(llvm::raw_ostream &OS, const char *Terminator, bool Quote, CrashReportInfo *CrashInfo=nullptr) const
Definition: Job.cpp:336
ForceSuccessCommand(const Action &Source_, const Tool &Creator_, const char *Executable_, const ArgStringList &Arguments_, ArrayRef< InputInfo > Inputs)
Definition: Job.cpp:313
FallbackCommand(const Action &Source_, const Tool &Creator_, const char *Executable_, const ArgStringList &Arguments_, ArrayRef< InputInfo > Inputs, std::unique_ptr< Command > Fallback_)
Definition: Job.cpp:272
int Execute(const StringRef **Redirects, std::string *ErrMsg, bool *ExecutionFailed) const override
Definition: Job.cpp:326