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
= [&](const DirectoryEntry
*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 (const FileEntry
*IncludingFile
=
125 SM
.getFileEntryForID(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
.getDir());
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() {
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
<64> File
;
208 // Using a version of createTemporaryFile with a file descriptor guarantees
209 // that we would never get a race condition in a multi-threaded setting
210 // (i.e., multiple threads getting the same temporary path).
213 llvm::sys::fs::createTemporaryFile("preamble", "pch", FD
, File
))
215 // We only needed to make sure the file exists, close the file right away.
216 llvm::sys::Process::SafelyCloseFileDescriptor(FD
);
217 return std::unique_ptr
<TempPCHFile
>(new TempPCHFile(File
.str().str()));
220 TempPCHFile
&operator=(const TempPCHFile
&) = delete;
221 TempPCHFile(const TempPCHFile
&) = delete;
222 ~TempPCHFile() { TemporaryFiles::getInstance().removeFile(FilePath
); };
224 /// A path where temporary file is stored.
225 llvm::StringRef
getFilePath() const { return FilePath
; };
228 TempPCHFile(std::string FilePath
) : FilePath(std::move(FilePath
)) {
229 TemporaryFiles::getInstance().addFile(this->FilePath
);
232 std::string FilePath
;
235 class PrecompilePreambleAction
: public ASTFrontendAction
{
237 PrecompilePreambleAction(std::shared_ptr
<PCHBuffer
> Buffer
, bool WritePCHFile
,
238 PreambleCallbacks
&Callbacks
)
239 : Buffer(std::move(Buffer
)), WritePCHFile(WritePCHFile
),
240 Callbacks(Callbacks
) {}
242 std::unique_ptr
<ASTConsumer
> CreateASTConsumer(CompilerInstance
&CI
,
243 StringRef InFile
) override
;
245 bool hasEmittedPreamblePCH() const { return HasEmittedPreamblePCH
; }
247 void setEmittedPreamblePCH(ASTWriter
&Writer
) {
249 *FileOS
<< Buffer
->Data
;
250 // Make sure it hits disk now.
254 this->HasEmittedPreamblePCH
= true;
255 Callbacks
.AfterPCHEmitted(Writer
);
258 bool BeginSourceFileAction(CompilerInstance
&CI
) override
{
259 assert(CI
.getLangOpts().CompilingPCH
);
260 return ASTFrontendAction::BeginSourceFileAction(CI
);
263 bool shouldEraseOutputFiles() override
{ return !hasEmittedPreamblePCH(); }
264 bool hasCodeCompletionSupport() const override
{ return false; }
265 bool hasASTFileSupport() const override
{ return false; }
266 TranslationUnitKind
getTranslationUnitKind() override
{ return TU_Prefix
; }
269 friend class PrecompilePreambleConsumer
;
271 bool HasEmittedPreamblePCH
= false;
272 std::shared_ptr
<PCHBuffer
> Buffer
;
273 bool WritePCHFile
; // otherwise the PCH is written into the PCHBuffer only.
274 std::unique_ptr
<llvm::raw_pwrite_stream
> FileOS
; // null if in-memory
275 PreambleCallbacks
&Callbacks
;
278 class PrecompilePreambleConsumer
: public PCHGenerator
{
280 PrecompilePreambleConsumer(PrecompilePreambleAction
&Action
,
281 const Preprocessor
&PP
,
282 InMemoryModuleCache
&ModuleCache
,
284 std::shared_ptr
<PCHBuffer
> Buffer
)
285 : PCHGenerator(PP
, ModuleCache
, "", isysroot
, std::move(Buffer
),
286 ArrayRef
<std::shared_ptr
<ModuleFileExtension
>>(),
287 /*AllowASTWithErrors=*/true),
290 bool HandleTopLevelDecl(DeclGroupRef DG
) override
{
291 Action
.Callbacks
.HandleTopLevelDecl(DG
);
295 void HandleTranslationUnit(ASTContext
&Ctx
) override
{
296 PCHGenerator::HandleTranslationUnit(Ctx
);
297 if (!hasEmittedPCH())
299 Action
.setEmittedPreamblePCH(getWriter());
302 bool shouldSkipFunctionBody(Decl
*D
) override
{
303 return Action
.Callbacks
.shouldSkipFunctionBody(D
);
307 PrecompilePreambleAction
&Action
;
310 std::unique_ptr
<ASTConsumer
>
311 PrecompilePreambleAction::CreateASTConsumer(CompilerInstance
&CI
,
314 if (!GeneratePCHAction::ComputeASTConsumerArguments(CI
, Sysroot
))
318 std::string OutputFile
; // unused
319 FileOS
= GeneratePCHAction::CreateOutputFile(CI
, InFile
, OutputFile
);
324 if (!CI
.getFrontendOpts().RelocatablePCH
)
327 return std::make_unique
<PrecompilePreambleConsumer
>(
328 *this, CI
.getPreprocessor(), CI
.getModuleCache(), Sysroot
, Buffer
);
331 template <class T
> bool moveOnNoError(llvm::ErrorOr
<T
> Val
, T
&Output
) {
334 Output
= std::move(*Val
);
340 PreambleBounds
clang::ComputePreambleBounds(const LangOptions
&LangOpts
,
341 const llvm::MemoryBufferRef
&Buffer
,
343 return Lexer::ComputePreamble(Buffer
.getBuffer(), LangOpts
, MaxLines
);
346 class PrecompiledPreamble::PCHStorage
{
348 static std::unique_ptr
<PCHStorage
> file(std::unique_ptr
<TempPCHFile
> File
) {
350 std::unique_ptr
<PCHStorage
> S(new PCHStorage());
351 S
->File
= std::move(File
);
354 static std::unique_ptr
<PCHStorage
> inMemory(std::shared_ptr
<PCHBuffer
> Buf
) {
355 std::unique_ptr
<PCHStorage
> S(new PCHStorage());
356 S
->Memory
= std::move(Buf
);
360 enum class Kind
{ InMemory
, TempFile
};
361 Kind
getKind() const {
363 return Kind::InMemory
;
365 return Kind::TempFile
;
366 llvm_unreachable("Neither Memory nor File?");
368 llvm::StringRef
filePath() const {
369 assert(getKind() == Kind::TempFile
);
370 return File
->getFilePath();
372 llvm::StringRef
memoryContents() const {
373 assert(getKind() == Kind::InMemory
);
374 return StringRef(Memory
->Data
.data(), Memory
->Data
.size());
377 // Shrink in-memory buffers to fit.
378 // This incurs a copy, but preambles tend to be long-lived.
379 // Only safe to call once nothing can alias the buffer.
383 Memory
->Data
= decltype(Memory
->Data
)(Memory
->Data
);
387 PCHStorage() = default;
388 PCHStorage(const PCHStorage
&) = delete;
389 PCHStorage
&operator=(const PCHStorage
&) = delete;
391 std::shared_ptr
<PCHBuffer
> Memory
;
392 std::unique_ptr
<TempPCHFile
> File
;
395 PrecompiledPreamble::~PrecompiledPreamble() = default;
396 PrecompiledPreamble::PrecompiledPreamble(PrecompiledPreamble
&&) = default;
397 PrecompiledPreamble
&
398 PrecompiledPreamble::operator=(PrecompiledPreamble
&&) = default;
400 llvm::ErrorOr
<PrecompiledPreamble
> PrecompiledPreamble::Build(
401 const CompilerInvocation
&Invocation
,
402 const llvm::MemoryBuffer
*MainFileBuffer
, PreambleBounds Bounds
,
403 DiagnosticsEngine
&Diagnostics
,
404 IntrusiveRefCntPtr
<llvm::vfs::FileSystem
> VFS
,
405 std::shared_ptr
<PCHContainerOperations
> PCHContainerOps
, bool StoreInMemory
,
406 PreambleCallbacks
&Callbacks
) {
407 assert(VFS
&& "VFS is null");
409 auto PreambleInvocation
= std::make_shared
<CompilerInvocation
>(Invocation
);
410 FrontendOptions
&FrontendOpts
= PreambleInvocation
->getFrontendOpts();
411 PreprocessorOptions
&PreprocessorOpts
=
412 PreambleInvocation
->getPreprocessorOpts();
414 std::shared_ptr
<PCHBuffer
> Buffer
= std::make_shared
<PCHBuffer
>();
415 std::unique_ptr
<PCHStorage
> Storage
;
417 Storage
= PCHStorage::inMemory(Buffer
);
419 // Create a temporary file for the precompiled preamble. In rare
420 // circumstances, this can fail.
421 std::unique_ptr
<TempPCHFile
> PreamblePCHFile
= TempPCHFile::create();
422 if (!PreamblePCHFile
)
423 return BuildPreambleError::CouldntCreateTempFile
;
424 Storage
= PCHStorage::file(std::move(PreamblePCHFile
));
427 // Save the preamble text for later; we'll need to compare against it for
428 // subsequent reparses.
429 std::vector
<char> PreambleBytes(MainFileBuffer
->getBufferStart(),
430 MainFileBuffer
->getBufferStart() +
432 bool PreambleEndsAtStartOfLine
= Bounds
.PreambleEndsAtStartOfLine
;
434 // Tell the compiler invocation to generate a temporary precompiled header.
435 FrontendOpts
.ProgramAction
= frontend::GeneratePCH
;
436 FrontendOpts
.OutputFile
= std::string(
437 StoreInMemory
? getInMemoryPreamblePath() : Storage
->filePath());
438 PreprocessorOpts
.PrecompiledPreambleBytes
.first
= 0;
439 PreprocessorOpts
.PrecompiledPreambleBytes
.second
= false;
440 // Inform preprocessor to record conditional stack when building the preamble.
441 PreprocessorOpts
.GeneratePreamble
= true;
443 // Create the compiler instance to use for building the precompiled preamble.
444 std::unique_ptr
<CompilerInstance
> Clang(
445 new CompilerInstance(std::move(PCHContainerOps
)));
447 // Recover resources if we crash before exiting this method.
448 llvm::CrashRecoveryContextCleanupRegistrar
<CompilerInstance
> CICleanup(
451 Clang
->setInvocation(std::move(PreambleInvocation
));
452 Clang
->setDiagnostics(&Diagnostics
);
454 // Create the target instance.
455 if (!Clang
->createTarget())
456 return BuildPreambleError::CouldntCreateTargetInfo
;
458 if (Clang
->getFrontendOpts().Inputs
.size() != 1 ||
459 Clang
->getFrontendOpts().Inputs
[0].getKind().getFormat() !=
461 Clang
->getFrontendOpts().Inputs
[0].getKind().getLanguage() ==
463 return BuildPreambleError::BadInputs
;
466 // Clear out old caches and data.
468 ProcessWarningOptions(Diagnostics
, Clang
->getDiagnosticOpts());
471 createVFSFromCompilerInvocation(Clang
->getInvocation(), Diagnostics
, VFS
);
473 // Create a file manager object to provide access to and cache the filesystem.
474 Clang
->setFileManager(new FileManager(Clang
->getFileSystemOpts(), VFS
));
476 // Create the source manager.
477 Clang
->setSourceManager(
478 new SourceManager(Diagnostics
, Clang
->getFileManager()));
480 auto PreambleDepCollector
= std::make_shared
<PreambleDependencyCollector
>();
481 Clang
->addDependencyCollector(PreambleDepCollector
);
483 Clang
->getLangOpts().CompilingPCH
= true;
485 // Remap the main source file to the preamble buffer.
486 StringRef MainFilePath
= FrontendOpts
.Inputs
[0].getFile();
487 auto PreambleInputBuffer
= llvm::MemoryBuffer::getMemBufferCopy(
488 MainFileBuffer
->getBuffer().slice(0, Bounds
.Size
), MainFilePath
);
489 if (PreprocessorOpts
.RetainRemappedFileBuffers
) {
490 // MainFileBuffer will be deleted by unique_ptr after leaving the method.
491 PreprocessorOpts
.addRemappedFile(MainFilePath
, PreambleInputBuffer
.get());
493 // In that case, remapped buffer will be deleted by CompilerInstance on
494 // BeginSourceFile, so we call release() to avoid double deletion.
495 PreprocessorOpts
.addRemappedFile(MainFilePath
,
496 PreambleInputBuffer
.release());
499 auto Act
= std::make_unique
<PrecompilePreambleAction
>(
501 /*WritePCHFile=*/Storage
->getKind() == PCHStorage::Kind::TempFile
,
503 if (!Act
->BeginSourceFile(*Clang
.get(), Clang
->getFrontendOpts().Inputs
[0]))
504 return BuildPreambleError::BeginSourceFileFailed
;
506 // Performed after BeginSourceFile to ensure Clang->Preprocessor can be
507 // referenced in the callback.
508 Callbacks
.BeforeExecute(*Clang
);
510 std::unique_ptr
<PPCallbacks
> DelegatedPPCallbacks
=
511 Callbacks
.createPPCallbacks();
512 if (DelegatedPPCallbacks
)
513 Clang
->getPreprocessor().addPPCallbacks(std::move(DelegatedPPCallbacks
));
514 if (auto CommentHandler
= Callbacks
.getCommentHandler())
515 Clang
->getPreprocessor().addCommentHandler(CommentHandler
);
516 llvm::StringSet
<> MissingFiles
;
517 Clang
->getPreprocessor().addPPCallbacks(
518 std::make_unique
<MissingFileCollector
>(
519 MissingFiles
, Clang
->getPreprocessor().getHeaderSearchInfo(),
520 Clang
->getSourceManager()));
522 if (llvm::Error Err
= Act
->Execute())
523 return errorToErrorCode(std::move(Err
));
525 // Run the callbacks.
526 Callbacks
.AfterExecute(*Clang
);
528 Act
->EndSourceFile();
530 if (!Act
->hasEmittedPreamblePCH())
531 return BuildPreambleError::CouldntEmitPCH
;
532 Act
.reset(); // Frees the PCH buffer, unless Storage keeps it in memory.
534 // Keep track of all of the files that the source manager knows about,
535 // so we can verify whether they have changed or not.
536 llvm::StringMap
<PrecompiledPreamble::PreambleFileHash
> FilesInPreamble
;
538 SourceManager
&SourceMgr
= Clang
->getSourceManager();
539 for (auto &Filename
: PreambleDepCollector
->getDependencies()) {
540 auto FileOrErr
= Clang
->getFileManager().getFile(Filename
);
542 *FileOrErr
== SourceMgr
.getFileEntryForID(SourceMgr
.getMainFileID()))
544 auto File
= *FileOrErr
;
545 if (time_t ModTime
= File
->getModificationTime()) {
546 FilesInPreamble
[File
->getName()] =
547 PrecompiledPreamble::PreambleFileHash::createForFile(File
->getSize(),
550 llvm::MemoryBufferRef Buffer
=
551 SourceMgr
.getMemoryBufferForFileOrFake(File
);
552 FilesInPreamble
[File
->getName()] =
553 PrecompiledPreamble::PreambleFileHash::createForMemoryBuffer(Buffer
);
557 // Shrinking the storage requires extra temporary memory.
558 // Destroying clang first reduces peak memory usage.
559 CICleanup
.unregister();
562 return PrecompiledPreamble(
563 std::move(Storage
), std::move(PreambleBytes
), PreambleEndsAtStartOfLine
,
564 std::move(FilesInPreamble
), std::move(MissingFiles
));
567 PreambleBounds
PrecompiledPreamble::getBounds() const {
568 return PreambleBounds(PreambleBytes
.size(), PreambleEndsAtStartOfLine
);
571 std::size_t PrecompiledPreamble::getSize() const {
572 switch (Storage
->getKind()) {
573 case PCHStorage::Kind::InMemory
:
574 return Storage
->memoryContents().size();
575 case PCHStorage::Kind::TempFile
: {
577 if (llvm::sys::fs::file_size(Storage
->filePath(), Result
))
580 assert(Result
<= std::numeric_limits
<std::size_t>::max() &&
581 "file size did not fit into size_t");
585 llvm_unreachable("Unhandled storage kind");
588 bool PrecompiledPreamble::CanReuse(const CompilerInvocation
&Invocation
,
589 const llvm::MemoryBufferRef
&MainFileBuffer
,
590 PreambleBounds Bounds
,
591 llvm::vfs::FileSystem
&VFS
) const {
594 Bounds
.Size
<= MainFileBuffer
.getBufferSize() &&
595 "Buffer is too large. Bounds were calculated from a different buffer?");
597 auto PreambleInvocation
= std::make_shared
<CompilerInvocation
>(Invocation
);
598 PreprocessorOptions
&PreprocessorOpts
=
599 PreambleInvocation
->getPreprocessorOpts();
601 // We've previously computed a preamble. Check whether we have the same
602 // preamble now that we did before, and that there's enough space in
603 // the main-file buffer within the precompiled preamble to fit the
605 if (PreambleBytes
.size() != Bounds
.Size
||
606 PreambleEndsAtStartOfLine
!= Bounds
.PreambleEndsAtStartOfLine
||
607 !std::equal(PreambleBytes
.begin(), PreambleBytes
.end(),
608 MainFileBuffer
.getBuffer().begin()))
610 // The preamble has not changed. We may be able to re-use the precompiled
613 // Check that none of the files used by the preamble have changed.
614 // First, make a record of those files that have been overridden via
615 // remapping or unsaved_files.
616 std::map
<llvm::sys::fs::UniqueID
, PreambleFileHash
> OverriddenFiles
;
617 llvm::StringSet
<> OverriddenAbsPaths
; // Either by buffers or files.
618 for (const auto &R
: PreprocessorOpts
.RemappedFiles
) {
619 llvm::vfs::Status Status
;
620 if (!moveOnNoError(VFS
.status(R
.second
), Status
)) {
621 // If we can't stat the file we're remapping to, assume that something
622 // horrible happened.
625 // If a mapped file was previously missing, then it has changed.
626 llvm::SmallString
<128> MappedPath(R
.first
);
627 if (!VFS
.makeAbsolute(MappedPath
))
628 OverriddenAbsPaths
.insert(MappedPath
);
630 OverriddenFiles
[Status
.getUniqueID()] = PreambleFileHash::createForFile(
631 Status
.getSize(), llvm::sys::toTimeT(Status
.getLastModificationTime()));
634 // OverridenFileBuffers tracks only the files not found in VFS.
635 llvm::StringMap
<PreambleFileHash
> OverridenFileBuffers
;
636 for (const auto &RB
: PreprocessorOpts
.RemappedFileBuffers
) {
637 const PrecompiledPreamble::PreambleFileHash PreambleHash
=
638 PreambleFileHash::createForMemoryBuffer(RB
.second
->getMemBufferRef());
639 llvm::vfs::Status Status
;
640 if (moveOnNoError(VFS
.status(RB
.first
), Status
))
641 OverriddenFiles
[Status
.getUniqueID()] = PreambleHash
;
643 OverridenFileBuffers
[RB
.first
] = PreambleHash
;
645 llvm::SmallString
<128> MappedPath(RB
.first
);
646 if (!VFS
.makeAbsolute(MappedPath
))
647 OverriddenAbsPaths
.insert(MappedPath
);
650 // Check whether anything has changed.
651 for (const auto &F
: FilesInPreamble
) {
652 auto OverridenFileBuffer
= OverridenFileBuffers
.find(F
.first());
653 if (OverridenFileBuffer
!= OverridenFileBuffers
.end()) {
654 // The file's buffer was remapped and the file was not found in VFS.
655 // Check whether it matches up with the previous mapping.
656 if (OverridenFileBuffer
->second
!= F
.second
)
661 llvm::vfs::Status Status
;
662 if (!moveOnNoError(VFS
.status(F
.first()), Status
)) {
663 // If the file's buffer is not remapped and we can't stat it,
664 // assume that something horrible happened.
668 std::map
<llvm::sys::fs::UniqueID
, PreambleFileHash
>::iterator Overridden
=
669 OverriddenFiles
.find(Status
.getUniqueID());
670 if (Overridden
!= OverriddenFiles
.end()) {
671 // This file was remapped; check whether the newly-mapped file
672 // matches up with the previous mapping.
673 if (Overridden
->second
!= F
.second
)
678 // Neither the file's buffer nor the file itself was remapped;
679 // check whether it has changed on disk.
680 if (Status
.getSize() != uint64_t(F
.second
.Size
) ||
681 llvm::sys::toTimeT(Status
.getLastModificationTime()) !=
685 for (const auto &F
: MissingFiles
) {
686 // A missing file may be "provided" by an override buffer or file.
687 if (OverriddenAbsPaths
.count(F
.getKey()))
689 // If a file previously recorded as missing exists as a regular file, then
690 // consider the preamble out-of-date.
691 if (auto Status
= VFS
.status(F
.getKey())) {
692 if (Status
->isRegularFile())
699 void PrecompiledPreamble::AddImplicitPreamble(
700 CompilerInvocation
&CI
, IntrusiveRefCntPtr
<llvm::vfs::FileSystem
> &VFS
,
701 llvm::MemoryBuffer
*MainFileBuffer
) const {
702 PreambleBounds
Bounds(PreambleBytes
.size(), PreambleEndsAtStartOfLine
);
703 configurePreamble(Bounds
, CI
, VFS
, MainFileBuffer
);
706 void PrecompiledPreamble::OverridePreamble(
707 CompilerInvocation
&CI
, IntrusiveRefCntPtr
<llvm::vfs::FileSystem
> &VFS
,
708 llvm::MemoryBuffer
*MainFileBuffer
) const {
709 auto Bounds
= ComputePreambleBounds(*CI
.getLangOpts(), *MainFileBuffer
, 0);
710 configurePreamble(Bounds
, CI
, VFS
, MainFileBuffer
);
713 PrecompiledPreamble::PrecompiledPreamble(
714 std::unique_ptr
<PCHStorage
> Storage
, std::vector
<char> PreambleBytes
,
715 bool PreambleEndsAtStartOfLine
,
716 llvm::StringMap
<PreambleFileHash
> FilesInPreamble
,
717 llvm::StringSet
<> MissingFiles
)
718 : Storage(std::move(Storage
)), FilesInPreamble(std::move(FilesInPreamble
)),
719 MissingFiles(std::move(MissingFiles
)),
720 PreambleBytes(std::move(PreambleBytes
)),
721 PreambleEndsAtStartOfLine(PreambleEndsAtStartOfLine
) {
722 assert(this->Storage
!= nullptr);
725 PrecompiledPreamble::PreambleFileHash
726 PrecompiledPreamble::PreambleFileHash::createForFile(off_t Size
,
728 PreambleFileHash Result
;
730 Result
.ModTime
= ModTime
;
735 PrecompiledPreamble::PreambleFileHash
736 PrecompiledPreamble::PreambleFileHash::createForMemoryBuffer(
737 const llvm::MemoryBufferRef
&Buffer
) {
738 PreambleFileHash Result
;
739 Result
.Size
= Buffer
.getBufferSize();
743 MD5Ctx
.update(Buffer
.getBuffer().data());
744 MD5Ctx
.final(Result
.MD5
);
749 void PrecompiledPreamble::configurePreamble(
750 PreambleBounds Bounds
, CompilerInvocation
&CI
,
751 IntrusiveRefCntPtr
<llvm::vfs::FileSystem
> &VFS
,
752 llvm::MemoryBuffer
*MainFileBuffer
) const {
755 auto &PreprocessorOpts
= CI
.getPreprocessorOpts();
757 // Remap main file to point to MainFileBuffer.
758 auto MainFilePath
= CI
.getFrontendOpts().Inputs
[0].getFile();
759 PreprocessorOpts
.addRemappedFile(MainFilePath
, MainFileBuffer
);
761 // Configure ImpicitPCHInclude.
762 PreprocessorOpts
.PrecompiledPreambleBytes
.first
= Bounds
.Size
;
763 PreprocessorOpts
.PrecompiledPreambleBytes
.second
=
764 Bounds
.PreambleEndsAtStartOfLine
;
765 PreprocessorOpts
.DisablePCHOrModuleValidation
=
766 DisableValidationForModuleKind::PCH
;
768 // Don't bother generating the long version of the predefines buffer.
769 // The preamble is going to overwrite it anyway.
770 PreprocessorOpts
.UsePredefines
= false;
772 setupPreambleStorage(*Storage
, PreprocessorOpts
, VFS
);
775 void PrecompiledPreamble::setupPreambleStorage(
776 const PCHStorage
&Storage
, PreprocessorOptions
&PreprocessorOpts
,
777 IntrusiveRefCntPtr
<llvm::vfs::FileSystem
> &VFS
) {
778 if (Storage
.getKind() == PCHStorage::Kind::TempFile
) {
779 llvm::StringRef PCHPath
= Storage
.filePath();
780 PreprocessorOpts
.ImplicitPCHInclude
= PCHPath
.str();
782 // Make sure we can access the PCH file even if we're using a VFS
783 IntrusiveRefCntPtr
<llvm::vfs::FileSystem
> RealFS
=
784 llvm::vfs::getRealFileSystem();
785 if (VFS
== RealFS
|| VFS
->exists(PCHPath
))
787 auto Buf
= RealFS
->getBufferForFile(PCHPath
);
789 // We can't read the file even from RealFS, this is clearly an error,
790 // but we'll just leave the current VFS as is and let clang's code
791 // figure out what to do with missing PCH.
795 // We have a slight inconsistency here -- we're using the VFS to
796 // read files, but the PCH was generated in the real file system.
797 VFS
= createVFSOverlayForPreamblePCH(PCHPath
, std::move(*Buf
), VFS
);
799 assert(Storage
.getKind() == PCHStorage::Kind::InMemory
);
800 // For in-memory preamble, we have to provide a VFS overlay that makes it
802 StringRef PCHPath
= getInMemoryPreamblePath();
803 PreprocessorOpts
.ImplicitPCHInclude
= std::string(PCHPath
);
805 auto Buf
= llvm::MemoryBuffer::getMemBuffer(
806 Storage
.memoryContents(), PCHPath
, /*RequiresNullTerminator=*/false);
807 VFS
= createVFSOverlayForPreamblePCH(PCHPath
, std::move(Buf
), VFS
);
811 void PreambleCallbacks::BeforeExecute(CompilerInstance
&CI
) {}
812 void PreambleCallbacks::AfterExecute(CompilerInstance
&CI
) {}
813 void PreambleCallbacks::AfterPCHEmitted(ASTWriter
&Writer
) {}
814 void PreambleCallbacks::HandleTopLevelDecl(DeclGroupRef DG
) {}
815 std::unique_ptr
<PPCallbacks
> PreambleCallbacks::createPPCallbacks() {
818 CommentHandler
*PreambleCallbacks::getCommentHandler() { return nullptr; }
820 static llvm::ManagedStatic
<BuildPreambleErrorCategory
> BuildPreambleErrCategory
;
822 std::error_code
clang::make_error_code(BuildPreambleError Error
) {
823 return std::error_code(static_cast<int>(Error
), *BuildPreambleErrCategory
);
826 const char *BuildPreambleErrorCategory::name() const noexcept
{
827 return "build-preamble.error";
830 std::string
BuildPreambleErrorCategory::message(int condition
) const {
831 switch (static_cast<BuildPreambleError
>(condition
)) {
832 case BuildPreambleError::CouldntCreateTempFile
:
833 return "Could not create temporary file for PCH";
834 case BuildPreambleError::CouldntCreateTargetInfo
:
835 return "CreateTargetInfo() return null";
836 case BuildPreambleError::BeginSourceFileFailed
:
837 return "BeginSourceFile() return an error";
838 case BuildPreambleError::CouldntEmitPCH
:
839 return "Could not emit PCH";
840 case BuildPreambleError::BadInputs
:
841 return "Command line arguments must contain exactly one source file";
843 llvm_unreachable("unexpected BuildPreambleError");