1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | #ifndef LLVM_CLANG_FRONTEND_PRECOMPILED_PREAMBLE_H |
14 | #define LLVM_CLANG_FRONTEND_PRECOMPILED_PREAMBLE_H |
15 | |
16 | #include "clang/Lex/Lexer.h" |
17 | #include "clang/Lex/Preprocessor.h" |
18 | #include "llvm/ADT/IntrusiveRefCntPtr.h" |
19 | #include "llvm/Support/AlignOf.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 | namespace vfs { |
29 | class FileSystem; |
30 | } |
31 | } |
32 | |
33 | namespace clang { |
34 | class CompilerInstance; |
35 | class CompilerInvocation; |
36 | class DeclGroupRef; |
37 | class PCHContainerOperations; |
38 | |
39 | |
40 | PreambleBounds ComputePreambleBounds(const LangOptions &LangOpts, |
41 | llvm::MemoryBuffer *Buffer, |
42 | unsigned MaxLines); |
43 | |
44 | class PreambleCallbacks; |
45 | |
46 | |
47 | |
48 | |
49 | class PrecompiledPreamble { |
50 | class PCHStorage; |
51 | struct PreambleFileHash; |
52 | |
53 | public: |
54 | |
55 | |
56 | |
57 | |
58 | |
59 | |
60 | |
61 | |
62 | |
63 | |
64 | |
65 | |
66 | |
67 | |
68 | |
69 | |
70 | |
71 | |
72 | |
73 | |
74 | |
75 | |
76 | |
77 | |
78 | static llvm::ErrorOr<PrecompiledPreamble> |
79 | Build(const CompilerInvocation &Invocation, |
80 | const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds, |
81 | DiagnosticsEngine &Diagnostics, |
82 | IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, |
83 | std::shared_ptr<PCHContainerOperations> PCHContainerOps, |
84 | bool StoreInMemory, PreambleCallbacks &Callbacks); |
85 | |
86 | PrecompiledPreamble(PrecompiledPreamble &&) = default; |
87 | PrecompiledPreamble &operator=(PrecompiledPreamble &&) = default; |
88 | |
89 | |
90 | PreambleBounds getBounds() const; |
91 | |
92 | |
93 | |
94 | |
95 | std::size_t getSize() const; |
96 | |
97 | |
98 | |
99 | bool CanReuse(const CompilerInvocation &Invocation, |
100 | const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds, |
101 | llvm::vfs::FileSystem *VFS) const; |
102 | |
103 | |
104 | |
105 | |
106 | |
107 | |
108 | |
109 | |
110 | |
111 | void AddImplicitPreamble(CompilerInvocation &CI, |
112 | IntrusiveRefCntPtr<llvm::vfs::FileSystem> &VFS, |
113 | llvm::MemoryBuffer *MainFileBuffer) const; |
114 | |
115 | |
116 | |
117 | |
118 | void OverridePreamble(CompilerInvocation &CI, |
119 | IntrusiveRefCntPtr<llvm::vfs::FileSystem> &VFS, |
120 | llvm::MemoryBuffer *MainFileBuffer) const; |
121 | |
122 | private: |
123 | PrecompiledPreamble(PCHStorage Storage, std::vector<char> PreambleBytes, |
124 | bool PreambleEndsAtStartOfLine, |
125 | llvm::StringMap<PreambleFileHash> FilesInPreamble); |
126 | |
127 | |
128 | |
129 | |
130 | |
131 | |
132 | class TempPCHFile { |
133 | public: |
134 | |
135 | static llvm::ErrorOr<TempPCHFile> CreateNewPreamblePCHFile(); |
136 | |
137 | |
138 | static llvm::ErrorOr<TempPCHFile> createInSystemTempDir(const Twine &Prefix, |
139 | StringRef Suffix); |
140 | |
141 | |
142 | |
143 | static llvm::ErrorOr<TempPCHFile> createFromCustomPath(const Twine &Path); |
144 | |
145 | private: |
146 | TempPCHFile(std::string FilePath); |
147 | |
148 | public: |
149 | TempPCHFile(TempPCHFile &&Other); |
150 | TempPCHFile &operator=(TempPCHFile &&Other); |
151 | |
152 | TempPCHFile(const TempPCHFile &) = delete; |
153 | ~TempPCHFile(); |
154 | |
155 | |
156 | llvm::StringRef getFilePath() const; |
157 | |
158 | private: |
159 | void RemoveFileIfPresent(); |
160 | |
161 | private: |
162 | llvm::Optional<std::string> FilePath; |
163 | }; |
164 | |
165 | class InMemoryPreamble { |
166 | public: |
167 | std::string Data; |
168 | }; |
169 | |
170 | class PCHStorage { |
171 | public: |
172 | enum class Kind { Empty, InMemory, TempFile }; |
173 | |
174 | PCHStorage() = default; |
175 | PCHStorage(TempPCHFile File); |
176 | PCHStorage(InMemoryPreamble Memory); |
177 | |
178 | PCHStorage(const PCHStorage &) = delete; |
179 | PCHStorage &operator=(const PCHStorage &) = delete; |
180 | |
181 | PCHStorage(PCHStorage &&Other); |
182 | PCHStorage &operator=(PCHStorage &&Other); |
183 | |
184 | ~PCHStorage(); |
185 | |
186 | Kind getKind() const; |
187 | |
188 | TempPCHFile &asFile(); |
189 | const TempPCHFile &asFile() const; |
190 | |
191 | InMemoryPreamble &asMemory(); |
192 | const InMemoryPreamble &asMemory() const; |
193 | |
194 | private: |
195 | void destroy(); |
196 | void setEmpty(); |
197 | |
198 | private: |
199 | Kind StorageKind = Kind::Empty; |
200 | llvm::AlignedCharArrayUnion<TempPCHFile, InMemoryPreamble> Storage = {}; |
201 | }; |
202 | |
203 | |
204 | struct PreambleFileHash { |
205 | |
206 | off_t Size = 0; |
207 | |
208 | |
209 | |
210 | time_t ModTime = 0; |
211 | |
212 | |
213 | |
214 | |
215 | llvm::MD5::MD5Result MD5 = {}; |
216 | |
217 | static PreambleFileHash createForFile(off_t Size, time_t ModTime); |
218 | static PreambleFileHash |
219 | createForMemoryBuffer(const llvm::MemoryBuffer *Buffer); |
220 | |
221 | friend bool operator==(const PreambleFileHash &LHS, |
222 | const PreambleFileHash &RHS) { |
223 | return LHS.Size == RHS.Size && LHS.ModTime == RHS.ModTime && |
224 | LHS.MD5 == RHS.MD5; |
225 | } |
226 | friend bool operator!=(const PreambleFileHash &LHS, |
227 | const PreambleFileHash &RHS) { |
228 | return !(LHS == RHS); |
229 | } |
230 | }; |
231 | |
232 | |
233 | |
234 | void configurePreamble(PreambleBounds Bounds, CompilerInvocation &CI, |
235 | IntrusiveRefCntPtr<llvm::vfs::FileSystem> &VFS, |
236 | llvm::MemoryBuffer *MainFileBuffer) const; |
237 | |
238 | |
239 | |
240 | |
241 | static void |
242 | setupPreambleStorage(const PCHStorage &Storage, |
243 | PreprocessorOptions &PreprocessorOpts, |
244 | IntrusiveRefCntPtr<llvm::vfs::FileSystem> &VFS); |
245 | |
246 | |
247 | PCHStorage Storage; |
248 | |
249 | |
250 | |
251 | |
252 | |
253 | llvm::StringMap<PreambleFileHash> FilesInPreamble; |
254 | |
255 | |
256 | |
257 | std::vector<char> PreambleBytes; |
258 | |
259 | bool PreambleEndsAtStartOfLine; |
260 | }; |
261 | |
262 | |
263 | class PreambleCallbacks { |
264 | public: |
265 | virtual ~PreambleCallbacks() = default; |
266 | |
267 | |
268 | |
269 | |
270 | |
271 | virtual void BeforeExecute(CompilerInstance &CI); |
272 | |
273 | |
274 | |
275 | virtual void AfterExecute(CompilerInstance &CI); |
276 | |
277 | |
278 | virtual void AfterPCHEmitted(ASTWriter &Writer); |
279 | |
280 | |
281 | |
282 | virtual void HandleTopLevelDecl(DeclGroupRef DG); |
283 | |
284 | |
285 | virtual std::unique_ptr<PPCallbacks> createPPCallbacks(); |
286 | |
287 | virtual CommentHandler *getCommentHandler(); |
288 | }; |
289 | |
290 | enum class BuildPreambleError { |
291 | CouldntCreateTempFile = 1, |
292 | CouldntCreateTargetInfo, |
293 | BeginSourceFileFailed, |
294 | CouldntEmitPCH |
295 | }; |
296 | |
297 | class BuildPreambleErrorCategory final : public std::error_category { |
298 | public: |
299 | const char *name() const noexcept override; |
300 | std::string message(int condition) const override; |
301 | }; |
302 | |
303 | std::error_code make_error_code(BuildPreambleError Error); |
304 | } |
305 | |
306 | namespace std { |
307 | template <> |
308 | struct is_error_code_enum<clang::BuildPreambleError> : std::true_type {}; |
309 | } |
310 | |
311 | #endif |
312 | |