Clang Project

clang_source_code/include/clang/Frontend/PrecompiledPreamble.h
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_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
26namespace llvm {
27class MemoryBuffer;
28namespace vfs {
29class FileSystem;
30}
31// namespace llvm
32
33namespace clang {
34class CompilerInstance;
35class CompilerInvocation;
36class DeclGroupRef;
37class PCHContainerOperations;
38
39/// Runs lexer to compute suggested preamble bounds.
40PreambleBounds ComputePreambleBounds(const LangOptions &LangOpts,
41                                     llvm::MemoryBuffer *Buffer,
42                                     unsigned MaxLines);
43
44class PreambleCallbacks;
45
46/// A class holding a PCH and all information to check whether it is valid to
47/// reuse the PCH for the subsequent runs. Use BuildPreamble to create PCH and
48/// CanReusePreamble + AddImplicitPreamble to make use of it.
49class PrecompiledPreamble {
50  class PCHStorage;
51  struct PreambleFileHash;
52
53public:
54  /// Try to build PrecompiledPreamble for \p Invocation. See
55  /// BuildPreambleError for possible error codes.
56  ///
57  /// \param Invocation Original CompilerInvocation with options to compile the
58  /// file.
59  ///
60  /// \param MainFileBuffer Buffer with the contents of the main file.
61  ///
62  /// \param Bounds Bounds of the preamble, result of calling
63  /// ComputePreambleBounds.
64  ///
65  /// \param Diagnostics Diagnostics engine to be used while building the
66  /// preamble.
67  ///
68  /// \param VFS An instance of vfs::FileSystem to be used for file
69  /// accesses.
70  ///
71  /// \param PCHContainerOps An instance of PCHContainerOperations.
72  ///
73  /// \param StoreInMemory Store PCH in memory. If false, PCH will be stored in
74  /// a temporary file.
75  ///
76  /// \param Callbacks A set of callbacks to be executed when building
77  /// the preamble.
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  /// PreambleBounds used to build the preamble.
90  PreambleBounds getBounds() const;
91
92  /// Returns the size, in bytes, that preamble takes on disk or in memory.
93  /// For on-disk preambles returns 0 if filesystem operations fail. Intended to
94  /// be used for logging and debugging purposes only.
95  std::size_t getSize() const;
96
97  /// Check whether PrecompiledPreamble can be reused for the new contents(\p
98  /// MainFileBuffer) of the main file.
99  bool CanReuse(const CompilerInvocation &Invocation,
100                const llvm::MemoryBuffer *MainFileBufferPreambleBounds Bounds,
101                llvm::vfs::FileSystem *VFSconst;
102
103  /// Changes options inside \p CI to use PCH from this preamble. Also remaps
104  /// main file to \p MainFileBuffer and updates \p VFS to ensure the preamble
105  /// is accessible.
106  /// Requires that CanReuse() is true.
107  /// For in-memory preambles, PrecompiledPreamble instance continues to own the
108  /// MemoryBuffer with the Preamble after this method returns. The caller is
109  /// responsible for making sure the PrecompiledPreamble instance outlives the
110  /// compiler run and the AST that will be using the PCH.
111  void AddImplicitPreamble(CompilerInvocation &CI,
112                           IntrusiveRefCntPtr<llvm::vfs::FileSystem> &VFS,
113                           llvm::MemoryBuffer *MainFileBufferconst;
114
115  /// Configure \p CI to use this preamble.
116  /// Like AddImplicitPreamble, but doesn't assume CanReuse() is true.
117  /// If this preamble does not match the file, it may parse differently.
118  void OverridePreamble(CompilerInvocation &CI,
119                        IntrusiveRefCntPtr<llvm::vfs::FileSystem> &VFS,
120                        llvm::MemoryBuffer *MainFileBufferconst;
121
122private:
123  PrecompiledPreamble(PCHStorage Storagestd::vector<charPreambleBytes,
124                      bool PreambleEndsAtStartOfLine,
125                      llvm::StringMap<PreambleFileHash> FilesInPreamble);
126
127  /// A temp file that would be deleted on destructor call. If destructor is not
128  /// called for any reason, the file will be deleted at static objects'
129  /// destruction.
130  /// An assertion will fire if two TempPCHFiles are created with the same name,
131  /// so it's not intended to be used outside preamble-handling.
132  class TempPCHFile {
133  public:
134    // A main method used to construct TempPCHFile.
135    static llvm::ErrorOr<TempPCHFile> CreateNewPreamblePCHFile();
136
137    /// Call llvm::sys::fs::createTemporaryFile to create a new temporary file.
138    static llvm::ErrorOr<TempPCHFile> createInSystemTempDir(const Twine &Prefix,
139                                                            StringRef Suffix);
140    /// Create a new instance of TemporaryFile for file at \p Path. Use with
141    /// extreme caution, there's an assertion checking that there's only a
142    /// single instance of TempPCHFile alive for each path.
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    /// A path where temporary file is stored.
156    llvm::StringRef getFilePath() const;
157
158  private:
159    void RemoveFileIfPresent();
160
161  private:
162    llvm::Optional<std::stringFilePath;
163  };
164
165  class InMemoryPreamble {
166  public:
167    std::string Data;
168  };
169
170  class PCHStorage {
171  public:
172    enum class Kind { EmptyInMemoryTempFile };
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  /// Data used to determine if a file used in the preamble has been changed.
204  struct PreambleFileHash {
205    /// All files have size set.
206    off_t Size = 0;
207
208    /// Modification time is set for files that are on disk.  For memory
209    /// buffers it is zero.
210    time_t ModTime = 0;
211
212    /// Memory buffers have MD5 instead of modification time.  We don't
213    /// compute MD5 for on-disk files because we hope that modification time is
214    /// enough to tell if the file was changed.
215    llvm::MD5::MD5Result MD5 = {};
216
217    static PreambleFileHash createForFile(off_t Sizetime_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  /// Helper function to set up PCH for the preamble into \p CI and \p VFS to
233  /// with the specified \p Bounds.
234  void configurePreamble(PreambleBounds BoundsCompilerInvocation &CI,
235                         IntrusiveRefCntPtr<llvm::vfs::FileSystem> &VFS,
236                         llvm::MemoryBuffer *MainFileBufferconst;
237
238  /// Sets up the PreprocessorOptions and changes VFS, so that PCH stored in \p
239  /// Storage is accessible to clang. This method is an implementation detail of
240  /// AddImplicitPreamble.
241  static void
242  setupPreambleStorage(const PCHStorage &Storage,
243                       PreprocessorOptions &PreprocessorOpts,
244                       IntrusiveRefCntPtr<llvm::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<charPreambleBytes;
258  /// See PreambleBounds::PreambleEndsAtStartOfLine
259  bool PreambleEndsAtStartOfLine;
260};
261
262/// A set of callbacks to gather useful information while building a preamble.
263class PreambleCallbacks {
264public:
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<PPCallbackscreatePPCallbacks();
286  /// The returned CommentHandler will be added to the preprocessor if not null.
287  virtual CommentHandler *getCommentHandler();
288};
289
290enum class BuildPreambleError {
291  CouldntCreateTempFile = 1,
292  CouldntCreateTargetInfo,
293  BeginSourceFileFailed,
294  CouldntEmitPCH
295};
296
297class BuildPreambleErrorCategory final : public std::error_category {
298public:
299  const char *name() const noexcept override;
300  std::string message(int conditionconst override;
301};
302
303std::error_code make_error_code(BuildPreambleError Error);
304// namespace clang
305
306namespace std {
307template <>
308struct is_error_code_enum<clang::BuildPreambleError> : std::true_type {};
309// namespace std
310
311#endif
312
clang::PrecompiledPreamble::Build
clang::PrecompiledPreamble::getBounds
clang::PrecompiledPreamble::getSize
clang::PrecompiledPreamble::CanReuse
clang::PrecompiledPreamble::AddImplicitPreamble
clang::PrecompiledPreamble::OverridePreamble
clang::PrecompiledPreamble::TempPCHFile
clang::PrecompiledPreamble::TempPCHFile::CreateNewPreamblePCHFile
clang::PrecompiledPreamble::TempPCHFile::createInSystemTempDir
clang::PrecompiledPreamble::TempPCHFile::createFromCustomPath
clang::PrecompiledPreamble::TempPCHFile::getFilePath
clang::PrecompiledPreamble::TempPCHFile::RemoveFileIfPresent
clang::PrecompiledPreamble::TempPCHFile::FilePath
clang::PrecompiledPreamble::InMemoryPreamble
clang::PrecompiledPreamble::InMemoryPreamble::Data
clang::PrecompiledPreamble::PCHStorage
clang::PrecompiledPreamble::PCHStorage::Kind
clang::PrecompiledPreamble::PCHStorage::getKind
clang::PrecompiledPreamble::PCHStorage::asFile
clang::PrecompiledPreamble::PCHStorage::asFile
clang::PrecompiledPreamble::PCHStorage::asMemory
clang::PrecompiledPreamble::PCHStorage::asMemory
clang::PrecompiledPreamble::PCHStorage::destroy
clang::PrecompiledPreamble::PCHStorage::setEmpty
clang::PrecompiledPreamble::PCHStorage::StorageKind
clang::PrecompiledPreamble::PCHStorage::Storage
clang::PrecompiledPreamble::PreambleFileHash
clang::PrecompiledPreamble::PreambleFileHash::Size
clang::PrecompiledPreamble::PreambleFileHash::ModTime
clang::PrecompiledPreamble::PreambleFileHash::MD5
clang::PrecompiledPreamble::PreambleFileHash::createForFile
clang::PrecompiledPreamble::PreambleFileHash::createForMemoryBuffer
clang::PrecompiledPreamble::configurePreamble
clang::PrecompiledPreamble::setupPreambleStorage
clang::PrecompiledPreamble::Storage
clang::PrecompiledPreamble::FilesInPreamble
clang::PrecompiledPreamble::PreambleBytes
clang::PrecompiledPreamble::PreambleEndsAtStartOfLine
clang::PreambleCallbacks::BeforeExecute
clang::PreambleCallbacks::AfterExecute
clang::PreambleCallbacks::AfterPCHEmitted
clang::PreambleCallbacks::HandleTopLevelDecl
clang::PreambleCallbacks::createPPCallbacks
clang::PreambleCallbacks::getCommentHandler
clang::BuildPreambleErrorCategory::name
clang::BuildPreambleErrorCategory::message