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/ManagedStatic.h"
32 #include "llvm/Support/Path.h"
33 #include "llvm/Support/Process.h"
34 #include "llvm/Support/VirtualFileSystem.h"
39 using namespace clang
;
43 StringRef
getInMemoryPreamblePath() {
44 #if defined(LLVM_ON_UNIX)
45 return "/__clang_tmp/___clang_inmemory_preamble___";
47 return "C:\\__clang_tmp\\___clang_inmemory_preamble___";
49 #warning "Unknown platform. Defaulting to UNIX-style paths for in-memory PCHs"
50 return "/__clang_tmp/___clang_inmemory_preamble___";
54 IntrusiveRefCntPtr
<llvm::vfs::FileSystem
>
55 createVFSOverlayForPreamblePCH(StringRef PCHFilename
,
56 std::unique_ptr
<llvm::MemoryBuffer
> PCHBuffer
,
57 IntrusiveRefCntPtr
<llvm::vfs::FileSystem
> VFS
) {
58 // We want only the PCH file from the real filesystem to be available,
59 // so we create an in-memory VFS with just that and overlay it on top.
60 IntrusiveRefCntPtr
<llvm::vfs::InMemoryFileSystem
> PCHFS(
61 new llvm::vfs::InMemoryFileSystem());
62 PCHFS
->addFile(PCHFilename
, 0, std::move(PCHBuffer
));
63 IntrusiveRefCntPtr
<llvm::vfs::OverlayFileSystem
> Overlay(
64 new llvm::vfs::OverlayFileSystem(VFS
));
65 Overlay
->pushOverlay(PCHFS
);
69 class PreambleDependencyCollector
: public DependencyCollector
{
71 // We want to collect all dependencies for correctness. Avoiding the real
72 // system dependencies (e.g. stl from /usr/lib) would probably be a good idea,
73 // but there is no way to distinguish between those and the ones that can be
74 // spuriously added by '-isystem' (e.g. to suppress warnings from those
76 bool needSystemDependencies() override
{ return true; }
79 // Collects files whose existence would invalidate the preamble.
80 // Collecting *all* of these would make validating it too slow though, so we
81 // just find all the candidates for 'file not found' diagnostics.
83 // A caveat that may be significant for generated files: we'll omit files under
84 // search path entries whose roots don't exist when the preamble is built.
85 // These are pruned by InitHeaderSearch and so we don't see the search path.
86 // It would be nice to include them but we don't want to duplicate all the rest
87 // of the InitHeaderSearch logic to reconstruct them.
88 class MissingFileCollector
: public PPCallbacks
{
89 llvm::StringSet
<> &Out
;
90 const HeaderSearch
&Search
;
91 const SourceManager
&SM
;
94 MissingFileCollector(llvm::StringSet
<> &Out
, const HeaderSearch
&Search
,
95 const SourceManager
&SM
)
96 : Out(Out
), Search(Search
), SM(SM
) {}
98 void InclusionDirective(SourceLocation HashLoc
, const Token
&IncludeTok
,
99 StringRef FileName
, bool IsAngled
,
100 CharSourceRange FilenameRange
,
101 OptionalFileEntryRef File
, StringRef SearchPath
,
102 StringRef RelativePath
, const Module
*SuggestedModule
,
104 SrcMgr::CharacteristicKind FileType
) override
{
105 // File is std::nullopt if it wasn't found.
106 // (We have some false negatives if PP recovered e.g. <foo> -> "foo")
110 // If it's a rare absolute include, we know the full path already.
111 if (llvm::sys::path::is_absolute(FileName
)) {
112 Out
.insert(FileName
);
116 // Reconstruct the filenames that would satisfy this directive...
117 llvm::SmallString
<256> Buf
;
118 auto NotFoundRelativeTo
= [&](DirectoryEntryRef DE
) {
120 llvm::sys::path::append(Buf
, FileName
);
121 llvm::sys::path::remove_dots(Buf
, /*remove_dot_dot=*/true);
124 // ...relative to the including file.
126 if (OptionalFileEntryRef IncludingFile
=
127 SM
.getFileEntryRefForID(SM
.getFileID(IncludeTok
.getLocation())))
128 if (IncludingFile
->getDir())
129 NotFoundRelativeTo(IncludingFile
->getDir());
131 // ...relative to the search paths.
132 for (const auto &Dir
: llvm::make_range(
133 IsAngled
? Search
.angled_dir_begin() : Search
.search_dir_begin(),
134 Search
.search_dir_end())) {
135 // No support for frameworks or header maps yet.
136 if (Dir
.isNormalDir())
137 NotFoundRelativeTo(*Dir
.getDirRef());
142 /// Keeps a track of files to be deleted in destructor.
143 class TemporaryFiles
{
145 // A static instance to be used by all clients.
146 static TemporaryFiles
&getInstance();
149 // Disallow constructing the class directly.
150 TemporaryFiles() = default;
152 TemporaryFiles(const TemporaryFiles
&) = delete;
157 /// Adds \p File to a set of tracked files.
158 void addFile(StringRef File
);
160 /// Remove \p File from disk and from the set of tracked files.
161 void removeFile(StringRef File
);
165 llvm::StringSet
<> Files
;
168 TemporaryFiles
&TemporaryFiles::getInstance() {
169 static TemporaryFiles Instance
;
173 TemporaryFiles::~TemporaryFiles() {
174 std::lock_guard
<std::mutex
> Guard(Mutex
);
175 for (const auto &File
: Files
)
176 llvm::sys::fs::remove(File
.getKey());
179 void TemporaryFiles::addFile(StringRef File
) {
180 std::lock_guard
<std::mutex
> Guard(Mutex
);
181 auto IsInserted
= Files
.insert(File
).second
;
183 assert(IsInserted
&& "File has already been added");
186 void TemporaryFiles::removeFile(StringRef File
) {
187 std::lock_guard
<std::mutex
> Guard(Mutex
);
188 auto WasPresent
= Files
.erase(File
);
190 assert(WasPresent
&& "File was not tracked");
191 llvm::sys::fs::remove(File
);
194 // A temp file that would be deleted on destructor call. If destructor is not
195 // called for any reason, the file will be deleted at static objects'
197 // An assertion will fire if two TempPCHFiles are created with the same name,
198 // so it's not intended to be used outside preamble-handling.
201 // A main method used to construct TempPCHFile.
202 static std::unique_ptr
<TempPCHFile
> create(StringRef StoragePath
) {
203 // FIXME: This is a hack so that we can override the preamble file during
204 // crash-recovery testing, which is the only case where the preamble files
205 // are not necessarily cleaned up.
206 if (const char *TmpFile
= ::getenv("CINDEXTEST_PREAMBLE_FILE"))
207 return std::unique_ptr
<TempPCHFile
>(new TempPCHFile(TmpFile
));
209 llvm::SmallString
<128> File
;
210 // Using the versions of createTemporaryFile() and
211 // createUniqueFile() with a file descriptor guarantees
212 // that we would never get a race condition in a multi-threaded setting
213 // (i.e., multiple threads getting the same temporary path).
216 if (StoragePath
.empty())
217 EC
= llvm::sys::fs::createTemporaryFile("preamble", "pch", FD
, File
);
219 llvm::SmallString
<128> TempPath
= StoragePath
;
220 // Use the same filename model as fs::createTemporaryFile().
221 llvm::sys::path::append(TempPath
, "preamble-%%%%%%.pch");
222 namespace fs
= llvm::sys::fs
;
223 // Use the same owner-only file permissions as fs::createTemporaryFile().
224 EC
= fs::createUniqueFile(TempPath
, FD
, File
, fs::OF_None
,
225 fs::owner_read
| fs::owner_write
);
229 // We only needed to make sure the file exists, close the file right away.
230 llvm::sys::Process::SafelyCloseFileDescriptor(FD
);
231 return std::unique_ptr
<TempPCHFile
>(new TempPCHFile(File
.str().str()));
234 TempPCHFile
&operator=(const TempPCHFile
&) = delete;
235 TempPCHFile(const TempPCHFile
&) = delete;
236 ~TempPCHFile() { TemporaryFiles::getInstance().removeFile(FilePath
); };
238 /// A path where temporary file is stored.
239 llvm::StringRef
getFilePath() const { return FilePath
; };
242 TempPCHFile(std::string FilePath
) : FilePath(std::move(FilePath
)) {
243 TemporaryFiles::getInstance().addFile(this->FilePath
);
246 std::string FilePath
;
249 class PrecompilePreambleAction
: public ASTFrontendAction
{
251 PrecompilePreambleAction(std::shared_ptr
<PCHBuffer
> Buffer
, bool WritePCHFile
,
252 PreambleCallbacks
&Callbacks
)
253 : Buffer(std::move(Buffer
)), WritePCHFile(WritePCHFile
),
254 Callbacks(Callbacks
) {}
256 std::unique_ptr
<ASTConsumer
> CreateASTConsumer(CompilerInstance
&CI
,
257 StringRef InFile
) override
;
259 bool hasEmittedPreamblePCH() const { return HasEmittedPreamblePCH
; }
261 void setEmittedPreamblePCH(ASTWriter
&Writer
) {
263 *FileOS
<< Buffer
->Data
;
264 // Make sure it hits disk now.
268 this->HasEmittedPreamblePCH
= true;
269 Callbacks
.AfterPCHEmitted(Writer
);
272 bool BeginSourceFileAction(CompilerInstance
&CI
) override
{
273 assert(CI
.getLangOpts().CompilingPCH
);
274 return ASTFrontendAction::BeginSourceFileAction(CI
);
277 bool shouldEraseOutputFiles() override
{ return !hasEmittedPreamblePCH(); }
278 bool hasCodeCompletionSupport() const override
{ return false; }
279 bool hasASTFileSupport() const override
{ return false; }
280 TranslationUnitKind
getTranslationUnitKind() override
{ return TU_Prefix
; }
283 friend class PrecompilePreambleConsumer
;
285 bool HasEmittedPreamblePCH
= false;
286 std::shared_ptr
<PCHBuffer
> Buffer
;
287 bool WritePCHFile
; // otherwise the PCH is written into the PCHBuffer only.
288 std::unique_ptr
<llvm::raw_pwrite_stream
> FileOS
; // null if in-memory
289 PreambleCallbacks
&Callbacks
;
292 class PrecompilePreambleConsumer
: public PCHGenerator
{
294 PrecompilePreambleConsumer(PrecompilePreambleAction
&Action
, Preprocessor
&PP
,
295 InMemoryModuleCache
&ModuleCache
,
297 std::shared_ptr
<PCHBuffer
> Buffer
)
298 : PCHGenerator(PP
, ModuleCache
, "", isysroot
, std::move(Buffer
),
299 ArrayRef
<std::shared_ptr
<ModuleFileExtension
>>(),
300 /*AllowASTWithErrors=*/true),
303 bool HandleTopLevelDecl(DeclGroupRef DG
) override
{
304 Action
.Callbacks
.HandleTopLevelDecl(DG
);
308 void HandleTranslationUnit(ASTContext
&Ctx
) override
{
309 PCHGenerator::HandleTranslationUnit(Ctx
);
310 if (!hasEmittedPCH())
312 Action
.setEmittedPreamblePCH(getWriter());
315 bool shouldSkipFunctionBody(Decl
*D
) override
{
316 return Action
.Callbacks
.shouldSkipFunctionBody(D
);
320 PrecompilePreambleAction
&Action
;
323 std::unique_ptr
<ASTConsumer
>
324 PrecompilePreambleAction::CreateASTConsumer(CompilerInstance
&CI
,
327 if (!GeneratePCHAction::ComputeASTConsumerArguments(CI
, Sysroot
))
331 std::string OutputFile
; // unused
332 FileOS
= GeneratePCHAction::CreateOutputFile(CI
, InFile
, OutputFile
);
337 if (!CI
.getFrontendOpts().RelocatablePCH
)
340 return std::make_unique
<PrecompilePreambleConsumer
>(
341 *this, CI
.getPreprocessor(), CI
.getModuleCache(), Sysroot
, Buffer
);
344 template <class T
> bool moveOnNoError(llvm::ErrorOr
<T
> Val
, T
&Output
) {
347 Output
= std::move(*Val
);
353 PreambleBounds
clang::ComputePreambleBounds(const LangOptions
&LangOpts
,
354 const llvm::MemoryBufferRef
&Buffer
,
356 return Lexer::ComputePreamble(Buffer
.getBuffer(), LangOpts
, MaxLines
);
359 class PrecompiledPreamble::PCHStorage
{
361 static std::unique_ptr
<PCHStorage
> file(std::unique_ptr
<TempPCHFile
> File
) {
363 std::unique_ptr
<PCHStorage
> S(new PCHStorage());
364 S
->File
= std::move(File
);
367 static std::unique_ptr
<PCHStorage
> inMemory(std::shared_ptr
<PCHBuffer
> Buf
) {
368 std::unique_ptr
<PCHStorage
> S(new PCHStorage());
369 S
->Memory
= std::move(Buf
);
373 enum class Kind
{ InMemory
, TempFile
};
374 Kind
getKind() const {
376 return Kind::InMemory
;
378 return Kind::TempFile
;
379 llvm_unreachable("Neither Memory nor File?");
381 llvm::StringRef
filePath() const {
382 assert(getKind() == Kind::TempFile
);
383 return File
->getFilePath();
385 llvm::StringRef
memoryContents() const {
386 assert(getKind() == Kind::InMemory
);
387 return StringRef(Memory
->Data
.data(), Memory
->Data
.size());
390 // Shrink in-memory buffers to fit.
391 // This incurs a copy, but preambles tend to be long-lived.
392 // Only safe to call once nothing can alias the buffer.
396 Memory
->Data
= decltype(Memory
->Data
)(Memory
->Data
);
400 PCHStorage() = default;
401 PCHStorage(const PCHStorage
&) = delete;
402 PCHStorage
&operator=(const PCHStorage
&) = delete;
404 std::shared_ptr
<PCHBuffer
> Memory
;
405 std::unique_ptr
<TempPCHFile
> File
;
408 PrecompiledPreamble::~PrecompiledPreamble() = default;
409 PrecompiledPreamble::PrecompiledPreamble(PrecompiledPreamble
&&) = default;
410 PrecompiledPreamble
&
411 PrecompiledPreamble::operator=(PrecompiledPreamble
&&) = default;
413 llvm::ErrorOr
<PrecompiledPreamble
> PrecompiledPreamble::Build(
414 const CompilerInvocation
&Invocation
,
415 const llvm::MemoryBuffer
*MainFileBuffer
, PreambleBounds Bounds
,
416 DiagnosticsEngine
&Diagnostics
,
417 IntrusiveRefCntPtr
<llvm::vfs::FileSystem
> VFS
,
418 std::shared_ptr
<PCHContainerOperations
> PCHContainerOps
, bool StoreInMemory
,
419 StringRef StoragePath
, PreambleCallbacks
&Callbacks
) {
420 assert(VFS
&& "VFS is null");
422 auto PreambleInvocation
= std::make_shared
<CompilerInvocation
>(Invocation
);
423 FrontendOptions
&FrontendOpts
= PreambleInvocation
->getFrontendOpts();
424 PreprocessorOptions
&PreprocessorOpts
=
425 PreambleInvocation
->getPreprocessorOpts();
427 std::shared_ptr
<PCHBuffer
> Buffer
= std::make_shared
<PCHBuffer
>();
428 std::unique_ptr
<PCHStorage
> Storage
;
430 Storage
= PCHStorage::inMemory(Buffer
);
432 // Create a temporary file for the precompiled preamble. In rare
433 // circumstances, this can fail.
434 std::unique_ptr
<TempPCHFile
> PreamblePCHFile
=
435 TempPCHFile::create(StoragePath
);
436 if (!PreamblePCHFile
)
437 return BuildPreambleError::CouldntCreateTempFile
;
438 Storage
= PCHStorage::file(std::move(PreamblePCHFile
));
441 // Save the preamble text for later; we'll need to compare against it for
442 // subsequent reparses.
443 std::vector
<char> PreambleBytes(MainFileBuffer
->getBufferStart(),
444 MainFileBuffer
->getBufferStart() +
446 bool PreambleEndsAtStartOfLine
= Bounds
.PreambleEndsAtStartOfLine
;
448 // Tell the compiler invocation to generate a temporary precompiled header.
449 FrontendOpts
.ProgramAction
= frontend::GeneratePCH
;
450 FrontendOpts
.OutputFile
= std::string(
451 StoreInMemory
? getInMemoryPreamblePath() : Storage
->filePath());
452 PreprocessorOpts
.PrecompiledPreambleBytes
.first
= 0;
453 PreprocessorOpts
.PrecompiledPreambleBytes
.second
= false;
454 // Inform preprocessor to record conditional stack when building the preamble.
455 PreprocessorOpts
.GeneratePreamble
= true;
457 // Create the compiler instance to use for building the precompiled preamble.
458 std::unique_ptr
<CompilerInstance
> Clang(
459 new CompilerInstance(std::move(PCHContainerOps
)));
461 // Recover resources if we crash before exiting this method.
462 llvm::CrashRecoveryContextCleanupRegistrar
<CompilerInstance
> CICleanup(
465 Clang
->setInvocation(std::move(PreambleInvocation
));
466 Clang
->setDiagnostics(&Diagnostics
);
468 // Create the target instance.
469 if (!Clang
->createTarget())
470 return BuildPreambleError::CouldntCreateTargetInfo
;
472 if (Clang
->getFrontendOpts().Inputs
.size() != 1 ||
473 Clang
->getFrontendOpts().Inputs
[0].getKind().getFormat() !=
475 Clang
->getFrontendOpts().Inputs
[0].getKind().getLanguage() ==
477 return BuildPreambleError::BadInputs
;
480 // Clear out old caches and data.
482 ProcessWarningOptions(Diagnostics
, Clang
->getDiagnosticOpts(), *VFS
);
485 createVFSFromCompilerInvocation(Clang
->getInvocation(), Diagnostics
, VFS
);
487 // Create a file manager object to provide access to and cache the filesystem.
488 Clang
->setFileManager(new FileManager(Clang
->getFileSystemOpts(), VFS
));
490 // Create the source manager.
491 Clang
->setSourceManager(
492 new SourceManager(Diagnostics
, Clang
->getFileManager()));
494 auto PreambleDepCollector
= std::make_shared
<PreambleDependencyCollector
>();
495 Clang
->addDependencyCollector(PreambleDepCollector
);
497 Clang
->getLangOpts().CompilingPCH
= true;
499 // Remap the main source file to the preamble buffer.
500 StringRef MainFilePath
= FrontendOpts
.Inputs
[0].getFile();
501 auto PreambleInputBuffer
= llvm::MemoryBuffer::getMemBufferCopy(
502 MainFileBuffer
->getBuffer().slice(0, Bounds
.Size
), MainFilePath
);
503 if (PreprocessorOpts
.RetainRemappedFileBuffers
) {
504 // MainFileBuffer will be deleted by unique_ptr after leaving the method.
505 PreprocessorOpts
.addRemappedFile(MainFilePath
, PreambleInputBuffer
.get());
507 // In that case, remapped buffer will be deleted by CompilerInstance on
508 // BeginSourceFile, so we call release() to avoid double deletion.
509 PreprocessorOpts
.addRemappedFile(MainFilePath
,
510 PreambleInputBuffer
.release());
513 auto Act
= std::make_unique
<PrecompilePreambleAction
>(
515 /*WritePCHFile=*/Storage
->getKind() == PCHStorage::Kind::TempFile
,
517 if (!Act
->BeginSourceFile(*Clang
.get(), Clang
->getFrontendOpts().Inputs
[0]))
518 return BuildPreambleError::BeginSourceFileFailed
;
520 // Performed after BeginSourceFile to ensure Clang->Preprocessor can be
521 // referenced in the callback.
522 Callbacks
.BeforeExecute(*Clang
);
524 std::unique_ptr
<PPCallbacks
> DelegatedPPCallbacks
=
525 Callbacks
.createPPCallbacks();
526 if (DelegatedPPCallbacks
)
527 Clang
->getPreprocessor().addPPCallbacks(std::move(DelegatedPPCallbacks
));
528 if (auto CommentHandler
= Callbacks
.getCommentHandler())
529 Clang
->getPreprocessor().addCommentHandler(CommentHandler
);
530 llvm::StringSet
<> MissingFiles
;
531 Clang
->getPreprocessor().addPPCallbacks(
532 std::make_unique
<MissingFileCollector
>(
533 MissingFiles
, Clang
->getPreprocessor().getHeaderSearchInfo(),
534 Clang
->getSourceManager()));
536 if (llvm::Error Err
= Act
->Execute())
537 return errorToErrorCode(std::move(Err
));
539 // Run the callbacks.
540 Callbacks
.AfterExecute(*Clang
);
542 Act
->EndSourceFile();
544 if (!Act
->hasEmittedPreamblePCH())
545 return BuildPreambleError::CouldntEmitPCH
;
546 Act
.reset(); // Frees the PCH buffer, unless Storage keeps it in memory.
548 // Keep track of all of the files that the source manager knows about,
549 // so we can verify whether they have changed or not.
550 llvm::StringMap
<PrecompiledPreamble::PreambleFileHash
> FilesInPreamble
;
552 SourceManager
&SourceMgr
= Clang
->getSourceManager();
553 for (auto &Filename
: PreambleDepCollector
->getDependencies()) {
554 auto MaybeFile
= Clang
->getFileManager().getOptionalFileRef(Filename
);
556 MaybeFile
== SourceMgr
.getFileEntryRefForID(SourceMgr
.getMainFileID()))
558 auto File
= *MaybeFile
;
559 if (time_t ModTime
= File
.getModificationTime()) {
560 FilesInPreamble
[File
.getName()] =
561 PrecompiledPreamble::PreambleFileHash::createForFile(File
.getSize(),
564 llvm::MemoryBufferRef Buffer
=
565 SourceMgr
.getMemoryBufferForFileOrFake(File
);
566 FilesInPreamble
[File
.getName()] =
567 PrecompiledPreamble::PreambleFileHash::createForMemoryBuffer(Buffer
);
571 // Shrinking the storage requires extra temporary memory.
572 // Destroying clang first reduces peak memory usage.
573 CICleanup
.unregister();
576 return PrecompiledPreamble(
577 std::move(Storage
), std::move(PreambleBytes
), PreambleEndsAtStartOfLine
,
578 std::move(FilesInPreamble
), std::move(MissingFiles
));
581 PreambleBounds
PrecompiledPreamble::getBounds() const {
582 return PreambleBounds(PreambleBytes
.size(), PreambleEndsAtStartOfLine
);
585 std::size_t PrecompiledPreamble::getSize() const {
586 switch (Storage
->getKind()) {
587 case PCHStorage::Kind::InMemory
:
588 return Storage
->memoryContents().size();
589 case PCHStorage::Kind::TempFile
: {
591 if (llvm::sys::fs::file_size(Storage
->filePath(), Result
))
594 assert(Result
<= std::numeric_limits
<std::size_t>::max() &&
595 "file size did not fit into size_t");
599 llvm_unreachable("Unhandled storage kind");
602 bool PrecompiledPreamble::CanReuse(const CompilerInvocation
&Invocation
,
603 const llvm::MemoryBufferRef
&MainFileBuffer
,
604 PreambleBounds Bounds
,
605 llvm::vfs::FileSystem
&VFS
) const {
608 Bounds
.Size
<= MainFileBuffer
.getBufferSize() &&
609 "Buffer is too large. Bounds were calculated from a different buffer?");
611 auto PreambleInvocation
= std::make_shared
<CompilerInvocation
>(Invocation
);
612 PreprocessorOptions
&PreprocessorOpts
=
613 PreambleInvocation
->getPreprocessorOpts();
615 // We've previously computed a preamble. Check whether we have the same
616 // preamble now that we did before, and that there's enough space in
617 // the main-file buffer within the precompiled preamble to fit the
619 if (PreambleBytes
.size() != Bounds
.Size
||
620 PreambleEndsAtStartOfLine
!= Bounds
.PreambleEndsAtStartOfLine
||
621 !std::equal(PreambleBytes
.begin(), PreambleBytes
.end(),
622 MainFileBuffer
.getBuffer().begin()))
624 // The preamble has not changed. We may be able to re-use the precompiled
627 // Check that none of the files used by the preamble have changed.
628 // First, make a record of those files that have been overridden via
629 // remapping or unsaved_files.
630 std::map
<llvm::sys::fs::UniqueID
, PreambleFileHash
> OverriddenFiles
;
631 llvm::StringSet
<> OverriddenAbsPaths
; // Either by buffers or files.
632 for (const auto &R
: PreprocessorOpts
.RemappedFiles
) {
633 llvm::vfs::Status Status
;
634 if (!moveOnNoError(VFS
.status(R
.second
), Status
)) {
635 // If we can't stat the file we're remapping to, assume that something
636 // horrible happened.
639 // If a mapped file was previously missing, then it has changed.
640 llvm::SmallString
<128> MappedPath(R
.first
);
641 if (!VFS
.makeAbsolute(MappedPath
))
642 OverriddenAbsPaths
.insert(MappedPath
);
644 OverriddenFiles
[Status
.getUniqueID()] = PreambleFileHash::createForFile(
645 Status
.getSize(), llvm::sys::toTimeT(Status
.getLastModificationTime()));
648 // OverridenFileBuffers tracks only the files not found in VFS.
649 llvm::StringMap
<PreambleFileHash
> OverridenFileBuffers
;
650 for (const auto &RB
: PreprocessorOpts
.RemappedFileBuffers
) {
651 const PrecompiledPreamble::PreambleFileHash PreambleHash
=
652 PreambleFileHash::createForMemoryBuffer(RB
.second
->getMemBufferRef());
653 llvm::vfs::Status Status
;
654 if (moveOnNoError(VFS
.status(RB
.first
), Status
))
655 OverriddenFiles
[Status
.getUniqueID()] = PreambleHash
;
657 OverridenFileBuffers
[RB
.first
] = PreambleHash
;
659 llvm::SmallString
<128> MappedPath(RB
.first
);
660 if (!VFS
.makeAbsolute(MappedPath
))
661 OverriddenAbsPaths
.insert(MappedPath
);
664 // Check whether anything has changed.
665 for (const auto &F
: FilesInPreamble
) {
666 auto OverridenFileBuffer
= OverridenFileBuffers
.find(F
.first());
667 if (OverridenFileBuffer
!= OverridenFileBuffers
.end()) {
668 // The file's buffer was remapped and the file was not found in VFS.
669 // Check whether it matches up with the previous mapping.
670 if (OverridenFileBuffer
->second
!= F
.second
)
675 llvm::vfs::Status Status
;
676 if (!moveOnNoError(VFS
.status(F
.first()), Status
)) {
677 // If the file's buffer is not remapped and we can't stat it,
678 // assume that something horrible happened.
682 std::map
<llvm::sys::fs::UniqueID
, PreambleFileHash
>::iterator Overridden
=
683 OverriddenFiles
.find(Status
.getUniqueID());
684 if (Overridden
!= OverriddenFiles
.end()) {
685 // This file was remapped; check whether the newly-mapped file
686 // matches up with the previous mapping.
687 if (Overridden
->second
!= F
.second
)
692 // Neither the file's buffer nor the file itself was remapped;
693 // check whether it has changed on disk.
694 if (Status
.getSize() != uint64_t(F
.second
.Size
) ||
695 llvm::sys::toTimeT(Status
.getLastModificationTime()) !=
699 for (const auto &F
: MissingFiles
) {
700 // A missing file may be "provided" by an override buffer or file.
701 if (OverriddenAbsPaths
.count(F
.getKey()))
703 // If a file previously recorded as missing exists as a regular file, then
704 // consider the preamble out-of-date.
705 if (auto Status
= VFS
.status(F
.getKey())) {
706 if (Status
->isRegularFile())
713 void PrecompiledPreamble::AddImplicitPreamble(
714 CompilerInvocation
&CI
, IntrusiveRefCntPtr
<llvm::vfs::FileSystem
> &VFS
,
715 llvm::MemoryBuffer
*MainFileBuffer
) const {
716 PreambleBounds
Bounds(PreambleBytes
.size(), PreambleEndsAtStartOfLine
);
717 configurePreamble(Bounds
, CI
, VFS
, MainFileBuffer
);
720 void PrecompiledPreamble::OverridePreamble(
721 CompilerInvocation
&CI
, IntrusiveRefCntPtr
<llvm::vfs::FileSystem
> &VFS
,
722 llvm::MemoryBuffer
*MainFileBuffer
) const {
723 auto Bounds
= ComputePreambleBounds(CI
.getLangOpts(), *MainFileBuffer
, 0);
724 configurePreamble(Bounds
, CI
, VFS
, MainFileBuffer
);
727 PrecompiledPreamble::PrecompiledPreamble(
728 std::unique_ptr
<PCHStorage
> Storage
, std::vector
<char> PreambleBytes
,
729 bool PreambleEndsAtStartOfLine
,
730 llvm::StringMap
<PreambleFileHash
> FilesInPreamble
,
731 llvm::StringSet
<> MissingFiles
)
732 : Storage(std::move(Storage
)), FilesInPreamble(std::move(FilesInPreamble
)),
733 MissingFiles(std::move(MissingFiles
)),
734 PreambleBytes(std::move(PreambleBytes
)),
735 PreambleEndsAtStartOfLine(PreambleEndsAtStartOfLine
) {
736 assert(this->Storage
!= nullptr);
739 PrecompiledPreamble::PreambleFileHash
740 PrecompiledPreamble::PreambleFileHash::createForFile(off_t Size
,
742 PreambleFileHash Result
;
744 Result
.ModTime
= ModTime
;
749 PrecompiledPreamble::PreambleFileHash
750 PrecompiledPreamble::PreambleFileHash::createForMemoryBuffer(
751 const llvm::MemoryBufferRef
&Buffer
) {
752 PreambleFileHash Result
;
753 Result
.Size
= Buffer
.getBufferSize();
757 MD5Ctx
.update(Buffer
.getBuffer().data());
758 MD5Ctx
.final(Result
.MD5
);
763 void PrecompiledPreamble::configurePreamble(
764 PreambleBounds Bounds
, CompilerInvocation
&CI
,
765 IntrusiveRefCntPtr
<llvm::vfs::FileSystem
> &VFS
,
766 llvm::MemoryBuffer
*MainFileBuffer
) const {
769 auto &PreprocessorOpts
= CI
.getPreprocessorOpts();
771 // Remap main file to point to MainFileBuffer.
772 auto MainFilePath
= CI
.getFrontendOpts().Inputs
[0].getFile();
773 PreprocessorOpts
.addRemappedFile(MainFilePath
, MainFileBuffer
);
775 // Configure ImpicitPCHInclude.
776 PreprocessorOpts
.PrecompiledPreambleBytes
.first
= Bounds
.Size
;
777 PreprocessorOpts
.PrecompiledPreambleBytes
.second
=
778 Bounds
.PreambleEndsAtStartOfLine
;
779 PreprocessorOpts
.DisablePCHOrModuleValidation
=
780 DisableValidationForModuleKind::PCH
;
782 // Don't bother generating the long version of the predefines buffer.
783 // The preamble is going to overwrite it anyway.
784 PreprocessorOpts
.UsePredefines
= false;
786 setupPreambleStorage(*Storage
, PreprocessorOpts
, VFS
);
789 void PrecompiledPreamble::setupPreambleStorage(
790 const PCHStorage
&Storage
, PreprocessorOptions
&PreprocessorOpts
,
791 IntrusiveRefCntPtr
<llvm::vfs::FileSystem
> &VFS
) {
792 if (Storage
.getKind() == PCHStorage::Kind::TempFile
) {
793 llvm::StringRef PCHPath
= Storage
.filePath();
794 PreprocessorOpts
.ImplicitPCHInclude
= PCHPath
.str();
796 // Make sure we can access the PCH file even if we're using a VFS
797 IntrusiveRefCntPtr
<llvm::vfs::FileSystem
> RealFS
=
798 llvm::vfs::getRealFileSystem();
799 if (VFS
== RealFS
|| VFS
->exists(PCHPath
))
801 auto Buf
= RealFS
->getBufferForFile(PCHPath
);
803 // We can't read the file even from RealFS, this is clearly an error,
804 // but we'll just leave the current VFS as is and let clang's code
805 // figure out what to do with missing PCH.
809 // We have a slight inconsistency here -- we're using the VFS to
810 // read files, but the PCH was generated in the real file system.
811 VFS
= createVFSOverlayForPreamblePCH(PCHPath
, std::move(*Buf
), VFS
);
813 assert(Storage
.getKind() == PCHStorage::Kind::InMemory
);
814 // For in-memory preamble, we have to provide a VFS overlay that makes it
816 StringRef PCHPath
= getInMemoryPreamblePath();
817 PreprocessorOpts
.ImplicitPCHInclude
= std::string(PCHPath
);
819 auto Buf
= llvm::MemoryBuffer::getMemBuffer(
820 Storage
.memoryContents(), PCHPath
, /*RequiresNullTerminator=*/false);
821 VFS
= createVFSOverlayForPreamblePCH(PCHPath
, std::move(Buf
), VFS
);
825 void PreambleCallbacks::BeforeExecute(CompilerInstance
&CI
) {}
826 void PreambleCallbacks::AfterExecute(CompilerInstance
&CI
) {}
827 void PreambleCallbacks::AfterPCHEmitted(ASTWriter
&Writer
) {}
828 void PreambleCallbacks::HandleTopLevelDecl(DeclGroupRef DG
) {}
829 std::unique_ptr
<PPCallbacks
> PreambleCallbacks::createPPCallbacks() {
832 CommentHandler
*PreambleCallbacks::getCommentHandler() { return nullptr; }
834 static llvm::ManagedStatic
<BuildPreambleErrorCategory
> BuildPreambleErrCategory
;
836 std::error_code
clang::make_error_code(BuildPreambleError Error
) {
837 return std::error_code(static_cast<int>(Error
), *BuildPreambleErrCategory
);
840 const char *BuildPreambleErrorCategory::name() const noexcept
{
841 return "build-preamble.error";
844 std::string
BuildPreambleErrorCategory::message(int condition
) const {
845 switch (static_cast<BuildPreambleError
>(condition
)) {
846 case BuildPreambleError::CouldntCreateTempFile
:
847 return "Could not create temporary file for PCH";
848 case BuildPreambleError::CouldntCreateTargetInfo
:
849 return "CreateTargetInfo() return null";
850 case BuildPreambleError::BeginSourceFileFailed
:
851 return "BeginSourceFile() return an error";
852 case BuildPreambleError::CouldntEmitPCH
:
853 return "Could not emit PCH";
854 case BuildPreambleError::BadInputs
:
855 return "Command line arguments must contain exactly one source file";
857 llvm_unreachable("unexpected BuildPreambleError");