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/MD5.h"
21#include <memory>
22#include <system_error>
23#include <type_traits>
24
25namespace llvm {
26class MemoryBuffer;
27}
28
29namespace clang {
30namespace vfs {
31class FileSystem;
32}
33
34class CompilerInstance;
35class CompilerInvocation;
36class DeclGroupRef;
37class PCHContainerOperations;
38
39/// \brief 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 TempPCHFile;
51  struct PreambleFileHash;
52
53public:
54  /// \brief 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 Callbacks A set of callbacks to be executed when building
74  /// the preamble.
75  static llvm::ErrorOr<PrecompiledPreamble>
76  Build(const CompilerInvocation &Invocation,
77        const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds,
78        DiagnosticsEngine &Diagnostics, IntrusiveRefCntPtr<vfs::FileSystem> VFS,
79        std::shared_ptr<PCHContainerOperations> PCHContainerOps,
80        PreambleCallbacks &Callbacks);
81
82  PrecompiledPreamble(PrecompiledPreamble &&) = default;
83  PrecompiledPreamble &operator=(PrecompiledPreamble &&) = default;
84
85  /// PreambleBounds used to build the preamble.
86  PreambleBounds getBounds() const;
87
88  /// The temporary file path at which the preamble PCH was placed.
89  StringRef GetPCHPath() const { return PCHFile.getFilePath(); }
90
91  /// Check whether PrecompiledPreamble can be reused for the new contents(\p
92  /// MainFileBuffer) of the main file.
93  bool CanReuse(const CompilerInvocation &Invocation,
94                const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds,
95                vfs::FileSystem *VFS) const;
96
97  /// Changes options inside \p CI to use PCH from this preamble. Also remaps
98  /// main file to \p MainFileBuffer.
99  void AddImplicitPreamble(CompilerInvocation &CI,
100                           llvm::MemoryBuffer *MainFileBuffer) const;
101
102private:
103  PrecompiledPreamble(TempPCHFile PCHFile, std::vector<char> PreambleBytes,
104                      bool PreambleEndsAtStartOfLine,
105                      llvm::StringMap<PreambleFileHash> FilesInPreamble);
106
107  /// A temp file that would be deleted on destructor call. If destructor is not
108  /// called for any reason, the file will be deleted at static objects'
109  /// destruction.
110  /// An assertion will fire if two TempPCHFiles are created with the same name,
111  /// so it's not intended to be used outside preamble-handling.
112  class TempPCHFile {
113  public:
114    // A main method used to construct TempPCHFile.
115    static llvm::ErrorOr<TempPCHFile> CreateNewPreamblePCHFile();
116
117    /// Call llvm::sys::fs::createTemporaryFile to create a new temporary file.
118    static llvm::ErrorOr<TempPCHFile> createInSystemTempDir(const Twine &Prefix,
119                                                            StringRef Suffix);
120    /// Create a new instance of TemporaryFile for file at \p Path. Use with
121    /// extreme caution, there's an assertion checking that there's only a
122    /// single instance of TempPCHFile alive for each path.
123    static llvm::ErrorOr<TempPCHFile> createFromCustomPath(const Twine &Path);
124
125  private:
126    TempPCHFile(std::string FilePath);
127
128  public:
129    TempPCHFile(TempPCHFile &&Other);
130    TempPCHFile &operator=(TempPCHFile &&Other);
131
132    TempPCHFile(const TempPCHFile &) = delete;
133    ~TempPCHFile();
134
135    /// A path where temporary file is stored.
136    llvm::StringRef getFilePath() const;
137
138  private:
139    void RemoveFileIfPresent();
140
141  private:
142    llvm::Optional<std::string> FilePath;
143  };
144
145  /// Data used to determine if a file used in the preamble has been changed.
146  struct PreambleFileHash {
147    /// All files have size set.
148    off_t Size = 0;
149
150    /// Modification time is set for files that are on disk.  For memory
151    /// buffers it is zero.
152    time_t ModTime = 0;
153
154    /// Memory buffers have MD5 instead of modification time.  We don't
155    /// compute MD5 for on-disk files because we hope that modification time is
156    /// enough to tell if the file was changed.
157    llvm::MD5::MD5Result MD5 = {};
158
159    static PreambleFileHash createForFile(off_t Size, time_t ModTime);
160    static PreambleFileHash
161    createForMemoryBuffer(const llvm::MemoryBuffer *Buffer);
162
163    friend bool operator==(const PreambleFileHash &LHS,
164                           const PreambleFileHash &RHS) {
165      return LHS.Size == RHS.Size && LHS.ModTime == RHS.ModTime &&
166             LHS.MD5 == RHS.MD5;
167    }
168    friend bool operator!=(const PreambleFileHash &LHS,
169                           const PreambleFileHash &RHS) {
170      return !(LHS == RHS);
171    }
172  };
173
174  /// Manages the lifetime of temporary file that stores a PCH.
175  TempPCHFile PCHFile;
176  /// Keeps track of the files that were used when computing the
177  /// preamble, with both their buffer size and their modification time.
178  ///
179  /// If any of the files have changed from one compile to the next,
180  /// the preamble must be thrown away.
181  llvm::StringMap<PreambleFileHash> FilesInPreamble;
182  /// The contents of the file that was used to precompile the preamble. Only
183  /// contains first PreambleBounds::Size bytes. Used to compare if the relevant
184  /// part of the file has not changed, so that preamble can be reused.
185  std::vector<char> PreambleBytes;
186  /// See PreambleBounds::PreambleEndsAtStartOfLine
187  bool PreambleEndsAtStartOfLine;
188};
189
190/// A set of callbacks to gather useful information while building a preamble.
191class PreambleCallbacks {
192public:
193  virtual ~PreambleCallbacks() = default;
194
195  /// Called after FrontendAction::Execute(), but before
196  /// FrontendAction::EndSourceFile(). Can be used to transfer ownership of
197  /// various CompilerInstance fields before they are destroyed.
198  virtual void AfterExecute(CompilerInstance &CI);
199  /// Called after PCH has been emitted. \p Writer may be used to retrieve
200  /// information about AST, serialized in PCH.
201  virtual void AfterPCHEmitted(ASTWriter &Writer);
202  /// Called for each TopLevelDecl.
203  /// NOTE: To allow more flexibility a custom ASTConsumer could probably be
204  /// used instead, but having only this method allows a simpler API.
205  virtual void HandleTopLevelDecl(DeclGroupRef DG);
206  /// Called for each macro defined in the Preamble.
207  /// NOTE: To allow more flexibility a custom PPCallbacks could probably be
208  /// used instead, but having only this method allows a simpler API.
209  virtual void HandleMacroDefined(const Token &MacroNameTok,
210                                  const MacroDirective *MD);
211};
212
213enum class BuildPreambleError {
214  PreambleIsEmpty = 1,
215  CouldntCreateTempFile,
216  CouldntCreateTargetInfo,
217  CouldntCreateVFSOverlay,
218  BeginSourceFileFailed,
219  CouldntEmitPCH
220};
221
222class BuildPreambleErrorCategory final : public std::error_category {
223public:
224  const char *name() const noexcept override;
225  std::string message(int condition) const override;
226};
227
228std::error_code make_error_code(BuildPreambleError Error);
229} // namespace clang
230
231namespace std {
232template <>
233struct is_error_code_enum<clang::BuildPreambleError> : std::true_type {};
234} // namespace std
235
236#endif
237