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 /// The list of program arguments (not including the implicit first 120 /// argument, which will be the executable). 121 llvm::opt::ArgStringList Arguments; 122 123 /// The list of program inputs. 124 std::vector<InputInfo> InputInfoList; 125 126 /// The list of program arguments which are outputs. May be empty. 127 std::vector<std::string> OutputFilenames; 128 129 /// Response file name, if this command is set to use one, or nullptr 130 /// otherwise 131 const char *ResponseFile = nullptr; 132 133 /// The input file list in case we need to emit a file list instead of a 134 /// proper response file 135 llvm::opt::ArgStringList InputFileList; 136 137 /// String storage if we need to create a new argument to specify a response 138 /// file 139 std::string ResponseFileFlag; 140 141 /// See Command::setEnvironment 142 std::vector<const char *> Environment; 143 144 /// Optional redirection for stdin, stdout, stderr. 145 std::vector<std::optional<std::string>> RedirectFiles; 146 147 /// Information on executable run provided by OS. 148 mutable std::optional<llvm::sys::ProcessStatistics> ProcStat; 149 150 /// When a response file is needed, we try to put most arguments in an 151 /// exclusive file, while others remains as regular command line arguments. 152 /// This functions fills a vector with the regular command line arguments, 153 /// argv, excluding the ones passed in a response file. 154 void buildArgvForResponseFile(llvm::SmallVectorImpl<const char *> &Out) const; 155 156 /// Encodes an array of C strings into a single string separated by whitespace. 157 /// This function will also put in quotes arguments that have whitespaces and 158 /// will escape the regular backslashes (used in Windows paths) and quotes. 159 /// The results are the contents of a response file, written into a raw_ostream. 160 void writeResponseFile(raw_ostream &OS) const; 161 162 public: 163 /// Whether to print the input filenames when executing. 164 bool PrintInputFilenames = false; 165 166 /// Whether the command will be executed in this process or not. 167 bool InProcess = false; 168 169 Command(const Action &Source, const Tool &Creator, 170 ResponseFileSupport ResponseSupport, const char *Executable, 171 const llvm::opt::ArgStringList &Arguments, ArrayRef<InputInfo> Inputs, 172 ArrayRef<InputInfo> Outputs = std::nullopt); 173 // FIXME: This really shouldn't be copyable, but is currently copied in some 174 // error handling in Driver::generateCompilationDiagnostics. 175 Command(const Command &) = default; 176 virtual ~Command() = default; 177 178 virtual void Print(llvm::raw_ostream &OS, const char *Terminator, bool Quote, 179 CrashReportInfo *CrashInfo = nullptr) const; 180 181 virtual int Execute(ArrayRef<std::optional<StringRef>> Redirects, 182 std::string *ErrMsg, bool *ExecutionFailed) const; 183 184 /// getSource - Return the Action which caused the creation of this job. getSource()185 const Action &getSource() const { return Source; } 186 187 /// getCreator - Return the Tool which caused the creation of this job. getCreator()188 const Tool &getCreator() const { return Creator; } 189 190 /// Returns the kind of response file supported by the current invocation. getResponseFileSupport()191 const ResponseFileSupport &getResponseFileSupport() { 192 return ResponseSupport; 193 } 194 195 /// Set to pass arguments via a response file when launching the command 196 void setResponseFile(const char *FileName); 197 198 /// Set an input file list, necessary if you specified an RF_FileList response 199 /// file support. setInputFileList(llvm::opt::ArgStringList List)200 void setInputFileList(llvm::opt::ArgStringList List) { 201 InputFileList = std::move(List); 202 } 203 204 /// Sets the environment to be used by the new process. 205 /// \param NewEnvironment An array of environment variables. 206 /// \remark If the environment remains unset, then the environment 207 /// from the parent process will be used. 208 virtual void setEnvironment(llvm::ArrayRef<const char *> NewEnvironment); 209 210 void 211 setRedirectFiles(const std::vector<std::optional<std::string>> &Redirects); 212 replaceArguments(llvm::opt::ArgStringList List)213 void replaceArguments(llvm::opt::ArgStringList List) { 214 Arguments = std::move(List); 215 } 216 replaceExecutable(const char * Exe)217 void replaceExecutable(const char *Exe) { Executable = Exe; } 218 getExecutable()219 const char *getExecutable() const { return Executable; } 220 getArguments()221 const llvm::opt::ArgStringList &getArguments() const { return Arguments; } 222 getInputInfos()223 const std::vector<InputInfo> &getInputInfos() const { return InputInfoList; } 224 getOutputFilenames()225 const std::vector<std::string> &getOutputFilenames() const { 226 return OutputFilenames; 227 } 228 getProcessStatistics()229 std::optional<llvm::sys::ProcessStatistics> getProcessStatistics() const { 230 return ProcStat; 231 } 232 233 protected: 234 /// Optionally print the filenames to be compiled 235 void PrintFileNames() const; 236 }; 237 238 /// Use the CC1 tool callback when available, to avoid creating a new process 239 class CC1Command : public Command { 240 public: 241 CC1Command(const Action &Source, const Tool &Creator, 242 ResponseFileSupport ResponseSupport, const char *Executable, 243 const llvm::opt::ArgStringList &Arguments, 244 ArrayRef<InputInfo> Inputs, 245 ArrayRef<InputInfo> Outputs = std::nullopt); 246 247 void Print(llvm::raw_ostream &OS, const char *Terminator, bool Quote, 248 CrashReportInfo *CrashInfo = nullptr) const override; 249 250 int Execute(ArrayRef<std::optional<StringRef>> Redirects, std::string *ErrMsg, 251 bool *ExecutionFailed) const override; 252 253 void setEnvironment(llvm::ArrayRef<const char *> NewEnvironment) override; 254 }; 255 256 /// Like Command, but always pretends that the wrapped command succeeded. 257 class ForceSuccessCommand : public Command { 258 public: 259 ForceSuccessCommand(const Action &Source_, const Tool &Creator_, 260 ResponseFileSupport ResponseSupport, 261 const char *Executable_, 262 const llvm::opt::ArgStringList &Arguments_, 263 ArrayRef<InputInfo> Inputs, 264 ArrayRef<InputInfo> Outputs = std::nullopt); 265 266 void Print(llvm::raw_ostream &OS, const char *Terminator, bool Quote, 267 CrashReportInfo *CrashInfo = nullptr) const override; 268 269 int Execute(ArrayRef<std::optional<StringRef>> Redirects, std::string *ErrMsg, 270 bool *ExecutionFailed) const override; 271 }; 272 273 /// JobList - A sequence of jobs to perform. 274 class JobList { 275 public: 276 using list_type = SmallVector<std::unique_ptr<Command>, 4>; 277 using size_type = list_type::size_type; 278 using iterator = llvm::pointee_iterator<list_type::iterator>; 279 using const_iterator = llvm::pointee_iterator<list_type::const_iterator>; 280 281 private: 282 list_type Jobs; 283 284 public: 285 void Print(llvm::raw_ostream &OS, const char *Terminator, 286 bool Quote, CrashReportInfo *CrashInfo = nullptr) const; 287 288 /// Add a job to the list (taking ownership). addJob(std::unique_ptr<Command> J)289 void addJob(std::unique_ptr<Command> J) { Jobs.push_back(std::move(J)); } 290 291 /// Clear the job list. 292 void clear(); 293 getJobs()294 const list_type &getJobs() const { return Jobs; } 295 empty()296 bool empty() const { return Jobs.empty(); } size()297 size_type size() const { return Jobs.size(); } begin()298 iterator begin() { return Jobs.begin(); } begin()299 const_iterator begin() const { return Jobs.begin(); } end()300 iterator end() { return Jobs.end(); } end()301 const_iterator end() const { return Jobs.end(); } 302 }; 303 304 } // namespace driver 305 } // namespace clang 306 307 #endif // LLVM_CLANG_DRIVER_JOB_H 308