//===- Compilation.h - Compilation Task Data Structure ----------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_DRIVER_COMPILATION_H #define LLVM_CLANG_DRIVER_COMPILATION_H #include "clang/Basic/LLVM.h" #include "clang/Driver/Action.h" #include "clang/Driver/Job.h" #include "clang/Driver/Util.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/StringRef.h" #include "llvm/Option/Option.h" #include #include #include #include #include #include namespace llvm { namespace opt { class DerivedArgList; class InputArgList; } // namespace opt } // namespace llvm namespace clang { namespace driver { class Driver; class ToolChain; /// Compilation - A set of tasks to perform for a single driver /// invocation. class Compilation { /// The driver we were created by. const Driver &TheDriver; /// The default tool chain. const ToolChain &DefaultToolChain; /// A mask of all the programming models the host has to support in the /// current compilation. unsigned ActiveOffloadMask = 0; /// Array with the toolchains of offloading host and devices in the order they /// were requested by the user. We are preserving that order in case the code /// generation needs to derive a programming-model-specific semantic out of /// it. std::multimap OrderedOffloadingToolchains; /// The original (untranslated) input argument list. llvm::opt::InputArgList *Args; /// The driver translated arguments. Note that toolchains may perform their /// own argument translation. llvm::opt::DerivedArgList *TranslatedArgs; /// The list of actions we've created via MakeAction. This is not accessible /// to consumers; it's here just to manage ownership. std::vector> AllActions; /// The list of actions. This is maintained and modified by consumers, via /// getActions(). ActionList Actions; /// The root list of jobs. JobList Jobs; /// Cache of translated arguments for a particular tool chain, bound /// architecture, and device offload kind. struct TCArgsKey final { const ToolChain *TC = nullptr; StringRef BoundArch; Action::OffloadKind DeviceOffloadKind = Action::OFK_None; TCArgsKey(const ToolChain *TC, StringRef BoundArch, Action::OffloadKind DeviceOffloadKind) : TC(TC), BoundArch(BoundArch), DeviceOffloadKind(DeviceOffloadKind) {} bool operator<(const TCArgsKey &K) const { if (TC < K.TC) return true; else if (TC == K.TC && BoundArch < K.BoundArch) return true; else if (TC == K.TC && BoundArch == K.BoundArch && DeviceOffloadKind < K.DeviceOffloadKind) return true; return false; } }; std::map TCArgs; /// Temporary files which should be removed on exit. llvm::opt::ArgStringList TempFiles; /// Result files which should be removed on failure. ArgStringMap ResultFiles; /// Result files which are generated correctly on failure, and which should /// only be removed if we crash. ArgStringMap FailureResultFiles; /// Optional redirection for stdin, stdout, stderr. std::vector> Redirects; /// Whether we're compiling for diagnostic purposes. bool ForDiagnostics = false; /// Whether an error during the parsing of the input args. bool ContainsError; /// Whether to keep temporary files regardless of -save-temps. bool ForceKeepTempFiles = false; public: Compilation(const Driver &D, const ToolChain &DefaultToolChain, llvm::opt::InputArgList *Args, llvm::opt::DerivedArgList *TranslatedArgs, bool ContainsError); ~Compilation(); const Driver &getDriver() const { return TheDriver; } const ToolChain &getDefaultToolChain() const { return DefaultToolChain; } unsigned isOffloadingHostKind(Action::OffloadKind Kind) const { return ActiveOffloadMask & Kind; } /// Iterator that visits device toolchains of a given kind. using const_offload_toolchains_iterator = const std::multimap::const_iterator; using const_offload_toolchains_range = std::pair; template const_offload_toolchains_range getOffloadToolChains() const { return OrderedOffloadingToolchains.equal_range(Kind); } /// Return true if an offloading tool chain of a given kind exists. template bool hasOffloadToolChain() const { return OrderedOffloadingToolchains.find(Kind) != OrderedOffloadingToolchains.end(); } /// Return an offload toolchain of the provided kind. Only one is expected to /// exist. template const ToolChain *getSingleOffloadToolChain() const { auto TCs = getOffloadToolChains(); assert(TCs.first != TCs.second && "No tool chains of the selected kind exist!"); assert(std::next(TCs.first) == TCs.second && "More than one tool chain of the this kind exist."); return TCs.first->second; } void addOffloadDeviceToolChain(const ToolChain *DeviceToolChain, Action::OffloadKind OffloadKind) { assert(OffloadKind != Action::OFK_Host && OffloadKind != Action::OFK_None && "This is not a device tool chain!"); // Update the host offload kind to also contain this kind. ActiveOffloadMask |= OffloadKind; OrderedOffloadingToolchains.insert( std::make_pair(OffloadKind, DeviceToolChain)); } const llvm::opt::InputArgList &getInputArgs() const { return *Args; } const llvm::opt::DerivedArgList &getArgs() const { return *TranslatedArgs; } llvm::opt::DerivedArgList &getArgs() { return *TranslatedArgs; } ActionList &getActions() { return Actions; } const ActionList &getActions() const { return Actions; } /// Creates a new Action owned by this Compilation. /// /// The new Action is *not* added to the list returned by getActions(). template T *MakeAction(Args &&... Arg) { T *RawPtr = new T(std::forward(Arg)...); AllActions.push_back(std::unique_ptr(RawPtr)); return RawPtr; } JobList &getJobs() { return Jobs; } const JobList &getJobs() const { return Jobs; } void addCommand(std::unique_ptr C) { Jobs.addJob(std::move(C)); } const llvm::opt::ArgStringList &getTempFiles() const { return TempFiles; } const ArgStringMap &getResultFiles() const { return ResultFiles; } const ArgStringMap &getFailureResultFiles() const { return FailureResultFiles; } /// Returns the sysroot path. StringRef getSysRoot() const; /// getArgsForToolChain - Return the derived argument list for the /// tool chain \p TC (or the default tool chain, if TC is not specified). /// If a device offloading kind is specified, a translation specific for that /// kind is performed, if any. /// /// \param BoundArch - The bound architecture name, or 0. /// \param DeviceOffloadKind - The offload device kind that should be used in /// the translation, if any. const llvm::opt::DerivedArgList & getArgsForToolChain(const ToolChain *TC, StringRef BoundArch, Action::OffloadKind DeviceOffloadKind); /// addTempFile - Add a file to remove on exit, and returns its /// argument. const char *addTempFile(const char *Name) { TempFiles.push_back(Name); return Name; } /// addResultFile - Add a file to remove on failure, and returns its /// argument. const char *addResultFile(const char *Name, const JobAction *JA) { ResultFiles[JA] = Name; return Name; } /// addFailureResultFile - Add a file to remove if we crash, and returns its /// argument. const char *addFailureResultFile(const char *Name, const JobAction *JA) { FailureResultFiles[JA] = Name; return Name; } /// CleanupFile - Delete a given file. /// /// \param IssueErrors - Report failures as errors. /// \return Whether the file was removed successfully. bool CleanupFile(const char *File, bool IssueErrors = false) const; /// CleanupFileList - Remove the files in the given list. /// /// \param IssueErrors - Report failures as errors. /// \return Whether all files were removed successfully. bool CleanupFileList(const llvm::opt::ArgStringList &Files, bool IssueErrors = false) const; /// CleanupFileMap - Remove the files in the given map. /// /// \param JA - If specified, only delete the files associated with this /// JobAction. Otherwise, delete all files in the map. /// \param IssueErrors - Report failures as errors. /// \return Whether all files were removed successfully. bool CleanupFileMap(const ArgStringMap &Files, const JobAction *JA, bool IssueErrors = false) const; /// ExecuteCommand - Execute an actual command. /// /// \param FailingCommand - For non-zero results, this will be set to the /// Command which failed, if any. /// \return The result code of the subprocess. int ExecuteCommand(const Command &C, const Command *&FailingCommand) const; /// ExecuteJob - Execute a single job. /// /// \param FailingCommands - For non-zero results, this will be a vector of /// failing commands and their associated result code. void ExecuteJobs( const JobList &Jobs, SmallVectorImpl> &FailingCommands) const; /// initCompilationForDiagnostics - Remove stale state and suppress output /// so compilation can be reexecuted to generate additional diagnostic /// information (e.g., preprocessed source(s)). void initCompilationForDiagnostics(); /// Return true if we're compiling for diagnostics. bool isForDiagnostics() const { return ForDiagnostics; } /// Return whether an error during the parsing of the input args. bool containsError() const { return ContainsError; } /// Redirect - Redirect output of this compilation. Can only be done once. /// /// \param Redirects - array of optional paths. The array should have a size /// of three. The inferior process's stdin(0), stdout(1), and stderr(2) will /// be redirected to the corresponding paths, if provided (not llvm::None). void Redirect(ArrayRef> Redirects); }; } // namespace driver } // namespace clang #endif // LLVM_CLANG_DRIVER_COMPILATION_H