PrecompiledPreamble.h revision c9cc9e7d29b8970d8ddb734c88fb62d01e0b7279
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/MD5.h" 21#include <memory> 22#include <system_error> 23#include <type_traits> 24 25namespace llvm { 26class MemoryBuffer; 27} 28 29namespace clang { 30namespace vfs { 31class FileSystem; 32} 33 34class CompilerInstance; 35class CompilerInvocation; 36class DeclGroupRef; 37class PCHContainerOperations; 38 39/// \brief Runs lexer to compute suggested preamble bounds. 40PreambleBounds ComputePreambleBounds(const LangOptions &LangOpts, 41 llvm::MemoryBuffer *Buffer, 42 unsigned MaxLines); 43 44class 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. 49class PrecompiledPreamble { 50 class TempPCHFile; 51 struct PreambleFileHash; 52 53public: 54 /// \brief 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 Callbacks A set of callbacks to be executed when building 74 /// the preamble. 75 static llvm::ErrorOr<PrecompiledPreamble> 76 Build(const CompilerInvocation &Invocation, 77 const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds, 78 DiagnosticsEngine &Diagnostics, IntrusiveRefCntPtr<vfs::FileSystem> VFS, 79 std::shared_ptr<PCHContainerOperations> PCHContainerOps, 80 PreambleCallbacks &Callbacks); 81 82 PrecompiledPreamble(PrecompiledPreamble &&) = default; 83 PrecompiledPreamble &operator=(PrecompiledPreamble &&) = default; 84 85 /// PreambleBounds used to build the preamble. 86 PreambleBounds getBounds() const; 87 88 /// The temporary file path at which the preamble PCH was placed. 89 StringRef GetPCHPath() const { return PCHFile.getFilePath(); } 90 91 /// Check whether PrecompiledPreamble can be reused for the new contents(\p 92 /// MainFileBuffer) of the main file. 93 bool CanReuse(const CompilerInvocation &Invocation, 94 const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds, 95 vfs::FileSystem *VFS) const; 96 97 /// Changes options inside \p CI to use PCH from this preamble. Also remaps 98 /// main file to \p MainFileBuffer. 99 void AddImplicitPreamble(CompilerInvocation &CI, 100 llvm::MemoryBuffer *MainFileBuffer) const; 101 102private: 103 PrecompiledPreamble(TempPCHFile PCHFile, std::vector<char> PreambleBytes, 104 bool PreambleEndsAtStartOfLine, 105 llvm::StringMap<PreambleFileHash> FilesInPreamble); 106 107 /// A temp file that would be deleted on destructor call. If destructor is not 108 /// called for any reason, the file will be deleted at static objects' 109 /// destruction. 110 /// An assertion will fire if two TempPCHFiles are created with the same name, 111 /// so it's not intended to be used outside preamble-handling. 112 class TempPCHFile { 113 public: 114 // A main method used to construct TempPCHFile. 115 static llvm::ErrorOr<TempPCHFile> CreateNewPreamblePCHFile(); 116 117 /// Call llvm::sys::fs::createTemporaryFile to create a new temporary file. 118 static llvm::ErrorOr<TempPCHFile> createInSystemTempDir(const Twine &Prefix, 119 StringRef Suffix); 120 /// Create a new instance of TemporaryFile for file at \p Path. Use with 121 /// extreme caution, there's an assertion checking that there's only a 122 /// single instance of TempPCHFile alive for each path. 123 static llvm::ErrorOr<TempPCHFile> createFromCustomPath(const Twine &Path); 124 125 private: 126 TempPCHFile(std::string FilePath); 127 128 public: 129 TempPCHFile(TempPCHFile &&Other); 130 TempPCHFile &operator=(TempPCHFile &&Other); 131 132 TempPCHFile(const TempPCHFile &) = delete; 133 ~TempPCHFile(); 134 135 /// A path where temporary file is stored. 136 llvm::StringRef getFilePath() const; 137 138 private: 139 void RemoveFileIfPresent(); 140 141 private: 142 llvm::Optional<std::string> FilePath; 143 }; 144 145 /// Data used to determine if a file used in the preamble has been changed. 146 struct PreambleFileHash { 147 /// All files have size set. 148 off_t Size = 0; 149 150 /// Modification time is set for files that are on disk. For memory 151 /// buffers it is zero. 152 time_t ModTime = 0; 153 154 /// Memory buffers have MD5 instead of modification time. We don't 155 /// compute MD5 for on-disk files because we hope that modification time is 156 /// enough to tell if the file was changed. 157 llvm::MD5::MD5Result MD5 = {}; 158 159 static PreambleFileHash createForFile(off_t Size, time_t ModTime); 160 static PreambleFileHash 161 createForMemoryBuffer(const llvm::MemoryBuffer *Buffer); 162 163 friend bool operator==(const PreambleFileHash &LHS, 164 const PreambleFileHash &RHS) { 165 return LHS.Size == RHS.Size && LHS.ModTime == RHS.ModTime && 166 LHS.MD5 == RHS.MD5; 167 } 168 friend bool operator!=(const PreambleFileHash &LHS, 169 const PreambleFileHash &RHS) { 170 return !(LHS == RHS); 171 } 172 }; 173 174 /// Manages the lifetime of temporary file that stores a PCH. 175 TempPCHFile PCHFile; 176 /// Keeps track of the files that were used when computing the 177 /// preamble, with both their buffer size and their modification time. 178 /// 179 /// If any of the files have changed from one compile to the next, 180 /// the preamble must be thrown away. 181 llvm::StringMap<PreambleFileHash> FilesInPreamble; 182 /// The contents of the file that was used to precompile the preamble. Only 183 /// contains first PreambleBounds::Size bytes. Used to compare if the relevant 184 /// part of the file has not changed, so that preamble can be reused. 185 std::vector<char> PreambleBytes; 186 /// See PreambleBounds::PreambleEndsAtStartOfLine 187 bool PreambleEndsAtStartOfLine; 188}; 189 190/// A set of callbacks to gather useful information while building a preamble. 191class PreambleCallbacks { 192public: 193 virtual ~PreambleCallbacks() = default; 194 195 /// Called after FrontendAction::Execute(), but before 196 /// FrontendAction::EndSourceFile(). Can be used to transfer ownership of 197 /// various CompilerInstance fields before they are destroyed. 198 virtual void AfterExecute(CompilerInstance &CI); 199 /// Called after PCH has been emitted. \p Writer may be used to retrieve 200 /// information about AST, serialized in PCH. 201 virtual void AfterPCHEmitted(ASTWriter &Writer); 202 /// Called for each TopLevelDecl. 203 /// NOTE: To allow more flexibility a custom ASTConsumer could probably be 204 /// used instead, but having only this method allows a simpler API. 205 virtual void HandleTopLevelDecl(DeclGroupRef DG); 206 /// Called for each macro defined in the Preamble. 207 /// NOTE: To allow more flexibility a custom PPCallbacks could probably be 208 /// used instead, but having only this method allows a simpler API. 209 virtual void HandleMacroDefined(const Token &MacroNameTok, 210 const MacroDirective *MD); 211}; 212 213enum class BuildPreambleError { 214 PreambleIsEmpty = 1, 215 CouldntCreateTempFile, 216 CouldntCreateTargetInfo, 217 CouldntCreateVFSOverlay, 218 BeginSourceFileFailed, 219 CouldntEmitPCH 220}; 221 222class BuildPreambleErrorCategory final : public std::error_category { 223public: 224 const char *name() const noexcept override; 225 std::string message(int condition) const override; 226}; 227 228std::error_code make_error_code(BuildPreambleError Error); 229} // namespace clang 230 231namespace std { 232template <> 233struct is_error_code_enum<clang::BuildPreambleError> : std::true_type {}; 234} // namespace std 235 236#endif 237