From: Daniel Dunbar Date: Wed, 13 Jan 2010 00:48:06 +0000 (+0000) Subject: cc1: Factor out CompilerInstance::ExecuteAction which has the majority of the X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0397af277e3bba16da1fd125ddba07415686b429;p=clang cc1: Factor out CompilerInstance::ExecuteAction which has the majority of the clang -cc1 logic for running an action against a set of options. - This should make it easier to build tools that have a clang -cc1 like interface, but aren't actually part of clang -cc1. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@93282 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Frontend/CompilerInstance.h b/include/clang/Frontend/CompilerInstance.h index 18ec429db7..35a983dbd7 100644 --- a/include/clang/Frontend/CompilerInstance.h +++ b/include/clang/Frontend/CompilerInstance.h @@ -32,6 +32,7 @@ class Diagnostic; class DiagnosticClient; class ExternalASTSource; class FileManager; +class FrontendAction; class Preprocessor; class Source; class SourceManager; @@ -103,6 +104,42 @@ public: bool _OwnsLLVMContext = true); ~CompilerInstance(); + /// @name High-Level Operations + /// { + + /// ExecuteAction - Execute the provided action against the compiler's + /// CompilerInvocation object. + /// + /// This function makes the following assumptions: + /// + /// - The invocation options should be initialized. This function does not + /// handle the '-help' or '-version' options, clients should handle those + /// directly. + /// + /// - The diagnostics engine should have already been created by the client. + /// + /// - No other CompilerInstance state should have been initialized (this is + /// an unchecked error). + /// + /// - Clients should have initialized any LLVM target features that may be + /// required. + /// + /// - Clients should eventually call llvm_shutdown() upon the completion of + /// this routine to ensure that any managed objects are properly destroyed. + /// + /// Note that this routine may write output to 'stderr'. + /// + /// \param Act - The action to execute. + /// \return - True on success. + // + // FIXME: This function should take the stream to write any debugging / + // verbose output to as an argument. + // + // FIXME: Eliminate the llvm_shutdown requirement, that should either be part + // of the context or else not CompilerInstance specific. + bool ExecuteAction(FrontendAction &Act); + + /// } /// @name LLVM Context /// { diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp index 2a6a8a8750..9f71ec6b23 100644 --- a/lib/Frontend/CompilerInstance.cpp +++ b/lib/Frontend/CompilerInstance.cpp @@ -14,10 +14,12 @@ #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Basic/Version.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/PTHManager.h" #include "clang/Frontend/ChainedDiagnosticClient.h" +#include "clang/Frontend/FrontendAction.h" #include "clang/Frontend/PCHReader.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Frontend/TextDiagnosticPrinter.h" @@ -28,6 +30,7 @@ #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/Timer.h" +#include "llvm/System/Host.h" #include "llvm/System/Path.h" #include "llvm/System/Program.h" using namespace clang; @@ -409,3 +412,87 @@ bool CompilerInstance::InitializeSourceManager(llvm::StringRef InputFile, return true; } + +// High-Level Operations + +bool CompilerInstance::ExecuteAction(FrontendAction &Act) { + assert(hasDiagnostics() && "Diagnostics engine is not initialized!"); + assert(!getFrontendOpts().ShowHelp && "Client must handle '-help'!"); + assert(!getFrontendOpts().ShowVersion && "Client must handle '-version'!"); + + // FIXME: Take this as an argument, once all the APIs we used have moved to + // taking it as an input instead of hard-coding llvm::errs. + llvm::raw_ostream &OS = llvm::errs(); + + // Create the target instance. + setTarget(TargetInfo::CreateTargetInfo(getDiagnostics(), getTargetOpts())); + if (!hasTarget()) + return false; + + // Inform the target of the language options. + // + // FIXME: We shouldn't need to do this, the target should be immutable once + // created. This complexity should be lifted elsewhere. + getTarget().setForcedLangOptions(getLangOpts()); + + // Validate/process some options. + if (getHeaderSearchOpts().Verbose) + OS << "clang -cc1 version " CLANG_VERSION_STRING + << " based upon " << PACKAGE_STRING + << " hosted on " << llvm::sys::getHostTriple() << "\n"; + + if (getFrontendOpts().ShowTimers) + createFrontendTimer(); + + for (unsigned i = 0, e = getFrontendOpts().Inputs.size(); i != e; ++i) { + const std::string &InFile = getFrontendOpts().Inputs[i].second; + + // If we aren't using an AST file, setup the file and source managers and + // the preprocessor. + bool IsAST = getFrontendOpts().Inputs[i].first == FrontendOptions::IK_AST; + if (!IsAST) { + if (!i) { + // Create a file manager object to provide access to and cache the + // filesystem. + createFileManager(); + + // Create the source manager. + createSourceManager(); + } else { + // Reset the ID tables if we are reusing the SourceManager. + getSourceManager().clearIDTables(); + } + + // Create the preprocessor. + createPreprocessor(); + } + + if (Act.BeginSourceFile(*this, InFile, IsAST)) { + Act.Execute(); + Act.EndSourceFile(); + } + } + + if (getDiagnosticOpts().ShowCarets) + if (unsigned NumDiagnostics = getDiagnostics().getNumDiagnostics()) + OS << NumDiagnostics << " diagnostic" + << (NumDiagnostics == 1 ? "" : "s") + << " generated.\n"; + + if (getFrontendOpts().ShowStats) { + getFileManager().PrintStats(); + OS << "\n"; + } + + // Return the appropriate status when verifying diagnostics. + // + // FIXME: If we could make getNumErrors() do the right thing, we wouldn't need + // this. + if (getDiagnosticOpts().VerifyDiagnostics) + return !static_cast( + getDiagnosticClient()).HadErrors(); + + return !getDiagnostics().getNumErrors(); +} + + diff --git a/tools/driver/cc1_main.cpp b/tools/driver/cc1_main.cpp index d901c6f8a1..d2f1017c21 100644 --- a/tools/driver/cc1_main.cpp +++ b/tools/driver/cc1_main.cpp @@ -14,10 +14,6 @@ //===----------------------------------------------------------------------===// #include "clang/Basic/Diagnostic.h" -#include "clang/Basic/FileManager.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Basic/TargetInfo.h" -#include "clang/Basic/Version.h" #include "clang/Driver/Arg.h" #include "clang/Driver/ArgList.h" #include "clang/Driver/CC1Options.h" @@ -30,7 +26,6 @@ #include "clang/Frontend/FrontendPluginRegistry.h" #include "clang/Frontend/TextDiagnosticBuffer.h" #include "clang/Frontend/TextDiagnosticPrinter.h" -#include "clang/Frontend/VerifyDiagnosticsClient.h" #include "llvm/LLVMContext.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/Support/ErrorHandling.h" @@ -38,8 +33,6 @@ #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/raw_ostream.h" #include "llvm/System/DynamicLibrary.h" -#include "llvm/System/Host.h" -#include "llvm/System/Path.h" #include "llvm/System/Signals.h" #include "llvm/Target/TargetSelect.h" #include @@ -207,13 +200,13 @@ int cc1_main(const char **ArgBegin, const char **ArgEnd, Diags); // Infer the builtin include path if unspecified. - if (Clang.getInvocation().getHeaderSearchOpts().UseBuiltinIncludes && - Clang.getInvocation().getHeaderSearchOpts().ResourceDir.empty()) - Clang.getInvocation().getHeaderSearchOpts().ResourceDir = + if (Clang.getHeaderSearchOpts().UseBuiltinIncludes && + Clang.getHeaderSearchOpts().ResourceDir.empty()) + Clang.getHeaderSearchOpts().ResourceDir = CompilerInvocation::GetResourcesPath(Argv0, MainAddr); // Honor -help. - if (Clang.getInvocation().getFrontendOpts().ShowHelp) { + if (Clang.getFrontendOpts().ShowHelp) { llvm::OwningPtr Opts(driver::createCC1OptTable()); Opts->PrintHelp(llvm::outs(), "clang -cc1", "LLVM 'Clang' Compiler: http://clang.llvm.org"); @@ -223,7 +216,7 @@ int cc1_main(const char **ArgBegin, const char **ArgEnd, // Honor -version. // // FIXME: Use a better -version message? - if (Clang.getInvocation().getFrontendOpts().ShowVersion) { + if (Clang.getFrontendOpts().ShowVersion) { llvm::cl::PrintVersionMessage(); return 0; } @@ -249,85 +242,18 @@ int cc1_main(const char **ArgBegin, const char **ArgEnd, Diags.Report(diag::err_fe_unable_to_load_plugin) << Path << Error; } - // Create the frontend action. - llvm::OwningPtr Act(CreateFrontendAction(Clang)); - - // If there were any errors in processing arguments, exit now. - if (!Act || Clang.getDiagnostics().getNumErrors()) - return 1; - - // Create the target instance. - Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(), - Clang.getTargetOpts())); - if (!Clang.hasTarget()) - return 1; - - // Inform the target of the language options. - // - // FIXME: We shouldn't need to do this, the target should be immutable once - // created. This complexity should be lifted elsewhere. - Clang.getTarget().setForcedLangOptions(Clang.getLangOpts()); - - // Validate/process some options. - if (Clang.getHeaderSearchOpts().Verbose) - llvm::errs() << "clang -cc1 version " CLANG_VERSION_STRING - << " based upon " << PACKAGE_STRING - << " hosted on " << llvm::sys::getHostTriple() << "\n"; - - if (Clang.getFrontendOpts().ShowTimers) - Clang.createFrontendTimer(); - - for (unsigned i = 0, e = Clang.getFrontendOpts().Inputs.size(); i != e; ++i) { - const std::string &InFile = Clang.getFrontendOpts().Inputs[i].second; - - // If we aren't using an AST file, setup the file and source managers and - // the preprocessor. - bool IsAST = - Clang.getFrontendOpts().Inputs[i].first == FrontendOptions::IK_AST; - if (!IsAST) { - if (!i) { - // Create a file manager object to provide access to and cache the - // filesystem. - Clang.createFileManager(); - - // Create the source manager. - Clang.createSourceManager(); - } else { - // Reset the ID tables if we are reusing the SourceManager. - Clang.getSourceManager().clearIDTables(); - } - - // Create the preprocessor. - Clang.createPreprocessor(); - } - - if (Act->BeginSourceFile(Clang, InFile, IsAST)) { - Act->Execute(); - Act->EndSourceFile(); - } + // If there were errors in processing arguments, don't do anything else. + bool Success = false; + if (!Clang.getDiagnostics().getNumErrors()) { + // Create and execute the frontend action. + llvm::OwningPtr Act(CreateFrontendAction(Clang)); + if (Act) + Success = Clang.ExecuteAction(*Act); } - if (Clang.getDiagnosticOpts().ShowCarets) - if (unsigned NumDiagnostics = Clang.getDiagnostics().getNumDiagnostics()) - fprintf(stderr, "%d diagnostic%s generated.\n", NumDiagnostics, - (NumDiagnostics == 1 ? "" : "s")); - - if (Clang.getFrontendOpts().ShowStats) { - Clang.getFileManager().PrintStats(); - fprintf(stderr, "\n"); - } - - // Return the appropriate status when verifying diagnostics. - // - // FIXME: If we could make getNumErrors() do the right thing, we wouldn't need - // this. - if (Clang.getDiagnosticOpts().VerifyDiagnostics) - return static_cast( - Clang.getDiagnosticClient()).HadErrors(); - // Managed static deconstruction. Useful for making things like // -time-passes usable. llvm::llvm_shutdown(); - return (Clang.getDiagnostics().getNumErrors() != 0); + return !Success; }