//===--- clang.cpp - C-Language Front-end ---------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This utility may be invoked in the following manner: // clang-cc --help - Output help info. // clang-cc [options] - Read from stdin. // clang-cc [options] file - Read from "file". // clang-cc [options] file1 file2 - Read these files. // //===----------------------------------------------------------------------===// #include "Options.h" #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/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/VerifyDiagnosticsClient.h" #include "llvm/LLVMContext.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/PluginLoader.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Timer.h" #include "llvm/Support/raw_ostream.h" #include "llvm/System/Host.h" #include "llvm/System/Path.h" #include "llvm/System/Signals.h" #include "llvm/Target/TargetSelect.h" using namespace clang; //===----------------------------------------------------------------------===// // Main driver //===----------------------------------------------------------------------===// std::string GetBuiltinIncludePath(const char *Argv0) { llvm::sys::Path P = llvm::sys::Path::GetMainExecutable(Argv0, (void*)(intptr_t) GetBuiltinIncludePath); if (!P.isEmpty()) { P.eraseComponent(); // Remove /clang from foo/bin/clang P.eraseComponent(); // Remove /bin from foo/bin // Get foo/lib/clang//include P.appendComponent("lib"); P.appendComponent("clang"); P.appendComponent(CLANG_VERSION_STRING); P.appendComponent("include"); } return P.str(); } 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); } /// ClangFrontendTimer - The front-end activities should charge time to it with /// TimeRegion. The -ftime-report option controls whether this will do /// anything. llvm::Timer *ClangFrontendTimer = 0; static FrontendAction *CreateFrontendAction(CompilerInstance &CI) { using namespace clang::frontend; switch (CI.getFrontendOpts().ProgramAction) { default: llvm::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 DumpRawTokens: return new DumpRawTokensAction(); case DumpRecordLayouts: return new DumpRecordAction(); 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 FixIt: return new FixItAction(); case GeneratePCH: return new GeneratePCHAction(); case GeneratePTH: return new GeneratePTHAction(); case InheritanceView: return new InheritanceViewAction(); 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-cc plugins:\n"; for (FrontendPluginRegistry::iterator it = FrontendPluginRegistry::begin(), ie = FrontendPluginRegistry::end(); it != ie; ++it) llvm::errs() << " " << it->getName() << " - " << it->getDesc() << "\n"; exit(1); } 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 RewriteBlocks: return new RewriteBlocksAction(); 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 TargetInfo * ConstructCompilerInvocation(CompilerInvocation &Opts, Diagnostic &Diags, const char *Argv0, bool &IsAST) { // Initialize target options. InitializeTargetOptions(Opts.getTargetOpts()); // Get information about the target being compiled for. llvm::OwningPtr Target( TargetInfo::CreateTargetInfo(Diags, Opts.getTargetOpts())); if (!Target) return 0; // Initialize frontend options. InitializeFrontendOptions(Opts.getFrontendOpts()); // Determine the input language, we currently require all files to match. FrontendOptions::InputKind IK = Opts.getFrontendOpts().Inputs[0].first; for (unsigned i = 1, e = Opts.getFrontendOpts().Inputs.size(); i != e; ++i) { if (Opts.getFrontendOpts().Inputs[i].first != IK) { llvm::errs() << "error: cannot have multiple input files of distinct " << "language kinds without -x\n"; return 0; } } // Initialize language options. // // FIXME: These aren't used during operations on ASTs. Split onto a separate // code path to make this obvious. IsAST = (IK == FrontendOptions::IK_AST); if (!IsAST) InitializeLangOptions(Opts.getLangOpts(), IK, *Target); // Initialize the static analyzer options. InitializeAnalyzerOptions(Opts.getAnalyzerOpts()); // Initialize the dependency output options (-M...). InitializeDependencyOutputOptions(Opts.getDependencyOutputOpts()); // Initialize the header search options. InitializeHeaderSearchOptions(Opts.getHeaderSearchOpts(), GetBuiltinIncludePath(Argv0)); // Initialize the other preprocessor options. InitializePreprocessorOptions(Opts.getPreprocessorOpts()); // Initialize the preprocessed output options. InitializePreprocessorOutputOptions(Opts.getPreprocessorOutputOpts()); // Initialize backend options, which may also be used to key some language // options. InitializeCodeGenOptions(Opts.getCodeGenOpts(), Opts.getLangOpts(), Opts.getFrontendOpts().ShowTimers); return Target.take(); } int main(int argc, char **argv) { llvm::sys::PrintStackTraceOnErrorSignal(); llvm::PrettyStackTraceProgram X(argc, argv); CompilerInstance Clang(&llvm::getGlobalContext(), false); // Initialize targets first, so that --version shows registered targets. llvm::InitializeAllTargets(); llvm::InitializeAllAsmPrinters(); llvm::cl::ParseCommandLineOptions(argc, argv, "LLVM 'Clang' Compiler: http://clang.llvm.org\n"); // Construct the diagnostic engine first, so that we can build a diagnostic // client to use for any errors during option handling. InitializeDiagnosticOptions(Clang.getDiagnosticOpts()); Clang.createDiagnostics(argc, argv); if (!Clang.hasDiagnostics()) return 1; // Set an error handler, so that any LLVM backend diagnostics go through our // error handler. llvm::llvm_install_error_handler(LLVMErrorHandler, static_cast(&Clang.getDiagnostics())); // Now that we have initialized the diagnostics engine, create the target and // the compiler invocation object. // // FIXME: We should move .ast inputs to taking a separate path, they are // really quite different. bool IsAST = false; Clang.setTarget( ConstructCompilerInvocation(Clang.getInvocation(), Clang.getDiagnostics(), argv[0], IsAST)); if (!Clang.hasTarget()) return 1; // Validate/process some options if (Clang.getHeaderSearchOpts().Verbose) llvm::errs() << "clang-cc version " CLANG_VERSION_STRING << " based upon " << PACKAGE_STRING << " hosted on " << llvm::sys::getHostTriple() << "\n"; if (Clang.getFrontendOpts().ShowTimers) ClangFrontendTimer = new llvm::Timer("Clang front-end time"); // Enforce certain implications. if (!Clang.getFrontendOpts().ViewClassInheritance.empty()) Clang.getFrontendOpts().ProgramAction = frontend::InheritanceView; if (!Clang.getFrontendOpts().FixItLocations.empty()) Clang.getFrontendOpts().ProgramAction = frontend::FixIt; 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. 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(); } llvm::OwningPtr Act(CreateFrontendAction(Clang)); if (!Act) break; Act->setCurrentTimer(ClangFrontendTimer); if (Act->BeginSourceFile(Clang, InFile, IsAST)) { Act->Execute(); Act->EndSourceFile(); } } 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"); } delete ClangFrontendTimer; // 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); }