123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270 |
- #pragma once
- #ifdef __GNUC__
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wunused-parameter"
- #endif
- //===--- PrecompiledPreamble.h - Build precompiled preambles ----*- C++ -*-===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // Helper class to build precompiled preamble.
- //
- //===----------------------------------------------------------------------===//
- #ifndef LLVM_CLANG_FRONTEND_PRECOMPILEDPREAMBLE_H
- #define LLVM_CLANG_FRONTEND_PRECOMPILEDPREAMBLE_H
- #include "clang/Lex/Lexer.h"
- #include "clang/Lex/Preprocessor.h"
- #include "llvm/ADT/IntrusiveRefCntPtr.h"
- #include "llvm/ADT/StringRef.h"
- #include "llvm/Support/MD5.h"
- #include <cstddef>
- #include <memory>
- #include <system_error>
- #include <type_traits>
- namespace llvm {
- class MemoryBuffer;
- class MemoryBufferRef;
- namespace vfs {
- class FileSystem;
- }
- } // namespace llvm
- namespace clang {
- class CompilerInstance;
- class CompilerInvocation;
- class Decl;
- class DeclGroupRef;
- class PCHContainerOperations;
- /// Runs lexer to compute suggested preamble bounds.
- PreambleBounds ComputePreambleBounds(const LangOptions &LangOpts,
- const llvm::MemoryBufferRef &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<llvm::vfs::FileSystem> VFS,
- std::shared_ptr<PCHContainerOperations> PCHContainerOps,
- bool StoreInMemory, PreambleCallbacks &Callbacks);
- PrecompiledPreamble(PrecompiledPreamble &&);
- PrecompiledPreamble &operator=(PrecompiledPreamble &&);
- ~PrecompiledPreamble();
- /// 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;
- /// Returned string is not null-terminated.
- llvm::StringRef getContents() const {
- return {PreambleBytes.data(), PreambleBytes.size()};
- }
- /// Check whether PrecompiledPreamble can be reused for the new contents(\p
- /// MainFileBuffer) of the main file.
- bool CanReuse(const CompilerInvocation &Invocation,
- const llvm::MemoryBufferRef &MainFileBuffer,
- PreambleBounds Bounds, llvm::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<llvm::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<llvm::vfs::FileSystem> &VFS,
- llvm::MemoryBuffer *MainFileBuffer) const;
- private:
- PrecompiledPreamble(std::unique_ptr<PCHStorage> Storage,
- std::vector<char> PreambleBytes,
- bool PreambleEndsAtStartOfLine,
- llvm::StringMap<PreambleFileHash> FilesInPreamble,
- llvm::StringSet<> MissingFiles);
- /// 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::MemoryBufferRef &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<llvm::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<llvm::vfs::FileSystem> &VFS);
- /// Manages the memory buffer or temporary file that stores the PCH.
- std::unique_ptr<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;
- /// Files that were not found during preamble building. If any of these now
- /// exist then the preamble should not be reused.
- ///
- /// Storing *all* the missing files that could invalidate the preamble would
- /// make it too expensive to revalidate (when the include path has many
- /// entries, each #include will miss half of them on average).
- /// Instead, we track only files that could have satisfied an #include that
- /// was ultimately not found.
- llvm::StringSet<> MissingFiles;
- /// 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::Execute.
- /// 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. Called after BeforeExecute.
- virtual std::unique_ptr<PPCallbacks> createPPCallbacks();
- /// The returned CommentHandler will be added to the preprocessor if not null.
- virtual CommentHandler *getCommentHandler();
- /// Determines which function bodies are parsed, by default skips everything.
- /// Only used if FrontendOpts::SkipFunctionBodies is true.
- /// See ASTConsumer::shouldSkipFunctionBody.
- virtual bool shouldSkipFunctionBody(Decl *D) { return true; }
- };
- enum class BuildPreambleError {
- CouldntCreateTempFile = 1,
- CouldntCreateTargetInfo,
- BeginSourceFileFailed,
- CouldntEmitPCH,
- BadInputs
- };
- 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
- #ifdef __GNUC__
- #pragma GCC diagnostic pop
- #endif
|