CompilerInstance.cpp revision d93256e55673a17d18543397ec462416acb13792
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 86namespace { 87 class BinaryDiagnosticSerializer : public DiagnosticClient { 88 llvm::raw_ostream &OS; 89 SourceManager *SourceMgr; 90 public: 91 explicit BinaryDiagnosticSerializer(llvm::raw_ostream &OS) 92 : OS(OS), SourceMgr(0) { } 93 94 virtual void HandleDiagnostic(Diagnostic::Level DiagLevel, 95 const DiagnosticInfo &Info); 96 }; 97} 98 99void BinaryDiagnosticSerializer::HandleDiagnostic(Diagnostic::Level DiagLevel, 100 const DiagnosticInfo &Info) { 101 Info.Serialize(DiagLevel, OS); 102} 103 104static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts, 105 unsigned argc, char **argv, 106 llvm::OwningPtr<DiagnosticClient> &DiagClient) { 107 std::string ErrorInfo; 108 llvm::raw_ostream *OS = 109 new llvm::raw_fd_ostream(DiagOpts.DumpBuildInformation.c_str(), ErrorInfo); 110 if (!ErrorInfo.empty()) { 111 // FIXME: Do not fail like this. 112 llvm::errs() << "error opening -dump-build-information file '" 113 << DiagOpts.DumpBuildInformation << "', option ignored!\n"; 114 delete OS; 115 return; 116 } 117 118 (*OS) << "clang -cc1 command line arguments: "; 119 for (unsigned i = 0; i != argc; ++i) 120 (*OS) << argv[i] << ' '; 121 (*OS) << '\n'; 122 123 // Chain in a diagnostic client which will log the diagnostics. 124 DiagnosticClient *Logger = 125 new TextDiagnosticPrinter(*OS, DiagOpts, /*OwnsOutputStream=*/true); 126 DiagClient.reset(new ChainedDiagnosticClient(DiagClient.take(), Logger)); 127} 128 129void CompilerInstance::createDiagnostics(int Argc, char **Argv) { 130 Diagnostics.reset(createDiagnostics(getDiagnosticOpts(), Argc, Argv)); 131 132 if (Diagnostics) 133 DiagClient.reset(Diagnostics->getClient()); 134} 135 136Diagnostic *CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts, 137 int Argc, char **Argv) { 138 llvm::OwningPtr<Diagnostic> Diags(new Diagnostic()); 139 140 // Create the diagnostic client for reporting errors or for 141 // implementing -verify. 142 llvm::OwningPtr<DiagnosticClient> DiagClient; 143 if (Opts.BinaryOutput) { 144 if (llvm::sys::Program::ChangeStderrToBinary()) { 145 // We weren't able to set standard error to binary, which is a 146 // bit of a problem. So, just create a text diagnostic printer 147 // to complain about this problem, and pretend that the user 148 // didn't try to use binary output. 149 DiagClient.reset(new TextDiagnosticPrinter(llvm::errs(), Opts)); 150 Diags->setClient(DiagClient.take()); 151 Diags->Report(diag::err_fe_stderr_binary); 152 return Diags.take(); 153 } else { 154 DiagClient.reset(new BinaryDiagnosticSerializer(llvm::errs())); 155 } 156 } else { 157 DiagClient.reset(new TextDiagnosticPrinter(llvm::errs(), Opts)); 158 } 159 160 // Chain in -verify checker, if requested. 161 if (Opts.VerifyDiagnostics) 162 DiagClient.reset(new VerifyDiagnosticsClient(*Diags, DiagClient.take())); 163 164 if (!Opts.DumpBuildInformation.empty()) 165 SetUpBuildDumpLog(Opts, Argc, Argv, DiagClient); 166 167 // Configure our handling of diagnostics. 168 Diags->setClient(DiagClient.take()); 169 if (ProcessWarningOptions(*Diags, Opts)) 170 return 0; 171 172 return Diags.take(); 173} 174 175// File Manager 176 177void CompilerInstance::createFileManager() { 178 FileMgr.reset(new FileManager()); 179} 180 181// Source Manager 182 183void CompilerInstance::createSourceManager() { 184 SourceMgr.reset(new SourceManager()); 185} 186 187// Preprocessor 188 189void CompilerInstance::createPreprocessor() { 190 PP.reset(createPreprocessor(getDiagnostics(), getLangOpts(), 191 getPreprocessorOpts(), getHeaderSearchOpts(), 192 getDependencyOutputOpts(), getTarget(), 193 getFrontendOpts(), getSourceManager(), 194 getFileManager())); 195} 196 197Preprocessor * 198CompilerInstance::createPreprocessor(Diagnostic &Diags, 199 const LangOptions &LangInfo, 200 const PreprocessorOptions &PPOpts, 201 const HeaderSearchOptions &HSOpts, 202 const DependencyOutputOptions &DepOpts, 203 const TargetInfo &Target, 204 const FrontendOptions &FEOpts, 205 SourceManager &SourceMgr, 206 FileManager &FileMgr) { 207 // Create a PTH manager if we are using some form of a token cache. 208 PTHManager *PTHMgr = 0; 209 if (!PPOpts.TokenCache.empty()) 210 PTHMgr = PTHManager::Create(PPOpts.TokenCache, Diags); 211 212 // Create the Preprocessor. 213 HeaderSearch *HeaderInfo = new HeaderSearch(FileMgr); 214 Preprocessor *PP = new Preprocessor(Diags, LangInfo, Target, 215 SourceMgr, *HeaderInfo, PTHMgr, 216 /*OwnsHeaderSearch=*/true); 217 218 // Note that this is different then passing PTHMgr to Preprocessor's ctor. 219 // That argument is used as the IdentifierInfoLookup argument to 220 // IdentifierTable's ctor. 221 if (PTHMgr) { 222 PTHMgr->setPreprocessor(PP); 223 PP->setPTHManager(PTHMgr); 224 } 225 226 InitializePreprocessor(*PP, PPOpts, HSOpts, FEOpts); 227 228 // Handle generating dependencies, if requested. 229 if (!DepOpts.OutputFile.empty()) 230 AttachDependencyFileGen(*PP, DepOpts); 231 232 return PP; 233} 234 235// ASTContext 236 237void CompilerInstance::createASTContext() { 238 Preprocessor &PP = getPreprocessor(); 239 Context.reset(new ASTContext(getLangOpts(), PP.getSourceManager(), 240 getTarget(), PP.getIdentifierTable(), 241 PP.getSelectorTable(), PP.getBuiltinInfo(), 242 /*FreeMemory=*/ !getFrontendOpts().DisableFree, 243 /*size_reserve=*/ 0)); 244} 245 246// ExternalASTSource 247 248void CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path) { 249 llvm::OwningPtr<ExternalASTSource> Source; 250 Source.reset(createPCHExternalASTSource(Path, getHeaderSearchOpts().Sysroot, 251 getPreprocessor(), getASTContext())); 252 getASTContext().setExternalSource(Source); 253} 254 255ExternalASTSource * 256CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path, 257 const std::string &Sysroot, 258 Preprocessor &PP, 259 ASTContext &Context) { 260 llvm::OwningPtr<PCHReader> Reader; 261 Reader.reset(new PCHReader(PP, &Context, 262 Sysroot.empty() ? 0 : Sysroot.c_str())); 263 264 switch (Reader->ReadPCH(Path)) { 265 case PCHReader::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 PCHReader::Failure: 272 // Unrecoverable failure: don't even try to process the input file. 273 break; 274 275 case PCHReader::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 285void CompilerInstance::createCodeCompletionConsumer() { 286 const ParsedSourceLocation &Loc = getFrontendOpts().CodeCompletionAt; 287 CompletionConsumer.reset( 288 createCodeCompletionConsumer(getPreprocessor(), 289 Loc.FileName, Loc.Line, Loc.Column, 290 getFrontendOpts().DebugCodeCompletionPrinter, 291 getFrontendOpts().ShowMacrosInCodeCompletion, 292 llvm::outs())); 293 294 if (CompletionConsumer->isOutputBinary() && 295 llvm::sys::Program::ChangeStdoutToBinary()) { 296 getPreprocessor().getDiagnostics().Report(diag::err_fe_stdout_binary); 297 CompletionConsumer.reset(); 298 } 299} 300 301void CompilerInstance::createFrontendTimer() { 302 FrontendTimer.reset(new llvm::Timer("Clang front-end timer")); 303} 304 305CodeCompleteConsumer * 306CompilerInstance::createCodeCompletionConsumer(Preprocessor &PP, 307 const std::string &Filename, 308 unsigned Line, 309 unsigned Column, 310 bool UseDebugPrinter, 311 bool ShowMacros, 312 llvm::raw_ostream &OS) { 313 // Tell the source manager to chop off the given file at a specific 314 // line and column. 315 const FileEntry *Entry = PP.getFileManager().getFile(Filename); 316 if (!Entry) { 317 PP.getDiagnostics().Report(diag::err_fe_invalid_code_complete_file) 318 << Filename; 319 return 0; 320 } 321 322 // Truncate the named file at the given line/column. 323 PP.SetCodeCompletionPoint(Entry, Line, Column); 324 325 // Set up the creation routine for code-completion. 326 if (UseDebugPrinter) 327 return new PrintingCodeCompleteConsumer(ShowMacros, OS); 328 else 329 return new CIndexCodeCompleteConsumer(ShowMacros, OS); 330} 331 332// Output Files 333 334void CompilerInstance::addOutputFile(llvm::StringRef Path, 335 llvm::raw_ostream *OS) { 336 assert(OS && "Attempt to add empty stream to output list!"); 337 OutputFiles.push_back(std::make_pair(Path, OS)); 338} 339 340void CompilerInstance::ClearOutputFiles(bool EraseFiles) { 341 for (std::list< std::pair<std::string, llvm::raw_ostream*> >::iterator 342 it = OutputFiles.begin(), ie = OutputFiles.end(); it != ie; ++it) { 343 delete it->second; 344 if (EraseFiles && !it->first.empty()) 345 llvm::sys::Path(it->first).eraseFromDisk(); 346 } 347 OutputFiles.clear(); 348} 349 350llvm::raw_fd_ostream * 351CompilerInstance::createDefaultOutputFile(bool Binary, 352 llvm::StringRef InFile, 353 llvm::StringRef Extension) { 354 return createOutputFile(getFrontendOpts().OutputFile, Binary, 355 InFile, Extension); 356} 357 358llvm::raw_fd_ostream * 359CompilerInstance::createOutputFile(llvm::StringRef OutputPath, 360 bool Binary, 361 llvm::StringRef InFile, 362 llvm::StringRef Extension) { 363 std::string Error, OutputPathName; 364 llvm::raw_fd_ostream *OS = createOutputFile(OutputPath, Error, Binary, 365 InFile, Extension, 366 &OutputPathName); 367 if (!OS) { 368 getDiagnostics().Report(diag::err_fe_unable_to_open_output) 369 << OutputPath << Error; 370 return 0; 371 } 372 373 // Add the output file -- but don't try to remove "-", since this means we are 374 // using stdin. 375 addOutputFile((OutputPathName != "-") ? OutputPathName : "", OS); 376 377 return OS; 378} 379 380llvm::raw_fd_ostream * 381CompilerInstance::createOutputFile(llvm::StringRef OutputPath, 382 std::string &Error, 383 bool Binary, 384 llvm::StringRef InFile, 385 llvm::StringRef Extension, 386 std::string *ResultPathName) { 387 std::string OutFile; 388 if (!OutputPath.empty()) { 389 OutFile = OutputPath; 390 } else if (InFile == "-") { 391 OutFile = "-"; 392 } else if (!Extension.empty()) { 393 llvm::sys::Path Path(InFile); 394 Path.eraseSuffix(); 395 Path.appendSuffix(Extension); 396 OutFile = Path.str(); 397 } else { 398 OutFile = "-"; 399 } 400 401 llvm::OwningPtr<llvm::raw_fd_ostream> OS( 402 new llvm::raw_fd_ostream(OutFile.c_str(), Error, 403 (Binary ? llvm::raw_fd_ostream::F_Binary : 0))); 404 if (!Error.empty()) 405 return 0; 406 407 if (ResultPathName) 408 *ResultPathName = OutFile; 409 410 return OS.take(); 411} 412 413// Initialization Utilities 414 415bool CompilerInstance::InitializeSourceManager(llvm::StringRef InputFile) { 416 return InitializeSourceManager(InputFile, getDiagnostics(), getFileManager(), 417 getSourceManager(), getFrontendOpts()); 418} 419 420bool CompilerInstance::InitializeSourceManager(llvm::StringRef InputFile, 421 Diagnostic &Diags, 422 FileManager &FileMgr, 423 SourceManager &SourceMgr, 424 const FrontendOptions &Opts) { 425 // Figure out where to get and map in the main file. 426 if (Opts.EmptyInputOnly) { 427 const char *EmptyStr = ""; 428 llvm::MemoryBuffer *SB = 429 llvm::MemoryBuffer::getMemBuffer(EmptyStr, EmptyStr, "<empty input>"); 430 SourceMgr.createMainFileIDForMemBuffer(SB); 431 } else if (InputFile != "-") { 432 const FileEntry *File = FileMgr.getFile(InputFile); 433 if (File) SourceMgr.createMainFileID(File, SourceLocation()); 434 if (SourceMgr.getMainFileID().isInvalid()) { 435 Diags.Report(diag::err_fe_error_reading) << InputFile; 436 return false; 437 } 438 } else { 439 llvm::MemoryBuffer *SB = llvm::MemoryBuffer::getSTDIN(); 440 SourceMgr.createMainFileIDForMemBuffer(SB); 441 if (SourceMgr.getMainFileID().isInvalid()) { 442 Diags.Report(diag::err_fe_error_reading_stdin); 443 return false; 444 } 445 } 446 447 return true; 448} 449 450// High-Level Operations 451 452bool CompilerInstance::ExecuteAction(FrontendAction &Act) { 453 assert(hasDiagnostics() && "Diagnostics engine is not initialized!"); 454 assert(!getFrontendOpts().ShowHelp && "Client must handle '-help'!"); 455 assert(!getFrontendOpts().ShowVersion && "Client must handle '-version'!"); 456 457 // FIXME: Take this as an argument, once all the APIs we used have moved to 458 // taking it as an input instead of hard-coding llvm::errs. 459 llvm::raw_ostream &OS = llvm::errs(); 460 461 // Create the target instance. 462 setTarget(TargetInfo::CreateTargetInfo(getDiagnostics(), getTargetOpts())); 463 if (!hasTarget()) 464 return false; 465 466 // Inform the target of the language options. 467 // 468 // FIXME: We shouldn't need to do this, the target should be immutable once 469 // created. This complexity should be lifted elsewhere. 470 getTarget().setForcedLangOptions(getLangOpts()); 471 472 // Validate/process some options. 473 if (getHeaderSearchOpts().Verbose) 474 OS << "clang -cc1 version " CLANG_VERSION_STRING 475 << " based upon " << PACKAGE_STRING 476 << " hosted on " << llvm::sys::getHostTriple() << "\n"; 477 478 if (getFrontendOpts().ShowTimers) 479 createFrontendTimer(); 480 481 for (unsigned i = 0, e = getFrontendOpts().Inputs.size(); i != e; ++i) { 482 const std::string &InFile = getFrontendOpts().Inputs[i].second; 483 484 // If we aren't using an AST file, setup the file and source managers and 485 // the preprocessor. 486 bool IsAST = getFrontendOpts().Inputs[i].first == FrontendOptions::IK_AST; 487 if (!IsAST) { 488 if (!i) { 489 // Create a file manager object to provide access to and cache the 490 // filesystem. 491 createFileManager(); 492 493 // Create the source manager. 494 createSourceManager(); 495 } else { 496 // Reset the ID tables if we are reusing the SourceManager. 497 getSourceManager().clearIDTables(); 498 } 499 500 // Create the preprocessor. 501 createPreprocessor(); 502 } 503 504 if (Act.BeginSourceFile(*this, InFile, IsAST)) { 505 Act.Execute(); 506 Act.EndSourceFile(); 507 } 508 } 509 510 if (getDiagnosticOpts().ShowCarets) 511 if (unsigned NumDiagnostics = getDiagnostics().getNumDiagnostics()) 512 OS << NumDiagnostics << " diagnostic" 513 << (NumDiagnostics == 1 ? "" : "s") 514 << " generated.\n"; 515 516 if (getFrontendOpts().ShowStats) { 517 getFileManager().PrintStats(); 518 OS << "\n"; 519 } 520 521 // Return the appropriate status when verifying diagnostics. 522 // 523 // FIXME: If we could make getNumErrors() do the right thing, we wouldn't need 524 // this. 525 if (getDiagnosticOpts().VerifyDiagnostics) 526 return !static_cast<VerifyDiagnosticsClient&>( 527 getDiagnosticClient()).HadErrors(); 528 529 return !getDiagnostics().getNumErrors(); 530} 531 532 533