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 | |
26 | namespace clang { |
27 | namespace driver { |
28 | |
29 | class Action; |
30 | class InputInfo; |
31 | class Tool; |
32 | |
33 | struct 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. |
44 | struct 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 {.ResponseKind: RF_None, .ResponseEncoding: llvm::sys::WEM_UTF8, .ResponseFlag: 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 {.ResponseKind: RF_Full, .ResponseEncoding: llvm::sys::WEM_UTF8, .ResponseFlag: "@" }; |
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 {.ResponseKind: RF_Full, .ResponseEncoding: llvm::sys::WEM_CurrentCodePage, .ResponseFlag: "@" }; |
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 {.ResponseKind: RF_Full, .ResponseEncoding: llvm::sys::WEM_UTF16, .ResponseFlag: "@" }; |
101 | } |
102 | }; |
103 | |
104 | /// Command - An executable path/name and argument vector to |
105 | /// execute. |
106 | class 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 | |
165 | public: |
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 | |
237 | protected: |
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 |
243 | class CC1Command : public Command { |
244 | public: |
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. |
262 | class JobList { |
263 | public: |
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 | |
269 | private: |
270 | list_type Jobs; |
271 | |
272 | public: |
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(Elt: 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 | |