1//===- Compilation.h - Compilation Task Data Structure ----------*- 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_COMPILATION_H
10#define LLVM_CLANG_DRIVER_COMPILATION_H
11
12#include "clang/Basic/LLVM.h"
13#include "clang/Driver/Action.h"
14#include "clang/Driver/Job.h"
15#include "clang/Driver/Util.h"
16#include "llvm/ADT/ArrayRef.h"
17#include "llvm/ADT/DenseMap.h"
18#include "llvm/ADT/StringRef.h"
19#include "llvm/Option/Option.h"
20#include <cassert>
21#include <iterator>
22#include <map>
23#include <memory>
24#include <optional>
25#include <utility>
26#include <vector>
27
28namespace llvm {
29namespace opt {
30
31class DerivedArgList;
32class InputArgList;
33
34} // namespace opt
35} // namespace llvm
36
37namespace clang {
38namespace driver {
39
40class Driver;
41class ToolChain;
42
43/// Compilation - A set of tasks to perform for a single driver
44/// invocation.
45class Compilation {
46 /// The driver we were created by.
47 const Driver &TheDriver;
48
49 /// The default tool chain.
50 const ToolChain &DefaultToolChain;
51
52 /// A mask of all the programming models the host has to support in the
53 /// current compilation.
54 unsigned ActiveOffloadMask = 0;
55
56 /// Array with the toolchains of offloading host and devices in the order they
57 /// were requested by the user. We are preserving that order in case the code
58 /// generation needs to derive a programming-model-specific semantic out of
59 /// it.
60 std::multimap<Action::OffloadKind, const ToolChain *>
61 OrderedOffloadingToolchains;
62
63 /// The original (untranslated) input argument list.
64 llvm::opt::InputArgList *Args;
65
66 /// The driver translated arguments. Note that toolchains may perform their
67 /// own argument translation.
68 llvm::opt::DerivedArgList *TranslatedArgs;
69
70 /// The list of actions we've created via MakeAction. This is not accessible
71 /// to consumers; it's here just to manage ownership.
72 std::vector<std::unique_ptr<Action>> AllActions;
73
74 /// The list of actions. This is maintained and modified by consumers, via
75 /// getActions().
76 ActionList Actions;
77
78 /// The root list of jobs.
79 JobList Jobs;
80
81 /// Cache of translated arguments for a particular tool chain, bound
82 /// architecture, and device offload kind.
83 struct TCArgsKey final {
84 const ToolChain *TC = nullptr;
85 StringRef BoundArch;
86 Action::OffloadKind DeviceOffloadKind = Action::OFK_None;
87
88 TCArgsKey(const ToolChain *TC, StringRef BoundArch,
89 Action::OffloadKind DeviceOffloadKind)
90 : TC(TC), BoundArch(BoundArch), DeviceOffloadKind(DeviceOffloadKind) {}
91
92 bool operator<(const TCArgsKey &K) const {
93 if (TC < K.TC)
94 return true;
95 else if (TC == K.TC && BoundArch < K.BoundArch)
96 return true;
97 else if (TC == K.TC && BoundArch == K.BoundArch &&
98 DeviceOffloadKind < K.DeviceOffloadKind)
99 return true;
100 return false;
101 }
102 };
103 std::map<TCArgsKey, llvm::opt::DerivedArgList *> TCArgs;
104
105 /// Temporary files which should be removed on exit.
106 llvm::opt::ArgStringList TempFiles;
107
108 /// Result files which should be removed on failure.
109 ArgStringMap ResultFiles;
110
111 /// Result files which are generated correctly on failure, and which should
112 /// only be removed if we crash.
113 ArgStringMap FailureResultFiles;
114
115 /// -ftime-trace result files.
116 ArgStringMap TimeTraceFiles;
117
118 /// Optional redirection for stdin, stdout, stderr.
119 std::vector<std::optional<StringRef>> Redirects;
120
121 /// Callback called after compilation job has been finished.
122 /// Arguments of the callback are the compilation job as an instance of
123 /// class Command and the exit status of the corresponding child process.
124 std::function<void(const Command &, int)> PostCallback;
125
126 /// Whether we're compiling for diagnostic purposes.
127 bool ForDiagnostics = false;
128
129 /// Whether an error during the parsing of the input args.
130 bool ContainsError;
131
132 /// Whether to keep temporary files regardless of -save-temps.
133 bool ForceKeepTempFiles = false;
134
135public:
136 Compilation(const Driver &D, const ToolChain &DefaultToolChain,
137 llvm::opt::InputArgList *Args,
138 llvm::opt::DerivedArgList *TranslatedArgs, bool ContainsError);
139 ~Compilation();
140
141 const Driver &getDriver() const { return TheDriver; }
142
143 const ToolChain &getDefaultToolChain() const { return DefaultToolChain; }
144
145 unsigned isOffloadingHostKind(Action::OffloadKind Kind) const {
146 return ActiveOffloadMask & Kind;
147 }
148
149 unsigned getActiveOffloadKinds() const { return ActiveOffloadMask; }
150
151 /// Iterator that visits device toolchains of a given kind.
152 using const_offload_toolchains_iterator =
153 const std::multimap<Action::OffloadKind,
154 const ToolChain *>::const_iterator;
155 using const_offload_toolchains_range =
156 std::pair<const_offload_toolchains_iterator,
157 const_offload_toolchains_iterator>;
158
159 template <Action::OffloadKind Kind>
160 const_offload_toolchains_range getOffloadToolChains() const {
161 return OrderedOffloadingToolchains.equal_range(x: Kind);
162 }
163
164 const_offload_toolchains_range
165 getOffloadToolChains(Action::OffloadKind Kind) const {
166 return OrderedOffloadingToolchains.equal_range(x: Kind);
167 }
168
169 /// Return true if an offloading tool chain of a given kind exists.
170 template <Action::OffloadKind Kind> bool hasOffloadToolChain() const {
171 return OrderedOffloadingToolchains.find(x: Kind) !=
172 OrderedOffloadingToolchains.end();
173 }
174
175 /// Return an offload toolchain of the provided kind. Only one is expected to
176 /// exist.
177 template <Action::OffloadKind Kind>
178 const ToolChain *getSingleOffloadToolChain() const {
179 auto TCs = getOffloadToolChains<Kind>();
180
181 assert(TCs.first != TCs.second &&
182 "No tool chains of the selected kind exist!");
183 assert(std::next(TCs.first) == TCs.second &&
184 "More than one tool chain of the this kind exist.");
185 return TCs.first->second;
186 }
187
188 void addOffloadDeviceToolChain(const ToolChain *DeviceToolChain,
189 Action::OffloadKind OffloadKind) {
190 assert(OffloadKind != Action::OFK_Host && OffloadKind != Action::OFK_None &&
191 "This is not a device tool chain!");
192
193 // Update the host offload kind to also contain this kind.
194 ActiveOffloadMask |= OffloadKind;
195 OrderedOffloadingToolchains.insert(
196 x: std::make_pair(x&: OffloadKind, y&: DeviceToolChain));
197 }
198
199 const llvm::opt::InputArgList &getInputArgs() const { return *Args; }
200
201 const llvm::opt::DerivedArgList &getArgs() const { return *TranslatedArgs; }
202
203 llvm::opt::DerivedArgList &getArgs() { return *TranslatedArgs; }
204
205 ActionList &getActions() { return Actions; }
206 const ActionList &getActions() const { return Actions; }
207
208 /// Creates a new Action owned by this Compilation.
209 ///
210 /// The new Action is *not* added to the list returned by getActions().
211 template <typename T, typename... Args> T *MakeAction(Args &&... Arg) {
212 T *RawPtr = new T(std::forward<Args>(Arg)...);
213 AllActions.push_back(x: std::unique_ptr<Action>(RawPtr));
214 return RawPtr;
215 }
216
217 JobList &getJobs() { return Jobs; }
218 const JobList &getJobs() const { return Jobs; }
219
220 void addCommand(std::unique_ptr<Command> C) { Jobs.addJob(J: std::move(C)); }
221
222 llvm::opt::ArgStringList &getTempFiles() { return TempFiles; }
223 const llvm::opt::ArgStringList &getTempFiles() const { return TempFiles; }
224
225 const ArgStringMap &getResultFiles() const { return ResultFiles; }
226
227 const ArgStringMap &getFailureResultFiles() const {
228 return FailureResultFiles;
229 }
230
231 /// Installs a handler that is executed when a compilation job is finished.
232 /// The arguments of the callback specify the compilation job as an instance
233 /// of class Command and the exit status of the child process executed that
234 /// job.
235 void setPostCallback(const std::function<void(const Command &, int)> &CB) {
236 PostCallback = CB;
237 }
238
239 /// Returns the sysroot path.
240 StringRef getSysRoot() const;
241
242 /// getArgsForToolChain - Return the derived argument list for the
243 /// tool chain \p TC (or the default tool chain, if TC is not specified).
244 /// If a device offloading kind is specified, a translation specific for that
245 /// kind is performed, if any.
246 ///
247 /// \param BoundArch - The bound architecture name, or 0.
248 /// \param DeviceOffloadKind - The offload device kind that should be used in
249 /// the translation, if any.
250 const llvm::opt::DerivedArgList &
251 getArgsForToolChain(const ToolChain *TC, StringRef BoundArch,
252 Action::OffloadKind DeviceOffloadKind);
253
254 /// addTempFile - Add a file to remove on exit, and returns its
255 /// argument.
256 const char *addTempFile(const char *Name) {
257 TempFiles.push_back(Elt: Name);
258 return Name;
259 }
260
261 /// addResultFile - Add a file to remove on failure, and returns its
262 /// argument.
263 const char *addResultFile(const char *Name, const JobAction *JA) {
264 ResultFiles[JA] = Name;
265 return Name;
266 }
267
268 /// addFailureResultFile - Add a file to remove if we crash, and returns its
269 /// argument.
270 const char *addFailureResultFile(const char *Name, const JobAction *JA) {
271 FailureResultFiles[JA] = Name;
272 return Name;
273 }
274
275 const char *getTimeTraceFile(const JobAction *JA) const {
276 return TimeTraceFiles.lookup(Val: JA);
277 }
278 void addTimeTraceFile(const char *Name, const JobAction *JA) {
279 assert(!TimeTraceFiles.contains(JA));
280 TimeTraceFiles[JA] = Name;
281 }
282
283 /// CleanupFile - Delete a given file.
284 ///
285 /// \param IssueErrors - Report failures as errors.
286 /// \return Whether the file was removed successfully.
287 bool CleanupFile(const char *File, bool IssueErrors = false) const;
288
289 /// CleanupFileList - Remove the files in the given list.
290 ///
291 /// \param IssueErrors - Report failures as errors.
292 /// \return Whether all files were removed successfully.
293 bool CleanupFileList(const llvm::opt::ArgStringList &Files,
294 bool IssueErrors = false) const;
295
296 /// CleanupFileMap - Remove the files in the given map.
297 ///
298 /// \param JA - If specified, only delete the files associated with this
299 /// JobAction. Otherwise, delete all files in the map.
300 /// \param IssueErrors - Report failures as errors.
301 /// \return Whether all files were removed successfully.
302 bool CleanupFileMap(const ArgStringMap &Files,
303 const JobAction *JA,
304 bool IssueErrors = false) const;
305
306 /// ExecuteCommand - Execute an actual command.
307 ///
308 /// \param FailingCommand - For non-zero results, this will be set to the
309 /// Command which failed, if any.
310 /// \param LogOnly - When true, only tries to log the command, not actually
311 /// execute it.
312 /// \return The result code of the subprocess.
313 int ExecuteCommand(const Command &C, const Command *&FailingCommand,
314 bool LogOnly = false) const;
315
316 /// ExecuteJob - Execute a single job.
317 ///
318 /// \param FailingCommands - For non-zero results, this will be a vector of
319 /// failing commands and their associated result code.
320 /// \param LogOnly - When true, only tries to log the command, not actually
321 /// execute it.
322 void
323 ExecuteJobs(const JobList &Jobs,
324 SmallVectorImpl<std::pair<int, const Command *>> &FailingCommands,
325 bool LogOnly = false) const;
326
327 /// initCompilationForDiagnostics - Remove stale state and suppress output
328 /// so compilation can be reexecuted to generate additional diagnostic
329 /// information (e.g., preprocessed source(s)).
330 void initCompilationForDiagnostics();
331
332 /// Return true if we're compiling for diagnostics.
333 bool isForDiagnostics() const { return ForDiagnostics; }
334
335 /// Return whether an error during the parsing of the input args.
336 bool containsError() const { return ContainsError; }
337
338 /// Force driver to fail before toolchain is created. This is necessary when
339 /// error happens in action builder.
340 void setContainsError() { ContainsError = true; }
341
342 /// Redirect - Redirect output of this compilation. Can only be done once.
343 ///
344 /// \param Redirects - array of optional paths. The array should have a size
345 /// of three. The inferior process's stdin(0), stdout(1), and stderr(2) will
346 /// be redirected to the corresponding paths, if provided (not std::nullopt).
347 void Redirect(ArrayRef<std::optional<StringRef>> Redirects);
348};
349
350} // namespace driver
351} // namespace clang
352
353#endif // LLVM_CLANG_DRIVER_COMPILATION_H
354