Warning: That file was not part of the compilation database. It may have many parsing errors.
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 | } |
30 | |
31 | namespace clang { |
32 | namespace vfs { |
33 | class FileSystem; |
34 | } |
35 | |
36 | class CompilerInstance; |
37 | class CompilerInvocation; |
38 | class DeclGroupRef; |
39 | class PCHContainerOperations; |
40 | |
41 | /// Runs lexer to compute suggested preamble bounds. |
42 | PreambleBounds ComputePreambleBounds(const LangOptions &LangOpts, |
43 | llvm::MemoryBuffer *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, IntrusiveRefCntPtr<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 | 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<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<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<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 setupPreambleStorage(const PCHStorage &Storage, |
243 | PreprocessorOptions &PreprocessorOpts, |
244 | IntrusiveRefCntPtr<vfs::FileSystem> &VFS); |
245 | |
246 | /// Manages the memory buffer or temporary file that stores the PCH. |
247 | PCHStorage Storage; |
248 | /// Keeps track of the files that were used when computing the |
249 | /// preamble, with both their buffer size and their modification time. |
250 | /// |
251 | /// If any of the files have changed from one compile to the next, |
252 | /// the preamble must be thrown away. |
253 | llvm::StringMap<PreambleFileHash> FilesInPreamble; |
254 | /// The contents of the file that was used to precompile the preamble. Only |
255 | /// contains first PreambleBounds::Size bytes. Used to compare if the relevant |
256 | /// part of the file has not changed, so that preamble can be reused. |
257 | std::vector<char> PreambleBytes; |
258 | /// See PreambleBounds::PreambleEndsAtStartOfLine |
259 | bool PreambleEndsAtStartOfLine; |
260 | }; |
261 | |
262 | /// A set of callbacks to gather useful information while building a preamble. |
263 | class PreambleCallbacks { |
264 | public: |
265 | virtual ~PreambleCallbacks() = default; |
266 | |
267 | /// Called before FrontendAction::BeginSourceFile. |
268 | /// Can be used to store references to various CompilerInstance fields |
269 | /// (e.g. SourceManager) that may be interesting to the consumers of other |
270 | /// callbacks. |
271 | virtual void BeforeExecute(CompilerInstance &CI); |
272 | /// Called after FrontendAction::Execute(), but before |
273 | /// FrontendAction::EndSourceFile(). Can be used to transfer ownership of |
274 | /// various CompilerInstance fields before they are destroyed. |
275 | virtual void AfterExecute(CompilerInstance &CI); |
276 | /// Called after PCH has been emitted. \p Writer may be used to retrieve |
277 | /// information about AST, serialized in PCH. |
278 | virtual void AfterPCHEmitted(ASTWriter &Writer); |
279 | /// Called for each TopLevelDecl. |
280 | /// NOTE: To allow more flexibility a custom ASTConsumer could probably be |
281 | /// used instead, but having only this method allows a simpler API. |
282 | virtual void HandleTopLevelDecl(DeclGroupRef DG); |
283 | /// Creates wrapper class for PPCallbacks so we can also process information |
284 | /// about includes that are inside of a preamble |
285 | virtual std::unique_ptr<PPCallbacks> createPPCallbacks(); |
286 | }; |
287 | |
288 | enum class BuildPreambleError { |
289 | PreambleIsEmpty = 1, |
290 | CouldntCreateTempFile, |
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 |
Warning: That file was not part of the compilation database. It may have many parsing errors.