1 //===- Utils.h - Misc utilities for the front-end ---------------*- 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 // This header contains miscellaneous utilities for various front-end actions. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #ifndef LLVM_CLANG_FRONTEND_UTILS_H 14 #define LLVM_CLANG_FRONTEND_UTILS_H 15 16 #include "clang/Basic/Diagnostic.h" 17 #include "clang/Basic/LLVM.h" 18 #include "clang/Frontend/DependencyOutputOptions.h" 19 #include "llvm/ADT/ArrayRef.h" 20 #include "llvm/ADT/IntrusiveRefCntPtr.h" 21 #include "llvm/ADT/StringMap.h" 22 #include "llvm/ADT/StringRef.h" 23 #include "llvm/ADT/StringSet.h" 24 #include "llvm/Option/OptSpecifier.h" 25 #include "llvm/Support/VirtualFileSystem.h" 26 #include <cstdint> 27 #include <memory> 28 #include <string> 29 #include <system_error> 30 #include <utility> 31 #include <vector> 32 33 namespace llvm { 34 35 class Triple; 36 37 namespace opt { 38 39 class ArgList; 40 41 } // namespace opt 42 43 } // namespace llvm 44 45 namespace clang { 46 47 class ASTReader; 48 class CompilerInstance; 49 class CompilerInvocation; 50 class DiagnosticsEngine; 51 class ExternalSemaSource; 52 class FrontendOptions; 53 class HeaderSearch; 54 class HeaderSearchOptions; 55 class LangOptions; 56 class PCHContainerReader; 57 class Preprocessor; 58 class PreprocessorOptions; 59 class PreprocessorOutputOptions; 60 61 /// Apply the header search options to get given HeaderSearch object. 62 void ApplyHeaderSearchOptions(HeaderSearch &HS, 63 const HeaderSearchOptions &HSOpts, 64 const LangOptions &Lang, 65 const llvm::Triple &triple); 66 67 /// InitializePreprocessor - Initialize the preprocessor getting it and the 68 /// environment ready to process a single file. 69 void InitializePreprocessor(Preprocessor &PP, const PreprocessorOptions &PPOpts, 70 const PCHContainerReader &PCHContainerRdr, 71 const FrontendOptions &FEOpts); 72 73 /// DoPrintPreprocessedInput - Implement -E mode. 74 void DoPrintPreprocessedInput(Preprocessor &PP, raw_ostream *OS, 75 const PreprocessorOutputOptions &Opts); 76 77 /// An interface for collecting the dependencies of a compilation. Users should 78 /// use \c attachToPreprocessor and \c attachToASTReader to get all of the 79 /// dependencies. 80 /// FIXME: Migrate DependencyGraphGen to use this interface. 81 class DependencyCollector { 82 public: 83 virtual ~DependencyCollector(); 84 85 virtual void attachToPreprocessor(Preprocessor &PP); 86 virtual void attachToASTReader(ASTReader &R); 87 ArrayRef<std::string> getDependencies() const { return Dependencies; } 88 89 /// Called when a new file is seen. Return true if \p Filename should be added 90 /// to the list of dependencies. 91 /// 92 /// The default implementation ignores <built-in> and system files. 93 virtual bool sawDependency(StringRef Filename, bool FromModule, 94 bool IsSystem, bool IsModuleFile, bool IsMissing); 95 96 /// Called when the end of the main file is reached. 97 virtual void finishedMainFile(DiagnosticsEngine &Diags) {} 98 99 /// Return true if system files should be passed to sawDependency(). 100 virtual bool needSystemDependencies() { return false; } 101 102 // implementation detail 103 /// Add a dependency \p Filename if it has not been seen before and 104 /// sawDependency() returns true. 105 void maybeAddDependency(StringRef Filename, bool FromModule, bool IsSystem, 106 bool IsModuleFile, bool IsMissing); 107 108 protected: 109 /// Return true if the filename was added to the list of dependencies, false 110 /// otherwise. 111 bool addDependency(StringRef Filename); 112 113 private: 114 llvm::StringSet<> Seen; 115 std::vector<std::string> Dependencies; 116 }; 117 118 /// Builds a dependency file when attached to a Preprocessor (for includes) and 119 /// ASTReader (for module imports), and writes it out at the end of processing 120 /// a source file. Users should attach to the ast reader whenever a module is 121 /// loaded. 122 class DependencyFileGenerator : public DependencyCollector { 123 public: 124 DependencyFileGenerator(const DependencyOutputOptions &Opts); 125 126 void attachToPreprocessor(Preprocessor &PP) override; 127 128 void finishedMainFile(DiagnosticsEngine &Diags) override; 129 130 bool needSystemDependencies() final override { return IncludeSystemHeaders; } 131 132 bool sawDependency(StringRef Filename, bool FromModule, bool IsSystem, 133 bool IsModuleFile, bool IsMissing) final override; 134 135 protected: 136 void outputDependencyFile(llvm::raw_ostream &OS); 137 138 private: 139 void outputDependencyFile(DiagnosticsEngine &Diags); 140 141 std::string OutputFile; 142 std::vector<std::string> Targets; 143 bool IncludeSystemHeaders; 144 bool PhonyTarget; 145 bool AddMissingHeaderDeps; 146 bool SeenMissingHeader; 147 bool IncludeModuleFiles; 148 DependencyOutputFormat OutputFormat; 149 unsigned InputFileIndex; 150 }; 151 152 /// Collects the dependencies for imported modules into a directory. Users 153 /// should attach to the AST reader whenever a module is loaded. 154 class ModuleDependencyCollector : public DependencyCollector { 155 std::string DestDir; 156 bool HasErrors = false; 157 llvm::StringSet<> Seen; 158 llvm::vfs::YAMLVFSWriter VFSWriter; 159 llvm::StringMap<std::string> SymLinkMap; 160 161 bool getRealPath(StringRef SrcPath, SmallVectorImpl<char> &Result); 162 std::error_code copyToRoot(StringRef Src, StringRef Dst = {}); 163 164 public: 165 ModuleDependencyCollector(std::string DestDir) 166 : DestDir(std::move(DestDir)) {} 167 ~ModuleDependencyCollector() override { writeFileMap(); } 168 169 StringRef getDest() { return DestDir; } 170 virtual bool insertSeen(StringRef Filename) { return Seen.insert(Filename).second; } 171 virtual void addFile(StringRef Filename, StringRef FileDst = {}); 172 173 virtual void addFileMapping(StringRef VPath, StringRef RPath) { 174 VFSWriter.addFileMapping(VPath, RPath); 175 } 176 177 void attachToPreprocessor(Preprocessor &PP) override; 178 void attachToASTReader(ASTReader &R) override; 179 180 virtual void writeFileMap(); 181 virtual bool hasErrors() { return HasErrors; } 182 }; 183 184 /// AttachDependencyGraphGen - Create a dependency graph generator, and attach 185 /// it to the given preprocessor. 186 void AttachDependencyGraphGen(Preprocessor &PP, StringRef OutputFile, 187 StringRef SysRoot); 188 189 /// AttachHeaderIncludeGen - Create a header include list generator, and attach 190 /// it to the given preprocessor. 191 /// 192 /// \param DepOpts - Options controlling the output. 193 /// \param ShowAllHeaders - If true, show all header information instead of just 194 /// headers following the predefines buffer. This is useful for making sure 195 /// includes mentioned on the command line are also reported, but differs from 196 /// the default behavior used by -H. 197 /// \param OutputPath - If non-empty, a path to write the header include 198 /// information to, instead of writing to stderr. 199 /// \param ShowDepth - Whether to indent to show the nesting of the includes. 200 /// \param MSStyle - Whether to print in cl.exe /showIncludes style. 201 void AttachHeaderIncludeGen(Preprocessor &PP, 202 const DependencyOutputOptions &DepOpts, 203 bool ShowAllHeaders = false, 204 StringRef OutputPath = {}, 205 bool ShowDepth = true, bool MSStyle = false); 206 207 /// The ChainedIncludesSource class converts headers to chained PCHs in 208 /// memory, mainly for testing. 209 IntrusiveRefCntPtr<ExternalSemaSource> 210 createChainedIncludesSource(CompilerInstance &CI, 211 IntrusiveRefCntPtr<ExternalSemaSource> &Reader); 212 213 /// createInvocationFromCommandLine - Construct a compiler invocation object for 214 /// a command line argument vector. 215 /// 216 /// \return A CompilerInvocation, or 0 if none was built for the given 217 /// argument vector. 218 std::unique_ptr<CompilerInvocation> createInvocationFromCommandLine( 219 ArrayRef<const char *> Args, 220 IntrusiveRefCntPtr<DiagnosticsEngine> Diags = 221 IntrusiveRefCntPtr<DiagnosticsEngine>(), 222 IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS = nullptr); 223 224 /// Return the value of the last argument as an integer, or a default. If Diags 225 /// is non-null, emits an error if the argument is given, but non-integral. 226 int getLastArgIntValue(const llvm::opt::ArgList &Args, 227 llvm::opt::OptSpecifier Id, int Default, 228 DiagnosticsEngine *Diags = nullptr); 229 230 inline int getLastArgIntValue(const llvm::opt::ArgList &Args, 231 llvm::opt::OptSpecifier Id, int Default, 232 DiagnosticsEngine &Diags) { 233 return getLastArgIntValue(Args, Id, Default, &Diags); 234 } 235 236 uint64_t getLastArgUInt64Value(const llvm::opt::ArgList &Args, 237 llvm::opt::OptSpecifier Id, uint64_t Default, 238 DiagnosticsEngine *Diags = nullptr); 239 240 inline uint64_t getLastArgUInt64Value(const llvm::opt::ArgList &Args, 241 llvm::opt::OptSpecifier Id, 242 uint64_t Default, 243 DiagnosticsEngine &Diags) { 244 return getLastArgUInt64Value(Args, Id, Default, &Diags); 245 } 246 247 // Frontend timing utils 248 249 /// If the user specifies the -ftime-report argument on an Clang command line 250 /// then the value of this boolean will be true, otherwise false. 251 extern bool FrontendTimesIsEnabled; 252 253 } // namespace clang 254 255 #endif // LLVM_CLANG_FRONTEND_UTILS_H 256