1 //===--- CompilerInstance.cpp ---------------------------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
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/Support/FileSystem.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
;
42 CompilerInstance::CompilerInstance()
43 : Invocation(new CompilerInvocation()) {
46 CompilerInstance::~CompilerInstance() {
49 void CompilerInstance::setInvocation(CompilerInvocation
*Value
) {
50 Invocation
.reset(Value
);
53 void CompilerInstance::setDiagnostics(Diagnostic
*Value
) {
57 void CompilerInstance::setTarget(TargetInfo
*Value
) {
61 void CompilerInstance::setFileManager(FileManager
*Value
) {
65 void CompilerInstance::setSourceManager(SourceManager
*Value
) {
66 SourceMgr
.reset(Value
);
69 void CompilerInstance::setPreprocessor(Preprocessor
*Value
) {
73 void CompilerInstance::setASTContext(ASTContext
*Value
) {
77 void CompilerInstance::setSema(Sema
*S
) {
81 void CompilerInstance::setASTConsumer(ASTConsumer
*Value
) {
82 Consumer
.reset(Value
);
85 void CompilerInstance::setCodeCompletionConsumer(CodeCompleteConsumer
*Value
) {
86 CompletionConsumer
.reset(Value
);
90 static void SetUpBuildDumpLog(const DiagnosticOptions
&DiagOpts
,
91 unsigned argc
, const char* const *argv
,
93 std::string ErrorInfo
;
94 llvm::OwningPtr
<llvm::raw_ostream
> OS(
95 new llvm::raw_fd_ostream(DiagOpts
.DumpBuildInformation
.c_str(), ErrorInfo
));
96 if (!ErrorInfo
.empty()) {
97 Diags
.Report(diag::err_fe_unable_to_open_logfile
)
98 << DiagOpts
.DumpBuildInformation
<< ErrorInfo
;
102 (*OS
) << "clang -cc1 command line arguments: ";
103 for (unsigned i
= 0; i
!= argc
; ++i
)
104 (*OS
) << argv
[i
] << ' ';
107 // Chain in a diagnostic client which will log the diagnostics.
108 DiagnosticClient
*Logger
=
109 new TextDiagnosticPrinter(*OS
.take(), DiagOpts
, /*OwnsOutputStream=*/true);
110 Diags
.setClient(new ChainedDiagnosticClient(Diags
.takeClient(), Logger
));
113 void CompilerInstance::createDiagnostics(int Argc
, const char* const *Argv
,
114 DiagnosticClient
*Client
) {
115 Diagnostics
= createDiagnostics(getDiagnosticOpts(), Argc
, Argv
, Client
);
118 llvm::IntrusiveRefCntPtr
<Diagnostic
>
119 CompilerInstance::createDiagnostics(const DiagnosticOptions
&Opts
,
120 int Argc
, const char* const *Argv
,
121 DiagnosticClient
*Client
) {
122 llvm::IntrusiveRefCntPtr
<DiagnosticIDs
> DiagID(new DiagnosticIDs());
123 llvm::IntrusiveRefCntPtr
<Diagnostic
> Diags(new Diagnostic(DiagID
));
125 // Create the diagnostic client for reporting errors or for
126 // implementing -verify.
128 Diags
->setClient(Client
);
130 Diags
->setClient(new TextDiagnosticPrinter(llvm::errs(), Opts
));
132 // Chain in -verify checker, if requested.
133 if (Opts
.VerifyDiagnostics
)
134 Diags
->setClient(new VerifyDiagnosticsClient(*Diags
, Diags
->takeClient()));
136 if (!Opts
.DumpBuildInformation
.empty())
137 SetUpBuildDumpLog(Opts
, Argc
, Argv
, *Diags
);
139 // Configure our handling of diagnostics.
140 ProcessWarningOptions(*Diags
, Opts
);
147 void CompilerInstance::createFileManager() {
148 FileMgr
.reset(new FileManager(getFileSystemOpts()));
153 void CompilerInstance::createSourceManager(FileManager
&FileMgr
) {
154 SourceMgr
.reset(new SourceManager(getDiagnostics(), FileMgr
));
159 void CompilerInstance::createPreprocessor() {
160 PP
.reset(createPreprocessor(getDiagnostics(), getLangOpts(),
161 getPreprocessorOpts(), getHeaderSearchOpts(),
162 getDependencyOutputOpts(), getTarget(),
163 getFrontendOpts(), getSourceManager(),
168 CompilerInstance::createPreprocessor(Diagnostic
&Diags
,
169 const LangOptions
&LangInfo
,
170 const PreprocessorOptions
&PPOpts
,
171 const HeaderSearchOptions
&HSOpts
,
172 const DependencyOutputOptions
&DepOpts
,
173 const TargetInfo
&Target
,
174 const FrontendOptions
&FEOpts
,
175 SourceManager
&SourceMgr
,
176 FileManager
&FileMgr
) {
177 // Create a PTH manager if we are using some form of a token cache.
178 PTHManager
*PTHMgr
= 0;
179 if (!PPOpts
.TokenCache
.empty())
180 PTHMgr
= PTHManager::Create(PPOpts
.TokenCache
, Diags
);
182 // Create the Preprocessor.
183 HeaderSearch
*HeaderInfo
= new HeaderSearch(FileMgr
);
184 Preprocessor
*PP
= new Preprocessor(Diags
, LangInfo
, Target
,
185 SourceMgr
, *HeaderInfo
, PTHMgr
,
186 /*OwnsHeaderSearch=*/true);
188 // Note that this is different then passing PTHMgr to Preprocessor's ctor.
189 // That argument is used as the IdentifierInfoLookup argument to
190 // IdentifierTable's ctor.
192 PTHMgr
->setPreprocessor(PP
);
193 PP
->setPTHManager(PTHMgr
);
196 if (PPOpts
.DetailedRecord
)
197 PP
->createPreprocessingRecord();
199 InitializePreprocessor(*PP
, PPOpts
, HSOpts
, FEOpts
);
201 // Handle generating dependencies, if requested.
202 if (!DepOpts
.OutputFile
.empty())
203 AttachDependencyFileGen(*PP
, DepOpts
);
205 // Handle generating header include information, if requested.
206 if (DepOpts
.ShowHeaderIncludes
)
207 AttachHeaderIncludeGen(*PP
);
208 if (!DepOpts
.HeaderIncludeOutputFile
.empty()) {
209 llvm::StringRef OutputPath
= DepOpts
.HeaderIncludeOutputFile
;
210 if (OutputPath
== "-")
212 AttachHeaderIncludeGen(*PP
, /*ShowAllHeaders=*/true, OutputPath
);
220 void CompilerInstance::createASTContext() {
221 Preprocessor
&PP
= getPreprocessor();
222 Context
.reset(new ASTContext(getLangOpts(), PP
.getSourceManager(),
223 getTarget(), PP
.getIdentifierTable(),
224 PP
.getSelectorTable(), PP
.getBuiltinInfo(),
225 /*size_reserve=*/ 0));
230 void CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path
,
231 bool DisablePCHValidation
,
232 bool DisableStatCache
,
233 void *DeserializationListener
){
234 llvm::OwningPtr
<ExternalASTSource
> Source
;
235 bool Preamble
= getPreprocessorOpts().PrecompiledPreambleBytes
.first
!= 0;
236 Source
.reset(createPCHExternalASTSource(Path
, getHeaderSearchOpts().Sysroot
,
237 DisablePCHValidation
,
239 getPreprocessor(), getASTContext(),
240 DeserializationListener
,
242 getASTContext().setExternalSource(Source
);
246 CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path
,
247 const std::string
&Sysroot
,
248 bool DisablePCHValidation
,
249 bool DisableStatCache
,
252 void *DeserializationListener
,
254 llvm::OwningPtr
<ASTReader
> Reader
;
255 Reader
.reset(new ASTReader(PP
, &Context
,
256 Sysroot
.empty() ? 0 : Sysroot
.c_str(),
257 DisablePCHValidation
, DisableStatCache
));
259 Reader
->setDeserializationListener(
260 static_cast<ASTDeserializationListener
*>(DeserializationListener
));
261 switch (Reader
->ReadAST(Path
,
262 Preamble
? ASTReader::Preamble
: ASTReader::PCH
)) {
263 case ASTReader::Success
:
264 // Set the predefines buffer as suggested by the PCH reader. Typically, the
265 // predefines buffer will be empty.
266 PP
.setPredefines(Reader
->getSuggestedPredefines());
267 return Reader
.take();
269 case ASTReader::Failure
:
270 // Unrecoverable failure: don't even try to process the input file.
273 case ASTReader::IgnorePCH
:
274 // No suitable PCH file could be found. Return an error.
283 static bool EnableCodeCompletion(Preprocessor
&PP
,
284 const std::string
&Filename
,
287 // Tell the source manager to chop off the given file at a specific
289 const FileEntry
*Entry
= PP
.getFileManager().getFile(Filename
);
291 PP
.getDiagnostics().Report(diag::err_fe_invalid_code_complete_file
)
296 // Truncate the named file at the given line/column.
297 PP
.SetCodeCompletionPoint(Entry
, Line
, Column
);
301 void CompilerInstance::createCodeCompletionConsumer() {
302 const ParsedSourceLocation
&Loc
= getFrontendOpts().CodeCompletionAt
;
303 if (!CompletionConsumer
) {
304 CompletionConsumer
.reset(
305 createCodeCompletionConsumer(getPreprocessor(),
306 Loc
.FileName
, Loc
.Line
, Loc
.Column
,
307 getFrontendOpts().ShowMacrosInCodeCompletion
,
308 getFrontendOpts().ShowCodePatternsInCodeCompletion
,
309 getFrontendOpts().ShowGlobalSymbolsInCodeCompletion
,
311 if (!CompletionConsumer
)
313 } else if (EnableCodeCompletion(getPreprocessor(), Loc
.FileName
,
314 Loc
.Line
, Loc
.Column
)) {
315 CompletionConsumer
.reset();
319 if (CompletionConsumer
->isOutputBinary() &&
320 llvm::sys::Program::ChangeStdoutToBinary()) {
321 getPreprocessor().getDiagnostics().Report(diag::err_fe_stdout_binary
);
322 CompletionConsumer
.reset();
326 void CompilerInstance::createFrontendTimer() {
327 FrontendTimer
.reset(new llvm::Timer("Clang front-end timer"));
330 CodeCompleteConsumer
*
331 CompilerInstance::createCodeCompletionConsumer(Preprocessor
&PP
,
332 const std::string
&Filename
,
336 bool ShowCodePatterns
,
338 llvm::raw_ostream
&OS
) {
339 if (EnableCodeCompletion(PP
, Filename
, Line
, Column
))
342 // Set up the creation routine for code-completion.
343 return new PrintingCodeCompleteConsumer(ShowMacros
, ShowCodePatterns
,
347 void CompilerInstance::createSema(bool CompleteTranslationUnit
,
348 CodeCompleteConsumer
*CompletionConsumer
) {
349 TheSema
.reset(new Sema(getPreprocessor(), getASTContext(), getASTConsumer(),
350 CompleteTranslationUnit
, CompletionConsumer
));
355 void CompilerInstance::addOutputFile(const OutputFile
&OutFile
) {
356 assert(OutFile
.OS
&& "Attempt to add empty stream to output list!");
357 OutputFiles
.push_back(OutFile
);
360 void CompilerInstance::clearOutputFiles(bool EraseFiles
) {
361 for (std::list
<OutputFile
>::iterator
362 it
= OutputFiles
.begin(), ie
= OutputFiles
.end(); it
!= ie
; ++it
) {
364 if (!it
->TempFilename
.empty()) {
365 llvm::sys::Path
TempPath(it
->TempFilename
);
367 TempPath
.eraseFromDisk();
370 llvm::sys::Path
NewOutFile(it
->Filename
);
371 // If '-working-directory' was passed, the output filename should be
373 FileManager::FixupRelativePath(NewOutFile
, getFileSystemOpts());
374 if (TempPath
.renamePathOnDisk(NewOutFile
, &Error
)) {
375 getDiagnostics().Report(diag::err_fe_unable_to_rename_temp
)
376 << it
->TempFilename
<< it
->Filename
<< Error
;
377 TempPath
.eraseFromDisk();
380 } else if (!it
->Filename
.empty() && EraseFiles
)
381 llvm::sys::Path(it
->Filename
).eraseFromDisk();
387 llvm::raw_fd_ostream
*
388 CompilerInstance::createDefaultOutputFile(bool Binary
,
389 llvm::StringRef InFile
,
390 llvm::StringRef Extension
) {
391 return createOutputFile(getFrontendOpts().OutputFile
, Binary
,
392 /*RemoveFileOnSignal=*/true, InFile
, Extension
);
395 llvm::raw_fd_ostream
*
396 CompilerInstance::createOutputFile(llvm::StringRef OutputPath
,
397 bool Binary
, bool RemoveFileOnSignal
,
398 llvm::StringRef InFile
,
399 llvm::StringRef Extension
) {
400 std::string Error
, OutputPathName
, TempPathName
;
401 llvm::raw_fd_ostream
*OS
= createOutputFile(OutputPath
, Error
, Binary
,
407 getDiagnostics().Report(diag::err_fe_unable_to_open_output
)
408 << OutputPath
<< Error
;
412 // Add the output file -- but don't try to remove "-", since this means we are
414 addOutputFile(OutputFile((OutputPathName
!= "-") ? OutputPathName
: "",
420 llvm::raw_fd_ostream
*
421 CompilerInstance::createOutputFile(llvm::StringRef OutputPath
,
424 bool RemoveFileOnSignal
,
425 llvm::StringRef InFile
,
426 llvm::StringRef Extension
,
427 std::string
*ResultPathName
,
428 std::string
*TempPathName
) {
429 std::string OutFile
, TempFile
;
430 if (!OutputPath
.empty()) {
431 OutFile
= OutputPath
;
432 } else if (InFile
== "-") {
434 } else if (!Extension
.empty()) {
435 llvm::sys::Path
Path(InFile
);
437 Path
.appendSuffix(Extension
);
438 OutFile
= Path
.str();
443 if (OutFile
!= "-") {
444 llvm::sys::Path
OutPath(OutFile
);
445 // Only create the temporary if we can actually write to OutPath, otherwise
446 // we want to fail early.
448 if ((llvm::sys::fs::exists(OutPath
.str(), Exists
) || !Exists
) ||
449 (OutPath
.isRegularFile() && OutPath
.canWrite())) {
450 // Create a temporary file.
451 llvm::sys::Path
TempPath(OutFile
);
452 if (!TempPath
.createTemporaryFileOnDisk())
453 TempFile
= TempPath
.str();
457 std::string OSFile
= OutFile
;
458 if (!TempFile
.empty())
461 llvm::OwningPtr
<llvm::raw_fd_ostream
> OS(
462 new llvm::raw_fd_ostream(OSFile
.c_str(), Error
,
463 (Binary
? llvm::raw_fd_ostream::F_Binary
: 0)));
467 // Make sure the out stream file gets removed if we crash.
468 if (RemoveFileOnSignal
)
469 llvm::sys::RemoveFileOnSignal(llvm::sys::Path(OSFile
));
472 *ResultPathName
= OutFile
;
474 *TempPathName
= TempFile
;
479 // Initialization Utilities
481 bool CompilerInstance::InitializeSourceManager(llvm::StringRef InputFile
) {
482 return InitializeSourceManager(InputFile
, getDiagnostics(), getFileManager(),
483 getSourceManager(), getFrontendOpts());
486 bool CompilerInstance::InitializeSourceManager(llvm::StringRef InputFile
,
488 FileManager
&FileMgr
,
489 SourceManager
&SourceMgr
,
490 const FrontendOptions
&Opts
) {
491 // Figure out where to get and map in the main file, unless it's already
492 // been created (e.g., by a precompiled preamble).
493 if (!SourceMgr
.getMainFileID().isInvalid()) {
494 // Do nothing: the main file has already been set.
495 } else if (InputFile
!= "-") {
496 const FileEntry
*File
= FileMgr
.getFile(InputFile
);
498 Diags
.Report(diag::err_fe_error_reading
) << InputFile
;
501 SourceMgr
.createMainFileID(File
);
503 llvm::OwningPtr
<llvm::MemoryBuffer
> SB
;
504 if (llvm::MemoryBuffer::getSTDIN(SB
)) {
505 // FIXME: Give ec.message() in this diag.
506 Diags
.Report(diag::err_fe_error_reading_stdin
);
509 const FileEntry
*File
= FileMgr
.getVirtualFile(SB
->getBufferIdentifier(),
510 SB
->getBufferSize(), 0);
511 SourceMgr
.createMainFileID(File
);
512 SourceMgr
.overrideFileContents(File
, SB
.take());
515 assert(!SourceMgr
.getMainFileID().isInvalid() &&
516 "Couldn't establish MainFileID!");
520 // High-Level Operations
522 bool CompilerInstance::ExecuteAction(FrontendAction
&Act
) {
523 assert(hasDiagnostics() && "Diagnostics engine is not initialized!");
524 assert(!getFrontendOpts().ShowHelp
&& "Client must handle '-help'!");
525 assert(!getFrontendOpts().ShowVersion
&& "Client must handle '-version'!");
527 // FIXME: Take this as an argument, once all the APIs we used have moved to
528 // taking it as an input instead of hard-coding llvm::errs.
529 llvm::raw_ostream
&OS
= llvm::errs();
531 // Create the target instance.
532 setTarget(TargetInfo::CreateTargetInfo(getDiagnostics(), getTargetOpts()));
536 // Inform the target of the language options.
538 // FIXME: We shouldn't need to do this, the target should be immutable once
539 // created. This complexity should be lifted elsewhere.
540 getTarget().setForcedLangOptions(getLangOpts());
542 // Validate/process some options.
543 if (getHeaderSearchOpts().Verbose
)
544 OS
<< "clang -cc1 version " CLANG_VERSION_STRING
545 << " based upon " << PACKAGE_STRING
546 << " hosted on " << llvm::sys::getHostTriple() << "\n";
548 if (getFrontendOpts().ShowTimers
)
549 createFrontendTimer();
551 if (getFrontendOpts().ShowStats
)
552 llvm::EnableStatistics();
554 for (unsigned i
= 0, e
= getFrontendOpts().Inputs
.size(); i
!= e
; ++i
) {
555 const std::string
&InFile
= getFrontendOpts().Inputs
[i
].second
;
557 // Reset the ID tables if we are reusing the SourceManager.
558 if (hasSourceManager())
559 getSourceManager().clearIDTables();
561 if (Act
.BeginSourceFile(*this, InFile
, getFrontendOpts().Inputs
[i
].first
)) {
567 if (getDiagnosticOpts().ShowCarets
) {
568 // We can have multiple diagnostics sharing one diagnostic client.
569 // Get the total number of warnings/errors from the client.
570 unsigned NumWarnings
= getDiagnostics().getClient()->getNumWarnings();
571 unsigned NumErrors
= getDiagnostics().getClient()->getNumErrors();
574 OS
<< NumWarnings
<< " warning" << (NumWarnings
== 1 ? "" : "s");
575 if (NumWarnings
&& NumErrors
)
578 OS
<< NumErrors
<< " error" << (NumErrors
== 1 ? "" : "s");
579 if (NumWarnings
|| NumErrors
)
580 OS
<< " generated.\n";
583 if (getFrontendOpts().ShowStats
&& hasFileManager()) {
584 getFileManager().PrintStats();
588 return !getDiagnostics().getClient()->getNumErrors();