Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 14 | pmbaty | 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 Callbacks A set of callbacks to be executed when building |
||
| 79 | /// the preamble. |
||
| 80 | static llvm::ErrorOr<PrecompiledPreamble> |
||
| 81 | Build(const CompilerInvocation &Invocation, |
||
| 82 | const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds, |
||
| 83 | DiagnosticsEngine &Diagnostics, |
||
| 84 | IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, |
||
| 85 | std::shared_ptr<PCHContainerOperations> PCHContainerOps, |
||
| 86 | bool StoreInMemory, PreambleCallbacks &Callbacks); |
||
| 87 | |||
| 88 | PrecompiledPreamble(PrecompiledPreamble &&); |
||
| 89 | PrecompiledPreamble &operator=(PrecompiledPreamble &&); |
||
| 90 | ~PrecompiledPreamble(); |
||
| 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(std::unique_ptr<PCHStorage> Storage, |
||
| 132 | std::vector<char> PreambleBytes, |
||
| 133 | bool PreambleEndsAtStartOfLine, |
||
| 134 | llvm::StringMap<PreambleFileHash> FilesInPreamble, |
||
| 135 | llvm::StringSet<> MissingFiles); |
||
| 136 | |||
| 137 | /// Data used to determine if a file used in the preamble has been changed. |
||
| 138 | struct PreambleFileHash { |
||
| 139 | /// All files have size set. |
||
| 140 | off_t Size = 0; |
||
| 141 | |||
| 142 | /// Modification time is set for files that are on disk. For memory |
||
| 143 | /// buffers it is zero. |
||
| 144 | time_t ModTime = 0; |
||
| 145 | |||
| 146 | /// Memory buffers have MD5 instead of modification time. We don't |
||
| 147 | /// compute MD5 for on-disk files because we hope that modification time is |
||
| 148 | /// enough to tell if the file was changed. |
||
| 149 | llvm::MD5::MD5Result MD5 = {}; |
||
| 150 | |||
| 151 | static PreambleFileHash createForFile(off_t Size, time_t ModTime); |
||
| 152 | static PreambleFileHash |
||
| 153 | createForMemoryBuffer(const llvm::MemoryBufferRef &Buffer); |
||
| 154 | |||
| 155 | friend bool operator==(const PreambleFileHash &LHS, |
||
| 156 | const PreambleFileHash &RHS) { |
||
| 157 | return LHS.Size == RHS.Size && LHS.ModTime == RHS.ModTime && |
||
| 158 | LHS.MD5 == RHS.MD5; |
||
| 159 | } |
||
| 160 | friend bool operator!=(const PreambleFileHash &LHS, |
||
| 161 | const PreambleFileHash &RHS) { |
||
| 162 | return !(LHS == RHS); |
||
| 163 | } |
||
| 164 | }; |
||
| 165 | |||
| 166 | /// Helper function to set up PCH for the preamble into \p CI and \p VFS to |
||
| 167 | /// with the specified \p Bounds. |
||
| 168 | void configurePreamble(PreambleBounds Bounds, CompilerInvocation &CI, |
||
| 169 | IntrusiveRefCntPtr<llvm::vfs::FileSystem> &VFS, |
||
| 170 | llvm::MemoryBuffer *MainFileBuffer) const; |
||
| 171 | |||
| 172 | /// Sets up the PreprocessorOptions and changes VFS, so that PCH stored in \p |
||
| 173 | /// Storage is accessible to clang. This method is an implementation detail of |
||
| 174 | /// AddImplicitPreamble. |
||
| 175 | static void |
||
| 176 | setupPreambleStorage(const PCHStorage &Storage, |
||
| 177 | PreprocessorOptions &PreprocessorOpts, |
||
| 178 | IntrusiveRefCntPtr<llvm::vfs::FileSystem> &VFS); |
||
| 179 | |||
| 180 | /// Manages the memory buffer or temporary file that stores the PCH. |
||
| 181 | std::unique_ptr<PCHStorage> Storage; |
||
| 182 | /// Keeps track of the files that were used when computing the |
||
| 183 | /// preamble, with both their buffer size and their modification time. |
||
| 184 | /// |
||
| 185 | /// If any of the files have changed from one compile to the next, |
||
| 186 | /// the preamble must be thrown away. |
||
| 187 | llvm::StringMap<PreambleFileHash> FilesInPreamble; |
||
| 188 | /// Files that were not found during preamble building. If any of these now |
||
| 189 | /// exist then the preamble should not be reused. |
||
| 190 | /// |
||
| 191 | /// Storing *all* the missing files that could invalidate the preamble would |
||
| 192 | /// make it too expensive to revalidate (when the include path has many |
||
| 193 | /// entries, each #include will miss half of them on average). |
||
| 194 | /// Instead, we track only files that could have satisfied an #include that |
||
| 195 | /// was ultimately not found. |
||
| 196 | llvm::StringSet<> MissingFiles; |
||
| 197 | /// The contents of the file that was used to precompile the preamble. Only |
||
| 198 | /// contains first PreambleBounds::Size bytes. Used to compare if the relevant |
||
| 199 | /// part of the file has not changed, so that preamble can be reused. |
||
| 200 | std::vector<char> PreambleBytes; |
||
| 201 | /// See PreambleBounds::PreambleEndsAtStartOfLine |
||
| 202 | bool PreambleEndsAtStartOfLine; |
||
| 203 | }; |
||
| 204 | |||
| 205 | /// A set of callbacks to gather useful information while building a preamble. |
||
| 206 | class PreambleCallbacks { |
||
| 207 | public: |
||
| 208 | virtual ~PreambleCallbacks() = default; |
||
| 209 | |||
| 210 | /// Called before FrontendAction::Execute. |
||
| 211 | /// Can be used to store references to various CompilerInstance fields |
||
| 212 | /// (e.g. SourceManager) that may be interesting to the consumers of other |
||
| 213 | /// callbacks. |
||
| 214 | virtual void BeforeExecute(CompilerInstance &CI); |
||
| 215 | /// Called after FrontendAction::Execute(), but before |
||
| 216 | /// FrontendAction::EndSourceFile(). Can be used to transfer ownership of |
||
| 217 | /// various CompilerInstance fields before they are destroyed. |
||
| 218 | virtual void AfterExecute(CompilerInstance &CI); |
||
| 219 | /// Called after PCH has been emitted. \p Writer may be used to retrieve |
||
| 220 | /// information about AST, serialized in PCH. |
||
| 221 | virtual void AfterPCHEmitted(ASTWriter &Writer); |
||
| 222 | /// Called for each TopLevelDecl. |
||
| 223 | /// NOTE: To allow more flexibility a custom ASTConsumer could probably be |
||
| 224 | /// used instead, but having only this method allows a simpler API. |
||
| 225 | virtual void HandleTopLevelDecl(DeclGroupRef DG); |
||
| 226 | /// Creates wrapper class for PPCallbacks so we can also process information |
||
| 227 | /// about includes that are inside of a preamble. Called after BeforeExecute. |
||
| 228 | virtual std::unique_ptr<PPCallbacks> createPPCallbacks(); |
||
| 229 | /// The returned CommentHandler will be added to the preprocessor if not null. |
||
| 230 | virtual CommentHandler *getCommentHandler(); |
||
| 231 | /// Determines which function bodies are parsed, by default skips everything. |
||
| 232 | /// Only used if FrontendOpts::SkipFunctionBodies is true. |
||
| 233 | /// See ASTConsumer::shouldSkipFunctionBody. |
||
| 234 | virtual bool shouldSkipFunctionBody(Decl *D) { return true; } |
||
| 235 | }; |
||
| 236 | |||
| 237 | enum class BuildPreambleError { |
||
| 238 | CouldntCreateTempFile = 1, |
||
| 239 | CouldntCreateTargetInfo, |
||
| 240 | BeginSourceFileFailed, |
||
| 241 | CouldntEmitPCH, |
||
| 242 | BadInputs |
||
| 243 | }; |
||
| 244 | |||
| 245 | class BuildPreambleErrorCategory final : public std::error_category { |
||
| 246 | public: |
||
| 247 | const char *name() const noexcept override; |
||
| 248 | std::string message(int condition) const override; |
||
| 249 | }; |
||
| 250 | |||
| 251 | std::error_code make_error_code(BuildPreambleError Error); |
||
| 252 | } // namespace clang |
||
| 253 | |||
| 254 | namespace std { |
||
| 255 | template <> |
||
| 256 | struct is_error_code_enum<clang::BuildPreambleError> : std::true_type {}; |
||
| 257 | } // namespace std |
||
| 258 | |||
| 259 | #endif |