blob: 2775d892f7803238570fdf8301efb0c68fccf392 [file] [log] [blame]
Nick Lewycky3fdcc6f2010-12-31 17:31:54 +00001//===--- Job.cpp - Command to Execute -------------------------------------===//
Daniel Dunbar789e2202009-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
Stephen Hines651f13c2014-04-23 16:59:28 -070010#include "clang/Driver/Driver.h"
11#include "clang/Driver/DriverDiagnostic.h"
Daniel Dunbar789e2202009-03-13 23:36:33 +000012#include "clang/Driver/Job.h"
Stephen Hines651f13c2014-04-23 16:59:28 -070013#include "clang/Driver/Tool.h"
14#include "clang/Driver/ToolChain.h"
Chad Rosier2b819102011-08-02 17:58:04 +000015#include "llvm/ADT/STLExtras.h"
Hans Wennborgfc338972013-09-12 18:23:34 +000016#include "llvm/ADT/StringRef.h"
17#include "llvm/ADT/StringSwitch.h"
Hans Wennborgaaaa2a12013-09-12 18:35:08 +000018#include "llvm/Support/Program.h"
Hans Wennborgfc338972013-09-12 18:23:34 +000019#include "llvm/Support/raw_ostream.h"
Daniel Dunbar789e2202009-03-13 23:36:33 +000020#include <cassert>
21using namespace clang::driver;
Hans Wennborgfc338972013-09-12 18:23:34 +000022using llvm::raw_ostream;
23using llvm::StringRef;
Daniel Dunbar789e2202009-03-13 23:36:33 +000024
25Job::~Job() {}
26
Daniel Dunbardaab7b12009-12-02 03:23:25 +000027Command::Command(const Action &_Source, const Tool &_Creator,
Hans Wennborg5c6ecf52013-09-18 00:21:51 +000028 const char *_Executable,
Hans Wennborg64228b62013-09-18 00:41:15 +000029 const ArgStringList &_Arguments)
Reid Klecknerb1e25a12013-06-14 17:17:23 +000030 : Job(CommandClass), Source(_Source), Creator(_Creator),
31 Executable(_Executable), Arguments(_Arguments) {}
Daniel Dunbar789e2202009-03-13 23:36:33 +000032
Hans Wennborgfc338972013-09-12 18:23:34 +000033static 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 .Case("-dwarf-debug-flags", 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 return 1;
67
68 return 0;
69}
70
71static bool quoteNextArg(const char *flag) {
72 return llvm::StringSwitch<bool>(flag)
73 .Case("-D", true)
74 .Default(false);
75}
76
77static void PrintArg(raw_ostream &OS, const char *Arg, bool Quote) {
78 const bool Escape = std::strpbrk(Arg, "\"\\$");
79
80 if (!Quote && !Escape) {
81 OS << Arg;
82 return;
83 }
84
85 // Quote and escape. This isn't really complete, but good enough.
86 OS << '"';
87 while (const char c = *Arg++) {
88 if (c == '"' || c == '\\' || c == '$')
89 OS << '\\';
90 OS << c;
91 }
92 OS << '"';
93}
94
95void Command::Print(raw_ostream &OS, const char *Terminator, bool Quote,
96 bool CrashReport) const {
97 OS << " \"" << Executable << '"';
98
99 for (size_t i = 0, e = Arguments.size(); i < e; ++i) {
100 const char *const Arg = Arguments[i];
101
102 if (CrashReport) {
103 if (int Skip = skipArgs(Arg)) {
104 i += Skip - 1;
105 continue;
106 }
107 }
108
109 OS << ' ';
110 PrintArg(OS, Arg, Quote);
111
112 if (CrashReport && quoteNextArg(Arg) && i + 1 < e) {
113 OS << ' ';
114 PrintArg(OS, Arguments[++i], true);
115 }
116 }
117 OS << Terminator;
118}
119
Hans Wennborg64228b62013-09-18 00:41:15 +0000120int Command::Execute(const StringRef **Redirects, std::string *ErrMsg,
Hans Wennborgaaaa2a12013-09-12 18:35:08 +0000121 bool *ExecutionFailed) const {
122 SmallVector<const char*, 128> Argv;
123 Argv.push_back(Executable);
124 for (size_t i = 0, e = Arguments.size(); i != e; ++i)
125 Argv.push_back(Arguments[i]);
126 Argv.push_back(0);
127
128 return llvm::sys::ExecuteAndWait(Executable, Argv.data(), /*env*/ 0,
129 Redirects, /*secondsToWait*/ 0,
130 /*memoryLimit*/ 0, ErrMsg, ExecutionFailed);
131}
132
Hans Wennborgc8ba0a02013-09-19 20:32:16 +0000133FallbackCommand::FallbackCommand(const Action &Source_, const Tool &Creator_,
134 const char *Executable_,
135 const ArgStringList &Arguments_,
136 Command *Fallback_)
137 : Command(Source_, Creator_, Executable_, Arguments_), Fallback(Fallback_) {
138}
139
140void FallbackCommand::Print(raw_ostream &OS, const char *Terminator,
141 bool Quote, bool CrashReport) const {
142 Command::Print(OS, "", Quote, CrashReport);
143 OS << " ||";
144 Fallback->Print(OS, Terminator, Quote, CrashReport);
145}
146
147static bool ShouldFallback(int ExitCode) {
148 // FIXME: We really just want to fall back for internal errors, such
149 // as when some symbol cannot be mangled, when we should be able to
150 // parse something but can't, etc.
151 return ExitCode != 0;
152}
153
154int FallbackCommand::Execute(const StringRef **Redirects, std::string *ErrMsg,
155 bool *ExecutionFailed) const {
156 int PrimaryStatus = Command::Execute(Redirects, ErrMsg, ExecutionFailed);
157 if (!ShouldFallback(PrimaryStatus))
158 return PrimaryStatus;
159
160 // Clear ExecutionFailed and ErrMsg before falling back.
161 if (ErrMsg)
162 ErrMsg->clear();
163 if (ExecutionFailed)
164 *ExecutionFailed = false;
165
Stephen Hines651f13c2014-04-23 16:59:28 -0700166 const Driver &D = getCreator().getToolChain().getDriver();
167 D.Diag(diag::warn_drv_invoking_fallback) << Fallback->getExecutable();
168
Hans Wennborgc8ba0a02013-09-19 20:32:16 +0000169 int SecondaryStatus = Fallback->Execute(Redirects, ErrMsg, ExecutionFailed);
170 return SecondaryStatus;
171}
172
Daniel Dunbar789e2202009-03-13 23:36:33 +0000173JobList::JobList() : Job(JobListClass) {}
Daniel Dunbar871adcf2009-03-18 07:06:02 +0000174
Daniel Dunbar9d440232010-03-11 18:04:49 +0000175JobList::~JobList() {
176 for (iterator it = begin(), ie = end(); it != ie; ++it)
177 delete *it;
178}
179
Hans Wennborgfc338972013-09-12 18:23:34 +0000180void JobList::Print(raw_ostream &OS, const char *Terminator, bool Quote,
181 bool CrashReport) const {
182 for (const_iterator it = begin(), ie = end(); it != ie; ++it)
183 (*it)->Print(OS, Terminator, Quote, CrashReport);
184}
185
Chad Rosier2b819102011-08-02 17:58:04 +0000186void JobList::clear() {
187 DeleteContainerPointers(Jobs);
188}