xref: /minix3/external/bsd/llvm/dist/clang/lib/Driver/Job.cpp (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
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