1 //===- Job.h - Commands to Execute ------------------------------*- 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_JOB_H 10 #define LLVM_CLANG_DRIVER_JOB_H 11 12 #include "clang/Basic/LLVM.h" 13 #include "clang/Driver/InputInfo.h" 14 #include "llvm/ADT/ArrayRef.h" 15 #include "llvm/ADT/SmallVector.h" 16 #include "llvm/ADT/StringRef.h" 17 #include "llvm/ADT/iterator.h" 18 #include "llvm/Option/Option.h" 19 #include "llvm/Support/Program.h" 20 #include <memory> 21 #include <optional> 22 #include <string> 23 #include <utility> 24 #include <vector> 25 26 namespace clang { 27 namespace driver { 28 29 class Action; 30 class InputInfo; 31 class Tool; 32 33 struct CrashReportInfo { 34 StringRef Filename; 35 StringRef VFSPath; 36 CrashReportInfoCrashReportInfo37 CrashReportInfo(StringRef Filename, StringRef VFSPath) 38 : Filename(Filename), VFSPath(VFSPath) {} 39 }; 40 41 // Encodes the kind of response file supported for a command invocation. 42 // Response files are necessary if the command line gets too large, requiring 43 // the arguments to be transferred to a file. 44 struct ResponseFileSupport { 45 enum ResponseFileKind { 46 // Provides full support for response files, which means we can transfer 47 // all tool input arguments to a file. 48 RF_Full, 49 // Input file names can live in a file, but flags can't. This is a special 50 // case for old versions of Apple's ld64. 51 RF_FileList, 52 // Does not support response files: all arguments must be passed via 53 // command line. 54 RF_None 55 }; 56 /// The level of support for response files. 57 ResponseFileKind ResponseKind; 58 59 /// The encoding to use when writing response files on Windows. Ignored on 60 /// other host OSes. 61 /// 62 /// Windows use cases: - GCC and Binutils on mingw only accept ANSI response 63 /// files encoded with the system current code page. 64 /// - MSVC's CL.exe and LINK.exe accept UTF16 on Windows. 65 /// - Clang accepts both UTF8 and UTF16. 66 /// 67 /// FIXME: When GNU tools learn how to parse UTF16 on Windows, we should 68 /// always use UTF16 for Windows, which is the Windows official encoding for 69 /// international characters. 70 llvm::sys::WindowsEncodingMethod ResponseEncoding; 71 72 /// What prefix to use for the command-line argument when passing a response 73 /// file. 74 const char *ResponseFlag; 75 76 /// Returns a ResponseFileSupport indicating that response files are not 77 /// supported. NoneResponseFileSupport78 static constexpr ResponseFileSupport None() { 79 return {RF_None, llvm::sys::WEM_UTF8, nullptr}; 80 } 81 82 /// Returns a ResponseFileSupport indicating that response files are 83 /// supported, using the @file syntax. On windows, the file is written in the 84 /// UTF8 encoding. On other OSes, no re-encoding occurs. AtFileUTF8ResponseFileSupport85 static constexpr ResponseFileSupport AtFileUTF8() { 86 return {RF_Full, llvm::sys::WEM_UTF8, "@"}; 87 } 88 89 /// Returns a ResponseFileSupport indicating that response files are 90 /// supported, using the @file syntax. On windows, the file is written in the 91 /// current ANSI code-page encoding. On other OSes, no re-encoding occurs. AtFileCurCPResponseFileSupport92 static constexpr ResponseFileSupport AtFileCurCP() { 93 return {RF_Full, llvm::sys::WEM_CurrentCodePage, "@"}; 94 } 95 96 /// Returns a ResponseFileSupport indicating that response files are 97 /// supported, using the @file syntax. On windows, the file is written in the 98 /// UTF-16 encoding. On other OSes, no re-encoding occurs. AtFileUTF16ResponseFileSupport99 static constexpr ResponseFileSupport AtFileUTF16() { 100 return {RF_Full, llvm::sys::WEM_UTF16, "@"}; 101 } 102 }; 103 104 /// Command - An executable path/name and argument vector to 105 /// execute. 106 class Command { 107 /// Source - The action which caused the creation of this job. 108 const Action &Source; 109 110 /// Tool - The tool which caused the creation of this job. 111 const Tool &Creator; 112 113 /// Whether and how to generate response files if the arguments are too long. 114 ResponseFileSupport ResponseSupport; 115 116 /// The executable to run. 117 const char *Executable; 118 119 /// Optional argument to prepend. 120 const char *PrependArg; 121 122 /// The list of program arguments (not including the implicit first 123 /// argument, which will be the executable). 124 llvm::opt::ArgStringList Arguments; 125 126 /// The list of program inputs. 127 std::vector<InputInfo> InputInfoList; 128 129 /// The list of program arguments which are outputs. May be empty. 130 std::vector<std::string> OutputFilenames; 131 132 /// Response file name, if this command is set to use one, or nullptr 133 /// otherwise 134 const char *ResponseFile = nullptr; 135 136 /// The input file list in case we need to emit a file list instead of a 137 /// proper response file 138 llvm::opt::ArgStringList InputFileList; 139 140 /// String storage if we need to create a new argument to specify a response 141 /// file 142 std::string ResponseFileFlag; 143 144 /// See Command::setEnvironment 145 std::vector<const char *> Environment; 146 147 /// Optional redirection for stdin, stdout, stderr. 148 std::vector<std::optional<std::string>> RedirectFiles; 149 150 /// Information on executable run provided by OS. 151 mutable std::optional<llvm::sys::ProcessStatistics> ProcStat; 152 153 /// When a response file is needed, we try to put most arguments in an 154 /// exclusive file, while others remains as regular command line arguments. 155 /// This functions fills a vector with the regular command line arguments, 156 /// argv, excluding the ones passed in a response file. 157 void buildArgvForResponseFile(llvm::SmallVectorImpl<const char *> &Out) const; 158 159 /// Encodes an array of C strings into a single string separated by whitespace. 160 /// This function will also put in quotes arguments that have whitespaces and 161 /// will escape the regular backslashes (used in Windows paths) and quotes. 162 /// The results are the contents of a response file, written into a raw_ostream. 163 void writeResponseFile(raw_ostream &OS) const; 164 165 public: 166 /// Whether to print the input filenames when executing. 167 bool PrintInputFilenames = false; 168 169 /// Whether the command will be executed in this process or not. 170 bool InProcess = false; 171 172 Command(const Action &Source, const Tool &Creator, 173 ResponseFileSupport ResponseSupport, const char *Executable, 174 const llvm::opt::ArgStringList &Arguments, ArrayRef<InputInfo> Inputs, 175 ArrayRef<InputInfo> Outputs = std::nullopt, 176 const char *PrependArg = nullptr); 177 // FIXME: This really shouldn't be copyable, but is currently copied in some 178 // error handling in Driver::generateCompilationDiagnostics. 179 Command(const Command &) = default; 180 virtual ~Command() = default; 181 182 virtual void Print(llvm::raw_ostream &OS, const char *Terminator, bool Quote, 183 CrashReportInfo *CrashInfo = nullptr) const; 184 185 virtual int Execute(ArrayRef<std::optional<StringRef>> Redirects, 186 std::string *ErrMsg, bool *ExecutionFailed) const; 187 188 /// getSource - Return the Action which caused the creation of this job. getSource()189 const Action &getSource() const { return Source; } 190 191 /// getCreator - Return the Tool which caused the creation of this job. getCreator()192 const Tool &getCreator() const { return Creator; } 193 194 /// Returns the kind of response file supported by the current invocation. getResponseFileSupport()195 const ResponseFileSupport &getResponseFileSupport() { 196 return ResponseSupport; 197 } 198 199 /// Set to pass arguments via a response file when launching the command 200 void setResponseFile(const char *FileName); 201 202 /// Set an input file list, necessary if you specified an RF_FileList response 203 /// file support. setInputFileList(llvm::opt::ArgStringList List)204 void setInputFileList(llvm::opt::ArgStringList List) { 205 InputFileList = std::move(List); 206 } 207 208 /// Sets the environment to be used by the new process. 209 /// \param NewEnvironment An array of environment variables. 210 /// \remark If the environment remains unset, then the environment 211 /// from the parent process will be used. 212 virtual void setEnvironment(llvm::ArrayRef<const char *> NewEnvironment); 213 214 void 215 setRedirectFiles(const std::vector<std::optional<std::string>> &Redirects); 216 replaceArguments(llvm::opt::ArgStringList List)217 void replaceArguments(llvm::opt::ArgStringList List) { 218 Arguments = std::move(List); 219 } 220 replaceExecutable(const char * Exe)221 void replaceExecutable(const char *Exe) { Executable = Exe; } 222 getExecutable()223 const char *getExecutable() const { return Executable; } 224 getArguments()225 const llvm::opt::ArgStringList &getArguments() const { return Arguments; } 226 getInputInfos()227 const std::vector<InputInfo> &getInputInfos() const { return InputInfoList; } 228 getOutputFilenames()229 const std::vector<std::string> &getOutputFilenames() const { 230 return OutputFilenames; 231 } 232 getProcessStatistics()233 std::optional<llvm::sys::ProcessStatistics> getProcessStatistics() const { 234 return ProcStat; 235 } 236 237 protected: 238 /// Optionally print the filenames to be compiled 239 void PrintFileNames() const; 240 }; 241 242 /// Use the CC1 tool callback when available, to avoid creating a new process 243 class CC1Command : public Command { 244 public: 245 CC1Command(const Action &Source, const Tool &Creator, 246 ResponseFileSupport ResponseSupport, const char *Executable, 247 const llvm::opt::ArgStringList &Arguments, 248 ArrayRef<InputInfo> Inputs, 249 ArrayRef<InputInfo> Outputs = std::nullopt, 250 const char *PrependArg = nullptr); 251 252 void Print(llvm::raw_ostream &OS, const char *Terminator, bool Quote, 253 CrashReportInfo *CrashInfo = nullptr) const override; 254 255 int Execute(ArrayRef<std::optional<StringRef>> Redirects, std::string *ErrMsg, 256 bool *ExecutionFailed) const override; 257 258 void setEnvironment(llvm::ArrayRef<const char *> NewEnvironment) override; 259 }; 260 261 /// JobList - A sequence of jobs to perform. 262 class JobList { 263 public: 264 using list_type = SmallVector<std::unique_ptr<Command>, 4>; 265 using size_type = list_type::size_type; 266 using iterator = llvm::pointee_iterator<list_type::iterator>; 267 using const_iterator = llvm::pointee_iterator<list_type::const_iterator>; 268 269 private: 270 list_type Jobs; 271 272 public: 273 void Print(llvm::raw_ostream &OS, const char *Terminator, 274 bool Quote, CrashReportInfo *CrashInfo = nullptr) const; 275 276 /// Add a job to the list (taking ownership). addJob(std::unique_ptr<Command> J)277 void addJob(std::unique_ptr<Command> J) { Jobs.push_back(std::move(J)); } 278 279 /// Clear the job list. 280 void clear(); 281 getJobs()282 const list_type &getJobs() const { return Jobs; } 283 empty()284 bool empty() const { return Jobs.empty(); } size()285 size_type size() const { return Jobs.size(); } begin()286 iterator begin() { return Jobs.begin(); } begin()287 const_iterator begin() const { return Jobs.begin(); } end()288 iterator end() { return Jobs.end(); } end()289 const_iterator end() const { return Jobs.end(); } 290 }; 291 292 } // namespace driver 293 } // namespace clang 294 295 #endif // LLVM_CLANG_DRIVER_JOB_H 296