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