CompilerInstance.cpp revision 96b1d4b4eb6b18dd6df7a2c0833332b45840580f
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 bool DisableStatCache, 238 void *DeserializationListener){ 239 llvm::OwningPtr<ExternalASTSource> Source; 240 bool Preamble = getPreprocessorOpts().PrecompiledPreambleBytes.first != 0; 241 Source.reset(createPCHExternalASTSource(Path, getHeaderSearchOpts().Sysroot, 242 DisablePCHValidation, 243 DisableStatCache, 244 getPreprocessor(), getASTContext(), 245 DeserializationListener, 246 Preamble)); 247 getASTContext().setExternalSource(Source); 248} 249 250ExternalASTSource * 251CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path, 252 const std::string &Sysroot, 253 bool DisablePCHValidation, 254 bool DisableStatCache, 255 Preprocessor &PP, 256 ASTContext &Context, 257 void *DeserializationListener, 258 bool Preamble) { 259 llvm::OwningPtr<ASTReader> Reader; 260 Reader.reset(new ASTReader(PP, &Context, 261 Sysroot.empty() ? 0 : Sysroot.c_str(), 262 DisablePCHValidation, DisableStatCache)); 263 264 Reader->setDeserializationListener( 265 static_cast<ASTDeserializationListener *>(DeserializationListener)); 266 switch (Reader->ReadAST(Path, 267 Preamble ? ASTReader::Preamble : ASTReader::PCH)) { 268 case ASTReader::Success: 269 // Set the predefines buffer as suggested by the PCH reader. Typically, the 270 // predefines buffer will be empty. 271 PP.setPredefines(Reader->getSuggestedPredefines()); 272 return Reader.take(); 273 274 case ASTReader::Failure: 275 // Unrecoverable failure: don't even try to process the input file. 276 break; 277 278 case ASTReader::IgnorePCH: 279 // No suitable PCH file could be found. Return an error. 280 break; 281 } 282 283 return 0; 284} 285 286// Code Completion 287 288static bool EnableCodeCompletion(Preprocessor &PP, 289 const std::string &Filename, 290 unsigned Line, 291 unsigned Column) { 292 // Tell the source manager to chop off the given file at a specific 293 // line and column. 294 const FileEntry *Entry = PP.getFileManager().getFile(Filename); 295 if (!Entry) { 296 PP.getDiagnostics().Report(diag::err_fe_invalid_code_complete_file) 297 << Filename; 298 return true; 299 } 300 301 // Truncate the named file at the given line/column. 302 PP.SetCodeCompletionPoint(Entry, Line, Column); 303 return false; 304} 305 306void CompilerInstance::createCodeCompletionConsumer() { 307 const ParsedSourceLocation &Loc = getFrontendOpts().CodeCompletionAt; 308 if (!CompletionConsumer) { 309 CompletionConsumer.reset( 310 createCodeCompletionConsumer(getPreprocessor(), 311 Loc.FileName, Loc.Line, Loc.Column, 312 getFrontendOpts().ShowMacrosInCodeCompletion, 313 getFrontendOpts().ShowCodePatternsInCodeCompletion, 314 getFrontendOpts().ShowGlobalSymbolsInCodeCompletion, 315 llvm::outs())); 316 if (!CompletionConsumer) 317 return; 318 } else if (EnableCodeCompletion(getPreprocessor(), Loc.FileName, 319 Loc.Line, Loc.Column)) { 320 CompletionConsumer.reset(); 321 return; 322 } 323 324 if (CompletionConsumer->isOutputBinary() && 325 llvm::sys::Program::ChangeStdoutToBinary()) { 326 getPreprocessor().getDiagnostics().Report(diag::err_fe_stdout_binary); 327 CompletionConsumer.reset(); 328 } 329} 330 331void CompilerInstance::createFrontendTimer() { 332 FrontendTimer.reset(new llvm::Timer("Clang front-end timer")); 333} 334 335CodeCompleteConsumer * 336CompilerInstance::createCodeCompletionConsumer(Preprocessor &PP, 337 const std::string &Filename, 338 unsigned Line, 339 unsigned Column, 340 bool ShowMacros, 341 bool ShowCodePatterns, 342 bool ShowGlobals, 343 llvm::raw_ostream &OS) { 344 if (EnableCodeCompletion(PP, Filename, Line, Column)) 345 return 0; 346 347 // Set up the creation routine for code-completion. 348 return new PrintingCodeCompleteConsumer(ShowMacros, ShowCodePatterns, 349 ShowGlobals, OS); 350} 351 352void CompilerInstance::createSema(bool CompleteTranslationUnit, 353 CodeCompleteConsumer *CompletionConsumer) { 354 TheSema.reset(new Sema(getPreprocessor(), getASTContext(), getASTConsumer(), 355 CompleteTranslationUnit, CompletionConsumer)); 356} 357 358// Output Files 359 360void CompilerInstance::addOutputFile(const OutputFile &OutFile) { 361 assert(OutFile.OS && "Attempt to add empty stream to output list!"); 362 OutputFiles.push_back(OutFile); 363} 364 365void CompilerInstance::clearOutputFiles(bool EraseFiles) { 366 for (std::list<OutputFile>::iterator 367 it = OutputFiles.begin(), ie = OutputFiles.end(); it != ie; ++it) { 368 delete it->OS; 369 if (!it->TempFilename.empty()) { 370 llvm::sys::Path TempPath(it->TempFilename); 371 if (EraseFiles) 372 TempPath.eraseFromDisk(); 373 else { 374 std::string Error; 375 llvm::sys::Path NewOutFile(it->Filename); 376 // If '-working-directory' was passed, the output filename should be 377 // relative to that. 378 FileManager::FixupRelativePath(NewOutFile, getFileSystemOpts()); 379 if (TempPath.renamePathOnDisk(NewOutFile, &Error)) { 380 getDiagnostics().Report(diag::err_fe_unable_to_rename_temp) 381 << it->TempFilename << it->Filename << Error; 382 TempPath.eraseFromDisk(); 383 } 384 } 385 } else if (!it->Filename.empty() && EraseFiles) 386 llvm::sys::Path(it->Filename).eraseFromDisk(); 387 388 } 389 OutputFiles.clear(); 390} 391 392llvm::raw_fd_ostream * 393CompilerInstance::createDefaultOutputFile(bool Binary, 394 llvm::StringRef InFile, 395 llvm::StringRef Extension) { 396 return createOutputFile(getFrontendOpts().OutputFile, Binary, 397 /*RemoveFileOnSignal=*/true, InFile, Extension); 398} 399 400llvm::raw_fd_ostream * 401CompilerInstance::createOutputFile(llvm::StringRef OutputPath, 402 bool Binary, bool RemoveFileOnSignal, 403 llvm::StringRef InFile, 404 llvm::StringRef Extension) { 405 std::string Error, OutputPathName, TempPathName; 406 llvm::raw_fd_ostream *OS = createOutputFile(OutputPath, Error, Binary, 407 RemoveFileOnSignal, 408 InFile, Extension, 409 &OutputPathName, 410 &TempPathName); 411 if (!OS) { 412 getDiagnostics().Report(diag::err_fe_unable_to_open_output) 413 << OutputPath << Error; 414 return 0; 415 } 416 417 // Add the output file -- but don't try to remove "-", since this means we are 418 // using stdin. 419 addOutputFile(OutputFile((OutputPathName != "-") ? OutputPathName : "", 420 TempPathName, OS)); 421 422 return OS; 423} 424 425llvm::raw_fd_ostream * 426CompilerInstance::createOutputFile(llvm::StringRef OutputPath, 427 std::string &Error, 428 bool Binary, 429 bool RemoveFileOnSignal, 430 llvm::StringRef InFile, 431 llvm::StringRef Extension, 432 std::string *ResultPathName, 433 std::string *TempPathName) { 434 std::string OutFile, TempFile; 435 if (!OutputPath.empty()) { 436 OutFile = OutputPath; 437 } else if (InFile == "-") { 438 OutFile = "-"; 439 } else if (!Extension.empty()) { 440 llvm::sys::Path Path(InFile); 441 Path.eraseSuffix(); 442 Path.appendSuffix(Extension); 443 OutFile = Path.str(); 444 } else { 445 OutFile = "-"; 446 } 447 448 if (OutFile != "-") { 449 llvm::sys::Path OutPath(OutFile); 450 // Only create the temporary if we can actually write to OutPath, otherwise 451 // we want to fail early. 452 bool Exists; 453 if ((llvm::sys::fs::exists(OutPath.str(), Exists) || !Exists) || 454 (OutPath.isRegularFile() && OutPath.canWrite())) { 455 // Create a temporary file. 456 llvm::sys::Path TempPath(OutFile); 457 if (!TempPath.createTemporaryFileOnDisk()) 458 TempFile = TempPath.str(); 459 } 460 } 461 462 std::string OSFile = OutFile; 463 if (!TempFile.empty()) 464 OSFile = TempFile; 465 466 llvm::OwningPtr<llvm::raw_fd_ostream> OS( 467 new llvm::raw_fd_ostream(OSFile.c_str(), Error, 468 (Binary ? llvm::raw_fd_ostream::F_Binary : 0))); 469 if (!Error.empty()) 470 return 0; 471 472 // Make sure the out stream file gets removed if we crash. 473 if (RemoveFileOnSignal) 474 llvm::sys::RemoveFileOnSignal(llvm::sys::Path(OSFile)); 475 476 if (ResultPathName) 477 *ResultPathName = OutFile; 478 if (TempPathName) 479 *TempPathName = TempFile; 480 481 return OS.take(); 482} 483 484// Initialization Utilities 485 486bool CompilerInstance::InitializeSourceManager(llvm::StringRef InputFile) { 487 return InitializeSourceManager(InputFile, getDiagnostics(), getFileManager(), 488 getSourceManager(), getFrontendOpts()); 489} 490 491bool CompilerInstance::InitializeSourceManager(llvm::StringRef InputFile, 492 Diagnostic &Diags, 493 FileManager &FileMgr, 494 SourceManager &SourceMgr, 495 const FrontendOptions &Opts) { 496 // Figure out where to get and map in the main file, unless it's already 497 // been created (e.g., by a precompiled preamble). 498 if (!SourceMgr.getMainFileID().isInvalid()) { 499 // Do nothing: the main file has already been set. 500 } else if (InputFile != "-") { 501 const FileEntry *File = FileMgr.getFile(InputFile); 502 if (!File) { 503 Diags.Report(diag::err_fe_error_reading) << InputFile; 504 return false; 505 } 506 SourceMgr.createMainFileID(File); 507 } else { 508 llvm::OwningPtr<llvm::MemoryBuffer> SB; 509 if (llvm::MemoryBuffer::getSTDIN(SB)) { 510 // FIXME: Give ec.message() in this diag. 511 Diags.Report(diag::err_fe_error_reading_stdin); 512 return false; 513 } 514 const FileEntry *File = FileMgr.getVirtualFile(SB->getBufferIdentifier(), 515 SB->getBufferSize(), 0); 516 SourceMgr.createMainFileID(File); 517 SourceMgr.overrideFileContents(File, SB.take()); 518 } 519 520 assert(!SourceMgr.getMainFileID().isInvalid() && 521 "Couldn't establish MainFileID!"); 522 return true; 523} 524 525// High-Level Operations 526 527bool CompilerInstance::ExecuteAction(FrontendAction &Act) { 528 assert(hasDiagnostics() && "Diagnostics engine is not initialized!"); 529 assert(!getFrontendOpts().ShowHelp && "Client must handle '-help'!"); 530 assert(!getFrontendOpts().ShowVersion && "Client must handle '-version'!"); 531 532 // FIXME: Take this as an argument, once all the APIs we used have moved to 533 // taking it as an input instead of hard-coding llvm::errs. 534 llvm::raw_ostream &OS = llvm::errs(); 535 536 // Create the target instance. 537 setTarget(TargetInfo::CreateTargetInfo(getDiagnostics(), getTargetOpts())); 538 if (!hasTarget()) 539 return false; 540 541 // Inform the target of the language options. 542 // 543 // FIXME: We shouldn't need to do this, the target should be immutable once 544 // created. This complexity should be lifted elsewhere. 545 getTarget().setForcedLangOptions(getLangOpts()); 546 547 // Validate/process some options. 548 if (getHeaderSearchOpts().Verbose) 549 OS << "clang -cc1 version " CLANG_VERSION_STRING 550 << " based upon " << PACKAGE_STRING 551 << " hosted on " << llvm::sys::getHostTriple() << "\n"; 552 553 if (getFrontendOpts().ShowTimers) 554 createFrontendTimer(); 555 556 if (getFrontendOpts().ShowStats) 557 llvm::EnableStatistics(); 558 559 for (unsigned i = 0, e = getFrontendOpts().Inputs.size(); i != e; ++i) { 560 const std::string &InFile = getFrontendOpts().Inputs[i].second; 561 562 // Reset the ID tables if we are reusing the SourceManager. 563 if (hasSourceManager()) 564 getSourceManager().clearIDTables(); 565 566 if (Act.BeginSourceFile(*this, InFile, getFrontendOpts().Inputs[i].first)) { 567 Act.Execute(); 568 Act.EndSourceFile(); 569 } 570 } 571 572 if (getDiagnosticOpts().ShowCarets) { 573 // We can have multiple diagnostics sharing one diagnostic client. 574 // Get the total number of warnings/errors from the client. 575 unsigned NumWarnings = getDiagnostics().getClient()->getNumWarnings(); 576 unsigned NumErrors = getDiagnostics().getClient()->getNumErrors(); 577 578 if (NumWarnings) 579 OS << NumWarnings << " warning" << (NumWarnings == 1 ? "" : "s"); 580 if (NumWarnings && NumErrors) 581 OS << " and "; 582 if (NumErrors) 583 OS << NumErrors << " error" << (NumErrors == 1 ? "" : "s"); 584 if (NumWarnings || NumErrors) 585 OS << " generated.\n"; 586 } 587 588 if (getFrontendOpts().ShowStats && hasFileManager()) { 589 getFileManager().PrintStats(); 590 OS << "\n"; 591 } 592 593 return !getDiagnostics().getClient()->getNumErrors(); 594} 595 596 597