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
26namespace llvm {
27class MemoryBuffer;
28class MemoryBufferRef;
29namespace vfs {
30class FileSystem;
31}
32} // namespace llvm
33
34namespace clang {
35class CompilerInstance;
36class CompilerInvocation;
37class Decl;
38class DeclGroupRef;
39class PCHContainerOperations;
40
41/// Runs lexer to compute suggested preamble bounds.
42PreambleBounds ComputePreambleBounds(const LangOptions &LangOpts,
43 const llvm::MemoryBufferRef &Buffer,
44 unsigned MaxLines);
45
46class 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.
51class PrecompiledPreamble {
52 class PCHStorage;
53 struct PreambleFileHash;
54
55public:
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 StoragePath The path to a directory, in which to create a temporary
79 /// file to store PCH in. If empty, the default system temporary directory is
80 /// used. This parameter is ignored if \p StoreInMemory is true.
81 ///
82 /// \param Callbacks A set of callbacks to be executed when building
83 /// the preamble.
84 static llvm::ErrorOr<PrecompiledPreamble>
85 Build(const CompilerInvocation &Invocation,
86 const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds,
87 DiagnosticsEngine &Diagnostics,
88 IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
89 std::shared_ptr<PCHContainerOperations> PCHContainerOps,
90 bool StoreInMemory, StringRef StoragePath,
91 PreambleCallbacks &Callbacks);
92
93 PrecompiledPreamble(PrecompiledPreamble &&);
94 PrecompiledPreamble &operator=(PrecompiledPreamble &&);
95 ~PrecompiledPreamble();
96
97 /// PreambleBounds used to build the preamble.
98 PreambleBounds getBounds() const;
99
100 /// Returns the size, in bytes, that preamble takes on disk or in memory.
101 /// For on-disk preambles returns 0 if filesystem operations fail. Intended to
102 /// be used for logging and debugging purposes only.
103 std::size_t getSize() const;
104
105 /// Returned string is not null-terminated.
106 llvm::StringRef getContents() const {
107 return {PreambleBytes.data(), PreambleBytes.size()};
108 }
109
110 /// Check whether PrecompiledPreamble can be reused for the new contents(\p
111 /// MainFileBuffer) of the main file.
112 bool CanReuse(const CompilerInvocation &Invocation,
113 const llvm::MemoryBufferRef &MainFileBuffer,
114 PreambleBounds Bounds, llvm::vfs::FileSystem &VFS) const;
115
116 /// Changes options inside \p CI to use PCH from this preamble. Also remaps
117 /// main file to \p MainFileBuffer and updates \p VFS to ensure the preamble
118 /// is accessible.
119 /// Requires that CanReuse() is true.
120 /// For in-memory preambles, PrecompiledPreamble instance continues to own the
121 /// MemoryBuffer with the Preamble after this method returns. The caller is
122 /// responsible for making sure the PrecompiledPreamble instance outlives the
123 /// compiler run and the AST that will be using the PCH.
124 void AddImplicitPreamble(CompilerInvocation &CI,
125 IntrusiveRefCntPtr<llvm::vfs::FileSystem> &VFS,
126 llvm::MemoryBuffer *MainFileBuffer) const;
127
128 /// Configure \p CI to use this preamble.
129 /// Like AddImplicitPreamble, but doesn't assume CanReuse() is true.
130 /// If this preamble does not match the file, it may parse differently.
131 void OverridePreamble(CompilerInvocation &CI,
132 IntrusiveRefCntPtr<llvm::vfs::FileSystem> &VFS,
133 llvm::MemoryBuffer *MainFileBuffer) const;
134
135private:
136 PrecompiledPreamble(std::unique_ptr<PCHStorage> Storage,
137 std::vector<char> PreambleBytes,
138 bool PreambleEndsAtStartOfLine,
139 llvm::StringMap<PreambleFileHash> FilesInPreamble,
140 llvm::StringSet<> MissingFiles);
141
142 /// Data used to determine if a file used in the preamble has been changed.
143 struct PreambleFileHash {
144 /// All files have size set.
145 off_t Size = 0;
146
147 /// Modification time is set for files that are on disk. For memory
148 /// buffers it is zero.
149 time_t ModTime = 0;
150
151 /// Memory buffers have MD5 instead of modification time. We don't
152 /// compute MD5 for on-disk files because we hope that modification time is
153 /// enough to tell if the file was changed.
154 llvm::MD5::MD5Result MD5 = {};
155
156 static PreambleFileHash createForFile(off_t Size, time_t ModTime);
157 static PreambleFileHash
158 createForMemoryBuffer(const llvm::MemoryBufferRef &Buffer);
159
160 friend bool operator==(const PreambleFileHash &LHS,
161 const PreambleFileHash &RHS) {
162 return LHS.Size == RHS.Size && LHS.ModTime == RHS.ModTime &&
163 LHS.MD5 == RHS.MD5;
164 }
165 friend bool operator!=(const PreambleFileHash &LHS,
166 const PreambleFileHash &RHS) {
167 return !(LHS == RHS);
168 }
169 };
170
171 /// Helper function to set up PCH for the preamble into \p CI and \p VFS to
172 /// with the specified \p Bounds.
173 void configurePreamble(PreambleBounds Bounds, CompilerInvocation &CI,
174 IntrusiveRefCntPtr<llvm::vfs::FileSystem> &VFS,
175 llvm::MemoryBuffer *MainFileBuffer) const;
176
177 /// Sets up the PreprocessorOptions and changes VFS, so that PCH stored in \p
178 /// Storage is accessible to clang. This method is an implementation detail of
179 /// AddImplicitPreamble.
180 static void
181 setupPreambleStorage(const PCHStorage &Storage,
182 PreprocessorOptions &PreprocessorOpts,
183 IntrusiveRefCntPtr<llvm::vfs::FileSystem> &VFS);
184
185 /// Manages the memory buffer or temporary file that stores the PCH.
186 std::unique_ptr<PCHStorage> Storage;
187 /// Keeps track of the files that were used when computing the
188 /// preamble, with both their buffer size and their modification time.
189 ///
190 /// If any of the files have changed from one compile to the next,
191 /// the preamble must be thrown away.
192 llvm::StringMap<PreambleFileHash> FilesInPreamble;
193 /// Files that were not found during preamble building. If any of these now
194 /// exist then the preamble should not be reused.
195 ///
196 /// Storing *all* the missing files that could invalidate the preamble would
197 /// make it too expensive to revalidate (when the include path has many
198 /// entries, each #include will miss half of them on average).
199 /// Instead, we track only files that could have satisfied an #include that
200 /// was ultimately not found.
201 llvm::StringSet<> MissingFiles;
202 /// The contents of the file that was used to precompile the preamble. Only
203 /// contains first PreambleBounds::Size bytes. Used to compare if the relevant
204 /// part of the file has not changed, so that preamble can be reused.
205 std::vector<char> PreambleBytes;
206 /// See PreambleBounds::PreambleEndsAtStartOfLine
207 bool PreambleEndsAtStartOfLine;
208};
209
210/// A set of callbacks to gather useful information while building a preamble.
211class PreambleCallbacks {
212public:
213 virtual ~PreambleCallbacks() = default;
214
215 /// Called before FrontendAction::Execute.
216 /// Can be used to store references to various CompilerInstance fields
217 /// (e.g. SourceManager) that may be interesting to the consumers of other
218 /// callbacks.
219 virtual void BeforeExecute(CompilerInstance &CI);
220 /// Called after FrontendAction::Execute(), but before
221 /// FrontendAction::EndSourceFile(). Can be used to transfer ownership of
222 /// various CompilerInstance fields before they are destroyed.
223 virtual void AfterExecute(CompilerInstance &CI);
224 /// Called after PCH has been emitted. \p Writer may be used to retrieve
225 /// information about AST, serialized in PCH.
226 virtual void AfterPCHEmitted(ASTWriter &Writer);
227 /// Called for each TopLevelDecl.
228 /// NOTE: To allow more flexibility a custom ASTConsumer could probably be
229 /// used instead, but having only this method allows a simpler API.
230 virtual void HandleTopLevelDecl(DeclGroupRef DG);
231 /// Creates wrapper class for PPCallbacks so we can also process information
232 /// about includes that are inside of a preamble. Called after BeforeExecute.
233 virtual std::unique_ptr<PPCallbacks> createPPCallbacks();
234 /// The returned CommentHandler will be added to the preprocessor if not null.
235 virtual CommentHandler *getCommentHandler();
236 /// Determines which function bodies are parsed, by default skips everything.
237 /// Only used if FrontendOpts::SkipFunctionBodies is true.
238 /// See ASTConsumer::shouldSkipFunctionBody.
239 virtual bool shouldSkipFunctionBody(Decl *D) { return true; }
240};
241
242enum class BuildPreambleError {
243 CouldntCreateTempFile = 1,
244 CouldntCreateTargetInfo,
245 BeginSourceFileFailed,
246 CouldntEmitPCH,
247 BadInputs
248};
249
250class BuildPreambleErrorCategory final : public std::error_category {
251public:
252 const char *name() const noexcept override;
253 std::string message(int condition) const override;
254};
255
256std::error_code make_error_code(BuildPreambleError Error);
257} // namespace clang
258
259namespace std {
260template <>
261struct is_error_code_enum<clang::BuildPreambleError> : std::true_type {};
262} // namespace std
263
264#endif
265

source code of clang/include/clang/Frontend/PrecompiledPreamble.h