| //===--- PrecompiledPreamble.h - Build precompiled preambles ----*- C++ -*-===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // Helper class to build precompiled preamble. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_CLANG_FRONTEND_PRECOMPILED_PREAMBLE_H |
| #define LLVM_CLANG_FRONTEND_PRECOMPILED_PREAMBLE_H |
| |
| #include "clang/Lex/Lexer.h" |
| #include "clang/Lex/Preprocessor.h" |
| #include "llvm/ADT/IntrusiveRefCntPtr.h" |
| #include "llvm/Support/AlignOf.h" |
| #include "llvm/Support/MD5.h" |
| #include <cstddef> |
| #include <memory> |
| #include <system_error> |
| #include <type_traits> |
| |
| namespace llvm { |
| class MemoryBuffer; |
| } |
| |
| namespace clang { |
| namespace vfs { |
| class FileSystem; |
| } |
| |
| class CompilerInstance; |
| class CompilerInvocation; |
| class DeclGroupRef; |
| class PCHContainerOperations; |
| |
| /// Runs lexer to compute suggested preamble bounds. |
| PreambleBounds ComputePreambleBounds(const LangOptions &LangOpts, |
| llvm::MemoryBuffer *Buffer, |
| unsigned MaxLines); |
| |
| class PreambleCallbacks; |
| |
| /// A class holding a PCH and all information to check whether it is valid to |
| /// reuse the PCH for the subsequent runs. Use BuildPreamble to create PCH and |
| /// CanReusePreamble + AddImplicitPreamble to make use of it. |
| class PrecompiledPreamble { |
| class PCHStorage; |
| struct PreambleFileHash; |
| |
| public: |
| /// Try to build PrecompiledPreamble for \p Invocation. See |
| /// BuildPreambleError for possible error codes. |
| /// |
| /// \param Invocation Original CompilerInvocation with options to compile the |
| /// file. |
| /// |
| /// \param MainFileBuffer Buffer with the contents of the main file. |
| /// |
| /// \param Bounds Bounds of the preamble, result of calling |
| /// ComputePreambleBounds. |
| /// |
| /// \param Diagnostics Diagnostics engine to be used while building the |
| /// preamble. |
| /// |
| /// \param VFS An instance of vfs::FileSystem to be used for file |
| /// accesses. |
| /// |
| /// \param PCHContainerOps An instance of PCHContainerOperations. |
| /// |
| /// \param StoreInMemory Store PCH in memory. If false, PCH will be stored in |
| /// a temporary file. |
| /// |
| /// \param Callbacks A set of callbacks to be executed when building |
| /// the preamble. |
| static llvm::ErrorOr<PrecompiledPreamble> |
| Build(const CompilerInvocation &Invocation, |
| const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds, |
| DiagnosticsEngine &Diagnostics, IntrusiveRefCntPtr<vfs::FileSystem> VFS, |
| std::shared_ptr<PCHContainerOperations> PCHContainerOps, |
| bool StoreInMemory, PreambleCallbacks &Callbacks); |
| |
| PrecompiledPreamble(PrecompiledPreamble &&) = default; |
| PrecompiledPreamble &operator=(PrecompiledPreamble &&) = default; |
| |
| /// PreambleBounds used to build the preamble. |
| PreambleBounds getBounds() const; |
| |
| /// Returns the size, in bytes, that preamble takes on disk or in memory. |
| /// For on-disk preambles returns 0 if filesystem operations fail. Intended to |
| /// be used for logging and debugging purposes only. |
| std::size_t getSize() const; |
| |
| /// Check whether PrecompiledPreamble can be reused for the new contents(\p |
| /// MainFileBuffer) of the main file. |
| bool CanReuse(const CompilerInvocation &Invocation, |
| const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds, |
| vfs::FileSystem *VFS) const; |
| |
| /// Changes options inside \p CI to use PCH from this preamble. Also remaps |
| /// main file to \p MainFileBuffer and updates \p VFS to ensure the preamble |
| /// is accessible. |
| /// Requires that CanReuse() is true. |
| /// For in-memory preambles, PrecompiledPreamble instance continues to own the |
| /// MemoryBuffer with the Preamble after this method returns. The caller is |
| /// responsible for making sure the PrecompiledPreamble instance outlives the |
| /// compiler run and the AST that will be using the PCH. |
| void AddImplicitPreamble(CompilerInvocation &CI, |
| IntrusiveRefCntPtr<vfs::FileSystem> &VFS, |
| llvm::MemoryBuffer *MainFileBuffer) const; |
| |
| /// Configure \p CI to use this preamble. |
| /// Like AddImplicitPreamble, but doesn't assume CanReuse() is true. |
| /// If this preamble does not match the file, it may parse differently. |
| void OverridePreamble(CompilerInvocation &CI, |
| IntrusiveRefCntPtr<vfs::FileSystem> &VFS, |
| llvm::MemoryBuffer *MainFileBuffer) const; |
| |
| private: |
| PrecompiledPreamble(PCHStorage Storage, std::vector<char> PreambleBytes, |
| bool PreambleEndsAtStartOfLine, |
| llvm::StringMap<PreambleFileHash> FilesInPreamble); |
| |
| /// A temp file that would be deleted on destructor call. If destructor is not |
| /// called for any reason, the file will be deleted at static objects' |
| /// destruction. |
| /// An assertion will fire if two TempPCHFiles are created with the same name, |
| /// so it's not intended to be used outside preamble-handling. |
| class TempPCHFile { |
| public: |
| // A main method used to construct TempPCHFile. |
| static llvm::ErrorOr<TempPCHFile> CreateNewPreamblePCHFile(); |
| |
| /// Call llvm::sys::fs::createTemporaryFile to create a new temporary file. |
| static llvm::ErrorOr<TempPCHFile> createInSystemTempDir(const Twine &Prefix, |
| StringRef Suffix); |
| /// Create a new instance of TemporaryFile for file at \p Path. Use with |
| /// extreme caution, there's an assertion checking that there's only a |
| /// single instance of TempPCHFile alive for each path. |
| static llvm::ErrorOr<TempPCHFile> createFromCustomPath(const Twine &Path); |
| |
| private: |
| TempPCHFile(std::string FilePath); |
| |
| public: |
| TempPCHFile(TempPCHFile &&Other); |
| TempPCHFile &operator=(TempPCHFile &&Other); |
| |
| TempPCHFile(const TempPCHFile &) = delete; |
| ~TempPCHFile(); |
| |
| /// A path where temporary file is stored. |
| llvm::StringRef getFilePath() const; |
| |
| private: |
| void RemoveFileIfPresent(); |
| |
| private: |
| llvm::Optional<std::string> FilePath; |
| }; |
| |
| class InMemoryPreamble { |
| public: |
| std::string Data; |
| }; |
| |
| class PCHStorage { |
| public: |
| enum class Kind { Empty, InMemory, TempFile }; |
| |
| PCHStorage() = default; |
| PCHStorage(TempPCHFile File); |
| PCHStorage(InMemoryPreamble Memory); |
| |
| PCHStorage(const PCHStorage &) = delete; |
| PCHStorage &operator=(const PCHStorage &) = delete; |
| |
| PCHStorage(PCHStorage &&Other); |
| PCHStorage &operator=(PCHStorage &&Other); |
| |
| ~PCHStorage(); |
| |
| Kind getKind() const; |
| |
| TempPCHFile &asFile(); |
| const TempPCHFile &asFile() const; |
| |
| InMemoryPreamble &asMemory(); |
| const InMemoryPreamble &asMemory() const; |
| |
| private: |
| void destroy(); |
| void setEmpty(); |
| |
| private: |
| Kind StorageKind = Kind::Empty; |
| llvm::AlignedCharArrayUnion<TempPCHFile, InMemoryPreamble> Storage = {}; |
| }; |
| |
| /// Data used to determine if a file used in the preamble has been changed. |
| struct PreambleFileHash { |
| /// All files have size set. |
| off_t Size = 0; |
| |
| /// Modification time is set for files that are on disk. For memory |
| /// buffers it is zero. |
| time_t ModTime = 0; |
| |
| /// Memory buffers have MD5 instead of modification time. We don't |
| /// compute MD5 for on-disk files because we hope that modification time is |
| /// enough to tell if the file was changed. |
| llvm::MD5::MD5Result MD5 = {}; |
| |
| static PreambleFileHash createForFile(off_t Size, time_t ModTime); |
| static PreambleFileHash |
| createForMemoryBuffer(const llvm::MemoryBuffer *Buffer); |
| |
| friend bool operator==(const PreambleFileHash &LHS, |
| const PreambleFileHash &RHS) { |
| return LHS.Size == RHS.Size && LHS.ModTime == RHS.ModTime && |
| LHS.MD5 == RHS.MD5; |
| } |
| friend bool operator!=(const PreambleFileHash &LHS, |
| const PreambleFileHash &RHS) { |
| return !(LHS == RHS); |
| } |
| }; |
| |
| /// Helper function to set up PCH for the preamble into \p CI and \p VFS to |
| /// with the specified \p Bounds. |
| void configurePreamble(PreambleBounds Bounds, CompilerInvocation &CI, |
| IntrusiveRefCntPtr<vfs::FileSystem> &VFS, |
| llvm::MemoryBuffer *MainFileBuffer) const; |
| |
| /// Sets up the PreprocessorOptions and changes VFS, so that PCH stored in \p |
| /// Storage is accessible to clang. This method is an implementation detail of |
| /// AddImplicitPreamble. |
| static void setupPreambleStorage(const PCHStorage &Storage, |
| PreprocessorOptions &PreprocessorOpts, |
| IntrusiveRefCntPtr<vfs::FileSystem> &VFS); |
| |
| /// Manages the memory buffer or temporary file that stores the PCH. |
| PCHStorage Storage; |
| /// Keeps track of the files that were used when computing the |
| /// preamble, with both their buffer size and their modification time. |
| /// |
| /// If any of the files have changed from one compile to the next, |
| /// the preamble must be thrown away. |
| llvm::StringMap<PreambleFileHash> FilesInPreamble; |
| /// The contents of the file that was used to precompile the preamble. Only |
| /// contains first PreambleBounds::Size bytes. Used to compare if the relevant |
| /// part of the file has not changed, so that preamble can be reused. |
| std::vector<char> PreambleBytes; |
| /// See PreambleBounds::PreambleEndsAtStartOfLine |
| bool PreambleEndsAtStartOfLine; |
| }; |
| |
| /// A set of callbacks to gather useful information while building a preamble. |
| class PreambleCallbacks { |
| public: |
| virtual ~PreambleCallbacks() = default; |
| |
| /// Called before FrontendAction::BeginSourceFile. |
| /// Can be used to store references to various CompilerInstance fields |
| /// (e.g. SourceManager) that may be interesting to the consumers of other |
| /// callbacks. |
| virtual void BeforeExecute(CompilerInstance &CI); |
| /// Called after FrontendAction::Execute(), but before |
| /// FrontendAction::EndSourceFile(). Can be used to transfer ownership of |
| /// various CompilerInstance fields before they are destroyed. |
| virtual void AfterExecute(CompilerInstance &CI); |
| /// Called after PCH has been emitted. \p Writer may be used to retrieve |
| /// information about AST, serialized in PCH. |
| virtual void AfterPCHEmitted(ASTWriter &Writer); |
| /// Called for each TopLevelDecl. |
| /// NOTE: To allow more flexibility a custom ASTConsumer could probably be |
| /// used instead, but having only this method allows a simpler API. |
| virtual void HandleTopLevelDecl(DeclGroupRef DG); |
| /// Creates wrapper class for PPCallbacks so we can also process information |
| /// about includes that are inside of a preamble |
| virtual std::unique_ptr<PPCallbacks> createPPCallbacks(); |
| }; |
| |
| enum class BuildPreambleError { |
| PreambleIsEmpty = 1, |
| CouldntCreateTempFile, |
| CouldntCreateTargetInfo, |
| BeginSourceFileFailed, |
| CouldntEmitPCH |
| }; |
| |
| class BuildPreambleErrorCategory final : public std::error_category { |
| public: |
| const char *name() const noexcept override; |
| std::string message(int condition) const override; |
| }; |
| |
| std::error_code make_error_code(BuildPreambleError Error); |
| } // namespace clang |
| |
| namespace std { |
| template <> |
| struct is_error_code_enum<clang::BuildPreambleError> : std::true_type {}; |
| } // namespace std |
| |
| #endif |