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 |