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