1 //===--- PrecompiledPreamble.h - Build precompiled preambles ----*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // Helper class to build precompiled preamble.
12 //===----------------------------------------------------------------------===//
14 #ifndef LLVM_CLANG_FRONTEND_PRECOMPILED_PREAMBLE_H
15 #define LLVM_CLANG_FRONTEND_PRECOMPILED_PREAMBLE_H
17 #include "clang/Lex/Lexer.h"
18 #include "clang/Lex/Preprocessor.h"
19 #include "llvm/ADT/IntrusiveRefCntPtr.h"
20 #include "llvm/Support/MD5.h"
22 #include <system_error>
23 #include <type_traits>
34 class CompilerInstance;
35 class CompilerInvocation;
37 class PCHContainerOperations;
39 /// A size of the preamble and a flag required by
40 /// PreprocessorOptions::PrecompiledPreambleBytes.
41 struct PreambleBounds {
42 PreambleBounds(unsigned Size, bool PreambleEndsAtStartOfLine)
43 : Size(Size), PreambleEndsAtStartOfLine(PreambleEndsAtStartOfLine) {}
45 /// \brief Size of the preamble in bytes.
47 /// \brief Whether the preamble ends at the start of a new line.
49 /// Used to inform the lexer as to whether it's starting at the beginning of
50 /// a line after skipping the preamble.
51 bool PreambleEndsAtStartOfLine;
54 /// \brief Runs lexer to compute suggested preamble bounds.
55 PreambleBounds ComputePreambleBounds(const LangOptions &LangOpts,
56 llvm::MemoryBuffer *Buffer,
59 class PreambleCallbacks;
61 /// A class holding a PCH and all information to check whether it is valid to
62 /// reuse the PCH for the subsequent runs. Use BuildPreamble to create PCH and
63 /// CanReusePreamble + AddImplicitPreamble to make use of it.
64 class PrecompiledPreamble {
66 struct PreambleFileHash;
69 /// \brief Try to build PrecompiledPreamble for \p Invocation. See
70 /// BuildPreambleError for possible error codes.
72 /// \param Invocation Original CompilerInvocation with options to compile the
75 /// \param MainFileBuffer Buffer with the contents of the main file.
77 /// \param Bounds Bounds of the preamble, result of calling
78 /// ComputePreambleBounds.
80 /// \param Diagnostics Diagnostics engine to be used while building the
83 /// \param VFS An instance of vfs::FileSystem to be used for file
86 /// \param PCHContainerOps An instance of PCHContainerOperations.
88 /// \param Callbacks A set of callbacks to be executed when building
90 static llvm::ErrorOr<PrecompiledPreamble>
91 Build(const CompilerInvocation &Invocation,
92 const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds,
93 DiagnosticsEngine &Diagnostics, IntrusiveRefCntPtr<vfs::FileSystem> VFS,
94 std::shared_ptr<PCHContainerOperations> PCHContainerOps,
95 PreambleCallbacks &Callbacks);
97 PrecompiledPreamble(PrecompiledPreamble &&) = default;
98 PrecompiledPreamble &operator=(PrecompiledPreamble &&) = default;
100 /// PreambleBounds used to build the preamble
101 PreambleBounds getBounds() const;
103 /// Check whether PrecompiledPreamble can be reused for the new contents(\p
104 /// MainFileBuffer) of the main file.
105 bool CanReuse(const CompilerInvocation &Invocation,
106 const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds,
107 vfs::FileSystem *VFS) const;
109 /// Changes options inside \p CI to use PCH from this preamble. Also remaps
110 /// main file to \p MainFileBuffer.
111 void AddImplicitPreamble(CompilerInvocation &CI,
112 llvm::MemoryBuffer *MainFileBuffer) const;
115 PrecompiledPreamble(TempPCHFile PCHFile, std::vector<char> PreambleBytes,
116 bool PreambleEndsAtStartOfLine,
117 llvm::StringMap<PreambleFileHash> FilesInPreamble);
119 /// A temp file that would be deleted on destructor call. If destructor is not
120 /// called for any reason, the file will be deleted at static objects'
122 /// An assertion will fire if two TempPCHFiles are created with the same name,
123 /// so it's not intended to be used outside preamble-handling.
126 // A main method used to construct TempPCHFile.
127 static llvm::ErrorOr<TempPCHFile> CreateNewPreamblePCHFile();
129 /// Call llvm::sys::fs::createTemporaryFile to create a new temporary file.
130 static llvm::ErrorOr<TempPCHFile> createInSystemTempDir(const Twine &Prefix,
132 /// Create a new instance of TemporaryFile for file at \p Path. Use with
133 /// extreme caution, there's an assertion checking that there's only a
134 /// single instance of TempPCHFile alive for each path.
135 static llvm::ErrorOr<TempPCHFile> createFromCustomPath(const Twine &Path);
138 TempPCHFile(std::string FilePath);
141 TempPCHFile(TempPCHFile &&Other);
142 TempPCHFile &operator=(TempPCHFile &&Other);
144 TempPCHFile(const TempPCHFile &) = delete;
147 /// A path where temporary file is stored.
148 llvm::StringRef getFilePath() const;
151 void RemoveFileIfPresent();
154 llvm::Optional<std::string> FilePath;
157 /// Data used to determine if a file used in the preamble has been changed.
158 struct PreambleFileHash {
159 /// All files have size set.
162 /// Modification time is set for files that are on disk. For memory
163 /// buffers it is zero.
166 /// Memory buffers have MD5 instead of modification time. We don't
167 /// compute MD5 for on-disk files because we hope that modification time is
168 /// enough to tell if the file was changed.
169 llvm::MD5::MD5Result MD5 = {};
171 static PreambleFileHash createForFile(off_t Size, time_t ModTime);
172 static PreambleFileHash
173 createForMemoryBuffer(const llvm::MemoryBuffer *Buffer);
175 friend bool operator==(const PreambleFileHash &LHS,
176 const PreambleFileHash &RHS) {
177 return LHS.Size == RHS.Size && LHS.ModTime == RHS.ModTime &&
180 friend bool operator!=(const PreambleFileHash &LHS,
181 const PreambleFileHash &RHS) {
182 return !(LHS == RHS);
186 /// Manages the lifetime of temporary file that stores a PCH.
188 /// Keeps track of the files that were used when computing the
189 /// preamble, with both their buffer size and their modification time.
191 /// If any of the files have changed from one compile to the next,
192 /// the preamble must be thrown away.
193 llvm::StringMap<PreambleFileHash> FilesInPreamble;
194 /// The contents of the file that was used to precompile the preamble. Only
195 /// contains first PreambleBounds::Size bytes. Used to compare if the relevant
196 /// part of the file has not changed, so that preamble can be reused.
197 std::vector<char> PreambleBytes;
198 /// See PreambleBounds::PreambleEndsAtStartOfLine
199 bool PreambleEndsAtStartOfLine;
202 /// A set of callbacks to gather useful information while building a preamble.
203 class PreambleCallbacks {
205 virtual ~PreambleCallbacks() = default;
207 /// Called after FrontendAction::Execute(), but before
208 /// FrontendAction::EndSourceFile(). Can be used to transfer ownership of
209 /// various CompilerInstance fields before they are destroyed.
210 virtual void AfterExecute(CompilerInstance &CI);
211 /// Called after PCH has been emitted. \p Writer may be used to retrieve
212 /// information about AST, serialized in PCH.
213 virtual void AfterPCHEmitted(ASTWriter &Writer);
214 /// Called for each TopLevelDecl.
215 /// NOTE: To allow more flexibility a custom ASTConsumer could probably be
216 /// used instead, but having only this method allows a simpler API.
217 virtual void HandleTopLevelDecl(DeclGroupRef DG);
218 /// Called for each macro defined in the Preamble.
219 /// NOTE: To allow more flexibility a custom PPCallbacks could probably be
220 /// used instead, but having only this method allows a simpler API.
221 virtual void HandleMacroDefined(const Token &MacroNameTok,
222 const MacroDirective *MD);
225 enum class BuildPreambleError {
227 CouldntCreateTempFile,
228 CouldntCreateTargetInfo,
229 CouldntCreateVFSOverlay,
230 BeginSourceFileFailed,
234 class BuildPreambleErrorCategory final : public std::error_category {
236 const char *name() const noexcept override;
237 std::string message(int condition) const override;
240 std::error_code make_error_code(BuildPreambleError Error);
245 struct is_error_code_enum<clang::BuildPreambleError> : std::true_type {};