Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:36:55

0001 //===--- PrecompiledPreamble.h - Build precompiled preambles ----*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 // Helper class to build precompiled preamble.
0010 //
0011 //===----------------------------------------------------------------------===//
0012 
0013 #ifndef LLVM_CLANG_FRONTEND_PRECOMPILEDPREAMBLE_H
0014 #define LLVM_CLANG_FRONTEND_PRECOMPILEDPREAMBLE_H
0015 
0016 #include "clang/Lex/Lexer.h"
0017 #include "clang/Lex/Preprocessor.h"
0018 #include "llvm/ADT/IntrusiveRefCntPtr.h"
0019 #include "llvm/ADT/StringRef.h"
0020 #include "llvm/Support/MD5.h"
0021 #include <cstddef>
0022 #include <memory>
0023 #include <system_error>
0024 #include <type_traits>
0025 
0026 namespace llvm {
0027 class MemoryBuffer;
0028 class MemoryBufferRef;
0029 namespace vfs {
0030 class FileSystem;
0031 }
0032 } // namespace llvm
0033 
0034 namespace clang {
0035 class CompilerInstance;
0036 class CompilerInvocation;
0037 class Decl;
0038 class DeclGroupRef;
0039 class PCHContainerOperations;
0040 
0041 /// Runs lexer to compute suggested preamble bounds.
0042 PreambleBounds ComputePreambleBounds(const LangOptions &LangOpts,
0043                                      const llvm::MemoryBufferRef &Buffer,
0044                                      unsigned MaxLines);
0045 
0046 class PreambleCallbacks;
0047 
0048 /// A class holding a PCH and all information to check whether it is valid to
0049 /// reuse the PCH for the subsequent runs. Use BuildPreamble to create PCH and
0050 /// CanReusePreamble + AddImplicitPreamble to make use of it.
0051 class PrecompiledPreamble {
0052   class PCHStorage;
0053   struct PreambleFileHash;
0054 
0055 public:
0056   /// Try to build PrecompiledPreamble for \p Invocation. See
0057   /// BuildPreambleError for possible error codes.
0058   ///
0059   /// \param Invocation Original CompilerInvocation with options to compile the
0060   /// file.
0061   ///
0062   /// \param MainFileBuffer Buffer with the contents of the main file.
0063   ///
0064   /// \param Bounds Bounds of the preamble, result of calling
0065   /// ComputePreambleBounds.
0066   ///
0067   /// \param Diagnostics Diagnostics engine to be used while building the
0068   /// preamble.
0069   ///
0070   /// \param VFS An instance of vfs::FileSystem to be used for file
0071   /// accesses.
0072   ///
0073   /// \param PCHContainerOps An instance of PCHContainerOperations.
0074   ///
0075   /// \param StoreInMemory Store PCH in memory. If false, PCH will be stored in
0076   /// a temporary file.
0077   ///
0078   /// \param StoragePath The path to a directory, in which to create a temporary
0079   /// file to store PCH in. If empty, the default system temporary directory is
0080   /// used. This parameter is ignored if \p StoreInMemory is true.
0081   ///
0082   /// \param Callbacks A set of callbacks to be executed when building
0083   /// the preamble.
0084   static llvm::ErrorOr<PrecompiledPreamble>
0085   Build(const CompilerInvocation &Invocation,
0086         const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds,
0087         DiagnosticsEngine &Diagnostics,
0088         IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
0089         std::shared_ptr<PCHContainerOperations> PCHContainerOps,
0090         bool StoreInMemory, StringRef StoragePath,
0091         PreambleCallbacks &Callbacks);
0092 
0093   PrecompiledPreamble(PrecompiledPreamble &&);
0094   PrecompiledPreamble &operator=(PrecompiledPreamble &&);
0095   ~PrecompiledPreamble();
0096 
0097   /// PreambleBounds used to build the preamble.
0098   PreambleBounds getBounds() const;
0099 
0100   /// Returns the size, in bytes, that preamble takes on disk or in memory.
0101   /// For on-disk preambles returns 0 if filesystem operations fail. Intended to
0102   /// be used for logging and debugging purposes only.
0103   std::size_t getSize() const;
0104 
0105   /// Returned string is not null-terminated.
0106   llvm::StringRef getContents() const {
0107     return {PreambleBytes.data(), PreambleBytes.size()};
0108   }
0109 
0110   /// Check whether PrecompiledPreamble can be reused for the new contents(\p
0111   /// MainFileBuffer) of the main file.
0112   bool CanReuse(const CompilerInvocation &Invocation,
0113                 const llvm::MemoryBufferRef &MainFileBuffer,
0114                 PreambleBounds Bounds, llvm::vfs::FileSystem &VFS) const;
0115 
0116   /// Changes options inside \p CI to use PCH from this preamble. Also remaps
0117   /// main file to \p MainFileBuffer and updates \p VFS to ensure the preamble
0118   /// is accessible.
0119   /// Requires that CanReuse() is true.
0120   /// For in-memory preambles, PrecompiledPreamble instance continues to own the
0121   /// MemoryBuffer with the Preamble after this method returns. The caller is
0122   /// responsible for making sure the PrecompiledPreamble instance outlives the
0123   /// compiler run and the AST that will be using the PCH.
0124   void AddImplicitPreamble(CompilerInvocation &CI,
0125                            IntrusiveRefCntPtr<llvm::vfs::FileSystem> &VFS,
0126                            llvm::MemoryBuffer *MainFileBuffer) const;
0127 
0128   /// Configure \p CI to use this preamble.
0129   /// Like AddImplicitPreamble, but doesn't assume CanReuse() is true.
0130   /// If this preamble does not match the file, it may parse differently.
0131   void OverridePreamble(CompilerInvocation &CI,
0132                         IntrusiveRefCntPtr<llvm::vfs::FileSystem> &VFS,
0133                         llvm::MemoryBuffer *MainFileBuffer) const;
0134 
0135 private:
0136   PrecompiledPreamble(std::unique_ptr<PCHStorage> Storage,
0137                       std::vector<char> PreambleBytes,
0138                       bool PreambleEndsAtStartOfLine,
0139                       llvm::StringMap<PreambleFileHash> FilesInPreamble,
0140                       llvm::StringSet<> MissingFiles);
0141 
0142   /// Data used to determine if a file used in the preamble has been changed.
0143   struct PreambleFileHash {
0144     /// All files have size set.
0145     off_t Size = 0;
0146 
0147     /// Modification time is set for files that are on disk.  For memory
0148     /// buffers it is zero.
0149     time_t ModTime = 0;
0150 
0151     /// Memory buffers have MD5 instead of modification time.  We don't
0152     /// compute MD5 for on-disk files because we hope that modification time is
0153     /// enough to tell if the file was changed.
0154     llvm::MD5::MD5Result MD5 = {};
0155 
0156     static PreambleFileHash createForFile(off_t Size, time_t ModTime);
0157     static PreambleFileHash
0158     createForMemoryBuffer(const llvm::MemoryBufferRef &Buffer);
0159 
0160     friend bool operator==(const PreambleFileHash &LHS,
0161                            const PreambleFileHash &RHS) {
0162       return LHS.Size == RHS.Size && LHS.ModTime == RHS.ModTime &&
0163              LHS.MD5 == RHS.MD5;
0164     }
0165     friend bool operator!=(const PreambleFileHash &LHS,
0166                            const PreambleFileHash &RHS) {
0167       return !(LHS == RHS);
0168     }
0169   };
0170 
0171   /// Helper function to set up PCH for the preamble into \p CI and \p VFS to
0172   /// with the specified \p Bounds.
0173   void configurePreamble(PreambleBounds Bounds, CompilerInvocation &CI,
0174                          IntrusiveRefCntPtr<llvm::vfs::FileSystem> &VFS,
0175                          llvm::MemoryBuffer *MainFileBuffer) const;
0176 
0177   /// Sets up the PreprocessorOptions and changes VFS, so that PCH stored in \p
0178   /// Storage is accessible to clang. This method is an implementation detail of
0179   /// AddImplicitPreamble.
0180   static void
0181   setupPreambleStorage(const PCHStorage &Storage,
0182                        PreprocessorOptions &PreprocessorOpts,
0183                        IntrusiveRefCntPtr<llvm::vfs::FileSystem> &VFS);
0184 
0185   /// Manages the memory buffer or temporary file that stores the PCH.
0186   std::unique_ptr<PCHStorage> Storage;
0187   /// Keeps track of the files that were used when computing the
0188   /// preamble, with both their buffer size and their modification time.
0189   ///
0190   /// If any of the files have changed from one compile to the next,
0191   /// the preamble must be thrown away.
0192   llvm::StringMap<PreambleFileHash> FilesInPreamble;
0193   /// Files that were not found during preamble building. If any of these now
0194   /// exist then the preamble should not be reused.
0195   ///
0196   /// Storing *all* the missing files that could invalidate the preamble would
0197   /// make it too expensive to revalidate (when the include path has many
0198   /// entries, each #include will miss half of them on average).
0199   /// Instead, we track only files that could have satisfied an #include that
0200   /// was ultimately not found.
0201   llvm::StringSet<> MissingFiles;
0202   /// The contents of the file that was used to precompile the preamble. Only
0203   /// contains first PreambleBounds::Size bytes. Used to compare if the relevant
0204   /// part of the file has not changed, so that preamble can be reused.
0205   std::vector<char> PreambleBytes;
0206   /// See PreambleBounds::PreambleEndsAtStartOfLine
0207   bool PreambleEndsAtStartOfLine;
0208 };
0209 
0210 /// A set of callbacks to gather useful information while building a preamble.
0211 class PreambleCallbacks {
0212 public:
0213   virtual ~PreambleCallbacks() = default;
0214 
0215   /// Called before FrontendAction::Execute.
0216   /// Can be used to store references to various CompilerInstance fields
0217   /// (e.g. SourceManager) that may be interesting to the consumers of other
0218   /// callbacks.
0219   virtual void BeforeExecute(CompilerInstance &CI);
0220   /// Called after FrontendAction::Execute(), but before
0221   /// FrontendAction::EndSourceFile(). Can be used to transfer ownership of
0222   /// various CompilerInstance fields before they are destroyed.
0223   virtual void AfterExecute(CompilerInstance &CI);
0224   /// Called after PCH has been emitted. \p Writer may be used to retrieve
0225   /// information about AST, serialized in PCH.
0226   virtual void AfterPCHEmitted(ASTWriter &Writer);
0227   /// Called for each TopLevelDecl.
0228   /// NOTE: To allow more flexibility a custom ASTConsumer could probably be
0229   /// used instead, but having only this method allows a simpler API.
0230   virtual void HandleTopLevelDecl(DeclGroupRef DG);
0231   /// Creates wrapper class for PPCallbacks so we can also process information
0232   /// about includes that are inside of a preamble. Called after BeforeExecute.
0233   virtual std::unique_ptr<PPCallbacks> createPPCallbacks();
0234   /// The returned CommentHandler will be added to the preprocessor if not null.
0235   virtual CommentHandler *getCommentHandler();
0236   /// Determines which function bodies are parsed, by default skips everything.
0237   /// Only used if FrontendOpts::SkipFunctionBodies is true.
0238   /// See ASTConsumer::shouldSkipFunctionBody.
0239   virtual bool shouldSkipFunctionBody(Decl *D) { return true; }
0240 };
0241 
0242 enum class BuildPreambleError {
0243   CouldntCreateTempFile = 1,
0244   CouldntCreateTargetInfo,
0245   BeginSourceFileFailed,
0246   CouldntEmitPCH,
0247   BadInputs
0248 };
0249 
0250 class BuildPreambleErrorCategory final : public std::error_category {
0251 public:
0252   const char *name() const noexcept override;
0253   std::string message(int condition) const override;
0254 };
0255 
0256 std::error_code make_error_code(BuildPreambleError Error);
0257 } // namespace clang
0258 
0259 template <>
0260 struct std::is_error_code_enum<clang::BuildPreambleError> : std::true_type {};
0261 
0262 #endif