Home | History | Annotate | Line # | Download | only in Frontend
      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/ADT/StringRef.h"
     20 #include "llvm/Support/AlignOf.h"
     21 #include "llvm/Support/MD5.h"
     22 #include <cstddef>
     23 #include <memory>
     24 #include <system_error>
     25 #include <type_traits>
     26 
     27 namespace llvm {
     28 class MemoryBuffer;
     29 class MemoryBufferRef;
     30 namespace vfs {
     31 class FileSystem;
     32 }
     33 } // namespace llvm
     34 
     35 namespace clang {
     36 class CompilerInstance;
     37 class CompilerInvocation;
     38 class Decl;
     39 class DeclGroupRef;
     40 class PCHContainerOperations;
     41 
     42 /// Runs lexer to compute suggested preamble bounds.
     43 PreambleBounds ComputePreambleBounds(const LangOptions &LangOpts,
     44                                      const llvm::MemoryBufferRef &Buffer,
     45                                      unsigned MaxLines);
     46 
     47 class PreambleCallbacks;
     48 
     49 /// A class holding a PCH and all information to check whether it is valid to
     50 /// reuse the PCH for the subsequent runs. Use BuildPreamble to create PCH and
     51 /// CanReusePreamble + AddImplicitPreamble to make use of it.
     52 class PrecompiledPreamble {
     53   class PCHStorage;
     54   struct PreambleFileHash;
     55 
     56 public:
     57   /// Try to build PrecompiledPreamble for \p Invocation. See
     58   /// BuildPreambleError for possible error codes.
     59   ///
     60   /// \param Invocation Original CompilerInvocation with options to compile the
     61   /// file.
     62   ///
     63   /// \param MainFileBuffer Buffer with the contents of the main file.
     64   ///
     65   /// \param Bounds Bounds of the preamble, result of calling
     66   /// ComputePreambleBounds.
     67   ///
     68   /// \param Diagnostics Diagnostics engine to be used while building the
     69   /// preamble.
     70   ///
     71   /// \param VFS An instance of vfs::FileSystem to be used for file
     72   /// accesses.
     73   ///
     74   /// \param PCHContainerOps An instance of PCHContainerOperations.
     75   ///
     76   /// \param StoreInMemory Store PCH in memory. If false, PCH will be stored in
     77   /// a temporary file.
     78   ///
     79   /// \param Callbacks A set of callbacks to be executed when building
     80   /// the preamble.
     81   static llvm::ErrorOr<PrecompiledPreamble>
     82   Build(const CompilerInvocation &Invocation,
     83         const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds,
     84         DiagnosticsEngine &Diagnostics,
     85         IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
     86         std::shared_ptr<PCHContainerOperations> PCHContainerOps,
     87         bool StoreInMemory, PreambleCallbacks &Callbacks);
     88 
     89   PrecompiledPreamble(PrecompiledPreamble &&) = default;
     90   PrecompiledPreamble &operator=(PrecompiledPreamble &&) = default;
     91 
     92   /// PreambleBounds used to build the preamble.
     93   PreambleBounds getBounds() const;
     94 
     95   /// Returns the size, in bytes, that preamble takes on disk or in memory.
     96   /// For on-disk preambles returns 0 if filesystem operations fail. Intended to
     97   /// be used for logging and debugging purposes only.
     98   std::size_t getSize() const;
     99 
    100   /// Returned string is not null-terminated.
    101   llvm::StringRef getContents() const {
    102     return {PreambleBytes.data(), PreambleBytes.size()};
    103   }
    104 
    105   /// Check whether PrecompiledPreamble can be reused for the new contents(\p
    106   /// MainFileBuffer) of the main file.
    107   bool CanReuse(const CompilerInvocation &Invocation,
    108                 const llvm::MemoryBufferRef &MainFileBuffer,
    109                 PreambleBounds Bounds, llvm::vfs::FileSystem &VFS) const;
    110 
    111   /// Changes options inside \p CI to use PCH from this preamble. Also remaps
    112   /// main file to \p MainFileBuffer and updates \p VFS to ensure the preamble
    113   /// is accessible.
    114   /// Requires that CanReuse() is true.
    115   /// For in-memory preambles, PrecompiledPreamble instance continues to own the
    116   /// MemoryBuffer with the Preamble after this method returns. The caller is
    117   /// responsible for making sure the PrecompiledPreamble instance outlives the
    118   /// compiler run and the AST that will be using the PCH.
    119   void AddImplicitPreamble(CompilerInvocation &CI,
    120                            IntrusiveRefCntPtr<llvm::vfs::FileSystem> &VFS,
    121                            llvm::MemoryBuffer *MainFileBuffer) const;
    122 
    123   /// Configure \p CI to use this preamble.
    124   /// Like AddImplicitPreamble, but doesn't assume CanReuse() is true.
    125   /// If this preamble does not match the file, it may parse differently.
    126   void OverridePreamble(CompilerInvocation &CI,
    127                         IntrusiveRefCntPtr<llvm::vfs::FileSystem> &VFS,
    128                         llvm::MemoryBuffer *MainFileBuffer) const;
    129 
    130 private:
    131   PrecompiledPreamble(PCHStorage Storage, std::vector<char> PreambleBytes,
    132                       bool PreambleEndsAtStartOfLine,
    133                       llvm::StringMap<PreambleFileHash> FilesInPreamble,
    134                       llvm::StringSet<> MissingFiles);
    135 
    136   /// A temp file that would be deleted on destructor call. If destructor is not
    137   /// called for any reason, the file will be deleted at static objects'
    138   /// destruction.
    139   /// An assertion will fire if two TempPCHFiles are created with the same name,
    140   /// so it's not intended to be used outside preamble-handling.
    141   class TempPCHFile {
    142   public:
    143     // A main method used to construct TempPCHFile.
    144     static llvm::ErrorOr<TempPCHFile> CreateNewPreamblePCHFile();
    145 
    146   private:
    147     TempPCHFile(std::string FilePath);
    148 
    149   public:
    150     TempPCHFile(TempPCHFile &&Other);
    151     TempPCHFile &operator=(TempPCHFile &&Other);
    152 
    153     TempPCHFile(const TempPCHFile &) = delete;
    154     ~TempPCHFile();
    155 
    156     /// A path where temporary file is stored.
    157     llvm::StringRef getFilePath() const;
    158 
    159   private:
    160     void RemoveFileIfPresent();
    161 
    162   private:
    163     llvm::Optional<std::string> FilePath;
    164   };
    165 
    166   class InMemoryPreamble {
    167   public:
    168     std::string Data;
    169   };
    170 
    171   class PCHStorage {
    172   public:
    173     enum class Kind { Empty, InMemory, TempFile };
    174 
    175     PCHStorage() = default;
    176     PCHStorage(TempPCHFile File);
    177     PCHStorage(InMemoryPreamble Memory);
    178 
    179     PCHStorage(const PCHStorage &) = delete;
    180     PCHStorage &operator=(const PCHStorage &) = delete;
    181 
    182     PCHStorage(PCHStorage &&Other);
    183     PCHStorage &operator=(PCHStorage &&Other);
    184 
    185     ~PCHStorage();
    186 
    187     Kind getKind() const;
    188 
    189     TempPCHFile &asFile();
    190     const TempPCHFile &asFile() const;
    191 
    192     InMemoryPreamble &asMemory();
    193     const InMemoryPreamble &asMemory() const;
    194 
    195   private:
    196     void destroy();
    197     void setEmpty();
    198 
    199   private:
    200     Kind StorageKind = Kind::Empty;
    201     llvm::AlignedCharArrayUnion<TempPCHFile, InMemoryPreamble> Storage = {};
    202   };
    203 
    204   /// Data used to determine if a file used in the preamble has been changed.
    205   struct PreambleFileHash {
    206     /// All files have size set.
    207     off_t Size = 0;
    208 
    209     /// Modification time is set for files that are on disk.  For memory
    210     /// buffers it is zero.
    211     time_t ModTime = 0;
    212 
    213     /// Memory buffers have MD5 instead of modification time.  We don't
    214     /// compute MD5 for on-disk files because we hope that modification time is
    215     /// enough to tell if the file was changed.
    216     llvm::MD5::MD5Result MD5 = {};
    217 
    218     static PreambleFileHash createForFile(off_t Size, time_t ModTime);
    219     static PreambleFileHash
    220     createForMemoryBuffer(const llvm::MemoryBufferRef &Buffer);
    221 
    222     friend bool operator==(const PreambleFileHash &LHS,
    223                            const PreambleFileHash &RHS) {
    224       return LHS.Size == RHS.Size && LHS.ModTime == RHS.ModTime &&
    225              LHS.MD5 == RHS.MD5;
    226     }
    227     friend bool operator!=(const PreambleFileHash &LHS,
    228                            const PreambleFileHash &RHS) {
    229       return !(LHS == RHS);
    230     }
    231   };
    232 
    233   /// Helper function to set up PCH for the preamble into \p CI and \p VFS to
    234   /// with the specified \p Bounds.
    235   void configurePreamble(PreambleBounds Bounds, CompilerInvocation &CI,
    236                          IntrusiveRefCntPtr<llvm::vfs::FileSystem> &VFS,
    237                          llvm::MemoryBuffer *MainFileBuffer) const;
    238 
    239   /// Sets up the PreprocessorOptions and changes VFS, so that PCH stored in \p
    240   /// Storage is accessible to clang. This method is an implementation detail of
    241   /// AddImplicitPreamble.
    242   static void
    243   setupPreambleStorage(const PCHStorage &Storage,
    244                        PreprocessorOptions &PreprocessorOpts,
    245                        IntrusiveRefCntPtr<llvm::vfs::FileSystem> &VFS);
    246 
    247   /// Manages the memory buffer or temporary file that stores the PCH.
    248   PCHStorage Storage;
    249   /// Keeps track of the files that were used when computing the
    250   /// preamble, with both their buffer size and their modification time.
    251   ///
    252   /// If any of the files have changed from one compile to the next,
    253   /// the preamble must be thrown away.
    254   llvm::StringMap<PreambleFileHash> FilesInPreamble;
    255   /// Files that were not found during preamble building. If any of these now
    256   /// exist then the preamble should not be reused.
    257   ///
    258   /// Storing *all* the missing files that could invalidate the preamble would
    259   /// make it too expensive to revalidate (when the include path has many
    260   /// entries, each #include will miss half of them on average).
    261   /// Instead, we track only files that could have satisfied an #include that
    262   /// was ultimately not found.
    263   llvm::StringSet<> MissingFiles;
    264   /// The contents of the file that was used to precompile the preamble. Only
    265   /// contains first PreambleBounds::Size bytes. Used to compare if the relevant
    266   /// part of the file has not changed, so that preamble can be reused.
    267   std::vector<char> PreambleBytes;
    268   /// See PreambleBounds::PreambleEndsAtStartOfLine
    269   bool PreambleEndsAtStartOfLine;
    270 };
    271 
    272 /// A set of callbacks to gather useful information while building a preamble.
    273 class PreambleCallbacks {
    274 public:
    275   virtual ~PreambleCallbacks() = default;
    276 
    277   /// Called before FrontendAction::BeginSourceFile.
    278   /// Can be used to store references to various CompilerInstance fields
    279   /// (e.g. SourceManager) that may be interesting to the consumers of other
    280   /// callbacks.
    281   virtual void BeforeExecute(CompilerInstance &CI);
    282   /// Called after FrontendAction::Execute(), but before
    283   /// FrontendAction::EndSourceFile(). Can be used to transfer ownership of
    284   /// various CompilerInstance fields before they are destroyed.
    285   virtual void AfterExecute(CompilerInstance &CI);
    286   /// Called after PCH has been emitted. \p Writer may be used to retrieve
    287   /// information about AST, serialized in PCH.
    288   virtual void AfterPCHEmitted(ASTWriter &Writer);
    289   /// Called for each TopLevelDecl.
    290   /// NOTE: To allow more flexibility a custom ASTConsumer could probably be
    291   /// used instead, but having only this method allows a simpler API.
    292   virtual void HandleTopLevelDecl(DeclGroupRef DG);
    293   /// Creates wrapper class for PPCallbacks so we can also process information
    294   /// about includes that are inside of a preamble
    295   virtual std::unique_ptr<PPCallbacks> createPPCallbacks();
    296   /// The returned CommentHandler will be added to the preprocessor if not null.
    297   virtual CommentHandler *getCommentHandler();
    298   /// Determines which function bodies are parsed, by default skips everything.
    299   /// Only used if FrontendOpts::SkipFunctionBodies is true.
    300   /// See ASTConsumer::shouldSkipFunctionBody.
    301   virtual bool shouldSkipFunctionBody(Decl *D) { return true; }
    302 };
    303 
    304 enum class BuildPreambleError {
    305   CouldntCreateTempFile = 1,
    306   CouldntCreateTargetInfo,
    307   BeginSourceFileFailed,
    308   CouldntEmitPCH,
    309   BadInputs
    310 };
    311 
    312 class BuildPreambleErrorCategory final : public std::error_category {
    313 public:
    314   const char *name() const noexcept override;
    315   std::string message(int condition) const override;
    316 };
    317 
    318 std::error_code make_error_code(BuildPreambleError Error);
    319 } // namespace clang
    320 
    321 namespace std {
    322 template <>
    323 struct is_error_code_enum<clang::BuildPreambleError> : std::true_type {};
    324 } // namespace std
    325 
    326 #endif
    327