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