1//===- Job.h - Commands to Execute ------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef LLVM_CLANG_DRIVER_JOB_H
10#define LLVM_CLANG_DRIVER_JOB_H
11
12#include "clang/Basic/LLVM.h"
13#include "clang/Driver/InputInfo.h"
14#include "llvm/ADT/ArrayRef.h"
15#include "llvm/ADT/SmallVector.h"
16#include "llvm/ADT/StringRef.h"
17#include "llvm/ADT/iterator.h"
18#include "llvm/Option/Option.h"
19#include "llvm/Support/Program.h"
20#include <memory>
21#include <optional>
22#include <string>
23#include <utility>
24#include <vector>
25
26namespace clang {
27namespace driver {
28
29class Action;
30class InputInfo;
31class Tool;
32
33struct CrashReportInfo {
34  StringRef Filename;
35  StringRef VFSPath;
36
37  CrashReportInfo(StringRef Filename, StringRef VFSPath)
38      : Filename(Filename), VFSPath(VFSPath) {}
39};
40
41// Encodes the kind of response file supported for a command invocation.
42// Response files are necessary if the command line gets too large, requiring
43// the arguments to be transferred to a file.
44struct ResponseFileSupport {
45  enum ResponseFileKind {
46    // Provides full support for response files, which means we can transfer
47    // all tool input arguments to a file.
48    RF_Full,
49    // Input file names can live in a file, but flags can't. This is a special
50    // case for old versions of Apple's ld64.
51    RF_FileList,
52    // Does not support response files: all arguments must be passed via
53    // command line.
54    RF_None
55  };
56  /// The level of support for response files.
57  ResponseFileKind ResponseKind;
58
59  /// The encoding to use when writing response files on Windows. Ignored on
60  /// other host OSes.
61  ///
62  /// Windows use cases: - GCC and Binutils on mingw only accept ANSI response
63  /// files encoded with the system current code page.
64  /// - MSVC's CL.exe and LINK.exe accept UTF16 on Windows.
65  /// - Clang accepts both UTF8 and UTF16.
66  ///
67  /// FIXME: When GNU tools learn how to parse UTF16 on Windows, we should
68  /// always use UTF16 for Windows, which is the Windows official encoding for
69  /// international characters.
70  llvm::sys::WindowsEncodingMethod ResponseEncoding;
71
72  /// What prefix to use for the command-line argument when passing a response
73  /// file.
74  const char *ResponseFlag;
75
76  /// Returns a ResponseFileSupport indicating that response files are not
77  /// supported.
78  static constexpr ResponseFileSupport None() {
79    return {RF_None, llvm::sys::WEM_UTF8, nullptr};
80  }
81
82  /// Returns a ResponseFileSupport indicating that response files are
83  /// supported, using the @file syntax. On windows, the file is written in the
84  /// UTF8 encoding. On other OSes, no re-encoding occurs.
85  static constexpr ResponseFileSupport AtFileUTF8() {
86    return {RF_Full, llvm::sys::WEM_UTF8, "@"};
87  }
88
89  /// Returns a ResponseFileSupport indicating that response files are
90  /// supported, using the @file syntax. On windows, the file is written in the
91  /// current ANSI code-page encoding. On other OSes, no re-encoding occurs.
92  static constexpr ResponseFileSupport AtFileCurCP() {
93    return {RF_Full, llvm::sys::WEM_CurrentCodePage, "@"};
94  }
95
96  /// Returns a ResponseFileSupport indicating that response files are
97  /// supported, using the @file syntax. On windows, the file is written in the
98  /// UTF-16 encoding. On other OSes, no re-encoding occurs.
99  static constexpr ResponseFileSupport AtFileUTF16() {
100    return {RF_Full, llvm::sys::WEM_UTF16, "@"};
101  }
102};
103
104/// Command - An executable path/name and argument vector to
105/// execute.
106class Command {
107  /// Source - The action which caused the creation of this job.
108  const Action &Source;
109
110  /// Tool - The tool which caused the creation of this job.
111  const Tool &Creator;
112
113  /// Whether and how to generate response files if the arguments are too long.
114  ResponseFileSupport ResponseSupport;
115
116  /// The executable to run.
117  const char *Executable;
118
119  /// Optional argument to prepend.
120  const char *PrependArg;
121
122  /// The list of program arguments (not including the implicit first
123  /// argument, which will be the executable).
124  llvm::opt::ArgStringList Arguments;
125
126  /// The list of program inputs.
127  std::vector<InputInfo> InputInfoList;
128
129  /// The list of program arguments which are outputs. May be empty.
130  std::vector<std::string> OutputFilenames;
131
132  /// Response file name, if this command is set to use one, or nullptr
133  /// otherwise
134  const char *ResponseFile = nullptr;
135
136  /// The input file list in case we need to emit a file list instead of a
137  /// proper response file
138  llvm::opt::ArgStringList InputFileList;
139
140  /// String storage if we need to create a new argument to specify a response
141  /// file
142  std::string ResponseFileFlag;
143
144  /// See Command::setEnvironment
145  std::vector<const char *> Environment;
146
147  /// Optional redirection for stdin, stdout, stderr.
148  std::vector<std::optional<std::string>> RedirectFiles;
149
150  /// Information on executable run provided by OS.
151  mutable std::optional<llvm::sys::ProcessStatistics> ProcStat;
152
153  /// When a response file is needed, we try to put most arguments in an
154  /// exclusive file, while others remains as regular command line arguments.
155  /// This functions fills a vector with the regular command line arguments,
156  /// argv, excluding the ones passed in a response file.
157  void buildArgvForResponseFile(llvm::SmallVectorImpl<const char *> &Out) const;
158
159  /// Encodes an array of C strings into a single string separated by whitespace.
160  /// This function will also put in quotes arguments that have whitespaces and
161  /// will escape the regular backslashes (used in Windows paths) and quotes.
162  /// The results are the contents of a response file, written into a raw_ostream.
163  void writeResponseFile(raw_ostream &OS) const;
164
165public:
166  /// Whether to print the input filenames when executing.
167  bool PrintInputFilenames = false;
168
169  /// Whether the command will be executed in this process or not.
170  bool InProcess = false;
171
172  Command(const Action &Source, const Tool &Creator,
173          ResponseFileSupport ResponseSupport, const char *Executable,
174          const llvm::opt::ArgStringList &Arguments, ArrayRef<InputInfo> Inputs,
175          ArrayRef<InputInfo> Outputs = std::nullopt,
176          const char *PrependArg = nullptr);
177  // FIXME: This really shouldn't be copyable, but is currently copied in some
178  // error handling in Driver::generateCompilationDiagnostics.
179  Command(const Command &) = default;
180  virtual ~Command() = default;
181
182  virtual void Print(llvm::raw_ostream &OS, const char *Terminator, bool Quote,
183                     CrashReportInfo *CrashInfo = nullptr) const;
184
185  virtual int Execute(ArrayRef<std::optional<StringRef>> Redirects,
186                      std::string *ErrMsg, bool *ExecutionFailed) const;
187
188  /// getSource - Return the Action which caused the creation of this job.
189  const Action &getSource() const { return Source; }
190
191  /// getCreator - Return the Tool which caused the creation of this job.
192  const Tool &getCreator() const { return Creator; }
193
194  /// Returns the kind of response file supported by the current invocation.
195  const ResponseFileSupport &getResponseFileSupport() {
196    return ResponseSupport;
197  }
198
199  /// Set to pass arguments via a response file when launching the command
200  void setResponseFile(const char *FileName);
201
202  /// Set an input file list, necessary if you specified an RF_FileList response
203  /// file support.
204  void setInputFileList(llvm::opt::ArgStringList List) {
205    InputFileList = std::move(List);
206  }
207
208  /// Sets the environment to be used by the new process.
209  /// \param NewEnvironment An array of environment variables.
210  /// \remark If the environment remains unset, then the environment
211  ///         from the parent process will be used.
212  virtual void setEnvironment(llvm::ArrayRef<const char *> NewEnvironment);
213
214  void
215  setRedirectFiles(const std::vector<std::optional<std::string>> &Redirects);
216
217  void replaceArguments(llvm::opt::ArgStringList List) {
218    Arguments = std::move(List);
219  }
220
221  void replaceExecutable(const char *Exe) { Executable = Exe; }
222
223  const char *getExecutable() const { return Executable; }
224
225  const llvm::opt::ArgStringList &getArguments() const { return Arguments; }
226
227  const std::vector<InputInfo> &getInputInfos() const { return InputInfoList; }
228
229  const std::vector<std::string> &getOutputFilenames() const {
230    return OutputFilenames;
231  }
232
233  std::optional<llvm::sys::ProcessStatistics> getProcessStatistics() const {
234    return ProcStat;
235  }
236
237protected:
238  /// Optionally print the filenames to be compiled
239  void PrintFileNames() const;
240};
241
242/// Use the CC1 tool callback when available, to avoid creating a new process
243class CC1Command : public Command {
244public:
245  CC1Command(const Action &Source, const Tool &Creator,
246             ResponseFileSupport ResponseSupport, const char *Executable,
247             const llvm::opt::ArgStringList &Arguments,
248             ArrayRef<InputInfo> Inputs,
249             ArrayRef<InputInfo> Outputs = std::nullopt,
250             const char *PrependArg = nullptr);
251
252  void Print(llvm::raw_ostream &OS, const char *Terminator, bool Quote,
253             CrashReportInfo *CrashInfo = nullptr) const override;
254
255  int Execute(ArrayRef<std::optional<StringRef>> Redirects, std::string *ErrMsg,
256              bool *ExecutionFailed) const override;
257
258  void setEnvironment(llvm::ArrayRef<const char *> NewEnvironment) override;
259};
260
261/// JobList - A sequence of jobs to perform.
262class JobList {
263public:
264  using list_type = SmallVector<std::unique_ptr<Command>, 4>;
265  using size_type = list_type::size_type;
266  using iterator = llvm::pointee_iterator<list_type::iterator>;
267  using const_iterator = llvm::pointee_iterator<list_type::const_iterator>;
268
269private:
270  list_type Jobs;
271
272public:
273  void Print(llvm::raw_ostream &OS, const char *Terminator,
274             bool Quote, CrashReportInfo *CrashInfo = nullptr) const;
275
276  /// Add a job to the list (taking ownership).
277  void addJob(std::unique_ptr<Command> J) { Jobs.push_back(std::move(J)); }
278
279  /// Clear the job list.
280  void clear();
281
282  const list_type &getJobs() const { return Jobs; }
283
284  bool empty() const { return Jobs.empty(); }
285  size_type size() const { return Jobs.size(); }
286  iterator begin() { return Jobs.begin(); }
287  const_iterator begin() const { return Jobs.begin(); }
288  iterator end() { return Jobs.end(); }
289  const_iterator end() const { return Jobs.end(); }
290};
291
292} // namespace driver
293} // namespace clang
294
295#endif // LLVM_CLANG_DRIVER_JOB_H
296