| //===- Job.h - Commands to Execute ------------------------------*- 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_JOB_H |
| #define LLVM_CLANG_DRIVER_JOB_H |
| |
| #include "clang/Basic/LLVM.h" |
| #include "clang/Driver/InputInfo.h" |
| #include "llvm/ADT/ArrayRef.h" |
| #include "llvm/ADT/Optional.h" |
| #include "llvm/ADT/SmallVector.h" |
| #include "llvm/ADT/StringRef.h" |
| #include "llvm/ADT/iterator.h" |
| #include "llvm/Option/Option.h" |
| #include "llvm/Support/Program.h" |
| #include <memory> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| namespace clang { |
| namespace driver { |
| |
| class Action; |
| class InputInfo; |
| class Tool; |
| |
| struct CrashReportInfo { |
| StringRef Filename; |
| StringRef VFSPath; |
| |
| CrashReportInfo(StringRef Filename, StringRef VFSPath) |
| : Filename(Filename), VFSPath(VFSPath) {} |
| }; |
| |
| // Encodes the kind of response file supported for a command invocation. |
| // Response files are necessary if the command line gets too large, requiring |
| // the arguments to be transferred to a file. |
| struct ResponseFileSupport { |
| enum ResponseFileKind { |
| // Provides full support for response files, which means we can transfer |
| // all tool input arguments to a file. |
| RF_Full, |
| // Input file names can live in a file, but flags can't. This is a special |
| // case for old versions of Apple's ld64. |
| RF_FileList, |
| // Does not support response files: all arguments must be passed via |
| // command line. |
| RF_None |
| }; |
| /// The level of support for response files. |
| ResponseFileKind ResponseKind; |
| |
| /// The encoding to use when writing response files on Windows. Ignored on |
| /// other host OSes. |
| /// |
| /// Windows use cases: - GCC and Binutils on mingw only accept ANSI response |
| /// files encoded with the system current code page. |
| /// - MSVC's CL.exe and LINK.exe accept UTF16 on Windows. |
| /// - Clang accepts both UTF8 and UTF16. |
| /// |
| /// FIXME: When GNU tools learn how to parse UTF16 on Windows, we should |
| /// always use UTF16 for Windows, which is the Windows official encoding for |
| /// international characters. |
| llvm::sys::WindowsEncodingMethod ResponseEncoding; |
| |
| /// What prefix to use for the command-line argument when passing a response |
| /// file. |
| const char *ResponseFlag; |
| |
| /// Returns a ResponseFileSupport indicating that response files are not |
| /// supported. |
| static constexpr ResponseFileSupport None() { |
| return {RF_None, llvm::sys::WEM_UTF8, nullptr}; |
| } |
| |
| /// Returns a ResponseFileSupport indicating that response files are |
| /// supported, using the @file syntax. On windows, the file is written in the |
| /// UTF8 encoding. On other OSes, no re-encoding occurs. |
| static constexpr ResponseFileSupport AtFileUTF8() { |
| return {RF_Full, llvm::sys::WEM_UTF8, "@"}; |
| } |
| |
| /// Returns a ResponseFileSupport indicating that response files are |
| /// supported, using the @file syntax. On windows, the file is written in the |
| /// current ANSI code-page encoding. On other OSes, no re-encoding occurs. |
| static constexpr ResponseFileSupport AtFileCurCP() { |
| return {RF_Full, llvm::sys::WEM_CurrentCodePage, "@"}; |
| } |
| |
| /// Returns a ResponseFileSupport indicating that response files are |
| /// supported, using the @file syntax. On windows, the file is written in the |
| /// UTF-16 encoding. On other OSes, no re-encoding occurs. |
| static constexpr ResponseFileSupport AtFileUTF16() { |
| return {RF_Full, llvm::sys::WEM_UTF16, "@"}; |
| } |
| }; |
| |
| /// Command - An executable path/name and argument vector to |
| /// execute. |
| class Command { |
| /// Source - The action which caused the creation of this job. |
| const Action &Source; |
| |
| /// Tool - The tool which caused the creation of this job. |
| const Tool &Creator; |
| |
| /// Whether and how to generate response files if the arguments are too long. |
| ResponseFileSupport ResponseSupport; |
| |
| /// The executable to run. |
| const char *Executable; |
| |
| /// The list of program arguments (not including the implicit first |
| /// argument, which will be the executable). |
| llvm::opt::ArgStringList Arguments; |
| |
| /// The list of program inputs. |
| std::vector<InputInfo> InputInfoList; |
| |
| /// The list of program arguments which are outputs. May be empty. |
| std::vector<std::string> OutputFilenames; |
| |
| /// Response file name, if this command is set to use one, or nullptr |
| /// otherwise |
| const char *ResponseFile = nullptr; |
| |
| /// The input file list in case we need to emit a file list instead of a |
| /// proper response file |
| llvm::opt::ArgStringList InputFileList; |
| |
| /// String storage if we need to create a new argument to specify a response |
| /// file |
| std::string ResponseFileFlag; |
| |
| /// See Command::setEnvironment |
| std::vector<const char *> Environment; |
| |
| /// Information on executable run provided by OS. |
| mutable Optional<llvm::sys::ProcessStatistics> ProcStat; |
| |
| /// When a response file is needed, we try to put most arguments in an |
| /// exclusive file, while others remains as regular command line arguments. |
| /// This functions fills a vector with the regular command line arguments, |
| /// argv, excluding the ones passed in a response file. |
| void buildArgvForResponseFile(llvm::SmallVectorImpl<const char *> &Out) const; |
| |
| /// Encodes an array of C strings into a single string separated by whitespace. |
| /// This function will also put in quotes arguments that have whitespaces and |
| /// will escape the regular backslashes (used in Windows paths) and quotes. |
| /// The results are the contents of a response file, written into a raw_ostream. |
| void writeResponseFile(raw_ostream &OS) const; |
| |
| public: |
| /// Whether to print the input filenames when executing. |
| bool PrintInputFilenames = false; |
| |
| /// Whether the command will be executed in this process or not. |
| bool InProcess = false; |
| |
| Command(const Action &Source, const Tool &Creator, |
| ResponseFileSupport ResponseSupport, const char *Executable, |
| const llvm::opt::ArgStringList &Arguments, ArrayRef<InputInfo> Inputs, |
| ArrayRef<InputInfo> Outputs = None); |
| // FIXME: This really shouldn't be copyable, but is currently copied in some |
| // error handling in Driver::generateCompilationDiagnostics. |
| Command(const Command &) = default; |
| virtual ~Command() = default; |
| |
| virtual void Print(llvm::raw_ostream &OS, const char *Terminator, bool Quote, |
| CrashReportInfo *CrashInfo = nullptr) const; |
| |
| virtual int Execute(ArrayRef<Optional<StringRef>> Redirects, |
| std::string *ErrMsg, bool *ExecutionFailed) const; |
| |
| /// getSource - Return the Action which caused the creation of this job. |
| const Action &getSource() const { return Source; } |
| |
| /// getCreator - Return the Tool which caused the creation of this job. |
| const Tool &getCreator() const { return Creator; } |
| |
| /// Returns the kind of response file supported by the current invocation. |
| const ResponseFileSupport &getResponseFileSupport() { |
| return ResponseSupport; |
| } |
| |
| /// Set to pass arguments via a response file when launching the command |
| void setResponseFile(const char *FileName); |
| |
| /// Set an input file list, necessary if you specified an RF_FileList response |
| /// file support. |
| void setInputFileList(llvm::opt::ArgStringList List) { |
| InputFileList = std::move(List); |
| } |
| |
| /// Sets the environment to be used by the new process. |
| /// \param NewEnvironment An array of environment variables. |
| /// \remark If the environment remains unset, then the environment |
| /// from the parent process will be used. |
| virtual void setEnvironment(llvm::ArrayRef<const char *> NewEnvironment); |
| |
| const char *getExecutable() const { return Executable; } |
| |
| const llvm::opt::ArgStringList &getArguments() const { return Arguments; } |
| |
| const std::vector<InputInfo> &getInputInfos() const { return InputInfoList; } |
| |
| const std::vector<std::string> &getOutputFilenames() const { |
| return OutputFilenames; |
| } |
| |
| Optional<llvm::sys::ProcessStatistics> getProcessStatistics() const { |
| return ProcStat; |
| } |
| |
| protected: |
| /// Optionally print the filenames to be compiled |
| void PrintFileNames() const; |
| }; |
| |
| /// Use the CC1 tool callback when available, to avoid creating a new process |
| class CC1Command : public Command { |
| public: |
| CC1Command(const Action &Source, const Tool &Creator, |
| ResponseFileSupport ResponseSupport, const char *Executable, |
| const llvm::opt::ArgStringList &Arguments, |
| ArrayRef<InputInfo> Inputs, ArrayRef<InputInfo> Outputs = None); |
| |
| void Print(llvm::raw_ostream &OS, const char *Terminator, bool Quote, |
| CrashReportInfo *CrashInfo = nullptr) const override; |
| |
| int Execute(ArrayRef<Optional<StringRef>> Redirects, std::string *ErrMsg, |
| bool *ExecutionFailed) const override; |
| |
| void setEnvironment(llvm::ArrayRef<const char *> NewEnvironment) override; |
| }; |
| |
| /// Like Command, but always pretends that the wrapped command succeeded. |
| class ForceSuccessCommand : public Command { |
| public: |
| ForceSuccessCommand(const Action &Source_, const Tool &Creator_, |
| ResponseFileSupport ResponseSupport, |
| const char *Executable_, |
| const llvm::opt::ArgStringList &Arguments_, |
| ArrayRef<InputInfo> Inputs, |
| ArrayRef<InputInfo> Outputs = None); |
| |
| void Print(llvm::raw_ostream &OS, const char *Terminator, bool Quote, |
| CrashReportInfo *CrashInfo = nullptr) const override; |
| |
| int Execute(ArrayRef<Optional<StringRef>> Redirects, std::string *ErrMsg, |
| bool *ExecutionFailed) const override; |
| }; |
| |
| /// JobList - A sequence of jobs to perform. |
| class JobList { |
| public: |
| using list_type = SmallVector<std::unique_ptr<Command>, 4>; |
| using size_type = list_type::size_type; |
| using iterator = llvm::pointee_iterator<list_type::iterator>; |
| using const_iterator = llvm::pointee_iterator<list_type::const_iterator>; |
| |
| private: |
| list_type Jobs; |
| |
| public: |
| void Print(llvm::raw_ostream &OS, const char *Terminator, |
| bool Quote, CrashReportInfo *CrashInfo = nullptr) const; |
| |
| /// Add a job to the list (taking ownership). |
| void addJob(std::unique_ptr<Command> J) { Jobs.push_back(std::move(J)); } |
| |
| /// Clear the job list. |
| void clear(); |
| |
| const list_type &getJobs() const { return Jobs; } |
| |
| bool empty() const { return Jobs.empty(); } |
| size_type size() const { return Jobs.size(); } |
| iterator begin() { return Jobs.begin(); } |
| const_iterator begin() const { return Jobs.begin(); } |
| iterator end() { return Jobs.end(); } |
| const_iterator end() const { return Jobs.end(); } |
| }; |
| |
| } // namespace driver |
| } // namespace clang |
| |
| #endif // LLVM_CLANG_DRIVER_JOB_H |