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