CompilerInstance.cpp revision b34d69b9292534c1c574f168f0ac10aea652adca
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/Sema/Sema.h" 12#include "clang/AST/ASTConsumer.h" 13#include "clang/AST/ASTContext.h" 14#include "clang/Basic/Diagnostic.h" 15#include "clang/Basic/FileManager.h" 16#include "clang/Basic/SourceManager.h" 17#include "clang/Basic/TargetInfo.h" 18#include "clang/Basic/Version.h" 19#include "clang/Lex/HeaderSearch.h" 20#include "clang/Lex/Preprocessor.h" 21#include "clang/Lex/PTHManager.h" 22#include "clang/Frontend/ChainedDiagnosticClient.h" 23#include "clang/Frontend/FrontendAction.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/Serialization/ASTReader.h" 29#include "clang/Sema/CodeCompleteConsumer.h" 30#include "llvm/LLVMContext.h" 31#include "llvm/Support/FileSystem.h" 32#include "llvm/Support/MemoryBuffer.h" 33#include "llvm/Support/raw_ostream.h" 34#include "llvm/ADT/Statistic.h" 35#include "llvm/Support/Timer.h" 36#include "llvm/Support/Host.h" 37#include "llvm/Support/Path.h" 38#include "llvm/Support/Program.h" 39#include "llvm/Support/Signals.h" 40#include "llvm/Support/system_error.h" 41using namespace clang; 42 43CompilerInstance::CompilerInstance() 44 : Invocation(new CompilerInvocation()) { 45} 46 47CompilerInstance::~CompilerInstance() { 48} 49 50void CompilerInstance::setLLVMContext(llvm::LLVMContext *Value) { 51 LLVMContext.reset(Value); 52} 53 54void CompilerInstance::setInvocation(CompilerInvocation *Value) { 55 Invocation.reset(Value); 56} 57 58void CompilerInstance::setDiagnostics(Diagnostic *Value) { 59 Diagnostics = Value; 60} 61 62void CompilerInstance::setTarget(TargetInfo *Value) { 63 Target.reset(Value); 64} 65 66void CompilerInstance::setFileManager(FileManager *Value) { 67 FileMgr.reset(Value); 68} 69 70void CompilerInstance::setSourceManager(SourceManager *Value) { 71 SourceMgr.reset(Value); 72} 73 74void CompilerInstance::setPreprocessor(Preprocessor *Value) { 75 PP.reset(Value); 76} 77 78void CompilerInstance::setASTContext(ASTContext *Value) { 79 Context.reset(Value); 80} 81 82void CompilerInstance::setSema(Sema *S) { 83 TheSema.reset(S); 84} 85 86void CompilerInstance::setASTConsumer(ASTConsumer *Value) { 87 Consumer.reset(Value); 88} 89 90void CompilerInstance::setCodeCompletionConsumer(CodeCompleteConsumer *Value) { 91 CompletionConsumer.reset(Value); 92} 93 94// Diagnostics 95static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts, 96 unsigned argc, const char* const *argv, 97 Diagnostic &Diags) { 98 std::string ErrorInfo; 99 llvm::OwningPtr<llvm::raw_ostream> OS( 100 new llvm::raw_fd_ostream(DiagOpts.DumpBuildInformation.c_str(), ErrorInfo)); 101 if (!ErrorInfo.empty()) { 102 Diags.Report(diag::err_fe_unable_to_open_logfile) 103 << DiagOpts.DumpBuildInformation << ErrorInfo; 104 return; 105 } 106 107 (*OS) << "clang -cc1 command line arguments: "; 108 for (unsigned i = 0; i != argc; ++i) 109 (*OS) << argv[i] << ' '; 110 (*OS) << '\n'; 111 112 // Chain in a diagnostic client which will log the diagnostics. 113 DiagnosticClient *Logger = 114 new TextDiagnosticPrinter(*OS.take(), DiagOpts, /*OwnsOutputStream=*/true); 115 Diags.setClient(new ChainedDiagnosticClient(Diags.takeClient(), Logger)); 116} 117 118void CompilerInstance::createDiagnostics(int Argc, const char* const *Argv, 119 DiagnosticClient *Client) { 120 Diagnostics = createDiagnostics(getDiagnosticOpts(), Argc, Argv, Client); 121} 122 123llvm::IntrusiveRefCntPtr<Diagnostic> 124CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts, 125 int Argc, const char* const *Argv, 126 DiagnosticClient *Client) { 127 llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 128 llvm::IntrusiveRefCntPtr<Diagnostic> Diags(new Diagnostic(DiagID)); 129 130 // Create the diagnostic client for reporting errors or for 131 // implementing -verify. 132 if (Client) 133 Diags->setClient(Client); 134 else 135 Diags->setClient(new TextDiagnosticPrinter(llvm::errs(), Opts)); 136 137 // Chain in -verify checker, if requested. 138 if (Opts.VerifyDiagnostics) 139 Diags->setClient(new VerifyDiagnosticsClient(*Diags, Diags->takeClient())); 140 141 if (!Opts.DumpBuildInformation.empty()) 142 SetUpBuildDumpLog(Opts, Argc, Argv, *Diags); 143 144 // Configure our handling of diagnostics. 145 ProcessWarningOptions(*Diags, Opts); 146 147 return Diags; 148} 149 150// File Manager 151 152void CompilerInstance::createFileManager() { 153 FileMgr.reset(new FileManager(getFileSystemOpts())); 154} 155 156// Source Manager 157 158void CompilerInstance::createSourceManager(FileManager &FileMgr) { 159 SourceMgr.reset(new SourceManager(getDiagnostics(), FileMgr)); 160} 161 162// Preprocessor 163 164void CompilerInstance::createPreprocessor() { 165 PP.reset(createPreprocessor(getDiagnostics(), getLangOpts(), 166 getPreprocessorOpts(), getHeaderSearchOpts(), 167 getDependencyOutputOpts(), getTarget(), 168 getFrontendOpts(), getSourceManager(), 169 getFileManager())); 170} 171 172Preprocessor * 173CompilerInstance::createPreprocessor(Diagnostic &Diags, 174 const LangOptions &LangInfo, 175 const PreprocessorOptions &PPOpts, 176 const HeaderSearchOptions &HSOpts, 177 const DependencyOutputOptions &DepOpts, 178 const TargetInfo &Target, 179 const FrontendOptions &FEOpts, 180 SourceManager &SourceMgr, 181 FileManager &FileMgr) { 182 // Create a PTH manager if we are using some form of a token cache. 183 PTHManager *PTHMgr = 0; 184 if (!PPOpts.TokenCache.empty()) 185 PTHMgr = PTHManager::Create(PPOpts.TokenCache, Diags); 186 187 // Create the Preprocessor. 188 HeaderSearch *HeaderInfo = new HeaderSearch(FileMgr); 189 Preprocessor *PP = new Preprocessor(Diags, LangInfo, Target, 190 SourceMgr, *HeaderInfo, PTHMgr, 191 /*OwnsHeaderSearch=*/true); 192 193 // Note that this is different then passing PTHMgr to Preprocessor's ctor. 194 // That argument is used as the IdentifierInfoLookup argument to 195 // IdentifierTable's ctor. 196 if (PTHMgr) { 197 PTHMgr->setPreprocessor(PP); 198 PP->setPTHManager(PTHMgr); 199 } 200 201 if (PPOpts.DetailedRecord) 202 PP->createPreprocessingRecord(); 203 204 InitializePreprocessor(*PP, PPOpts, HSOpts, FEOpts); 205 206 // Handle generating dependencies, if requested. 207 if (!DepOpts.OutputFile.empty()) 208 AttachDependencyFileGen(*PP, DepOpts); 209 210 // Handle generating header include information, if requested. 211 if (DepOpts.ShowHeaderIncludes) 212 AttachHeaderIncludeGen(*PP); 213 if (!DepOpts.HeaderIncludeOutputFile.empty()) { 214 llvm::StringRef OutputPath = DepOpts.HeaderIncludeOutputFile; 215 if (OutputPath == "-") 216 OutputPath = ""; 217 AttachHeaderIncludeGen(*PP, /*ShowAllHeaders=*/true, OutputPath); 218 } 219 220 return PP; 221} 222 223// ASTContext 224 225void CompilerInstance::createASTContext() { 226 Preprocessor &PP = getPreprocessor(); 227 Context.reset(new ASTContext(getLangOpts(), PP.getSourceManager(), 228 getTarget(), PP.getIdentifierTable(), 229 PP.getSelectorTable(), PP.getBuiltinInfo(), 230 /*size_reserve=*/ 0)); 231} 232 233// ExternalASTSource 234 235void CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path, 236 bool DisablePCHValidation, 237 void *DeserializationListener){ 238 llvm::OwningPtr<ExternalASTSource> Source; 239 bool Preamble = getPreprocessorOpts().PrecompiledPreambleBytes.first != 0; 240 Source.reset(createPCHExternalASTSource(Path, getHeaderSearchOpts().Sysroot, 241 DisablePCHValidation, 242 getPreprocessor(), getASTContext(), 243 DeserializationListener, 244 Preamble)); 245 getASTContext().setExternalSource(Source); 246} 247 248ExternalASTSource * 249CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path, 250 const std::string &Sysroot, 251 bool DisablePCHValidation, 252 Preprocessor &PP, 253 ASTContext &Context, 254 void *DeserializationListener, 255 bool Preamble) { 256 llvm::OwningPtr<ASTReader> Reader; 257 Reader.reset(new ASTReader(PP, &Context, 258 Sysroot.empty() ? 0 : Sysroot.c_str(), 259 DisablePCHValidation)); 260 261 Reader->setDeserializationListener( 262 static_cast<ASTDeserializationListener *>(DeserializationListener)); 263 switch (Reader->ReadAST(Path, 264 Preamble ? ASTReader::Preamble : ASTReader::PCH)) { 265 case ASTReader::Success: 266 // Set the predefines buffer as suggested by the PCH reader. Typically, the 267 // predefines buffer will be empty. 268 PP.setPredefines(Reader->getSuggestedPredefines()); 269 return Reader.take(); 270 271 case ASTReader::Failure: 272 // Unrecoverable failure: don't even try to process the input file. 273 break; 274 275 case ASTReader::IgnorePCH: 276 // No suitable PCH file could be found. Return an error. 277 break; 278 } 279 280 return 0; 281} 282 283// Code Completion 284 285static bool EnableCodeCompletion(Preprocessor &PP, 286 const std::string &Filename, 287 unsigned Line, 288 unsigned Column) { 289 // Tell the source manager to chop off the given file at a specific 290 // line and column. 291 const FileEntry *Entry = PP.getFileManager().getFile(Filename); 292 if (!Entry) { 293 PP.getDiagnostics().Report(diag::err_fe_invalid_code_complete_file) 294 << Filename; 295 return true; 296 } 297 298 // Truncate the named file at the given line/column. 299 PP.SetCodeCompletionPoint(Entry, Line, Column); 300 return false; 301} 302 303void CompilerInstance::createCodeCompletionConsumer() { 304 const ParsedSourceLocation &Loc = getFrontendOpts().CodeCompletionAt; 305 if (!CompletionConsumer) { 306 CompletionConsumer.reset( 307 createCodeCompletionConsumer(getPreprocessor(), 308 Loc.FileName, Loc.Line, Loc.Column, 309 getFrontendOpts().ShowMacrosInCodeCompletion, 310 getFrontendOpts().ShowCodePatternsInCodeCompletion, 311 getFrontendOpts().ShowGlobalSymbolsInCodeCompletion, 312 llvm::outs())); 313 if (!CompletionConsumer) 314 return; 315 } else if (EnableCodeCompletion(getPreprocessor(), Loc.FileName, 316 Loc.Line, Loc.Column)) { 317 CompletionConsumer.reset(); 318 return; 319 } 320 321 if (CompletionConsumer->isOutputBinary() && 322 llvm::sys::Program::ChangeStdoutToBinary()) { 323 getPreprocessor().getDiagnostics().Report(diag::err_fe_stdout_binary); 324 CompletionConsumer.reset(); 325 } 326} 327 328void CompilerInstance::createFrontendTimer() { 329 FrontendTimer.reset(new llvm::Timer("Clang front-end timer")); 330} 331 332CodeCompleteConsumer * 333CompilerInstance::createCodeCompletionConsumer(Preprocessor &PP, 334 const std::string &Filename, 335 unsigned Line, 336 unsigned Column, 337 bool ShowMacros, 338 bool ShowCodePatterns, 339 bool ShowGlobals, 340 llvm::raw_ostream &OS) { 341 if (EnableCodeCompletion(PP, Filename, Line, Column)) 342 return 0; 343 344 // Set up the creation routine for code-completion. 345 return new PrintingCodeCompleteConsumer(ShowMacros, ShowCodePatterns, 346 ShowGlobals, OS); 347} 348 349void CompilerInstance::createSema(bool CompleteTranslationUnit, 350 CodeCompleteConsumer *CompletionConsumer) { 351 TheSema.reset(new Sema(getPreprocessor(), getASTContext(), getASTConsumer(), 352 CompleteTranslationUnit, CompletionConsumer)); 353} 354 355// Output Files 356 357void CompilerInstance::addOutputFile(const OutputFile &OutFile) { 358 assert(OutFile.OS && "Attempt to add empty stream to output list!"); 359 OutputFiles.push_back(OutFile); 360} 361 362void CompilerInstance::clearOutputFiles(bool EraseFiles) { 363 for (std::list<OutputFile>::iterator 364 it = OutputFiles.begin(), ie = OutputFiles.end(); it != ie; ++it) { 365 delete it->OS; 366 if (!it->TempFilename.empty()) { 367 llvm::sys::Path TempPath(it->TempFilename); 368 if (EraseFiles) 369 TempPath.eraseFromDisk(); 370 else { 371 std::string Error; 372 llvm::sys::Path NewOutFile(it->Filename); 373 // If '-working-directory' was passed, the output filename should be 374 // relative to that. 375 FileManager::FixupRelativePath(NewOutFile, getFileSystemOpts()); 376 if (TempPath.renamePathOnDisk(NewOutFile, &Error)) { 377 getDiagnostics().Report(diag::err_fe_unable_to_rename_temp) 378 << it->TempFilename << it->Filename << Error; 379 TempPath.eraseFromDisk(); 380 } 381 } 382 } else if (!it->Filename.empty() && EraseFiles) 383 llvm::sys::Path(it->Filename).eraseFromDisk(); 384 385 } 386 OutputFiles.clear(); 387} 388 389llvm::raw_fd_ostream * 390CompilerInstance::createDefaultOutputFile(bool Binary, 391 llvm::StringRef InFile, 392 llvm::StringRef Extension) { 393 return createOutputFile(getFrontendOpts().OutputFile, Binary, 394 /*RemoveFileOnSignal=*/true, InFile, Extension); 395} 396 397llvm::raw_fd_ostream * 398CompilerInstance::createOutputFile(llvm::StringRef OutputPath, 399 bool Binary, bool RemoveFileOnSignal, 400 llvm::StringRef InFile, 401 llvm::StringRef Extension) { 402 std::string Error, OutputPathName, TempPathName; 403 llvm::raw_fd_ostream *OS = createOutputFile(OutputPath, Error, Binary, 404 RemoveFileOnSignal, 405 InFile, Extension, 406 &OutputPathName, 407 &TempPathName); 408 if (!OS) { 409 getDiagnostics().Report(diag::err_fe_unable_to_open_output) 410 << OutputPath << Error; 411 return 0; 412 } 413 414 // Add the output file -- but don't try to remove "-", since this means we are 415 // using stdin. 416 addOutputFile(OutputFile((OutputPathName != "-") ? OutputPathName : "", 417 TempPathName, OS)); 418 419 return OS; 420} 421 422llvm::raw_fd_ostream * 423CompilerInstance::createOutputFile(llvm::StringRef OutputPath, 424 std::string &Error, 425 bool Binary, 426 bool RemoveFileOnSignal, 427 llvm::StringRef InFile, 428 llvm::StringRef Extension, 429 std::string *ResultPathName, 430 std::string *TempPathName) { 431 std::string OutFile, TempFile; 432 if (!OutputPath.empty()) { 433 OutFile = OutputPath; 434 } else if (InFile == "-") { 435 OutFile = "-"; 436 } else if (!Extension.empty()) { 437 llvm::sys::Path Path(InFile); 438 Path.eraseSuffix(); 439 Path.appendSuffix(Extension); 440 OutFile = Path.str(); 441 } else { 442 OutFile = "-"; 443 } 444 445 if (OutFile != "-") { 446 llvm::sys::Path OutPath(OutFile); 447 // Only create the temporary if we can actually write to OutPath, otherwise 448 // we want to fail early. 449 bool Exists; 450 if ((llvm::sys::fs::exists(OutPath.str(), Exists) || !Exists) || 451 (OutPath.isRegularFile() && OutPath.canWrite())) { 452 // Create a temporary file. 453 llvm::sys::Path TempPath(OutFile); 454 if (!TempPath.createTemporaryFileOnDisk()) 455 TempFile = TempPath.str(); 456 } 457 } 458 459 std::string OSFile = OutFile; 460 if (!TempFile.empty()) 461 OSFile = TempFile; 462 463 llvm::OwningPtr<llvm::raw_fd_ostream> OS( 464 new llvm::raw_fd_ostream(OSFile.c_str(), Error, 465 (Binary ? llvm::raw_fd_ostream::F_Binary : 0))); 466 if (!Error.empty()) 467 return 0; 468 469 // Make sure the out stream file gets removed if we crash. 470 if (RemoveFileOnSignal) 471 llvm::sys::RemoveFileOnSignal(llvm::sys::Path(OSFile)); 472 473 if (ResultPathName) 474 *ResultPathName = OutFile; 475 if (TempPathName) 476 *TempPathName = TempFile; 477 478 return OS.take(); 479} 480 481// Initialization Utilities 482 483bool CompilerInstance::InitializeSourceManager(llvm::StringRef InputFile) { 484 return InitializeSourceManager(InputFile, getDiagnostics(), getFileManager(), 485 getSourceManager(), getFrontendOpts()); 486} 487 488bool CompilerInstance::InitializeSourceManager(llvm::StringRef InputFile, 489 Diagnostic &Diags, 490 FileManager &FileMgr, 491 SourceManager &SourceMgr, 492 const FrontendOptions &Opts) { 493 // Figure out where to get and map in the main file, unless it's already 494 // been created (e.g., by a precompiled preamble). 495 if (!SourceMgr.getMainFileID().isInvalid()) { 496 // Do nothing: the main file has already been set. 497 } else if (InputFile != "-") { 498 const FileEntry *File = FileMgr.getFile(InputFile); 499 if (!File) { 500 Diags.Report(diag::err_fe_error_reading) << InputFile; 501 return false; 502 } 503 SourceMgr.createMainFileID(File); 504 } else { 505 llvm::OwningPtr<llvm::MemoryBuffer> SB; 506 if (llvm::MemoryBuffer::getSTDIN(SB)) { 507 // FIXME: Give ec.message() in this diag. 508 Diags.Report(diag::err_fe_error_reading_stdin); 509 return false; 510 } 511 const FileEntry *File = FileMgr.getVirtualFile(SB->getBufferIdentifier(), 512 SB->getBufferSize(), 0); 513 SourceMgr.createMainFileID(File); 514 SourceMgr.overrideFileContents(File, SB.take()); 515 } 516 517 assert(!SourceMgr.getMainFileID().isInvalid() && 518 "Couldn't establish MainFileID!"); 519 return true; 520} 521 522// High-Level Operations 523 524bool CompilerInstance::ExecuteAction(FrontendAction &Act) { 525 assert(hasDiagnostics() && "Diagnostics engine is not initialized!"); 526 assert(!getFrontendOpts().ShowHelp && "Client must handle '-help'!"); 527 assert(!getFrontendOpts().ShowVersion && "Client must handle '-version'!"); 528 529 // FIXME: Take this as an argument, once all the APIs we used have moved to 530 // taking it as an input instead of hard-coding llvm::errs. 531 llvm::raw_ostream &OS = llvm::errs(); 532 533 // Create the target instance. 534 setTarget(TargetInfo::CreateTargetInfo(getDiagnostics(), getTargetOpts())); 535 if (!hasTarget()) 536 return false; 537 538 // Inform the target of the language options. 539 // 540 // FIXME: We shouldn't need to do this, the target should be immutable once 541 // created. This complexity should be lifted elsewhere. 542 getTarget().setForcedLangOptions(getLangOpts()); 543 544 // Validate/process some options. 545 if (getHeaderSearchOpts().Verbose) 546 OS << "clang -cc1 version " CLANG_VERSION_STRING 547 << " based upon " << PACKAGE_STRING 548 << " hosted on " << llvm::sys::getHostTriple() << "\n"; 549 550 if (getFrontendOpts().ShowTimers) 551 createFrontendTimer(); 552 553 if (getFrontendOpts().ShowStats) 554 llvm::EnableStatistics(); 555 556 for (unsigned i = 0, e = getFrontendOpts().Inputs.size(); i != e; ++i) { 557 const std::string &InFile = getFrontendOpts().Inputs[i].second; 558 559 // Reset the ID tables if we are reusing the SourceManager. 560 if (hasSourceManager()) 561 getSourceManager().clearIDTables(); 562 563 if (Act.BeginSourceFile(*this, InFile, getFrontendOpts().Inputs[i].first)) { 564 Act.Execute(); 565 Act.EndSourceFile(); 566 } 567 } 568 569 if (getDiagnosticOpts().ShowCarets) { 570 // We can have multiple diagnostics sharing one diagnostic client. 571 // Get the total number of warnings/errors from the client. 572 unsigned NumWarnings = getDiagnostics().getClient()->getNumWarnings(); 573 unsigned NumErrors = getDiagnostics().getClient()->getNumErrors(); 574 575 if (NumWarnings) 576 OS << NumWarnings << " warning" << (NumWarnings == 1 ? "" : "s"); 577 if (NumWarnings && NumErrors) 578 OS << " and "; 579 if (NumErrors) 580 OS << NumErrors << " error" << (NumErrors == 1 ? "" : "s"); 581 if (NumWarnings || NumErrors) 582 OS << " generated.\n"; 583 } 584 585 if (getFrontendOpts().ShowStats && hasFileManager()) { 586 getFileManager().PrintStats(); 587 OS << "\n"; 588 } 589 590 return !getDiagnostics().getClient()->getNumErrors(); 591} 592 593 594