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