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 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 135 public: 136 Compilation(const Driver &D, const ToolChain &DefaultToolChain, 137 llvm::opt::InputArgList *Args, 138 llvm::opt::DerivedArgList *TranslatedArgs, bool ContainsError); 139 ~Compilation(); 140 getDriver()141 const Driver &getDriver() const { return TheDriver; } 142 getDefaultToolChain()143 const ToolChain &getDefaultToolChain() const { return DefaultToolChain; } 144 isOffloadingHostKind(Action::OffloadKind Kind)145 unsigned isOffloadingHostKind(Action::OffloadKind Kind) const { 146 return ActiveOffloadMask & Kind; 147 } 148 getActiveOffloadKinds()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> getOffloadToolChains()160 const_offload_toolchains_range getOffloadToolChains() const { 161 return OrderedOffloadingToolchains.equal_range(Kind); 162 } 163 164 const_offload_toolchains_range getOffloadToolChains(Action::OffloadKind Kind)165 getOffloadToolChains(Action::OffloadKind Kind) const { 166 return OrderedOffloadingToolchains.equal_range(Kind); 167 } 168 169 /// Return true if an offloading tool chain of a given kind exists. hasOffloadToolChain()170 template <Action::OffloadKind Kind> bool hasOffloadToolChain() const { 171 return OrderedOffloadingToolchains.find(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> getSingleOffloadToolChain()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 addOffloadDeviceToolChain(const ToolChain * DeviceToolChain,Action::OffloadKind OffloadKind)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 std::make_pair(OffloadKind, DeviceToolChain)); 197 } 198 getInputArgs()199 const llvm::opt::InputArgList &getInputArgs() const { return *Args; } 200 getArgs()201 const llvm::opt::DerivedArgList &getArgs() const { return *TranslatedArgs; } 202 getArgs()203 llvm::opt::DerivedArgList &getArgs() { return *TranslatedArgs; } 204 getActions()205 ActionList &getActions() { return Actions; } getActions()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(). MakeAction(Args &&...Arg)211 template <typename T, typename... Args> T *MakeAction(Args &&... Arg) { 212 T *RawPtr = new T(std::forward<Args>(Arg)...); 213 AllActions.push_back(std::unique_ptr<Action>(RawPtr)); 214 return RawPtr; 215 } 216 getJobs()217 JobList &getJobs() { return Jobs; } getJobs()218 const JobList &getJobs() const { return Jobs; } 219 addCommand(std::unique_ptr<Command> C)220 void addCommand(std::unique_ptr<Command> C) { Jobs.addJob(std::move(C)); } 221 getTempFiles()222 llvm::opt::ArgStringList &getTempFiles() { return TempFiles; } getTempFiles()223 const llvm::opt::ArgStringList &getTempFiles() const { return TempFiles; } 224 getResultFiles()225 const ArgStringMap &getResultFiles() const { return ResultFiles; } 226 getFailureResultFiles()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. setPostCallback(const std::function<void (const Command &,int)> & CB)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. addTempFile(const char * Name)256 const char *addTempFile(const char *Name) { 257 TempFiles.push_back(Name); 258 return Name; 259 } 260 261 /// addResultFile - Add a file to remove on failure, and returns its 262 /// argument. addResultFile(const char * Name,const JobAction * JA)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. addFailureResultFile(const char * Name,const JobAction * JA)270 const char *addFailureResultFile(const char *Name, const JobAction *JA) { 271 FailureResultFiles[JA] = Name; 272 return Name; 273 } 274 getTimeTraceFile(const JobAction * JA)275 const char *getTimeTraceFile(const JobAction *JA) const { 276 return TimeTraceFiles.lookup(JA); 277 } addTimeTraceFile(const char * Name,const JobAction * JA)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. isForDiagnostics()333 bool isForDiagnostics() const { return ForDiagnostics; } 334 335 /// Return whether an error during the parsing of the input args. containsError()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. setContainsError()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