blob: 22904e5398a0b60c9b1831ecc829ea85325b2367 [file] [log] [blame]
Nick Lewycky6da90772010-12-31 17:31:54 +00001//===--- Job.cpp - Command to Execute -------------------------------------===//
Daniel Dunbar313c2912009-03-13 23:36:33 +00002//
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
Justin Bognerd3371d82015-07-17 03:35:54 +000010#include "InputInfo.h"
Hans Wennborgc5afd062014-02-18 21:42:51 +000011#include "clang/Driver/Driver.h"
12#include "clang/Driver/DriverDiagnostic.h"
Daniel Dunbar313c2912009-03-13 23:36:33 +000013#include "clang/Driver/Job.h"
Hans Wennborgc5afd062014-02-18 21:42:51 +000014#include "clang/Driver/Tool.h"
15#include "clang/Driver/ToolChain.h"
Reid Kleckner0290c9c2014-09-15 17:45:39 +000016#include "llvm/ADT/ArrayRef.h"
Chad Rosierbe10f982011-08-02 17:58:04 +000017#include "llvm/ADT/STLExtras.h"
Hans Wennborgb212b342013-09-12 18:23:34 +000018#include "llvm/ADT/StringRef.h"
Reid Kleckner0290c9c2014-09-15 17:45:39 +000019#include "llvm/ADT/StringSet.h"
Hans Wennborgb212b342013-09-12 18:23:34 +000020#include "llvm/ADT/StringSwitch.h"
Hans Wennborge8677ef2013-09-12 18:35:08 +000021#include "llvm/Support/Program.h"
Hans Wennborgb212b342013-09-12 18:23:34 +000022#include "llvm/Support/raw_ostream.h"
Daniel Dunbar313c2912009-03-13 23:36:33 +000023#include <cassert>
24using namespace clang::driver;
Hans Wennborgb212b342013-09-12 18:23:34 +000025using llvm::raw_ostream;
26using llvm::StringRef;
Reid Kleckner0290c9c2014-09-15 17:45:39 +000027using llvm::ArrayRef;
Daniel Dunbar313c2912009-03-13 23:36:33 +000028
Justin Bogner94817612015-07-02 22:52:04 +000029Command::Command(const Action &Source, const Tool &Creator,
Justin Bognerd3371d82015-07-17 03:35:54 +000030 const char *Executable, const ArgStringList &Arguments,
31 ArrayRef<InputInfo> Inputs)
Justin Bogner0cd92482015-07-02 22:52:08 +000032 : Source(Source), Creator(Creator), Executable(Executable),
Justin Bognerd3371d82015-07-17 03:35:54 +000033 Arguments(Arguments), ResponseFile(nullptr) {
34 for (const auto &II : Inputs)
35 if (II.isFilename())
36 InputFilenames.push_back(II.getFilename());
37}
Daniel Dunbar313c2912009-03-13 23:36:33 +000038
Justin Bogner0cb14752015-03-12 00:52:56 +000039static int skipArgs(const char *Flag, bool HaveCrashVFS) {
Hans Wennborgb212b342013-09-12 18:23:34 +000040 // These flags are all of the form -Flag <Arg> and are treated as two
41 // arguments. Therefore, we need to skip the flag and the next argument.
42 bool Res = llvm::StringSwitch<bool>(Flag)
43 .Cases("-I", "-MF", "-MT", "-MQ", true)
44 .Cases("-o", "-coverage-file", "-dependency-file", true)
45 .Cases("-fdebug-compilation-dir", "-idirafter", true)
46 .Cases("-include", "-include-pch", "-internal-isystem", true)
47 .Cases("-internal-externc-isystem", "-iprefix", "-iwithprefix", true)
Justin Bogner0cb14752015-03-12 00:52:56 +000048 .Cases("-iwithprefixbefore", "-isystem", "-iquote", true)
Hans Wennborgb212b342013-09-12 18:23:34 +000049 .Cases("-resource-dir", "-serialize-diagnostic-file", true)
Justin Bogner61c0e432014-06-22 20:35:10 +000050 .Cases("-dwarf-debug-flags", "-ivfsoverlay", true)
Justin Bognere03437c2015-08-05 23:49:44 +000051 .Cases("-header-include-file", "-diagnostic-log-file", true)
Justin Bogner0cb14752015-03-12 00:52:56 +000052 // Some include flags shouldn't be skipped if we have a crash VFS
53 .Case("-isysroot", !HaveCrashVFS)
Hans Wennborgb212b342013-09-12 18:23:34 +000054 .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);
Justin Bognerf893a652014-04-22 21:30:17 +000074 if (FlagRef.startswith("-F") || FlagRef.startswith("-I") ||
75 FlagRef.startswith("-fmodules-cache-path="))
Hans Wennborgb212b342013-09-12 18:23:34 +000076 return 1;
77
78 return 0;
79}
80
Justin Bognered9cbe02015-07-09 06:58:31 +000081void Command::printArg(raw_ostream &OS, const char *Arg, bool Quote) {
Hans Wennborgb212b342013-09-12 18:23:34 +000082 const bool Escape = std::strpbrk(Arg, "\"\\$");
83
84 if (!Quote && !Escape) {
85 OS << Arg;
86 return;
87 }
88
89 // Quote and escape. This isn't really complete, but good enough.
90 OS << '"';
91 while (const char c = *Arg++) {
92 if (c == '"' || c == '\\' || c == '$')
93 OS << '\\';
94 OS << c;
95 }
96 OS << '"';
97}
98
Reid Kleckner0290c9c2014-09-15 17:45:39 +000099void Command::writeResponseFile(raw_ostream &OS) const {
100 // In a file list, we only write the set of inputs to the response file
101 if (Creator.getResponseFilesSupport() == Tool::RF_FileList) {
102 for (const char *Arg : InputFileList) {
103 OS << Arg << '\n';
104 }
105 return;
106 }
107
Reid Klecknere2d03442015-07-15 22:42:37 +0000108 // In regular response files, we send all arguments to the response file.
109 // Wrapping all arguments in double quotes ensures that both Unix tools and
110 // Windows tools understand the response file.
Reid Kleckner0290c9c2014-09-15 17:45:39 +0000111 for (const char *Arg : Arguments) {
112 OS << '"';
113
114 for (; *Arg != '\0'; Arg++) {
115 if (*Arg == '\"' || *Arg == '\\') {
116 OS << '\\';
117 }
118 OS << *Arg;
119 }
120
121 OS << "\" ";
122 }
123}
124
125void Command::buildArgvForResponseFile(
126 llvm::SmallVectorImpl<const char *> &Out) const {
127 // When not a file list, all arguments are sent to the response file.
128 // This leaves us to set the argv to a single parameter, requesting the tool
129 // to read the response file.
130 if (Creator.getResponseFilesSupport() != Tool::RF_FileList) {
131 Out.push_back(Executable);
132 Out.push_back(ResponseFileFlag.c_str());
133 return;
134 }
135
136 llvm::StringSet<> Inputs;
137 for (const char *InputName : InputFileList)
138 Inputs.insert(InputName);
139 Out.push_back(Executable);
140 // In a file list, build args vector ignoring parameters that will go in the
141 // response file (elements of the InputFileList vector)
142 bool FirstInput = true;
143 for (const char *Arg : Arguments) {
144 if (Inputs.count(Arg) == 0) {
145 Out.push_back(Arg);
146 } else if (FirstInput) {
147 FirstInput = false;
148 Out.push_back(Creator.getResponseFileFlag());
149 Out.push_back(ResponseFile);
150 }
151 }
152}
153
Hans Wennborgb212b342013-09-12 18:23:34 +0000154void Command::Print(raw_ostream &OS, const char *Terminator, bool Quote,
Justin Bogner25645152014-10-21 17:24:44 +0000155 CrashReportInfo *CrashInfo) const {
Reid Kleckner822434d2014-08-05 20:49:12 +0000156 // Always quote the exe.
Reid Kleckner4f1fc352014-08-07 00:05:00 +0000157 OS << ' ';
Justin Bognered9cbe02015-07-09 06:58:31 +0000158 printArg(OS, Executable, /*Quote=*/true);
Hans Wennborgb212b342013-09-12 18:23:34 +0000159
Reid Kleckner0290c9c2014-09-15 17:45:39 +0000160 llvm::ArrayRef<const char *> Args = Arguments;
161 llvm::SmallVector<const char *, 128> ArgsRespFile;
162 if (ResponseFile != nullptr) {
163 buildArgvForResponseFile(ArgsRespFile);
164 Args = ArrayRef<const char *>(ArgsRespFile).slice(1); // no executable name
165 }
166
Justin Bogner0cb14752015-03-12 00:52:56 +0000167 bool HaveCrashVFS = CrashInfo && !CrashInfo->VFSPath.empty();
Reid Kleckner0290c9c2014-09-15 17:45:39 +0000168 for (size_t i = 0, e = Args.size(); i < e; ++i) {
169 const char *const Arg = Args[i];
Hans Wennborgb212b342013-09-12 18:23:34 +0000170
Justin Bogner25645152014-10-21 17:24:44 +0000171 if (CrashInfo) {
Justin Bogner0cb14752015-03-12 00:52:56 +0000172 if (int Skip = skipArgs(Arg, HaveCrashVFS)) {
Hans Wennborgb212b342013-09-12 18:23:34 +0000173 i += Skip - 1;
174 continue;
Justin Bognerd3371d82015-07-17 03:35:54 +0000175 }
176 auto Found = std::find_if(InputFilenames.begin(), InputFilenames.end(),
177 [&Arg](StringRef IF) { return IF == Arg; });
178 if (Found != InputFilenames.end() &&
179 (i == 0 || StringRef(Args[i - 1]) != "-main-file-name")) {
Justin Bogner25645152014-10-21 17:24:44 +0000180 // Replace the input file name with the crashinfo's file name.
181 OS << ' ';
182 StringRef ShortName = llvm::sys::path::filename(CrashInfo->Filename);
Justin Bognered9cbe02015-07-09 06:58:31 +0000183 printArg(OS, ShortName.str().c_str(), Quote);
Justin Bogner25645152014-10-21 17:24:44 +0000184 continue;
Hans Wennborgb212b342013-09-12 18:23:34 +0000185 }
186 }
187
188 OS << ' ';
Justin Bognered9cbe02015-07-09 06:58:31 +0000189 printArg(OS, Arg, Quote);
Hans Wennborgb212b342013-09-12 18:23:34 +0000190 }
Reid Kleckner0290c9c2014-09-15 17:45:39 +0000191
Justin Bogner0cb14752015-03-12 00:52:56 +0000192 if (CrashInfo && HaveCrashVFS) {
Justin Bogner25645152014-10-21 17:24:44 +0000193 OS << ' ';
Justin Bognered9cbe02015-07-09 06:58:31 +0000194 printArg(OS, "-ivfsoverlay", Quote);
Justin Bogner25645152014-10-21 17:24:44 +0000195 OS << ' ';
Justin Bognered9cbe02015-07-09 06:58:31 +0000196 printArg(OS, CrashInfo->VFSPath.str().c_str(), Quote);
Justin Bogner25645152014-10-21 17:24:44 +0000197 }
198
Reid Kleckner0290c9c2014-09-15 17:45:39 +0000199 if (ResponseFile != nullptr) {
200 OS << "\n Arguments passed via response file:\n";
201 writeResponseFile(OS);
202 // Avoiding duplicated newline terminator, since FileLists are
203 // newline-separated.
204 if (Creator.getResponseFilesSupport() != Tool::RF_FileList)
205 OS << "\n";
206 OS << " (end of response file)";
207 }
208
Hans Wennborgb212b342013-09-12 18:23:34 +0000209 OS << Terminator;
210}
211
Reid Kleckner0290c9c2014-09-15 17:45:39 +0000212void Command::setResponseFile(const char *FileName) {
213 ResponseFile = FileName;
214 ResponseFileFlag = Creator.getResponseFileFlag();
215 ResponseFileFlag += FileName;
216}
217
Hans Wennborge693e842013-09-18 00:41:15 +0000218int Command::Execute(const StringRef **Redirects, std::string *ErrMsg,
Hans Wennborge8677ef2013-09-12 18:35:08 +0000219 bool *ExecutionFailed) const {
220 SmallVector<const char*, 128> Argv;
Reid Kleckner0290c9c2014-09-15 17:45:39 +0000221
222 if (ResponseFile == nullptr) {
223 Argv.push_back(Executable);
Benjamin Kramerf9890422015-02-17 16:48:30 +0000224 Argv.append(Arguments.begin(), Arguments.end());
Reid Kleckner0290c9c2014-09-15 17:45:39 +0000225 Argv.push_back(nullptr);
226
227 return llvm::sys::ExecuteAndWait(Executable, Argv.data(), /*env*/ nullptr,
228 Redirects, /*secondsToWait*/ 0,
229 /*memoryLimit*/ 0, ErrMsg,
230 ExecutionFailed);
231 }
232
233 // We need to put arguments in a response file (command is too large)
234 // Open stream to store the response file contents
235 std::string RespContents;
236 llvm::raw_string_ostream SS(RespContents);
237
238 // Write file contents and build the Argv vector
239 writeResponseFile(SS);
240 buildArgvForResponseFile(Argv);
Craig Topper92fc2df2014-05-17 16:56:41 +0000241 Argv.push_back(nullptr);
Reid Kleckner0290c9c2014-09-15 17:45:39 +0000242 SS.flush();
243
244 // Save the response file in the appropriate encoding
245 if (std::error_code EC = writeFileWithEncoding(
246 ResponseFile, RespContents, Creator.getResponseFileEncoding())) {
247 if (ErrMsg)
248 *ErrMsg = EC.message();
249 if (ExecutionFailed)
250 *ExecutionFailed = true;
251 return -1;
252 }
Hans Wennborge8677ef2013-09-12 18:35:08 +0000253
Craig Topper92fc2df2014-05-17 16:56:41 +0000254 return llvm::sys::ExecuteAndWait(Executable, Argv.data(), /*env*/ nullptr,
Hans Wennborge8677ef2013-09-12 18:35:08 +0000255 Redirects, /*secondsToWait*/ 0,
256 /*memoryLimit*/ 0, ErrMsg, ExecutionFailed);
257}
258
Hans Wennborg87cfa712013-09-19 20:32:16 +0000259FallbackCommand::FallbackCommand(const Action &Source_, const Tool &Creator_,
260 const char *Executable_,
261 const ArgStringList &Arguments_,
Justin Bognerd3371d82015-07-17 03:35:54 +0000262 ArrayRef<InputInfo> Inputs,
David Blaikiec11bf802014-09-04 16:04:28 +0000263 std::unique_ptr<Command> Fallback_)
Justin Bognerd3371d82015-07-17 03:35:54 +0000264 : Command(Source_, Creator_, Executable_, Arguments_, Inputs),
David Blaikiec11bf802014-09-04 16:04:28 +0000265 Fallback(std::move(Fallback_)) {}
Hans Wennborg87cfa712013-09-19 20:32:16 +0000266
267void FallbackCommand::Print(raw_ostream &OS, const char *Terminator,
Justin Bogner25645152014-10-21 17:24:44 +0000268 bool Quote, CrashReportInfo *CrashInfo) const {
269 Command::Print(OS, "", Quote, CrashInfo);
Hans Wennborg87cfa712013-09-19 20:32:16 +0000270 OS << " ||";
Justin Bogner25645152014-10-21 17:24:44 +0000271 Fallback->Print(OS, Terminator, Quote, CrashInfo);
Hans Wennborg87cfa712013-09-19 20:32:16 +0000272}
273
274static bool ShouldFallback(int ExitCode) {
275 // FIXME: We really just want to fall back for internal errors, such
276 // as when some symbol cannot be mangled, when we should be able to
277 // parse something but can't, etc.
278 return ExitCode != 0;
279}
280
281int FallbackCommand::Execute(const StringRef **Redirects, std::string *ErrMsg,
282 bool *ExecutionFailed) const {
283 int PrimaryStatus = Command::Execute(Redirects, ErrMsg, ExecutionFailed);
284 if (!ShouldFallback(PrimaryStatus))
285 return PrimaryStatus;
286
287 // Clear ExecutionFailed and ErrMsg before falling back.
288 if (ErrMsg)
289 ErrMsg->clear();
290 if (ExecutionFailed)
291 *ExecutionFailed = false;
292
Hans Wennborgc5afd062014-02-18 21:42:51 +0000293 const Driver &D = getCreator().getToolChain().getDriver();
Hans Wennborg897a69b2014-02-19 02:10:19 +0000294 D.Diag(diag::warn_drv_invoking_fallback) << Fallback->getExecutable();
Hans Wennborgc5afd062014-02-18 21:42:51 +0000295
Hans Wennborg87cfa712013-09-19 20:32:16 +0000296 int SecondaryStatus = Fallback->Execute(Redirects, ErrMsg, ExecutionFailed);
297 return SecondaryStatus;
298}
299
Hans Wennborgb212b342013-09-12 18:23:34 +0000300void JobList::Print(raw_ostream &OS, const char *Terminator, bool Quote,
Justin Bogner25645152014-10-21 17:24:44 +0000301 CrashReportInfo *CrashInfo) const {
Justin Bogneraab97922014-10-03 01:04:53 +0000302 for (const auto &Job : *this)
Justin Bogner25645152014-10-21 17:24:44 +0000303 Job.Print(OS, Terminator, Quote, CrashInfo);
Hans Wennborgb212b342013-09-12 18:23:34 +0000304}
305
David Blaikiec11bf802014-09-04 16:04:28 +0000306void JobList::clear() { Jobs.clear(); }