1 //===--- PrecompiledPreamble.h - Build precompiled preambles ----*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // Helper class to build precompiled preamble. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #ifndef LLVM_CLANG_FRONTEND_PRECOMPILED_PREAMBLE_H 15 #define LLVM_CLANG_FRONTEND_PRECOMPILED_PREAMBLE_H 16 17 #include "clang/Lex/Lexer.h" 18 #include "clang/Lex/Preprocessor.h" 19 #include "llvm/ADT/IntrusiveRefCntPtr.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 namespace vfs { 30 class FileSystem; 31 } 32 } // namespace llvm 33 34 namespace clang { 35 class CompilerInstance; 36 class CompilerInvocation; 37 class DeclGroupRef; 38 class PCHContainerOperations; 39 40 /// Runs lexer to compute suggested preamble bounds. 41 PreambleBounds ComputePreambleBounds(const LangOptions &LangOpts, 42 llvm::MemoryBuffer *Buffer, 43 unsigned MaxLines); 44 45 class PreambleCallbacks; 46 47 /// A class holding a PCH and all information to check whether it is valid to 48 /// reuse the PCH for the subsequent runs. Use BuildPreamble to create PCH and 49 /// CanReusePreamble + AddImplicitPreamble to make use of it. 50 class PrecompiledPreamble { 51 class PCHStorage; 52 struct PreambleFileHash; 53 54 public: 55 /// Try to build PrecompiledPreamble for \p Invocation. See 56 /// BuildPreambleError for possible error codes. 57 /// 58 /// \param Invocation Original CompilerInvocation with options to compile the 59 /// file. 60 /// 61 /// \param MainFileBuffer Buffer with the contents of the main file. 62 /// 63 /// \param Bounds Bounds of the preamble, result of calling 64 /// ComputePreambleBounds. 65 /// 66 /// \param Diagnostics Diagnostics engine to be used while building the 67 /// preamble. 68 /// 69 /// \param VFS An instance of vfs::FileSystem to be used for file 70 /// accesses. 71 /// 72 /// \param PCHContainerOps An instance of PCHContainerOperations. 73 /// 74 /// \param StoreInMemory Store PCH in memory. If false, PCH will be stored in 75 /// a temporary file. 76 /// 77 /// \param Callbacks A set of callbacks to be executed when building 78 /// the preamble. 79 static llvm::ErrorOr<PrecompiledPreamble> 80 Build(const CompilerInvocation &Invocation, 81 const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds, 82 DiagnosticsEngine &Diagnostics, 83 IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, 84 std::shared_ptr<PCHContainerOperations> PCHContainerOps, 85 bool StoreInMemory, PreambleCallbacks &Callbacks); 86 87 PrecompiledPreamble(PrecompiledPreamble &&) = default; 88 PrecompiledPreamble &operator=(PrecompiledPreamble &&) = default; 89 90 /// PreambleBounds used to build the preamble. 91 PreambleBounds getBounds() const; 92 93 /// Returns the size, in bytes, that preamble takes on disk or in memory. 94 /// For on-disk preambles returns 0 if filesystem operations fail. Intended to 95 /// be used for logging and debugging purposes only. 96 std::size_t getSize() const; 97 98 /// Check whether PrecompiledPreamble can be reused for the new contents(\p 99 /// MainFileBuffer) of the main file. 100 bool CanReuse(const CompilerInvocation &Invocation, 101 const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds, 102 llvm::vfs::FileSystem *VFS) const; 103 104 /// Changes options inside \p CI to use PCH from this preamble. Also remaps 105 /// main file to \p MainFileBuffer and updates \p VFS to ensure the preamble 106 /// is accessible. 107 /// Requires that CanReuse() is true. 108 /// For in-memory preambles, PrecompiledPreamble instance continues to own the 109 /// MemoryBuffer with the Preamble after this method returns. The caller is 110 /// responsible for making sure the PrecompiledPreamble instance outlives the 111 /// compiler run and the AST that will be using the PCH. 112 void AddImplicitPreamble(CompilerInvocation &CI, 113 IntrusiveRefCntPtr<llvm::vfs::FileSystem> &VFS, 114 llvm::MemoryBuffer *MainFileBuffer) const; 115 116 /// Configure \p CI to use this preamble. 117 /// Like AddImplicitPreamble, but doesn't assume CanReuse() is true. 118 /// If this preamble does not match the file, it may parse differently. 119 void OverridePreamble(CompilerInvocation &CI, 120 IntrusiveRefCntPtr<llvm::vfs::FileSystem> &VFS, 121 llvm::MemoryBuffer *MainFileBuffer) const; 122 123 private: 124 PrecompiledPreamble(PCHStorage Storage, std::vector<char> PreambleBytes, 125 bool PreambleEndsAtStartOfLine, 126 llvm::StringMap<PreambleFileHash> FilesInPreamble); 127 128 /// A temp file that would be deleted on destructor call. If destructor is not 129 /// called for any reason, the file will be deleted at static objects' 130 /// destruction. 131 /// An assertion will fire if two TempPCHFiles are created with the same name, 132 /// so it's not intended to be used outside preamble-handling. 133 class TempPCHFile { 134 public: 135 // A main method used to construct TempPCHFile. 136 static llvm::ErrorOr<TempPCHFile> CreateNewPreamblePCHFile(); 137 138 /// Call llvm::sys::fs::createTemporaryFile to create a new temporary file. 139 static llvm::ErrorOr<TempPCHFile> createInSystemTempDir(const Twine &Prefix, 140 StringRef Suffix); 141 /// Create a new instance of TemporaryFile for file at \p Path. Use with 142 /// extreme caution, there's an assertion checking that there's only a 143 /// single instance of TempPCHFile alive for each path. 144 static llvm::ErrorOr<TempPCHFile> createFromCustomPath(const Twine &Path); 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::MemoryBuffer *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 /// The contents of the file that was used to precompile the preamble. Only 256 /// contains first PreambleBounds::Size bytes. Used to compare if the relevant 257 /// part of the file has not changed, so that preamble can be reused. 258 std::vector<char> PreambleBytes; 259 /// See PreambleBounds::PreambleEndsAtStartOfLine 260 bool PreambleEndsAtStartOfLine; 261 }; 262 263 /// A set of callbacks to gather useful information while building a preamble. 264 class PreambleCallbacks { 265 public: 266 virtual ~PreambleCallbacks() = default; 267 268 /// Called before FrontendAction::BeginSourceFile. 269 /// Can be used to store references to various CompilerInstance fields 270 /// (e.g. SourceManager) that may be interesting to the consumers of other 271 /// callbacks. 272 virtual void BeforeExecute(CompilerInstance &CI); 273 /// Called after FrontendAction::Execute(), but before 274 /// FrontendAction::EndSourceFile(). Can be used to transfer ownership of 275 /// various CompilerInstance fields before they are destroyed. 276 virtual void AfterExecute(CompilerInstance &CI); 277 /// Called after PCH has been emitted. \p Writer may be used to retrieve 278 /// information about AST, serialized in PCH. 279 virtual void AfterPCHEmitted(ASTWriter &Writer); 280 /// Called for each TopLevelDecl. 281 /// NOTE: To allow more flexibility a custom ASTConsumer could probably be 282 /// used instead, but having only this method allows a simpler API. 283 virtual void HandleTopLevelDecl(DeclGroupRef DG); 284 /// Creates wrapper class for PPCallbacks so we can also process information 285 /// about includes that are inside of a preamble 286 virtual std::unique_ptr<PPCallbacks> createPPCallbacks(); 287 }; 288 289 enum class BuildPreambleError { 290 CouldntCreateTempFile = 1, 291 CouldntCreateTargetInfo, 292 BeginSourceFileFailed, 293 CouldntEmitPCH 294 }; 295 296 class BuildPreambleErrorCategory final : public std::error_category { 297 public: 298 const char *name() const noexcept override; 299 std::string message(int condition) const override; 300 }; 301 302 std::error_code make_error_code(BuildPreambleError Error); 303 } // namespace clang 304 305 namespace std { 306 template <> 307 struct is_error_code_enum<clang::BuildPreambleError> : std::true_type {}; 308 } // namespace std 309 310 #endif 311