CompilerInstance.cpp revision 202379
1//===--- CompilerInstance.cpp ---------------------------------------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9 10#include "clang/Frontend/CompilerInstance.h" 11#include "clang/AST/ASTConsumer.h" 12#include "clang/AST/ASTContext.h" 13#include "clang/Basic/Diagnostic.h" 14#include "clang/Basic/FileManager.h" 15#include "clang/Basic/SourceManager.h" 16#include "clang/Basic/TargetInfo.h" 17#include "clang/Basic/Version.h" 18#include "clang/Lex/HeaderSearch.h" 19#include "clang/Lex/Preprocessor.h" 20#include "clang/Lex/PTHManager.h" 21#include "clang/Frontend/ChainedDiagnosticClient.h" 22#include "clang/Frontend/FrontendAction.h" 23#include "clang/Frontend/PCHReader.h" 24#include "clang/Frontend/FrontendDiagnostic.h" 25#include "clang/Frontend/TextDiagnosticPrinter.h" 26#include "clang/Frontend/VerifyDiagnosticsClient.h" 27#include "clang/Frontend/Utils.h" 28#include "clang/Sema/CodeCompleteConsumer.h" 29#include "llvm/LLVMContext.h" 30#include "llvm/Support/MemoryBuffer.h" 31#include "llvm/Support/raw_ostream.h" 32#include "llvm/Support/Timer.h" 33#include "llvm/System/Host.h" 34#include "llvm/System/Path.h" 35#include "llvm/System/Program.h" 36using namespace clang; 37 38CompilerInstance::CompilerInstance(llvm::LLVMContext *_LLVMContext, 39 bool _OwnsLLVMContext) 40 : LLVMContext(_LLVMContext), 41 OwnsLLVMContext(_OwnsLLVMContext) { 42 } 43 44CompilerInstance::~CompilerInstance() { 45 if (OwnsLLVMContext) 46 delete LLVMContext; 47} 48 49void CompilerInstance::setDiagnostics(Diagnostic *Value) { 50 Diagnostics.reset(Value); 51} 52 53void CompilerInstance::setDiagnosticClient(DiagnosticClient *Value) { 54 DiagClient.reset(Value); 55} 56 57void CompilerInstance::setTarget(TargetInfo *Value) { 58 Target.reset(Value); 59} 60 61void CompilerInstance::setFileManager(FileManager *Value) { 62 FileMgr.reset(Value); 63} 64 65void CompilerInstance::setSourceManager(SourceManager *Value) { 66 SourceMgr.reset(Value); 67} 68 69void CompilerInstance::setPreprocessor(Preprocessor *Value) { 70 PP.reset(Value); 71} 72 73void CompilerInstance::setASTContext(ASTContext *Value) { 74 Context.reset(Value); 75} 76 77void CompilerInstance::setASTConsumer(ASTConsumer *Value) { 78 Consumer.reset(Value); 79} 80 81void CompilerInstance::setCodeCompletionConsumer(CodeCompleteConsumer *Value) { 82 CompletionConsumer.reset(Value); 83} 84 85// Diagnostics 86 87static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts, 88 unsigned argc, char **argv, 89 llvm::OwningPtr<DiagnosticClient> &DiagClient) { 90 std::string ErrorInfo; 91 llvm::raw_ostream *OS = 92 new llvm::raw_fd_ostream(DiagOpts.DumpBuildInformation.c_str(), ErrorInfo); 93 if (!ErrorInfo.empty()) { 94 // FIXME: Do not fail like this. 95 llvm::errs() << "error opening -dump-build-information file '" 96 << DiagOpts.DumpBuildInformation << "', option ignored!\n"; 97 delete OS; 98 return; 99 } 100 101 (*OS) << "clang -cc1 command line arguments: "; 102 for (unsigned i = 0; i != argc; ++i) 103 (*OS) << argv[i] << ' '; 104 (*OS) << '\n'; 105 106 // Chain in a diagnostic client which will log the diagnostics. 107 DiagnosticClient *Logger = 108 new TextDiagnosticPrinter(*OS, DiagOpts, /*OwnsOutputStream=*/true); 109 DiagClient.reset(new ChainedDiagnosticClient(DiagClient.take(), Logger)); 110} 111 112void CompilerInstance::createDiagnostics(int Argc, char **Argv) { 113 Diagnostics.reset(createDiagnostics(getDiagnosticOpts(), Argc, Argv)); 114 115 if (Diagnostics) 116 DiagClient.reset(Diagnostics->getClient()); 117} 118 119Diagnostic *CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts, 120 int Argc, char **Argv) { 121 llvm::OwningPtr<Diagnostic> Diags(new Diagnostic()); 122 123 // Create the diagnostic client for reporting errors or for 124 // implementing -verify. 125 llvm::OwningPtr<DiagnosticClient> DiagClient( 126 new TextDiagnosticPrinter(llvm::errs(), Opts)); 127 128 // Chain in -verify checker, if requested. 129 if (Opts.VerifyDiagnostics) 130 DiagClient.reset(new VerifyDiagnosticsClient(*Diags, DiagClient.take())); 131 132 if (!Opts.DumpBuildInformation.empty()) 133 SetUpBuildDumpLog(Opts, Argc, Argv, DiagClient); 134 135 // Configure our handling of diagnostics. 136 Diags->setClient(DiagClient.take()); 137 if (ProcessWarningOptions(*Diags, Opts)) 138 return 0; 139 140 return Diags.take(); 141} 142 143// File Manager 144 145void CompilerInstance::createFileManager() { 146 FileMgr.reset(new FileManager()); 147} 148 149// Source Manager 150 151void CompilerInstance::createSourceManager() { 152 SourceMgr.reset(new SourceManager()); 153} 154 155// Preprocessor 156 157void CompilerInstance::createPreprocessor() { 158 PP.reset(createPreprocessor(getDiagnostics(), getLangOpts(), 159 getPreprocessorOpts(), getHeaderSearchOpts(), 160 getDependencyOutputOpts(), getTarget(), 161 getFrontendOpts(), getSourceManager(), 162 getFileManager())); 163} 164 165Preprocessor * 166CompilerInstance::createPreprocessor(Diagnostic &Diags, 167 const LangOptions &LangInfo, 168 const PreprocessorOptions &PPOpts, 169 const HeaderSearchOptions &HSOpts, 170 const DependencyOutputOptions &DepOpts, 171 const TargetInfo &Target, 172 const FrontendOptions &FEOpts, 173 SourceManager &SourceMgr, 174 FileManager &FileMgr) { 175 // Create a PTH manager if we are using some form of a token cache. 176 PTHManager *PTHMgr = 0; 177 if (!PPOpts.TokenCache.empty()) 178 PTHMgr = PTHManager::Create(PPOpts.TokenCache, Diags); 179 180 // Create the Preprocessor. 181 HeaderSearch *HeaderInfo = new HeaderSearch(FileMgr); 182 Preprocessor *PP = new Preprocessor(Diags, LangInfo, Target, 183 SourceMgr, *HeaderInfo, PTHMgr, 184 /*OwnsHeaderSearch=*/true); 185 186 // Note that this is different then passing PTHMgr to Preprocessor's ctor. 187 // That argument is used as the IdentifierInfoLookup argument to 188 // IdentifierTable's ctor. 189 if (PTHMgr) { 190 PTHMgr->setPreprocessor(PP); 191 PP->setPTHManager(PTHMgr); 192 } 193 194 InitializePreprocessor(*PP, PPOpts, HSOpts, FEOpts); 195 196 // Handle generating dependencies, if requested. 197 if (!DepOpts.OutputFile.empty()) 198 AttachDependencyFileGen(*PP, DepOpts); 199 200 return PP; 201} 202 203// ASTContext 204 205void CompilerInstance::createASTContext() { 206 Preprocessor &PP = getPreprocessor(); 207 Context.reset(new ASTContext(getLangOpts(), PP.getSourceManager(), 208 getTarget(), PP.getIdentifierTable(), 209 PP.getSelectorTable(), PP.getBuiltinInfo(), 210 /*FreeMemory=*/ !getFrontendOpts().DisableFree, 211 /*size_reserve=*/ 0)); 212} 213 214// ExternalASTSource 215 216void CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path) { 217 llvm::OwningPtr<ExternalASTSource> Source; 218 Source.reset(createPCHExternalASTSource(Path, getHeaderSearchOpts().Sysroot, 219 getPreprocessor(), getASTContext())); 220 getASTContext().setExternalSource(Source); 221} 222 223ExternalASTSource * 224CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path, 225 const std::string &Sysroot, 226 Preprocessor &PP, 227 ASTContext &Context) { 228 llvm::OwningPtr<PCHReader> Reader; 229 Reader.reset(new PCHReader(PP, &Context, 230 Sysroot.empty() ? 0 : Sysroot.c_str())); 231 232 switch (Reader->ReadPCH(Path)) { 233 case PCHReader::Success: 234 // Set the predefines buffer as suggested by the PCH reader. Typically, the 235 // predefines buffer will be empty. 236 PP.setPredefines(Reader->getSuggestedPredefines()); 237 return Reader.take(); 238 239 case PCHReader::Failure: 240 // Unrecoverable failure: don't even try to process the input file. 241 break; 242 243 case PCHReader::IgnorePCH: 244 // No suitable PCH file could be found. Return an error. 245 break; 246 } 247 248 return 0; 249} 250 251// Code Completion 252 253void CompilerInstance::createCodeCompletionConsumer() { 254 const ParsedSourceLocation &Loc = getFrontendOpts().CodeCompletionAt; 255 CompletionConsumer.reset( 256 createCodeCompletionConsumer(getPreprocessor(), 257 Loc.FileName, Loc.Line, Loc.Column, 258 getFrontendOpts().DebugCodeCompletionPrinter, 259 getFrontendOpts().ShowMacrosInCodeCompletion, 260 llvm::outs())); 261 262 if (CompletionConsumer->isOutputBinary() && 263 llvm::sys::Program::ChangeStdoutToBinary()) { 264 getPreprocessor().getDiagnostics().Report(diag::err_fe_stdout_binary); 265 CompletionConsumer.reset(); 266 } 267} 268 269void CompilerInstance::createFrontendTimer() { 270 FrontendTimer.reset(new llvm::Timer("Clang front-end timer")); 271} 272 273CodeCompleteConsumer * 274CompilerInstance::createCodeCompletionConsumer(Preprocessor &PP, 275 const std::string &Filename, 276 unsigned Line, 277 unsigned Column, 278 bool UseDebugPrinter, 279 bool ShowMacros, 280 llvm::raw_ostream &OS) { 281 // Tell the source manager to chop off the given file at a specific 282 // line and column. 283 const FileEntry *Entry = PP.getFileManager().getFile(Filename); 284 if (!Entry) { 285 PP.getDiagnostics().Report(diag::err_fe_invalid_code_complete_file) 286 << Filename; 287 return 0; 288 } 289 290 // Truncate the named file at the given line/column. 291 PP.SetCodeCompletionPoint(Entry, Line, Column); 292 293 // Set up the creation routine for code-completion. 294 if (UseDebugPrinter) 295 return new PrintingCodeCompleteConsumer(ShowMacros, OS); 296 else 297 return new CIndexCodeCompleteConsumer(ShowMacros, OS); 298} 299 300// Output Files 301 302void CompilerInstance::addOutputFile(llvm::StringRef Path, 303 llvm::raw_ostream *OS) { 304 assert(OS && "Attempt to add empty stream to output list!"); 305 OutputFiles.push_back(std::make_pair(Path, OS)); 306} 307 308void CompilerInstance::ClearOutputFiles(bool EraseFiles) { 309 for (std::list< std::pair<std::string, llvm::raw_ostream*> >::iterator 310 it = OutputFiles.begin(), ie = OutputFiles.end(); it != ie; ++it) { 311 delete it->second; 312 if (EraseFiles && !it->first.empty()) 313 llvm::sys::Path(it->first).eraseFromDisk(); 314 } 315 OutputFiles.clear(); 316} 317 318llvm::raw_fd_ostream * 319CompilerInstance::createDefaultOutputFile(bool Binary, 320 llvm::StringRef InFile, 321 llvm::StringRef Extension) { 322 return createOutputFile(getFrontendOpts().OutputFile, Binary, 323 InFile, Extension); 324} 325 326llvm::raw_fd_ostream * 327CompilerInstance::createOutputFile(llvm::StringRef OutputPath, 328 bool Binary, 329 llvm::StringRef InFile, 330 llvm::StringRef Extension) { 331 std::string Error, OutputPathName; 332 llvm::raw_fd_ostream *OS = createOutputFile(OutputPath, Error, Binary, 333 InFile, Extension, 334 &OutputPathName); 335 if (!OS) { 336 getDiagnostics().Report(diag::err_fe_unable_to_open_output) 337 << OutputPath << Error; 338 return 0; 339 } 340 341 // Add the output file -- but don't try to remove "-", since this means we are 342 // using stdin. 343 addOutputFile((OutputPathName != "-") ? OutputPathName : "", OS); 344 345 return OS; 346} 347 348llvm::raw_fd_ostream * 349CompilerInstance::createOutputFile(llvm::StringRef OutputPath, 350 std::string &Error, 351 bool Binary, 352 llvm::StringRef InFile, 353 llvm::StringRef Extension, 354 std::string *ResultPathName) { 355 std::string OutFile; 356 if (!OutputPath.empty()) { 357 OutFile = OutputPath; 358 } else if (InFile == "-") { 359 OutFile = "-"; 360 } else if (!Extension.empty()) { 361 llvm::sys::Path Path(InFile); 362 Path.eraseSuffix(); 363 Path.appendSuffix(Extension); 364 OutFile = Path.str(); 365 } else { 366 OutFile = "-"; 367 } 368 369 llvm::OwningPtr<llvm::raw_fd_ostream> OS( 370 new llvm::raw_fd_ostream(OutFile.c_str(), Error, 371 (Binary ? llvm::raw_fd_ostream::F_Binary : 0))); 372 if (!Error.empty()) 373 return 0; 374 375 if (ResultPathName) 376 *ResultPathName = OutFile; 377 378 return OS.take(); 379} 380 381// Initialization Utilities 382 383bool CompilerInstance::InitializeSourceManager(llvm::StringRef InputFile) { 384 return InitializeSourceManager(InputFile, getDiagnostics(), getFileManager(), 385 getSourceManager(), getFrontendOpts()); 386} 387 388bool CompilerInstance::InitializeSourceManager(llvm::StringRef InputFile, 389 Diagnostic &Diags, 390 FileManager &FileMgr, 391 SourceManager &SourceMgr, 392 const FrontendOptions &Opts) { 393 // Figure out where to get and map in the main file. 394 if (Opts.EmptyInputOnly) { 395 const char *EmptyStr = ""; 396 llvm::MemoryBuffer *SB = 397 llvm::MemoryBuffer::getMemBuffer(EmptyStr, EmptyStr, "<empty input>"); 398 SourceMgr.createMainFileIDForMemBuffer(SB); 399 } else if (InputFile != "-") { 400 const FileEntry *File = FileMgr.getFile(InputFile); 401 if (File) SourceMgr.createMainFileID(File, SourceLocation()); 402 if (SourceMgr.getMainFileID().isInvalid()) { 403 Diags.Report(diag::err_fe_error_reading) << InputFile; 404 return false; 405 } 406 } else { 407 llvm::MemoryBuffer *SB = llvm::MemoryBuffer::getSTDIN(); 408 SourceMgr.createMainFileIDForMemBuffer(SB); 409 if (SourceMgr.getMainFileID().isInvalid()) { 410 Diags.Report(diag::err_fe_error_reading_stdin); 411 return false; 412 } 413 } 414 415 return true; 416} 417 418// High-Level Operations 419 420bool CompilerInstance::ExecuteAction(FrontendAction &Act) { 421 assert(hasDiagnostics() && "Diagnostics engine is not initialized!"); 422 assert(!getFrontendOpts().ShowHelp && "Client must handle '-help'!"); 423 assert(!getFrontendOpts().ShowVersion && "Client must handle '-version'!"); 424 425 // FIXME: Take this as an argument, once all the APIs we used have moved to 426 // taking it as an input instead of hard-coding llvm::errs. 427 llvm::raw_ostream &OS = llvm::errs(); 428 429 // Create the target instance. 430 setTarget(TargetInfo::CreateTargetInfo(getDiagnostics(), getTargetOpts())); 431 if (!hasTarget()) 432 return false; 433 434 // Inform the target of the language options. 435 // 436 // FIXME: We shouldn't need to do this, the target should be immutable once 437 // created. This complexity should be lifted elsewhere. 438 getTarget().setForcedLangOptions(getLangOpts()); 439 440 // Validate/process some options. 441 if (getHeaderSearchOpts().Verbose) 442 OS << "clang -cc1 version " CLANG_VERSION_STRING 443 << " based upon " << PACKAGE_STRING 444 << " hosted on " << llvm::sys::getHostTriple() << "\n"; 445 446 if (getFrontendOpts().ShowTimers) 447 createFrontendTimer(); 448 449 for (unsigned i = 0, e = getFrontendOpts().Inputs.size(); i != e; ++i) { 450 const std::string &InFile = getFrontendOpts().Inputs[i].second; 451 452 // If we aren't using an AST file, setup the file and source managers and 453 // the preprocessor. 454 bool IsAST = getFrontendOpts().Inputs[i].first == FrontendOptions::IK_AST; 455 if (!IsAST) { 456 if (!i) { 457 // Create a file manager object to provide access to and cache the 458 // filesystem. 459 createFileManager(); 460 461 // Create the source manager. 462 createSourceManager(); 463 } else { 464 // Reset the ID tables if we are reusing the SourceManager. 465 getSourceManager().clearIDTables(); 466 } 467 468 // Create the preprocessor. 469 createPreprocessor(); 470 } 471 472 if (Act.BeginSourceFile(*this, InFile, IsAST)) { 473 Act.Execute(); 474 Act.EndSourceFile(); 475 } 476 } 477 478 if (getDiagnosticOpts().ShowCarets) 479 if (unsigned NumDiagnostics = getDiagnostics().getNumDiagnostics()) 480 OS << NumDiagnostics << " diagnostic" 481 << (NumDiagnostics == 1 ? "" : "s") 482 << " generated.\n"; 483 484 if (getFrontendOpts().ShowStats) { 485 getFileManager().PrintStats(); 486 OS << "\n"; 487 } 488 489 // Return the appropriate status when verifying diagnostics. 490 // 491 // FIXME: If we could make getNumErrors() do the right thing, we wouldn't need 492 // this. 493 if (getDiagnosticOpts().VerifyDiagnostics) 494 return !static_cast<VerifyDiagnosticsClient&>( 495 getDiagnosticClient()).HadErrors(); 496 497 return !getDiagnostics().getNumErrors(); 498} 499 500 501