1 //===--- PrecompiledPreamble.cpp - Build precompiled preambles --*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // Helper class to build precompiled preamble.
11 //===----------------------------------------------------------------------===//
13 #include "clang/Frontend/PrecompiledPreamble.h"
14 #include "clang/Basic/FileManager.h"
15 #include "clang/Basic/LangStandard.h"
16 #include "clang/Frontend/CompilerInstance.h"
17 #include "clang/Frontend/CompilerInvocation.h"
18 #include "clang/Frontend/FrontendActions.h"
19 #include "clang/Frontend/FrontendOptions.h"
20 #include "clang/Lex/HeaderSearch.h"
21 #include "clang/Lex/Lexer.h"
22 #include "clang/Lex/Preprocessor.h"
23 #include "clang/Lex/PreprocessorOptions.h"
24 #include "clang/Serialization/ASTWriter.h"
25 #include "llvm/ADT/SmallString.h"
26 #include "llvm/ADT/StringSet.h"
27 #include "llvm/ADT/iterator_range.h"
28 #include "llvm/Config/llvm-config.h"
29 #include "llvm/Support/CrashRecoveryContext.h"
30 #include "llvm/Support/FileSystem.h"
31 #include "llvm/Support/Path.h"
32 #include "llvm/Support/Process.h"
33 #include "llvm/Support/VirtualFileSystem.h"
38 using namespace clang
;
42 StringRef
getInMemoryPreamblePath() {
43 #if defined(LLVM_ON_UNIX)
44 return "/__clang_tmp/___clang_inmemory_preamble___";
46 return "C:\\__clang_tmp\\___clang_inmemory_preamble___";
48 #warning "Unknown platform. Defaulting to UNIX-style paths for in-memory PCHs"
49 return "/__clang_tmp/___clang_inmemory_preamble___";
53 IntrusiveRefCntPtr
<llvm::vfs::FileSystem
>
54 createVFSOverlayForPreamblePCH(StringRef PCHFilename
,
55 std::unique_ptr
<llvm::MemoryBuffer
> PCHBuffer
,
56 IntrusiveRefCntPtr
<llvm::vfs::FileSystem
> VFS
) {
57 // We want only the PCH file from the real filesystem to be available,
58 // so we create an in-memory VFS with just that and overlay it on top.
59 IntrusiveRefCntPtr
<llvm::vfs::InMemoryFileSystem
> PCHFS(
60 new llvm::vfs::InMemoryFileSystem());
61 PCHFS
->addFile(PCHFilename
, 0, std::move(PCHBuffer
));
62 IntrusiveRefCntPtr
<llvm::vfs::OverlayFileSystem
> Overlay(
63 new llvm::vfs::OverlayFileSystem(VFS
));
64 Overlay
->pushOverlay(PCHFS
);
68 class PreambleDependencyCollector
: public DependencyCollector
{
70 // We want to collect all dependencies for correctness. Avoiding the real
71 // system dependencies (e.g. stl from /usr/lib) would probably be a good idea,
72 // but there is no way to distinguish between those and the ones that can be
73 // spuriously added by '-isystem' (e.g. to suppress warnings from those
75 bool needSystemDependencies() override
{ return true; }
78 // Collects files whose existence would invalidate the preamble.
79 // Collecting *all* of these would make validating it too slow though, so we
80 // just find all the candidates for 'file not found' diagnostics.
82 // A caveat that may be significant for generated files: we'll omit files under
83 // search path entries whose roots don't exist when the preamble is built.
84 // These are pruned by InitHeaderSearch and so we don't see the search path.
85 // It would be nice to include them but we don't want to duplicate all the rest
86 // of the InitHeaderSearch logic to reconstruct them.
87 class MissingFileCollector
: public PPCallbacks
{
88 llvm::StringSet
<> &Out
;
89 const HeaderSearch
&Search
;
90 const SourceManager
&SM
;
93 MissingFileCollector(llvm::StringSet
<> &Out
, const HeaderSearch
&Search
,
94 const SourceManager
&SM
)
95 : Out(Out
), Search(Search
), SM(SM
) {}
97 void InclusionDirective(SourceLocation HashLoc
, const Token
&IncludeTok
,
98 StringRef FileName
, bool IsAngled
,
99 CharSourceRange FilenameRange
,
100 OptionalFileEntryRef File
, StringRef SearchPath
,
101 StringRef RelativePath
, const Module
*Imported
,
102 SrcMgr::CharacteristicKind FileType
) override
{
103 // File is std::nullopt if it wasn't found.
104 // (We have some false negatives if PP recovered e.g. <foo> -> "foo")
108 // If it's a rare absolute include, we know the full path already.
109 if (llvm::sys::path::is_absolute(FileName
)) {
110 Out
.insert(FileName
);
114 // Reconstruct the filenames that would satisfy this directive...
115 llvm::SmallString
<256> Buf
;
116 auto NotFoundRelativeTo
= [&](DirectoryEntryRef DE
) {
118 llvm::sys::path::append(Buf
, FileName
);
119 llvm::sys::path::remove_dots(Buf
, /*remove_dot_dot=*/true);
122 // ...relative to the including file.
124 if (OptionalFileEntryRef IncludingFile
=
125 SM
.getFileEntryRefForID(SM
.getFileID(IncludeTok
.getLocation())))
126 if (IncludingFile
->getDir())
127 NotFoundRelativeTo(IncludingFile
->getDir());
129 // ...relative to the search paths.
130 for (const auto &Dir
: llvm::make_range(
131 IsAngled
? Search
.angled_dir_begin() : Search
.search_dir_begin(),
132 Search
.search_dir_end())) {
133 // No support for frameworks or header maps yet.
134 if (Dir
.isNormalDir())
135 NotFoundRelativeTo(*Dir
.getDirRef());
140 /// Keeps a track of files to be deleted in destructor.
141 class TemporaryFiles
{
143 // A static instance to be used by all clients.
144 static TemporaryFiles
&getInstance();
147 // Disallow constructing the class directly.
148 TemporaryFiles() = default;
150 TemporaryFiles(const TemporaryFiles
&) = delete;
155 /// Adds \p File to a set of tracked files.
156 void addFile(StringRef File
);
158 /// Remove \p File from disk and from the set of tracked files.
159 void removeFile(StringRef File
);
163 llvm::StringSet
<> Files
;
166 TemporaryFiles
&TemporaryFiles::getInstance() {
167 static TemporaryFiles Instance
;
171 TemporaryFiles::~TemporaryFiles() {
172 std::lock_guard
<std::mutex
> Guard(Mutex
);
173 for (const auto &File
: Files
)
174 llvm::sys::fs::remove(File
.getKey());
177 void TemporaryFiles::addFile(StringRef File
) {
178 std::lock_guard
<std::mutex
> Guard(Mutex
);
179 auto IsInserted
= Files
.insert(File
).second
;
181 assert(IsInserted
&& "File has already been added");
184 void TemporaryFiles::removeFile(StringRef File
) {
185 std::lock_guard
<std::mutex
> Guard(Mutex
);
186 auto WasPresent
= Files
.erase(File
);
188 assert(WasPresent
&& "File was not tracked");
189 llvm::sys::fs::remove(File
);
192 // A temp file that would be deleted on destructor call. If destructor is not
193 // called for any reason, the file will be deleted at static objects'
195 // An assertion will fire if two TempPCHFiles are created with the same name,
196 // so it's not intended to be used outside preamble-handling.
199 // A main method used to construct TempPCHFile.
200 static std::unique_ptr
<TempPCHFile
> create(StringRef StoragePath
) {
201 // FIXME: This is a hack so that we can override the preamble file during
202 // crash-recovery testing, which is the only case where the preamble files
203 // are not necessarily cleaned up.
204 if (const char *TmpFile
= ::getenv("CINDEXTEST_PREAMBLE_FILE"))
205 return std::unique_ptr
<TempPCHFile
>(new TempPCHFile(TmpFile
));
207 llvm::SmallString
<128> File
;
208 // Using the versions of createTemporaryFile() and
209 // createUniqueFile() with a file descriptor guarantees
210 // that we would never get a race condition in a multi-threaded setting
211 // (i.e., multiple threads getting the same temporary path).
214 if (StoragePath
.empty())
215 EC
= llvm::sys::fs::createTemporaryFile("preamble", "pch", FD
, File
);
217 llvm::SmallString
<128> TempPath
= StoragePath
;
218 // Use the same filename model as fs::createTemporaryFile().
219 llvm::sys::path::append(TempPath
, "preamble-%%%%%%.pch");
220 namespace fs
= llvm::sys::fs
;
221 // Use the same owner-only file permissions as fs::createTemporaryFile().
222 EC
= fs::createUniqueFile(TempPath
, FD
, File
, fs::OF_None
,
223 fs::owner_read
| fs::owner_write
);
227 // We only needed to make sure the file exists, close the file right away.
228 llvm::sys::Process::SafelyCloseFileDescriptor(FD
);
229 return std::unique_ptr
<TempPCHFile
>(new TempPCHFile(File
.str().str()));
232 TempPCHFile
&operator=(const TempPCHFile
&) = delete;
233 TempPCHFile(const TempPCHFile
&) = delete;
234 ~TempPCHFile() { TemporaryFiles::getInstance().removeFile(FilePath
); };
236 /// A path where temporary file is stored.
237 llvm::StringRef
getFilePath() const { return FilePath
; };
240 TempPCHFile(std::string FilePath
) : FilePath(std::move(FilePath
)) {
241 TemporaryFiles::getInstance().addFile(this->FilePath
);
244 std::string FilePath
;
247 class PrecompilePreambleAction
: public ASTFrontendAction
{
249 PrecompilePreambleAction(std::shared_ptr
<PCHBuffer
> Buffer
, bool WritePCHFile
,
250 PreambleCallbacks
&Callbacks
)
251 : Buffer(std::move(Buffer
)), WritePCHFile(WritePCHFile
),
252 Callbacks(Callbacks
) {}
254 std::unique_ptr
<ASTConsumer
> CreateASTConsumer(CompilerInstance
&CI
,
255 StringRef InFile
) override
;
257 bool hasEmittedPreamblePCH() const { return HasEmittedPreamblePCH
; }
259 void setEmittedPreamblePCH(ASTWriter
&Writer
) {
261 *FileOS
<< Buffer
->Data
;
262 // Make sure it hits disk now.
266 this->HasEmittedPreamblePCH
= true;
267 Callbacks
.AfterPCHEmitted(Writer
);
270 bool BeginSourceFileAction(CompilerInstance
&CI
) override
{
271 assert(CI
.getLangOpts().CompilingPCH
);
272 return ASTFrontendAction::BeginSourceFileAction(CI
);
275 bool shouldEraseOutputFiles() override
{ return !hasEmittedPreamblePCH(); }
276 bool hasCodeCompletionSupport() const override
{ return false; }
277 bool hasASTFileSupport() const override
{ return false; }
278 TranslationUnitKind
getTranslationUnitKind() override
{ return TU_Prefix
; }
281 friend class PrecompilePreambleConsumer
;
283 bool HasEmittedPreamblePCH
= false;
284 std::shared_ptr
<PCHBuffer
> Buffer
;
285 bool WritePCHFile
; // otherwise the PCH is written into the PCHBuffer only.
286 std::unique_ptr
<llvm::raw_pwrite_stream
> FileOS
; // null if in-memory
287 PreambleCallbacks
&Callbacks
;
290 class PrecompilePreambleConsumer
: public PCHGenerator
{
292 PrecompilePreambleConsumer(PrecompilePreambleAction
&Action
,
293 const Preprocessor
&PP
,
294 InMemoryModuleCache
&ModuleCache
,
296 std::shared_ptr
<PCHBuffer
> Buffer
)
297 : PCHGenerator(PP
, ModuleCache
, "", isysroot
, std::move(Buffer
),
298 ArrayRef
<std::shared_ptr
<ModuleFileExtension
>>(),
299 /*AllowASTWithErrors=*/true),
302 bool HandleTopLevelDecl(DeclGroupRef DG
) override
{
303 Action
.Callbacks
.HandleTopLevelDecl(DG
);
307 void HandleTranslationUnit(ASTContext
&Ctx
) override
{
308 PCHGenerator::HandleTranslationUnit(Ctx
);
309 if (!hasEmittedPCH())
311 Action
.setEmittedPreamblePCH(getWriter());
314 bool shouldSkipFunctionBody(Decl
*D
) override
{
315 return Action
.Callbacks
.shouldSkipFunctionBody(D
);
319 PrecompilePreambleAction
&Action
;
322 std::unique_ptr
<ASTConsumer
>
323 PrecompilePreambleAction::CreateASTConsumer(CompilerInstance
&CI
,
326 if (!GeneratePCHAction::ComputeASTConsumerArguments(CI
, Sysroot
))
330 std::string OutputFile
; // unused
331 FileOS
= GeneratePCHAction::CreateOutputFile(CI
, InFile
, OutputFile
);
336 if (!CI
.getFrontendOpts().RelocatablePCH
)
339 return std::make_unique
<PrecompilePreambleConsumer
>(
340 *this, CI
.getPreprocessor(), CI
.getModuleCache(), Sysroot
, Buffer
);
343 template <class T
> bool moveOnNoError(llvm::ErrorOr
<T
> Val
, T
&Output
) {
346 Output
= std::move(*Val
);
352 PreambleBounds
clang::ComputePreambleBounds(const LangOptions
&LangOpts
,
353 const llvm::MemoryBufferRef
&Buffer
,
355 return Lexer::ComputePreamble(Buffer
.getBuffer(), LangOpts
, MaxLines
);
358 class PrecompiledPreamble::PCHStorage
{
360 static std::unique_ptr
<PCHStorage
> file(std::unique_ptr
<TempPCHFile
> File
) {
362 std::unique_ptr
<PCHStorage
> S(new PCHStorage());
363 S
->File
= std::move(File
);
366 static std::unique_ptr
<PCHStorage
> inMemory(std::shared_ptr
<PCHBuffer
> Buf
) {
367 std::unique_ptr
<PCHStorage
> S(new PCHStorage());
368 S
->Memory
= std::move(Buf
);
372 enum class Kind
{ InMemory
, TempFile
};
373 Kind
getKind() const {
375 return Kind::InMemory
;
377 return Kind::TempFile
;
378 llvm_unreachable("Neither Memory nor File?");
380 llvm::StringRef
filePath() const {
381 assert(getKind() == Kind::TempFile
);
382 return File
->getFilePath();
384 llvm::StringRef
memoryContents() const {
385 assert(getKind() == Kind::InMemory
);
386 return StringRef(Memory
->Data
.data(), Memory
->Data
.size());
389 // Shrink in-memory buffers to fit.
390 // This incurs a copy, but preambles tend to be long-lived.
391 // Only safe to call once nothing can alias the buffer.
395 Memory
->Data
= decltype(Memory
->Data
)(Memory
->Data
);
399 PCHStorage() = default;
400 PCHStorage(const PCHStorage
&) = delete;
401 PCHStorage
&operator=(const PCHStorage
&) = delete;
403 std::shared_ptr
<PCHBuffer
> Memory
;
404 std::unique_ptr
<TempPCHFile
> File
;
407 PrecompiledPreamble::~PrecompiledPreamble() = default;
408 PrecompiledPreamble::PrecompiledPreamble(PrecompiledPreamble
&&) = default;
409 PrecompiledPreamble
&
410 PrecompiledPreamble::operator=(PrecompiledPreamble
&&) = default;
412 llvm::ErrorOr
<PrecompiledPreamble
> PrecompiledPreamble::Build(
413 const CompilerInvocation
&Invocation
,
414 const llvm::MemoryBuffer
*MainFileBuffer
, PreambleBounds Bounds
,
415 DiagnosticsEngine
&Diagnostics
,
416 IntrusiveRefCntPtr
<llvm::vfs::FileSystem
> VFS
,
417 std::shared_ptr
<PCHContainerOperations
> PCHContainerOps
, bool StoreInMemory
,
418 StringRef StoragePath
, PreambleCallbacks
&Callbacks
) {
419 assert(VFS
&& "VFS is null");
421 auto PreambleInvocation
= std::make_shared
<CompilerInvocation
>(Invocation
);
422 FrontendOptions
&FrontendOpts
= PreambleInvocation
->getFrontendOpts();
423 PreprocessorOptions
&PreprocessorOpts
=
424 PreambleInvocation
->getPreprocessorOpts();
426 std::shared_ptr
<PCHBuffer
> Buffer
= std::make_shared
<PCHBuffer
>();
427 std::unique_ptr
<PCHStorage
> Storage
;
429 Storage
= PCHStorage::inMemory(Buffer
);
431 // Create a temporary file for the precompiled preamble. In rare
432 // circumstances, this can fail.
433 std::unique_ptr
<TempPCHFile
> PreamblePCHFile
=
434 TempPCHFile::create(StoragePath
);
435 if (!PreamblePCHFile
)
436 return BuildPreambleError::CouldntCreateTempFile
;
437 Storage
= PCHStorage::file(std::move(PreamblePCHFile
));
440 // Save the preamble text for later; we'll need to compare against it for
441 // subsequent reparses.
442 std::vector
<char> PreambleBytes(MainFileBuffer
->getBufferStart(),
443 MainFileBuffer
->getBufferStart() +
445 bool PreambleEndsAtStartOfLine
= Bounds
.PreambleEndsAtStartOfLine
;
447 // Tell the compiler invocation to generate a temporary precompiled header.
448 FrontendOpts
.ProgramAction
= frontend::GeneratePCH
;
449 FrontendOpts
.OutputFile
= std::string(
450 StoreInMemory
? getInMemoryPreamblePath() : Storage
->filePath());
451 PreprocessorOpts
.PrecompiledPreambleBytes
.first
= 0;
452 PreprocessorOpts
.PrecompiledPreambleBytes
.second
= false;
453 // Inform preprocessor to record conditional stack when building the preamble.
454 PreprocessorOpts
.GeneratePreamble
= true;
456 // Create the compiler instance to use for building the precompiled preamble.
457 std::unique_ptr
<CompilerInstance
> Clang(
458 new CompilerInstance(std::move(PCHContainerOps
)));
460 // Recover resources if we crash before exiting this method.
461 llvm::CrashRecoveryContextCleanupRegistrar
<CompilerInstance
> CICleanup(
464 Clang
->setInvocation(std::move(PreambleInvocation
));
465 Clang
->setDiagnostics(&Diagnostics
);
467 // Create the target instance.
468 if (!Clang
->createTarget())
469 return BuildPreambleError::CouldntCreateTargetInfo
;
471 if (Clang
->getFrontendOpts().Inputs
.size() != 1 ||
472 Clang
->getFrontendOpts().Inputs
[0].getKind().getFormat() !=
474 Clang
->getFrontendOpts().Inputs
[0].getKind().getLanguage() ==
476 return BuildPreambleError::BadInputs
;
479 // Clear out old caches and data.
481 ProcessWarningOptions(Diagnostics
, Clang
->getDiagnosticOpts());
484 createVFSFromCompilerInvocation(Clang
->getInvocation(), Diagnostics
, VFS
);
486 // Create a file manager object to provide access to and cache the filesystem.
487 Clang
->setFileManager(new FileManager(Clang
->getFileSystemOpts(), VFS
));
489 // Create the source manager.
490 Clang
->setSourceManager(
491 new SourceManager(Diagnostics
, Clang
->getFileManager()));
493 auto PreambleDepCollector
= std::make_shared
<PreambleDependencyCollector
>();
494 Clang
->addDependencyCollector(PreambleDepCollector
);
496 Clang
->getLangOpts().CompilingPCH
= true;
498 // Remap the main source file to the preamble buffer.
499 StringRef MainFilePath
= FrontendOpts
.Inputs
[0].getFile();
500 auto PreambleInputBuffer
= llvm::MemoryBuffer::getMemBufferCopy(
501 MainFileBuffer
->getBuffer().slice(0, Bounds
.Size
), MainFilePath
);
502 if (PreprocessorOpts
.RetainRemappedFileBuffers
) {
503 // MainFileBuffer will be deleted by unique_ptr after leaving the method.
504 PreprocessorOpts
.addRemappedFile(MainFilePath
, PreambleInputBuffer
.get());
506 // In that case, remapped buffer will be deleted by CompilerInstance on
507 // BeginSourceFile, so we call release() to avoid double deletion.
508 PreprocessorOpts
.addRemappedFile(MainFilePath
,
509 PreambleInputBuffer
.release());
512 auto Act
= std::make_unique
<PrecompilePreambleAction
>(
514 /*WritePCHFile=*/Storage
->getKind() == PCHStorage::Kind::TempFile
,
516 if (!Act
->BeginSourceFile(*Clang
.get(), Clang
->getFrontendOpts().Inputs
[0]))
517 return BuildPreambleError::BeginSourceFileFailed
;
519 // Performed after BeginSourceFile to ensure Clang->Preprocessor can be
520 // referenced in the callback.
521 Callbacks
.BeforeExecute(*Clang
);
523 std::unique_ptr
<PPCallbacks
> DelegatedPPCallbacks
=
524 Callbacks
.createPPCallbacks();
525 if (DelegatedPPCallbacks
)
526 Clang
->getPreprocessor().addPPCallbacks(std::move(DelegatedPPCallbacks
));
527 if (auto CommentHandler
= Callbacks
.getCommentHandler())
528 Clang
->getPreprocessor().addCommentHandler(CommentHandler
);
529 llvm::StringSet
<> MissingFiles
;
530 Clang
->getPreprocessor().addPPCallbacks(
531 std::make_unique
<MissingFileCollector
>(
532 MissingFiles
, Clang
->getPreprocessor().getHeaderSearchInfo(),
533 Clang
->getSourceManager()));
535 if (llvm::Error Err
= Act
->Execute())
536 return errorToErrorCode(std::move(Err
));
538 // Run the callbacks.
539 Callbacks
.AfterExecute(*Clang
);
541 Act
->EndSourceFile();
543 if (!Act
->hasEmittedPreamblePCH())
544 return BuildPreambleError::CouldntEmitPCH
;
545 Act
.reset(); // Frees the PCH buffer, unless Storage keeps it in memory.
547 // Keep track of all of the files that the source manager knows about,
548 // so we can verify whether they have changed or not.
549 llvm::StringMap
<PrecompiledPreamble::PreambleFileHash
> FilesInPreamble
;
551 SourceManager
&SourceMgr
= Clang
->getSourceManager();
552 for (auto &Filename
: PreambleDepCollector
->getDependencies()) {
553 auto MaybeFile
= Clang
->getFileManager().getOptionalFileRef(Filename
);
555 MaybeFile
== SourceMgr
.getFileEntryRefForID(SourceMgr
.getMainFileID()))
557 auto File
= *MaybeFile
;
558 if (time_t ModTime
= File
.getModificationTime()) {
559 FilesInPreamble
[File
.getName()] =
560 PrecompiledPreamble::PreambleFileHash::createForFile(File
.getSize(),
563 llvm::MemoryBufferRef Buffer
=
564 SourceMgr
.getMemoryBufferForFileOrFake(File
);
565 FilesInPreamble
[File
.getName()] =
566 PrecompiledPreamble::PreambleFileHash::createForMemoryBuffer(Buffer
);
570 // Shrinking the storage requires extra temporary memory.
571 // Destroying clang first reduces peak memory usage.
572 CICleanup
.unregister();
575 return PrecompiledPreamble(
576 std::move(Storage
), std::move(PreambleBytes
), PreambleEndsAtStartOfLine
,
577 std::move(FilesInPreamble
), std::move(MissingFiles
));
580 PreambleBounds
PrecompiledPreamble::getBounds() const {
581 return PreambleBounds(PreambleBytes
.size(), PreambleEndsAtStartOfLine
);
584 std::size_t PrecompiledPreamble::getSize() const {
585 switch (Storage
->getKind()) {
586 case PCHStorage::Kind::InMemory
:
587 return Storage
->memoryContents().size();
588 case PCHStorage::Kind::TempFile
: {
590 if (llvm::sys::fs::file_size(Storage
->filePath(), Result
))
593 assert(Result
<= std::numeric_limits
<std::size_t>::max() &&
594 "file size did not fit into size_t");
598 llvm_unreachable("Unhandled storage kind");
601 bool PrecompiledPreamble::CanReuse(const CompilerInvocation
&Invocation
,
602 const llvm::MemoryBufferRef
&MainFileBuffer
,
603 PreambleBounds Bounds
,
604 llvm::vfs::FileSystem
&VFS
) const {
607 Bounds
.Size
<= MainFileBuffer
.getBufferSize() &&
608 "Buffer is too large. Bounds were calculated from a different buffer?");
610 auto PreambleInvocation
= std::make_shared
<CompilerInvocation
>(Invocation
);
611 PreprocessorOptions
&PreprocessorOpts
=
612 PreambleInvocation
->getPreprocessorOpts();
614 // We've previously computed a preamble. Check whether we have the same
615 // preamble now that we did before, and that there's enough space in
616 // the main-file buffer within the precompiled preamble to fit the
618 if (PreambleBytes
.size() != Bounds
.Size
||
619 PreambleEndsAtStartOfLine
!= Bounds
.PreambleEndsAtStartOfLine
||
620 !std::equal(PreambleBytes
.begin(), PreambleBytes
.end(),
621 MainFileBuffer
.getBuffer().begin()))
623 // The preamble has not changed. We may be able to re-use the precompiled
626 // Check that none of the files used by the preamble have changed.
627 // First, make a record of those files that have been overridden via
628 // remapping or unsaved_files.
629 std::map
<llvm::sys::fs::UniqueID
, PreambleFileHash
> OverriddenFiles
;
630 llvm::StringSet
<> OverriddenAbsPaths
; // Either by buffers or files.
631 for (const auto &R
: PreprocessorOpts
.RemappedFiles
) {
632 llvm::vfs::Status Status
;
633 if (!moveOnNoError(VFS
.status(R
.second
), Status
)) {
634 // If we can't stat the file we're remapping to, assume that something
635 // horrible happened.
638 // If a mapped file was previously missing, then it has changed.
639 llvm::SmallString
<128> MappedPath(R
.first
);
640 if (!VFS
.makeAbsolute(MappedPath
))
641 OverriddenAbsPaths
.insert(MappedPath
);
643 OverriddenFiles
[Status
.getUniqueID()] = PreambleFileHash::createForFile(
644 Status
.getSize(), llvm::sys::toTimeT(Status
.getLastModificationTime()));
647 // OverridenFileBuffers tracks only the files not found in VFS.
648 llvm::StringMap
<PreambleFileHash
> OverridenFileBuffers
;
649 for (const auto &RB
: PreprocessorOpts
.RemappedFileBuffers
) {
650 const PrecompiledPreamble::PreambleFileHash PreambleHash
=
651 PreambleFileHash::createForMemoryBuffer(RB
.second
->getMemBufferRef());
652 llvm::vfs::Status Status
;
653 if (moveOnNoError(VFS
.status(RB
.first
), Status
))
654 OverriddenFiles
[Status
.getUniqueID()] = PreambleHash
;
656 OverridenFileBuffers
[RB
.first
] = PreambleHash
;
658 llvm::SmallString
<128> MappedPath(RB
.first
);
659 if (!VFS
.makeAbsolute(MappedPath
))
660 OverriddenAbsPaths
.insert(MappedPath
);
663 // Check whether anything has changed.
664 for (const auto &F
: FilesInPreamble
) {
665 auto OverridenFileBuffer
= OverridenFileBuffers
.find(F
.first());
666 if (OverridenFileBuffer
!= OverridenFileBuffers
.end()) {
667 // The file's buffer was remapped and the file was not found in VFS.
668 // Check whether it matches up with the previous mapping.
669 if (OverridenFileBuffer
->second
!= F
.second
)
674 llvm::vfs::Status Status
;
675 if (!moveOnNoError(VFS
.status(F
.first()), Status
)) {
676 // If the file's buffer is not remapped and we can't stat it,
677 // assume that something horrible happened.
681 std::map
<llvm::sys::fs::UniqueID
, PreambleFileHash
>::iterator Overridden
=
682 OverriddenFiles
.find(Status
.getUniqueID());
683 if (Overridden
!= OverriddenFiles
.end()) {
684 // This file was remapped; check whether the newly-mapped file
685 // matches up with the previous mapping.
686 if (Overridden
->second
!= F
.second
)
691 // Neither the file's buffer nor the file itself was remapped;
692 // check whether it has changed on disk.
693 if (Status
.getSize() != uint64_t(F
.second
.Size
) ||
694 llvm::sys::toTimeT(Status
.getLastModificationTime()) !=
698 for (const auto &F
: MissingFiles
) {
699 // A missing file may be "provided" by an override buffer or file.
700 if (OverriddenAbsPaths
.count(F
.getKey()))
702 // If a file previously recorded as missing exists as a regular file, then
703 // consider the preamble out-of-date.
704 if (auto Status
= VFS
.status(F
.getKey())) {
705 if (Status
->isRegularFile())
712 void PrecompiledPreamble::AddImplicitPreamble(
713 CompilerInvocation
&CI
, IntrusiveRefCntPtr
<llvm::vfs::FileSystem
> &VFS
,
714 llvm::MemoryBuffer
*MainFileBuffer
) const {
715 PreambleBounds
Bounds(PreambleBytes
.size(), PreambleEndsAtStartOfLine
);
716 configurePreamble(Bounds
, CI
, VFS
, MainFileBuffer
);
719 void PrecompiledPreamble::OverridePreamble(
720 CompilerInvocation
&CI
, IntrusiveRefCntPtr
<llvm::vfs::FileSystem
> &VFS
,
721 llvm::MemoryBuffer
*MainFileBuffer
) const {
722 auto Bounds
= ComputePreambleBounds(CI
.getLangOpts(), *MainFileBuffer
, 0);
723 configurePreamble(Bounds
, CI
, VFS
, MainFileBuffer
);
726 PrecompiledPreamble::PrecompiledPreamble(
727 std::unique_ptr
<PCHStorage
> Storage
, std::vector
<char> PreambleBytes
,
728 bool PreambleEndsAtStartOfLine
,
729 llvm::StringMap
<PreambleFileHash
> FilesInPreamble
,
730 llvm::StringSet
<> MissingFiles
)
731 : Storage(std::move(Storage
)), FilesInPreamble(std::move(FilesInPreamble
)),
732 MissingFiles(std::move(MissingFiles
)),
733 PreambleBytes(std::move(PreambleBytes
)),
734 PreambleEndsAtStartOfLine(PreambleEndsAtStartOfLine
) {
735 assert(this->Storage
!= nullptr);
738 PrecompiledPreamble::PreambleFileHash
739 PrecompiledPreamble::PreambleFileHash::createForFile(off_t Size
,
741 PreambleFileHash Result
;
743 Result
.ModTime
= ModTime
;
748 PrecompiledPreamble::PreambleFileHash
749 PrecompiledPreamble::PreambleFileHash::createForMemoryBuffer(
750 const llvm::MemoryBufferRef
&Buffer
) {
751 PreambleFileHash Result
;
752 Result
.Size
= Buffer
.getBufferSize();
756 MD5Ctx
.update(Buffer
.getBuffer().data());
757 MD5Ctx
.final(Result
.MD5
);
762 void PrecompiledPreamble::configurePreamble(
763 PreambleBounds Bounds
, CompilerInvocation
&CI
,
764 IntrusiveRefCntPtr
<llvm::vfs::FileSystem
> &VFS
,
765 llvm::MemoryBuffer
*MainFileBuffer
) const {
768 auto &PreprocessorOpts
= CI
.getPreprocessorOpts();
770 // Remap main file to point to MainFileBuffer.
771 auto MainFilePath
= CI
.getFrontendOpts().Inputs
[0].getFile();
772 PreprocessorOpts
.addRemappedFile(MainFilePath
, MainFileBuffer
);
774 // Configure ImpicitPCHInclude.
775 PreprocessorOpts
.PrecompiledPreambleBytes
.first
= Bounds
.Size
;
776 PreprocessorOpts
.PrecompiledPreambleBytes
.second
=
777 Bounds
.PreambleEndsAtStartOfLine
;
778 PreprocessorOpts
.DisablePCHOrModuleValidation
=
779 DisableValidationForModuleKind::PCH
;
781 // Don't bother generating the long version of the predefines buffer.
782 // The preamble is going to overwrite it anyway.
783 PreprocessorOpts
.UsePredefines
= false;
785 setupPreambleStorage(*Storage
, PreprocessorOpts
, VFS
);
788 void PrecompiledPreamble::setupPreambleStorage(
789 const PCHStorage
&Storage
, PreprocessorOptions
&PreprocessorOpts
,
790 IntrusiveRefCntPtr
<llvm::vfs::FileSystem
> &VFS
) {
791 if (Storage
.getKind() == PCHStorage::Kind::TempFile
) {
792 llvm::StringRef PCHPath
= Storage
.filePath();
793 PreprocessorOpts
.ImplicitPCHInclude
= PCHPath
.str();
795 // Make sure we can access the PCH file even if we're using a VFS
796 IntrusiveRefCntPtr
<llvm::vfs::FileSystem
> RealFS
=
797 llvm::vfs::getRealFileSystem();
798 if (VFS
== RealFS
|| VFS
->exists(PCHPath
))
800 auto Buf
= RealFS
->getBufferForFile(PCHPath
);
802 // We can't read the file even from RealFS, this is clearly an error,
803 // but we'll just leave the current VFS as is and let clang's code
804 // figure out what to do with missing PCH.
808 // We have a slight inconsistency here -- we're using the VFS to
809 // read files, but the PCH was generated in the real file system.
810 VFS
= createVFSOverlayForPreamblePCH(PCHPath
, std::move(*Buf
), VFS
);
812 assert(Storage
.getKind() == PCHStorage::Kind::InMemory
);
813 // For in-memory preamble, we have to provide a VFS overlay that makes it
815 StringRef PCHPath
= getInMemoryPreamblePath();
816 PreprocessorOpts
.ImplicitPCHInclude
= std::string(PCHPath
);
818 auto Buf
= llvm::MemoryBuffer::getMemBuffer(
819 Storage
.memoryContents(), PCHPath
, /*RequiresNullTerminator=*/false);
820 VFS
= createVFSOverlayForPreamblePCH(PCHPath
, std::move(Buf
), VFS
);
824 void PreambleCallbacks::BeforeExecute(CompilerInstance
&CI
) {}
825 void PreambleCallbacks::AfterExecute(CompilerInstance
&CI
) {}
826 void PreambleCallbacks::AfterPCHEmitted(ASTWriter
&Writer
) {}
827 void PreambleCallbacks::HandleTopLevelDecl(DeclGroupRef DG
) {}
828 std::unique_ptr
<PPCallbacks
> PreambleCallbacks::createPPCallbacks() {
831 CommentHandler
*PreambleCallbacks::getCommentHandler() { return nullptr; }
833 static llvm::ManagedStatic
<BuildPreambleErrorCategory
> BuildPreambleErrCategory
;
835 std::error_code
clang::make_error_code(BuildPreambleError Error
) {
836 return std::error_code(static_cast<int>(Error
), *BuildPreambleErrCategory
);
839 const char *BuildPreambleErrorCategory::name() const noexcept
{
840 return "build-preamble.error";
843 std::string
BuildPreambleErrorCategory::message(int condition
) const {
844 switch (static_cast<BuildPreambleError
>(condition
)) {
845 case BuildPreambleError::CouldntCreateTempFile
:
846 return "Could not create temporary file for PCH";
847 case BuildPreambleError::CouldntCreateTargetInfo
:
848 return "CreateTargetInfo() return null";
849 case BuildPreambleError::BeginSourceFileFailed
:
850 return "BeginSourceFile() return an error";
851 case BuildPreambleError::CouldntEmitPCH
:
852 return "Could not emit PCH";
853 case BuildPreambleError::BadInputs
:
854 return "Command line arguments must contain exactly one source file";
856 llvm_unreachable("unexpected BuildPreambleError");