1 //===--- PrecompiledPreamble.h - Build precompiled preambles ----*- 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 // Helper class to build precompiled preamble. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #ifndef LLVM_CLANG_FRONTEND_PRECOMPILEDPREAMBLE_H 14 #define LLVM_CLANG_FRONTEND_PRECOMPILEDPREAMBLE_H 15 16 #include "clang/Lex/Lexer.h" 17 #include "clang/Lex/Preprocessor.h" 18 #include "llvm/ADT/IntrusiveRefCntPtr.h" 19 #include "llvm/ADT/StringRef.h" 20 #include "llvm/Support/MD5.h" 21 #include <cstddef> 22 #include <memory> 23 #include <system_error> 24 #include <type_traits> 25 26 namespace llvm { 27 class MemoryBuffer; 28 class MemoryBufferRef; 29 namespace vfs { 30 class FileSystem; 31 } 32 } // namespace llvm 33 34 namespace clang { 35 class CompilerInstance; 36 class CompilerInvocation; 37 class Decl; 38 class DeclGroupRef; 39 class PCHContainerOperations; 40 41 /// Runs lexer to compute suggested preamble bounds. 42 PreambleBounds ComputePreambleBounds(const LangOptions &LangOpts, 43 const llvm::MemoryBufferRef &Buffer, 44 unsigned MaxLines); 45 46 class PreambleCallbacks; 47 48 /// A class holding a PCH and all information to check whether it is valid to 49 /// reuse the PCH for the subsequent runs. Use BuildPreamble to create PCH and 50 /// CanReusePreamble + AddImplicitPreamble to make use of it. 51 class PrecompiledPreamble { 52 class PCHStorage; 53 struct PreambleFileHash; 54 55 public: 56 /// Try to build PrecompiledPreamble for \p Invocation. See 57 /// BuildPreambleError for possible error codes. 58 /// 59 /// \param Invocation Original CompilerInvocation with options to compile the 60 /// file. 61 /// 62 /// \param MainFileBuffer Buffer with the contents of the main file. 63 /// 64 /// \param Bounds Bounds of the preamble, result of calling 65 /// ComputePreambleBounds. 66 /// 67 /// \param Diagnostics Diagnostics engine to be used while building the 68 /// preamble. 69 /// 70 /// \param VFS An instance of vfs::FileSystem to be used for file 71 /// accesses. 72 /// 73 /// \param PCHContainerOps An instance of PCHContainerOperations. 74 /// 75 /// \param StoreInMemory Store PCH in memory. If false, PCH will be stored in 76 /// a temporary file. 77 /// 78 /// \param StoragePath The path to a directory, in which to create a temporary 79 /// file to store PCH in. If empty, the default system temporary directory is 80 /// used. This parameter is ignored if \p StoreInMemory is true. 81 /// 82 /// \param Callbacks A set of callbacks to be executed when building 83 /// the preamble. 84 static llvm::ErrorOr<PrecompiledPreamble> 85 Build(const CompilerInvocation &Invocation, 86 const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds, 87 DiagnosticsEngine &Diagnostics, 88 IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, 89 std::shared_ptr<PCHContainerOperations> PCHContainerOps, 90 bool StoreInMemory, StringRef StoragePath, 91 PreambleCallbacks &Callbacks); 92 93 PrecompiledPreamble(PrecompiledPreamble &&); 94 PrecompiledPreamble &operator=(PrecompiledPreamble &&); 95 ~PrecompiledPreamble(); 96 97 /// PreambleBounds used to build the preamble. 98 PreambleBounds getBounds() const; 99 100 /// Returns the size, in bytes, that preamble takes on disk or in memory. 101 /// For on-disk preambles returns 0 if filesystem operations fail. Intended to 102 /// be used for logging and debugging purposes only. 103 std::size_t getSize() const; 104 105 /// Returned string is not null-terminated. getContents()106 llvm::StringRef getContents() const { 107 return {PreambleBytes.data(), PreambleBytes.size()}; 108 } 109 110 /// Check whether PrecompiledPreamble can be reused for the new contents(\p 111 /// MainFileBuffer) of the main file. 112 bool CanReuse(const CompilerInvocation &Invocation, 113 const llvm::MemoryBufferRef &MainFileBuffer, 114 PreambleBounds Bounds, llvm::vfs::FileSystem &VFS) const; 115 116 /// Changes options inside \p CI to use PCH from this preamble. Also remaps 117 /// main file to \p MainFileBuffer and updates \p VFS to ensure the preamble 118 /// is accessible. 119 /// Requires that CanReuse() is true. 120 /// For in-memory preambles, PrecompiledPreamble instance continues to own the 121 /// MemoryBuffer with the Preamble after this method returns. The caller is 122 /// responsible for making sure the PrecompiledPreamble instance outlives the 123 /// compiler run and the AST that will be using the PCH. 124 void AddImplicitPreamble(CompilerInvocation &CI, 125 IntrusiveRefCntPtr<llvm::vfs::FileSystem> &VFS, 126 llvm::MemoryBuffer *MainFileBuffer) const; 127 128 /// Configure \p CI to use this preamble. 129 /// Like AddImplicitPreamble, but doesn't assume CanReuse() is true. 130 /// If this preamble does not match the file, it may parse differently. 131 void OverridePreamble(CompilerInvocation &CI, 132 IntrusiveRefCntPtr<llvm::vfs::FileSystem> &VFS, 133 llvm::MemoryBuffer *MainFileBuffer) const; 134 135 private: 136 PrecompiledPreamble(std::unique_ptr<PCHStorage> Storage, 137 std::vector<char> PreambleBytes, 138 bool PreambleEndsAtStartOfLine, 139 llvm::StringMap<PreambleFileHash> FilesInPreamble, 140 llvm::StringSet<> MissingFiles); 141 142 /// Data used to determine if a file used in the preamble has been changed. 143 struct PreambleFileHash { 144 /// All files have size set. 145 off_t Size = 0; 146 147 /// Modification time is set for files that are on disk. For memory 148 /// buffers it is zero. 149 time_t ModTime = 0; 150 151 /// Memory buffers have MD5 instead of modification time. We don't 152 /// compute MD5 for on-disk files because we hope that modification time is 153 /// enough to tell if the file was changed. 154 llvm::MD5::MD5Result MD5 = {}; 155 156 static PreambleFileHash createForFile(off_t Size, time_t ModTime); 157 static PreambleFileHash 158 createForMemoryBuffer(const llvm::MemoryBufferRef &Buffer); 159 160 friend bool operator==(const PreambleFileHash &LHS, 161 const PreambleFileHash &RHS) { 162 return LHS.Size == RHS.Size && LHS.ModTime == RHS.ModTime && 163 LHS.MD5 == RHS.MD5; 164 } 165 friend bool operator!=(const PreambleFileHash &LHS, 166 const PreambleFileHash &RHS) { 167 return !(LHS == RHS); 168 } 169 }; 170 171 /// Helper function to set up PCH for the preamble into \p CI and \p VFS to 172 /// with the specified \p Bounds. 173 void configurePreamble(PreambleBounds Bounds, CompilerInvocation &CI, 174 IntrusiveRefCntPtr<llvm::vfs::FileSystem> &VFS, 175 llvm::MemoryBuffer *MainFileBuffer) const; 176 177 /// Sets up the PreprocessorOptions and changes VFS, so that PCH stored in \p 178 /// Storage is accessible to clang. This method is an implementation detail of 179 /// AddImplicitPreamble. 180 static void 181 setupPreambleStorage(const PCHStorage &Storage, 182 PreprocessorOptions &PreprocessorOpts, 183 IntrusiveRefCntPtr<llvm::vfs::FileSystem> &VFS); 184 185 /// Manages the memory buffer or temporary file that stores the PCH. 186 std::unique_ptr<PCHStorage> Storage; 187 /// Keeps track of the files that were used when computing the 188 /// preamble, with both their buffer size and their modification time. 189 /// 190 /// If any of the files have changed from one compile to the next, 191 /// the preamble must be thrown away. 192 llvm::StringMap<PreambleFileHash> FilesInPreamble; 193 /// Files that were not found during preamble building. If any of these now 194 /// exist then the preamble should not be reused. 195 /// 196 /// Storing *all* the missing files that could invalidate the preamble would 197 /// make it too expensive to revalidate (when the include path has many 198 /// entries, each #include will miss half of them on average). 199 /// Instead, we track only files that could have satisfied an #include that 200 /// was ultimately not found. 201 llvm::StringSet<> MissingFiles; 202 /// The contents of the file that was used to precompile the preamble. Only 203 /// contains first PreambleBounds::Size bytes. Used to compare if the relevant 204 /// part of the file has not changed, so that preamble can be reused. 205 std::vector<char> PreambleBytes; 206 /// See PreambleBounds::PreambleEndsAtStartOfLine 207 bool PreambleEndsAtStartOfLine; 208 }; 209 210 /// A set of callbacks to gather useful information while building a preamble. 211 class PreambleCallbacks { 212 public: 213 virtual ~PreambleCallbacks() = default; 214 215 /// Called before FrontendAction::Execute. 216 /// Can be used to store references to various CompilerInstance fields 217 /// (e.g. SourceManager) that may be interesting to the consumers of other 218 /// callbacks. 219 virtual void BeforeExecute(CompilerInstance &CI); 220 /// Called after FrontendAction::Execute(), but before 221 /// FrontendAction::EndSourceFile(). Can be used to transfer ownership of 222 /// various CompilerInstance fields before they are destroyed. 223 virtual void AfterExecute(CompilerInstance &CI); 224 /// Called after PCH has been emitted. \p Writer may be used to retrieve 225 /// information about AST, serialized in PCH. 226 virtual void AfterPCHEmitted(ASTWriter &Writer); 227 /// Called for each TopLevelDecl. 228 /// NOTE: To allow more flexibility a custom ASTConsumer could probably be 229 /// used instead, but having only this method allows a simpler API. 230 virtual void HandleTopLevelDecl(DeclGroupRef DG); 231 /// Creates wrapper class for PPCallbacks so we can also process information 232 /// about includes that are inside of a preamble. Called after BeforeExecute. 233 virtual std::unique_ptr<PPCallbacks> createPPCallbacks(); 234 /// The returned CommentHandler will be added to the preprocessor if not null. 235 virtual CommentHandler *getCommentHandler(); 236 /// Determines which function bodies are parsed, by default skips everything. 237 /// Only used if FrontendOpts::SkipFunctionBodies is true. 238 /// See ASTConsumer::shouldSkipFunctionBody. shouldSkipFunctionBody(Decl * D)239 virtual bool shouldSkipFunctionBody(Decl *D) { return true; } 240 }; 241 242 enum class BuildPreambleError { 243 CouldntCreateTempFile = 1, 244 CouldntCreateTargetInfo, 245 BeginSourceFileFailed, 246 CouldntEmitPCH, 247 BadInputs 248 }; 249 250 class BuildPreambleErrorCategory final : public std::error_category { 251 public: 252 const char *name() const noexcept override; 253 std::string message(int condition) const override; 254 }; 255 256 std::error_code make_error_code(BuildPreambleError Error); 257 } // namespace clang 258 259 template <> 260 struct std::is_error_code_enum<clang::BuildPreambleError> : std::true_type {}; 261 262 #endif 263