| //===-- CompilerInstance.h - Flang Compiler Instance ------------*- 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 |
| // |
| //===----------------------------------------------------------------------===// |
| #ifndef LLVM_FLANG_FRONTEND_COMPILERINSTANCE_H |
| #define LLVM_FLANG_FRONTEND_COMPILERINSTANCE_H |
| |
| #include "flang/Frontend/CompilerInvocation.h" |
| #include "flang/Frontend/FrontendAction.h" |
| #include "flang/Frontend/PreprocessorOptions.h" |
| #include "flang/Parser/parsing.h" |
| #include "flang/Parser/provenance.h" |
| #include "flang/Semantics/semantics.h" |
| #include "llvm/Support/raw_ostream.h" |
| |
| namespace Fortran::frontend { |
| |
| /// Helper class for managing a single instance of the Flang compiler. |
| /// |
| /// This class serves two purposes: |
| /// (1) It manages the various objects which are necessary to run the compiler |
| /// (2) It provides utility routines for constructing and manipulating the |
| /// common Flang objects. |
| /// |
| /// The compiler instance generally owns the instance of all the objects that it |
| /// manages. However, clients can still share objects by manually setting the |
| /// object and retaking ownership prior to destroying the CompilerInstance. |
| /// |
| /// The compiler instance is intended to simplify clients, but not to lock them |
| /// in to the compiler instance for everything. When possible, utility functions |
| /// come in two forms; a short form that reuses the CompilerInstance objects, |
| /// and a long form that takes explicit instances of any required objects. |
| class CompilerInstance { |
| |
| /// The options used in this compiler instance. |
| std::shared_ptr<CompilerInvocation> invocation_; |
| |
| /// Flang file manager. |
| std::shared_ptr<Fortran::parser::AllSources> allSources_; |
| |
| std::shared_ptr<Fortran::parser::AllCookedSources> allCookedSources_; |
| |
| std::shared_ptr<Fortran::parser::Parsing> parsing_; |
| |
| std::unique_ptr<Fortran::semantics::Semantics> semantics_; |
| |
| /// The stream for diagnostics from Semantics |
| llvm::raw_ostream *semaOutputStream_ = &llvm::errs(); |
| |
| /// The stream for diagnostics from Semantics if owned, otherwise nullptr. |
| std::unique_ptr<llvm::raw_ostream> ownedSemaOutputStream_; |
| |
| /// The diagnostics engine instance. |
| llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> diagnostics_; |
| |
| /// Holds information about the output file. |
| struct OutputFile { |
| std::string filename_; |
| OutputFile(std::string inputFilename) |
| : filename_(std::move(inputFilename)) {} |
| }; |
| |
| /// The list of active output files. |
| std::list<OutputFile> outputFiles_; |
| |
| /// Holds the output stream provided by the user. Normally, users of |
| /// CompilerInstance will call CreateOutputFile to obtain/create an output |
| /// stream. If they want to provide their own output stream, this field will |
| /// facilitate this. It is optional and will normally be just a nullptr. |
| std::unique_ptr<llvm::raw_pwrite_stream> outputStream_; |
| |
| public: |
| explicit CompilerInstance(); |
| |
| ~CompilerInstance(); |
| |
| /// @name Compiler Invocation |
| /// { |
| |
| CompilerInvocation &invocation() { |
| assert(invocation_ && "Compiler instance has no invocation!"); |
| return *invocation_; |
| }; |
| |
| /// Replace the current invocation. |
| void set_invocation(std::shared_ptr<CompilerInvocation> value); |
| |
| /// } |
| /// @name File manager |
| /// { |
| |
| /// Return the current allSources. |
| Fortran::parser::AllSources &allSources() const { return *allSources_; } |
| |
| bool HasAllSources() const { return allSources_ != nullptr; } |
| |
| parser::AllCookedSources &allCookedSources() { |
| assert(allCookedSources_ && "Compiler instance has no AllCookedSources!"); |
| return *allCookedSources_; |
| }; |
| |
| /// } |
| /// @name Parser Operations |
| /// { |
| |
| /// Return parsing to be used by Actions. |
| Fortran::parser::Parsing &parsing() const { return *parsing_; } |
| |
| /// } |
| /// @name Semantic analysis |
| /// { |
| |
| /// Replace the current stream for verbose output. |
| void set_semaOutputStream(llvm::raw_ostream &Value); |
| |
| /// Replace the current stream for verbose output. |
| void set_semaOutputStream(std::unique_ptr<llvm::raw_ostream> Value); |
| |
| /// Get the current stream for verbose output. |
| llvm::raw_ostream &semaOutputStream() { return *semaOutputStream_; } |
| |
| Fortran::semantics::Semantics &semantics() { return *semantics_; } |
| const Fortran::semantics::Semantics &semantics() const { return *semantics_; } |
| |
| void setSemantics(std::unique_ptr<Fortran::semantics::Semantics> semantics) { |
| semantics_ = std::move(semantics); |
| } |
| |
| /// } |
| /// @name High-Level Operations |
| /// { |
| |
| /// Execute the provided action against the compiler's |
| /// CompilerInvocation object. |
| /// \param act - The action to execute. |
| /// \return - True on success. |
| bool ExecuteAction(FrontendAction &act); |
| |
| /// } |
| /// @name Forwarding Methods |
| /// { |
| |
| clang::DiagnosticOptions &GetDiagnosticOpts() { |
| return invocation_->GetDiagnosticOpts(); |
| } |
| const clang::DiagnosticOptions &GetDiagnosticOpts() const { |
| return invocation_->GetDiagnosticOpts(); |
| } |
| |
| FrontendOptions &frontendOpts() { return invocation_->frontendOpts(); } |
| const FrontendOptions &frontendOpts() const { |
| return invocation_->frontendOpts(); |
| } |
| |
| PreprocessorOptions &preprocessorOpts() { |
| return invocation_->preprocessorOpts(); |
| } |
| const PreprocessorOptions &preprocessorOpts() const { |
| return invocation_->preprocessorOpts(); |
| } |
| |
| /// } |
| /// @name Diagnostics Engine |
| /// { |
| |
| bool HasDiagnostics() const { return diagnostics_ != nullptr; } |
| |
| /// Get the current diagnostics engine. |
| clang::DiagnosticsEngine &diagnostics() const { |
| assert(diagnostics_ && "Compiler instance has no diagnostics!"); |
| return *diagnostics_; |
| } |
| |
| clang::DiagnosticConsumer &GetDiagnosticClient() const { |
| assert(diagnostics_ && diagnostics_->getClient() && |
| "Compiler instance has no diagnostic client!"); |
| return *diagnostics_->getClient(); |
| } |
| |
| /// { |
| /// @name Output Files |
| /// { |
| |
| /// Clear the output file list. |
| void ClearOutputFiles(bool eraseFiles); |
| |
| /// Create the default output file (based on the invocation's options) and |
| /// add it to the list of tracked output files. If the name of the output |
| /// file is not provided, it will be derived from the input file. |
| /// |
| /// \param binary The mode to open the file in. |
| /// \param baseInput If the invocation contains no output file name (i.e. |
| /// outputFile in FrontendOptions is empty), the input path |
| /// name to use for deriving the output path. |
| /// \param extension The extension to use for output names derived from |
| /// \p baseInput. |
| /// \return Null on error, ostream for the output file otherwise |
| std::unique_ptr<llvm::raw_pwrite_stream> CreateDefaultOutputFile( |
| bool binary = true, llvm::StringRef baseInput = "", |
| llvm::StringRef extension = ""); |
| |
| private: |
| /// Create a new output file |
| /// |
| /// \param outputPath The path to the output file. |
| /// \param binary The mode to open the file in. |
| /// \return Null on error, ostream for the output file otherwise |
| llvm::Expected<std::unique_ptr<llvm::raw_pwrite_stream>> CreateOutputFileImpl( |
| llvm::StringRef outputPath, bool binary); |
| |
| public: |
| /// } |
| /// @name Construction Utility Methods |
| /// { |
| |
| /// Create a DiagnosticsEngine object |
| /// |
| /// If no diagnostic client is provided, this method creates a |
| /// DiagnosticConsumer that is owned by the returned diagnostic object. If |
| /// using directly the caller is responsible for releasing the returned |
| /// DiagnosticsEngine's client eventually. |
| /// |
| /// \param opts - The diagnostic options; note that the created text |
| /// diagnostic object contains a reference to these options. |
| /// |
| /// \param client - If non-NULL, a diagnostic client that will be attached to |
| /// (and optionally, depending on /p shouldOwnClient, owned by) the returned |
| /// DiagnosticsEngine object. |
| /// |
| /// \return The new object on success, or null on failure. |
| static clang::IntrusiveRefCntPtr<clang::DiagnosticsEngine> CreateDiagnostics( |
| clang::DiagnosticOptions *opts, |
| clang::DiagnosticConsumer *client = nullptr, bool shouldOwnClient = true); |
| void CreateDiagnostics( |
| clang::DiagnosticConsumer *client = nullptr, bool shouldOwnClient = true); |
| |
| /// } |
| /// @name Output Stream Methods |
| /// { |
| void set_outputStream(std::unique_ptr<llvm::raw_pwrite_stream> outStream) { |
| outputStream_ = std::move(outStream); |
| } |
| |
| bool IsOutputStreamNull() { return (outputStream_ == nullptr); } |
| |
| // Allow the frontend compiler to write in the output stream. |
| void WriteOutputStream(const std::string &message) { |
| *outputStream_ << message; |
| } |
| }; |
| |
| } // end namespace Fortran::frontend |
| #endif // LLVM_FLANG_FRONTEND_COMPILERINSTANCE_H |