//===-- cc1_main.cpp - Clang CC1 Compiler Frontend ------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This is the entry point to the clang -cc1 functionality, which implements the // core compiler functionality along with a number of additional tools for // demonstration and testing purposes. // //===----------------------------------------------------------------------===// #include "clang/Basic/Diagnostic.h" #include "clang/Driver/Arg.h" #include "clang/Driver/ArgList.h" #include "clang/Driver/CC1Options.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/OptTable.h" #include "clang/Frontend/CodeGenAction.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/FrontendActions.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Frontend/FrontendPluginRegistry.h" #include "clang/Frontend/TextDiagnosticBuffer.h" #include "clang/Frontend/TextDiagnosticPrinter.h" #include "llvm/LLVMContext.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/Timer.h" #include "llvm/Support/raw_ostream.h" #include "llvm/System/DynamicLibrary.h" #include "llvm/Target/TargetSelect.h" #include using namespace clang; //===----------------------------------------------------------------------===// // Main driver //===----------------------------------------------------------------------===// static void LLVMErrorHandler(void *UserData, const std::string &Message) { Diagnostic &Diags = *static_cast(UserData); Diags.Report(diag::err_fe_error_backend) << Message; // We cannot recover from llvm errors. exit(1); } static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) { using namespace clang::frontend; switch (CI.getFrontendOpts().ProgramAction) { default: llvm_unreachable("Invalid program action!"); case ASTDump: return new ASTDumpAction(); case ASTPrint: return new ASTPrintAction(); case ASTPrintXML: return new ASTPrintXMLAction(); case ASTView: return new ASTViewAction(); case BoostCon: return new BoostConAction(); case DumpRawTokens: return new DumpRawTokensAction(); case DumpTokens: return new DumpTokensAction(); case EmitAssembly: return new EmitAssemblyAction(); case EmitBC: return new EmitBCAction(); case EmitHTML: return new HTMLPrintAction(); case EmitLLVM: return new EmitLLVMAction(); case EmitLLVMOnly: return new EmitLLVMOnlyAction(); case EmitCodeGenOnly: return new EmitCodeGenOnlyAction(); case EmitObj: return new EmitObjAction(); case FixIt: return new FixItAction(); case GeneratePCH: return new GeneratePCHAction(); case GeneratePTH: return new GeneratePTHAction(); case InheritanceView: return new InheritanceViewAction(); case InitOnly: return new InitOnlyAction(); case ParseNoop: return new ParseOnlyAction(); case ParsePrintCallbacks: return new PrintParseAction(); case ParseSyntaxOnly: return new SyntaxOnlyAction(); case PluginAction: { if (CI.getFrontendOpts().ActionName == "help") { llvm::errs() << "clang -cc1 plugins:\n"; for (FrontendPluginRegistry::iterator it = FrontendPluginRegistry::begin(), ie = FrontendPluginRegistry::end(); it != ie; ++it) llvm::errs() << " " << it->getName() << " - " << it->getDesc() << "\n"; return 0; } for (FrontendPluginRegistry::iterator it = FrontendPluginRegistry::begin(), ie = FrontendPluginRegistry::end(); it != ie; ++it) { if (it->getName() == CI.getFrontendOpts().ActionName) return it->instantiate(); } CI.getDiagnostics().Report(diag::err_fe_invalid_plugin_name) << CI.getFrontendOpts().ActionName; return 0; } case PrintDeclContext: return new DeclContextPrintAction(); case PrintPreprocessedInput: return new PrintPreprocessedAction(); case RewriteMacros: return new RewriteMacrosAction(); case RewriteObjC: return new RewriteObjCAction(); case RewriteTest: return new RewriteTestAction(); case RunAnalysis: return new AnalysisAction(); case RunPreprocessorOnly: return new PreprocessOnlyAction(); } } static FrontendAction *CreateFrontendAction(CompilerInstance &CI) { // Create the underlying action. FrontendAction *Act = CreateFrontendBaseAction(CI); if (!Act) return 0; // If there are any AST files to merge, create a frontend action // adaptor to perform the merge. if (!CI.getFrontendOpts().ASTMergeFiles.empty()) Act = new ASTMergeAction(Act, &CI.getFrontendOpts().ASTMergeFiles[0], CI.getFrontendOpts().ASTMergeFiles.size()); return Act; } // FIXME: Define the need for this testing away. static int cc1_test(Diagnostic &Diags, const char **ArgBegin, const char **ArgEnd) { using namespace clang::driver; llvm::errs() << "cc1 argv:"; for (const char **i = ArgBegin; i != ArgEnd; ++i) llvm::errs() << " \"" << *i << '"'; llvm::errs() << "\n"; // Parse the arguments. OptTable *Opts = createCC1OptTable(); unsigned MissingArgIndex, MissingArgCount; InputArgList *Args = Opts->ParseArgs(ArgBegin, ArgEnd, MissingArgIndex, MissingArgCount); // Check for missing argument error. if (MissingArgCount) Diags.Report(clang::diag::err_drv_missing_argument) << Args->getArgString(MissingArgIndex) << MissingArgCount; // Dump the parsed arguments. llvm::errs() << "cc1 parsed options:\n"; for (ArgList::const_iterator it = Args->begin(), ie = Args->end(); it != ie; ++it) (*it)->dump(); // Create a compiler invocation. llvm::errs() << "cc1 creating invocation.\n"; CompilerInvocation Invocation; CompilerInvocation::CreateFromArgs(Invocation, ArgBegin, ArgEnd, Diags); // Convert the invocation back to argument strings. std::vector InvocationArgs; Invocation.toArgs(InvocationArgs); // Dump the converted arguments. llvm::SmallVector Invocation2Args; llvm::errs() << "invocation argv :"; for (unsigned i = 0, e = InvocationArgs.size(); i != e; ++i) { Invocation2Args.push_back(InvocationArgs[i].c_str()); llvm::errs() << " \"" << InvocationArgs[i] << '"'; } llvm::errs() << "\n"; // Convert those arguments to another invocation, and check that we got the // same thing. CompilerInvocation Invocation2; CompilerInvocation::CreateFromArgs(Invocation2, Invocation2Args.begin(), Invocation2Args.end(), Diags); // FIXME: Implement CompilerInvocation comparison. if (true) { //llvm::errs() << "warning: Invocations differ!\n"; std::vector Invocation2Args; Invocation2.toArgs(Invocation2Args); llvm::errs() << "invocation2 argv:"; for (unsigned i = 0, e = Invocation2Args.size(); i != e; ++i) llvm::errs() << " \"" << Invocation2Args[i] << '"'; llvm::errs() << "\n"; } return 0; } int cc1_main(const char **ArgBegin, const char **ArgEnd, const char *Argv0, void *MainAddr) { llvm::OwningPtr Clang(new CompilerInstance()); Clang->setLLVMContext(new llvm::LLVMContext()); // Run clang -cc1 test. if (ArgBegin != ArgEnd && llvm::StringRef(ArgBegin[0]) == "-cc1test") { TextDiagnosticPrinter DiagClient(llvm::errs(), DiagnosticOptions()); Diagnostic Diags(&DiagClient); return cc1_test(Diags, ArgBegin + 1, ArgEnd); } // Initialize targets first, so that --version shows registered targets. llvm::InitializeAllTargets(); llvm::InitializeAllAsmPrinters(); llvm::InitializeAllAsmParsers(); // Buffer diagnostics from argument parsing so that we can output them using a // well formed diagnostic object. TextDiagnosticBuffer DiagsBuffer; Diagnostic Diags(&DiagsBuffer); CompilerInvocation::CreateFromArgs(Clang->getInvocation(), ArgBegin, ArgEnd, Diags); // Infer the builtin include path if unspecified. if (Clang->getHeaderSearchOpts().UseBuiltinIncludes && Clang->getHeaderSearchOpts().ResourceDir.empty()) Clang->getHeaderSearchOpts().ResourceDir = CompilerInvocation::GetResourcesPath(Argv0, MainAddr); // Honor -help. if (Clang->getFrontendOpts().ShowHelp) { llvm::OwningPtr Opts(driver::createCC1OptTable()); Opts->PrintHelp(llvm::outs(), "clang -cc1", "LLVM 'Clang' Compiler: http://clang.llvm.org"); return 0; } // Honor -version. // // FIXME: Use a better -version message? if (Clang->getFrontendOpts().ShowVersion) { llvm::cl::PrintVersionMessage(); return 0; } // Honor -mllvm. // // FIXME: Remove this, one day. if (!Clang->getFrontendOpts().LLVMArgs.empty()) { unsigned NumArgs = Clang->getFrontendOpts().LLVMArgs.size(); const char **Args = new const char*[NumArgs + 2]; Args[0] = "clang (LLVM option parsing)"; for (unsigned i = 0; i != NumArgs; ++i) Args[i + 1] = Clang->getFrontendOpts().LLVMArgs[i].c_str(); Args[NumArgs + 1] = 0; llvm::cl::ParseCommandLineOptions(NumArgs + 1, const_cast(Args)); } // Create the actual diagnostics engine. Clang->createDiagnostics(ArgEnd - ArgBegin, const_cast(ArgBegin)); if (!Clang->hasDiagnostics()) return 1; // Set an error handler, so that any LLVM backend diagnostics go through our // error handler. llvm::install_fatal_error_handler(LLVMErrorHandler, static_cast(&Clang->getDiagnostics())); DiagsBuffer.FlushDiagnostics(Clang->getDiagnostics()); // Load any requested plugins. for (unsigned i = 0, e = Clang->getFrontendOpts().Plugins.size(); i != e; ++i) { const std::string &Path = Clang->getFrontendOpts().Plugins[i]; std::string Error; if (llvm::sys::DynamicLibrary::LoadLibraryPermanently(Path.c_str(), &Error)) Diags.Report(diag::err_fe_unable_to_load_plugin) << Path << Error; } // 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->getFrontendOpts().DisableFree) Act.take(); } } // If any timers were active but haven't been destroyed yet, print their // results now. This happens in -disable-free mode. llvm::TimerGroup::printAll(llvm::errs()); // When running with -disable-free, don't do any destruction or shutdown. if (Clang->getFrontendOpts().DisableFree) { if (Clang->getFrontendOpts().ShowStats) llvm::PrintStatistics(); Clang.take(); return !Success; } // Managed static deconstruction. Useful for making things like // -time-passes usable. llvm::llvm_shutdown(); return !Success; }