clang  9.0.0
PrecompiledPreamble.cpp
Go to the documentation of this file.
1 //===--- PrecompiledPreamble.cpp - Build precompiled preambles --*- C++ -*-===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Helper class to build precompiled preamble.
10 //
11 //===----------------------------------------------------------------------===//
12 
14 #include "clang/AST/DeclObjC.h"
15 #include "clang/Basic/TargetInfo.h"
20 #include "clang/Lex/Lexer.h"
21 #include "clang/Lex/Preprocessor.h"
24 #include "llvm/ADT/StringExtras.h"
25 #include "llvm/ADT/StringSet.h"
26 #include "llvm/Config/llvm-config.h"
27 #include "llvm/Support/CrashRecoveryContext.h"
28 #include "llvm/Support/FileSystem.h"
29 #include "llvm/Support/Mutex.h"
30 #include "llvm/Support/MutexGuard.h"
31 #include "llvm/Support/Process.h"
32 #include "llvm/Support/VirtualFileSystem.h"
33 #include <limits>
34 #include <utility>
35 
36 using namespace clang;
37 
38 namespace {
39 
40 StringRef getInMemoryPreamblePath() {
41 #if defined(LLVM_ON_UNIX)
42  return "/__clang_tmp/___clang_inmemory_preamble___";
43 #elif defined(_WIN32)
44  return "C:\\__clang_tmp\\___clang_inmemory_preamble___";
45 #else
46 #warning "Unknown platform. Defaulting to UNIX-style paths for in-memory PCHs"
47  return "/__clang_tmp/___clang_inmemory_preamble___";
48 #endif
49 }
50 
52 createVFSOverlayForPreamblePCH(StringRef PCHFilename,
53  std::unique_ptr<llvm::MemoryBuffer> PCHBuffer,
55  // We want only the PCH file from the real filesystem to be available,
56  // so we create an in-memory VFS with just that and overlay it on top.
58  new llvm::vfs::InMemoryFileSystem());
59  PCHFS->addFile(PCHFilename, 0, std::move(PCHBuffer));
61  new llvm::vfs::OverlayFileSystem(VFS));
62  Overlay->pushOverlay(PCHFS);
63  return Overlay;
64 }
65 
66 class PreambleDependencyCollector : public DependencyCollector {
67 public:
68  // We want to collect all dependencies for correctness. Avoiding the real
69  // system dependencies (e.g. stl from /usr/lib) would probably be a good idea,
70  // but there is no way to distinguish between those and the ones that can be
71  // spuriously added by '-isystem' (e.g. to suppress warnings from those
72  // headers).
73  bool needSystemDependencies() override { return true; }
74 };
75 
76 /// Keeps a track of files to be deleted in destructor.
77 class TemporaryFiles {
78 public:
79  // A static instance to be used by all clients.
80  static TemporaryFiles &getInstance();
81 
82 private:
83  // Disallow constructing the class directly.
84  TemporaryFiles() = default;
85  // Disallow copy.
86  TemporaryFiles(const TemporaryFiles &) = delete;
87 
88 public:
89  ~TemporaryFiles();
90 
91  /// Adds \p File to a set of tracked files.
92  void addFile(StringRef File);
93 
94  /// Remove \p File from disk and from the set of tracked files.
95  void removeFile(StringRef File);
96 
97 private:
98  llvm::sys::SmartMutex<false> Mutex;
99  llvm::StringSet<> Files;
100 };
101 
102 TemporaryFiles &TemporaryFiles::getInstance() {
103  static TemporaryFiles Instance;
104  return Instance;
105 }
106 
107 TemporaryFiles::~TemporaryFiles() {
108  llvm::MutexGuard Guard(Mutex);
109  for (const auto &File : Files)
110  llvm::sys::fs::remove(File.getKey());
111 }
112 
113 void TemporaryFiles::addFile(StringRef File) {
114  llvm::MutexGuard Guard(Mutex);
115  auto IsInserted = Files.insert(File).second;
116  (void)IsInserted;
117  assert(IsInserted && "File has already been added");
118 }
119 
120 void TemporaryFiles::removeFile(StringRef File) {
121  llvm::MutexGuard Guard(Mutex);
122  auto WasPresent = Files.erase(File);
123  (void)WasPresent;
124  assert(WasPresent && "File was not tracked");
125  llvm::sys::fs::remove(File);
126 }
127 
128 class PrecompilePreambleAction : public ASTFrontendAction {
129 public:
130  PrecompilePreambleAction(std::string *InMemStorage,
131  PreambleCallbacks &Callbacks)
132  : InMemStorage(InMemStorage), Callbacks(Callbacks) {}
133 
134  std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
135  StringRef InFile) override;
136 
137  bool hasEmittedPreamblePCH() const { return HasEmittedPreamblePCH; }
138 
139  void setEmittedPreamblePCH(ASTWriter &Writer) {
140  this->HasEmittedPreamblePCH = true;
141  Callbacks.AfterPCHEmitted(Writer);
142  }
143 
144  bool shouldEraseOutputFiles() override { return !hasEmittedPreamblePCH(); }
145  bool hasCodeCompletionSupport() const override { return false; }
146  bool hasASTFileSupport() const override { return false; }
147  TranslationUnitKind getTranslationUnitKind() override { return TU_Prefix; }
148 
149 private:
150  friend class PrecompilePreambleConsumer;
151 
152  bool HasEmittedPreamblePCH = false;
153  std::string *InMemStorage;
154  PreambleCallbacks &Callbacks;
155 };
156 
157 class PrecompilePreambleConsumer : public PCHGenerator {
158 public:
159  PrecompilePreambleConsumer(PrecompilePreambleAction &Action,
160  const Preprocessor &PP,
161  InMemoryModuleCache &ModuleCache,
162  StringRef isysroot,
163  std::unique_ptr<raw_ostream> Out)
164  : PCHGenerator(PP, ModuleCache, "", isysroot,
165  std::make_shared<PCHBuffer>(),
166  ArrayRef<std::shared_ptr<ModuleFileExtension>>(),
167  /*AllowASTWithErrors=*/true),
168  Action(Action), Out(std::move(Out)) {}
169 
170  bool HandleTopLevelDecl(DeclGroupRef DG) override {
171  Action.Callbacks.HandleTopLevelDecl(DG);
172  return true;
173  }
174 
175  void HandleTranslationUnit(ASTContext &Ctx) override {
177  if (!hasEmittedPCH())
178  return;
179 
180  // Write the generated bitstream to "Out".
181  *Out << getPCH();
182  // Make sure it hits disk now.
183  Out->flush();
184  // Free the buffer.
186  getPCH() = std::move(Empty);
187 
188  Action.setEmittedPreamblePCH(getWriter());
189  }
190 
191 private:
192  PrecompilePreambleAction &Action;
193  std::unique_ptr<raw_ostream> Out;
194 };
195 
196 std::unique_ptr<ASTConsumer>
197 PrecompilePreambleAction::CreateASTConsumer(CompilerInstance &CI,
198  StringRef InFile) {
199  std::string Sysroot;
201  return nullptr;
202 
203  std::unique_ptr<llvm::raw_ostream> OS;
204  if (InMemStorage) {
205  OS = llvm::make_unique<llvm::raw_string_ostream>(*InMemStorage);
206  } else {
207  std::string OutputFile;
208  OS = GeneratePCHAction::CreateOutputFile(CI, InFile, OutputFile);
209  }
210  if (!OS)
211  return nullptr;
212 
214  Sysroot.clear();
215 
216  return llvm::make_unique<PrecompilePreambleConsumer>(
217  *this, CI.getPreprocessor(), CI.getModuleCache(), Sysroot, std::move(OS));
218 }
219 
220 template <class T> bool moveOnNoError(llvm::ErrorOr<T> Val, T &Output) {
221  if (!Val)
222  return false;
223  Output = std::move(*Val);
224  return true;
225 }
226 
227 } // namespace
228 
230  llvm::MemoryBuffer *Buffer,
231  unsigned MaxLines) {
232  return Lexer::ComputePreamble(Buffer->getBuffer(), LangOpts, MaxLines);
233 }
234 
235 llvm::ErrorOr<PrecompiledPreamble> PrecompiledPreamble::Build(
236  const CompilerInvocation &Invocation,
237  const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds,
238  DiagnosticsEngine &Diagnostics,
240  std::shared_ptr<PCHContainerOperations> PCHContainerOps, bool StoreInMemory,
241  PreambleCallbacks &Callbacks) {
242  assert(VFS && "VFS is null");
243 
244  auto PreambleInvocation = std::make_shared<CompilerInvocation>(Invocation);
245  FrontendOptions &FrontendOpts = PreambleInvocation->getFrontendOpts();
246  PreprocessorOptions &PreprocessorOpts =
247  PreambleInvocation->getPreprocessorOpts();
248 
250  if (!StoreInMemory) {
251  // Create a temporary file for the precompiled preamble. In rare
252  // circumstances, this can fail.
253  llvm::ErrorOr<PrecompiledPreamble::TempPCHFile> PreamblePCHFile =
254  PrecompiledPreamble::TempPCHFile::CreateNewPreamblePCHFile();
255  if (!PreamblePCHFile)
257  TempFile = std::move(*PreamblePCHFile);
258  }
259 
260  PCHStorage Storage = StoreInMemory ? PCHStorage(InMemoryPreamble())
261  : PCHStorage(std::move(*TempFile));
262 
263  // Save the preamble text for later; we'll need to compare against it for
264  // subsequent reparses.
265  std::vector<char> PreambleBytes(MainFileBuffer->getBufferStart(),
266  MainFileBuffer->getBufferStart() +
267  Bounds.Size);
268  bool PreambleEndsAtStartOfLine = Bounds.PreambleEndsAtStartOfLine;
269 
270  // Tell the compiler invocation to generate a temporary precompiled header.
271  FrontendOpts.ProgramAction = frontend::GeneratePCH;
272  FrontendOpts.OutputFile = StoreInMemory ? getInMemoryPreamblePath()
273  : Storage.asFile().getFilePath();
274  PreprocessorOpts.PrecompiledPreambleBytes.first = 0;
275  PreprocessorOpts.PrecompiledPreambleBytes.second = false;
276  // Inform preprocessor to record conditional stack when building the preamble.
277  PreprocessorOpts.GeneratePreamble = true;
278 
279  // Create the compiler instance to use for building the precompiled preamble.
280  std::unique_ptr<CompilerInstance> Clang(
281  new CompilerInstance(std::move(PCHContainerOps)));
282 
283  // Recover resources if we crash before exiting this method.
284  llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance> CICleanup(
285  Clang.get());
286 
287  Clang->setInvocation(std::move(PreambleInvocation));
288  Clang->setDiagnostics(&Diagnostics);
289 
290  // Create the target instance.
291  Clang->setTarget(TargetInfo::CreateTargetInfo(
292  Clang->getDiagnostics(), Clang->getInvocation().TargetOpts));
293  if (!Clang->hasTarget())
295 
296  // Inform the target of the language options.
297  //
298  // FIXME: We shouldn't need to do this, the target should be immutable once
299  // created. This complexity should be lifted elsewhere.
300  Clang->getTarget().adjust(Clang->getLangOpts());
301 
302  if (Clang->getFrontendOpts().Inputs.size() != 1 ||
303  Clang->getFrontendOpts().Inputs[0].getKind().getFormat() !=
305  Clang->getFrontendOpts().Inputs[0].getKind().getLanguage() ==
308  }
309 
310  // Clear out old caches and data.
311  Diagnostics.Reset();
312  ProcessWarningOptions(Diagnostics, Clang->getDiagnosticOpts());
313 
314  VFS =
315  createVFSFromCompilerInvocation(Clang->getInvocation(), Diagnostics, VFS);
316 
317  // Create a file manager object to provide access to and cache the filesystem.
318  Clang->setFileManager(new FileManager(Clang->getFileSystemOpts(), VFS));
319 
320  // Create the source manager.
321  Clang->setSourceManager(
322  new SourceManager(Diagnostics, Clang->getFileManager()));
323 
324  auto PreambleDepCollector = std::make_shared<PreambleDependencyCollector>();
325  Clang->addDependencyCollector(PreambleDepCollector);
326 
327  // Remap the main source file to the preamble buffer.
328  StringRef MainFilePath = FrontendOpts.Inputs[0].getFile();
329  auto PreambleInputBuffer = llvm::MemoryBuffer::getMemBufferCopy(
330  MainFileBuffer->getBuffer().slice(0, Bounds.Size), MainFilePath);
331  if (PreprocessorOpts.RetainRemappedFileBuffers) {
332  // MainFileBuffer will be deleted by unique_ptr after leaving the method.
333  PreprocessorOpts.addRemappedFile(MainFilePath, PreambleInputBuffer.get());
334  } else {
335  // In that case, remapped buffer will be deleted by CompilerInstance on
336  // BeginSourceFile, so we call release() to avoid double deletion.
337  PreprocessorOpts.addRemappedFile(MainFilePath,
338  PreambleInputBuffer.release());
339  }
340 
341  std::unique_ptr<PrecompilePreambleAction> Act;
342  Act.reset(new PrecompilePreambleAction(
343  StoreInMemory ? &Storage.asMemory().Data : nullptr, Callbacks));
344  Callbacks.BeforeExecute(*Clang);
345  if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0]))
347 
348  std::unique_ptr<PPCallbacks> DelegatedPPCallbacks =
349  Callbacks.createPPCallbacks();
350  if (DelegatedPPCallbacks)
351  Clang->getPreprocessor().addPPCallbacks(std::move(DelegatedPPCallbacks));
352  if (auto CommentHandler = Callbacks.getCommentHandler())
353  Clang->getPreprocessor().addCommentHandler(CommentHandler);
354 
355  if (llvm::Error Err = Act->Execute())
356  return errorToErrorCode(std::move(Err));
357 
358  // Run the callbacks.
359  Callbacks.AfterExecute(*Clang);
360 
361  Act->EndSourceFile();
362 
363  if (!Act->hasEmittedPreamblePCH())
365 
366  // Keep track of all of the files that the source manager knows about,
367  // so we can verify whether they have changed or not.
368  llvm::StringMap<PrecompiledPreamble::PreambleFileHash> FilesInPreamble;
369 
370  SourceManager &SourceMgr = Clang->getSourceManager();
371  for (auto &Filename : PreambleDepCollector->getDependencies()) {
372  const FileEntry *File = Clang->getFileManager().getFile(Filename);
373  if (!File || File == SourceMgr.getFileEntryForID(SourceMgr.getMainFileID()))
374  continue;
375  if (time_t ModTime = File->getModificationTime()) {
376  FilesInPreamble[File->getName()] =
377  PrecompiledPreamble::PreambleFileHash::createForFile(File->getSize(),
378  ModTime);
379  } else {
380  const llvm::MemoryBuffer *Buffer = SourceMgr.getMemoryBufferForFile(File);
381  FilesInPreamble[File->getName()] =
382  PrecompiledPreamble::PreambleFileHash::createForMemoryBuffer(Buffer);
383  }
384  }
385 
386  return PrecompiledPreamble(std::move(Storage), std::move(PreambleBytes),
387  PreambleEndsAtStartOfLine,
388  std::move(FilesInPreamble));
389 }
390 
392  return PreambleBounds(PreambleBytes.size(), PreambleEndsAtStartOfLine);
393 }
394 
396  switch (Storage.getKind()) {
397  case PCHStorage::Kind::Empty:
398  assert(false && "Calling getSize() on invalid PrecompiledPreamble. "
399  "Was it std::moved?");
400  return 0;
401  case PCHStorage::Kind::InMemory:
402  return Storage.asMemory().Data.size();
403  case PCHStorage::Kind::TempFile: {
404  uint64_t Result;
405  if (llvm::sys::fs::file_size(Storage.asFile().getFilePath(), Result))
406  return 0;
407 
408  assert(Result <= std::numeric_limits<std::size_t>::max() &&
409  "file size did not fit into size_t");
410  return Result;
411  }
412  }
413  llvm_unreachable("Unhandled storage kind");
414 }
415 
417  const llvm::MemoryBuffer *MainFileBuffer,
418  PreambleBounds Bounds,
419  llvm::vfs::FileSystem *VFS) const {
420 
421  assert(
422  Bounds.Size <= MainFileBuffer->getBufferSize() &&
423  "Buffer is too large. Bounds were calculated from a different buffer?");
424 
425  auto PreambleInvocation = std::make_shared<CompilerInvocation>(Invocation);
426  PreprocessorOptions &PreprocessorOpts =
427  PreambleInvocation->getPreprocessorOpts();
428 
429  // We've previously computed a preamble. Check whether we have the same
430  // preamble now that we did before, and that there's enough space in
431  // the main-file buffer within the precompiled preamble to fit the
432  // new main file.
433  if (PreambleBytes.size() != Bounds.Size ||
434  PreambleEndsAtStartOfLine != Bounds.PreambleEndsAtStartOfLine ||
435  !std::equal(PreambleBytes.begin(), PreambleBytes.end(),
436  MainFileBuffer->getBuffer().begin()))
437  return false;
438  // The preamble has not changed. We may be able to re-use the precompiled
439  // preamble.
440 
441  // Check that none of the files used by the preamble have changed.
442  // First, make a record of those files that have been overridden via
443  // remapping or unsaved_files.
444  std::map<llvm::sys::fs::UniqueID, PreambleFileHash> OverriddenFiles;
445  for (const auto &R : PreprocessorOpts.RemappedFiles) {
446  llvm::vfs::Status Status;
447  if (!moveOnNoError(VFS->status(R.second), Status)) {
448  // If we can't stat the file we're remapping to, assume that something
449  // horrible happened.
450  return false;
451  }
452 
453  OverriddenFiles[Status.getUniqueID()] = PreambleFileHash::createForFile(
454  Status.getSize(), llvm::sys::toTimeT(Status.getLastModificationTime()));
455  }
456 
457  // OverridenFileBuffers tracks only the files not found in VFS.
458  llvm::StringMap<PreambleFileHash> OverridenFileBuffers;
459  for (const auto &RB : PreprocessorOpts.RemappedFileBuffers) {
460  const PrecompiledPreamble::PreambleFileHash PreambleHash =
461  PreambleFileHash::createForMemoryBuffer(RB.second);
462  llvm::vfs::Status Status;
463  if (moveOnNoError(VFS->status(RB.first), Status))
464  OverriddenFiles[Status.getUniqueID()] = PreambleHash;
465  else
466  OverridenFileBuffers[RB.first] = PreambleHash;
467  }
468 
469  // Check whether anything has changed.
470  for (const auto &F : FilesInPreamble) {
471  auto OverridenFileBuffer = OverridenFileBuffers.find(F.first());
472  if (OverridenFileBuffer != OverridenFileBuffers.end()) {
473  // The file's buffer was remapped and the file was not found in VFS.
474  // Check whether it matches up with the previous mapping.
475  if (OverridenFileBuffer->second != F.second)
476  return false;
477  continue;
478  }
479 
480  llvm::vfs::Status Status;
481  if (!moveOnNoError(VFS->status(F.first()), Status)) {
482  // If the file's buffer is not remapped and we can't stat it,
483  // assume that something horrible happened.
484  return false;
485  }
486 
487  std::map<llvm::sys::fs::UniqueID, PreambleFileHash>::iterator Overridden =
488  OverriddenFiles.find(Status.getUniqueID());
489  if (Overridden != OverriddenFiles.end()) {
490  // This file was remapped; check whether the newly-mapped file
491  // matches up with the previous mapping.
492  if (Overridden->second != F.second)
493  return false;
494  continue;
495  }
496 
497  // Neither the file's buffer nor the file itself was remapped;
498  // check whether it has changed on disk.
499  if (Status.getSize() != uint64_t(F.second.Size) ||
500  llvm::sys::toTimeT(Status.getLastModificationTime()) !=
501  F.second.ModTime)
502  return false;
503  }
504  return true;
505 }
506 
509  llvm::MemoryBuffer *MainFileBuffer) const {
510  PreambleBounds Bounds(PreambleBytes.size(), PreambleEndsAtStartOfLine);
511  configurePreamble(Bounds, CI, VFS, MainFileBuffer);
512 }
513 
516  llvm::MemoryBuffer *MainFileBuffer) const {
517  auto Bounds = ComputePreambleBounds(*CI.getLangOpts(), MainFileBuffer, 0);
518  configurePreamble(Bounds, CI, VFS, MainFileBuffer);
519 }
520 
522  PCHStorage Storage, std::vector<char> PreambleBytes,
523  bool PreambleEndsAtStartOfLine,
524  llvm::StringMap<PreambleFileHash> FilesInPreamble)
525  : Storage(std::move(Storage)), FilesInPreamble(std::move(FilesInPreamble)),
526  PreambleBytes(std::move(PreambleBytes)),
527  PreambleEndsAtStartOfLine(PreambleEndsAtStartOfLine) {
528  assert(this->Storage.getKind() != PCHStorage::Kind::Empty);
529 }
530 
531 llvm::ErrorOr<PrecompiledPreamble::TempPCHFile>
532 PrecompiledPreamble::TempPCHFile::CreateNewPreamblePCHFile() {
533  // FIXME: This is a hack so that we can override the preamble file during
534  // crash-recovery testing, which is the only case where the preamble files
535  // are not necessarily cleaned up.
536  const char *TmpFile = ::getenv("CINDEXTEST_PREAMBLE_FILE");
537  if (TmpFile)
538  return TempPCHFile::createFromCustomPath(TmpFile);
539  return TempPCHFile::createInSystemTempDir("preamble", "pch");
540 }
541 
542 llvm::ErrorOr<PrecompiledPreamble::TempPCHFile>
543 PrecompiledPreamble::TempPCHFile::createInSystemTempDir(const Twine &Prefix,
544  StringRef Suffix) {
546  // Using a version of createTemporaryFile with a file descriptor guarantees
547  // that we would never get a race condition in a multi-threaded setting
548  // (i.e., multiple threads getting the same temporary path).
549  int FD;
550  auto EC = llvm::sys::fs::createTemporaryFile(Prefix, Suffix, FD, File);
551  if (EC)
552  return EC;
553  // We only needed to make sure the file exists, close the file right away.
554  llvm::sys::Process::SafelyCloseFileDescriptor(FD);
555  return TempPCHFile(std::move(File).str());
556 }
557 
558 llvm::ErrorOr<PrecompiledPreamble::TempPCHFile>
559 PrecompiledPreamble::TempPCHFile::createFromCustomPath(const Twine &Path) {
560  return TempPCHFile(Path.str());
561 }
562 
563 PrecompiledPreamble::TempPCHFile::TempPCHFile(std::string FilePath)
564  : FilePath(std::move(FilePath)) {
565  TemporaryFiles::getInstance().addFile(*this->FilePath);
566 }
567 
568 PrecompiledPreamble::TempPCHFile::TempPCHFile(TempPCHFile &&Other) {
569  FilePath = std::move(Other.FilePath);
570  Other.FilePath = None;
571 }
572 
573 PrecompiledPreamble::TempPCHFile &PrecompiledPreamble::TempPCHFile::
574 operator=(TempPCHFile &&Other) {
575  RemoveFileIfPresent();
576 
577  FilePath = std::move(Other.FilePath);
578  Other.FilePath = None;
579  return *this;
580 }
581 
582 PrecompiledPreamble::TempPCHFile::~TempPCHFile() { RemoveFileIfPresent(); }
583 
584 void PrecompiledPreamble::TempPCHFile::RemoveFileIfPresent() {
585  if (FilePath) {
586  TemporaryFiles::getInstance().removeFile(*FilePath);
587  FilePath = None;
588  }
589 }
590 
591 llvm::StringRef PrecompiledPreamble::TempPCHFile::getFilePath() const {
592  assert(FilePath && "TempPCHFile doesn't have a FilePath. Had it been moved?");
593  return *FilePath;
594 }
595 
596 PrecompiledPreamble::PCHStorage::PCHStorage(TempPCHFile File)
597  : StorageKind(Kind::TempFile) {
598  new (&asFile()) TempPCHFile(std::move(File));
599 }
600 
601 PrecompiledPreamble::PCHStorage::PCHStorage(InMemoryPreamble Memory)
602  : StorageKind(Kind::InMemory) {
603  new (&asMemory()) InMemoryPreamble(std::move(Memory));
604 }
605 
606 PrecompiledPreamble::PCHStorage::PCHStorage(PCHStorage &&Other) : PCHStorage() {
607  *this = std::move(Other);
608 }
609 
610 PrecompiledPreamble::PCHStorage &PrecompiledPreamble::PCHStorage::
611 operator=(PCHStorage &&Other) {
612  destroy();
613 
614  StorageKind = Other.StorageKind;
615  switch (StorageKind) {
616  case Kind::Empty:
617  // do nothing;
618  break;
619  case Kind::TempFile:
620  new (&asFile()) TempPCHFile(std::move(Other.asFile()));
621  break;
622  case Kind::InMemory:
623  new (&asMemory()) InMemoryPreamble(std::move(Other.asMemory()));
624  break;
625  }
626 
627  Other.setEmpty();
628  return *this;
629 }
630 
631 PrecompiledPreamble::PCHStorage::~PCHStorage() { destroy(); }
632 
633 PrecompiledPreamble::PCHStorage::Kind
635  return StorageKind;
636 }
637 
638 PrecompiledPreamble::TempPCHFile &PrecompiledPreamble::PCHStorage::asFile() {
639  assert(getKind() == Kind::TempFile);
640  return *reinterpret_cast<TempPCHFile *>(Storage.buffer);
641 }
642 
643 const PrecompiledPreamble::TempPCHFile &
644 PrecompiledPreamble::PCHStorage::asFile() const {
645  return const_cast<PCHStorage *>(this)->asFile();
646 }
647 
648 PrecompiledPreamble::InMemoryPreamble &
649 PrecompiledPreamble::PCHStorage::asMemory() {
650  assert(getKind() == Kind::InMemory);
651  return *reinterpret_cast<InMemoryPreamble *>(Storage.buffer);
652 }
653 
654 const PrecompiledPreamble::InMemoryPreamble &
655 PrecompiledPreamble::PCHStorage::asMemory() const {
656  return const_cast<PCHStorage *>(this)->asMemory();
657 }
658 
659 void PrecompiledPreamble::PCHStorage::destroy() {
660  switch (StorageKind) {
661  case Kind::Empty:
662  return;
663  case Kind::TempFile:
664  asFile().~TempPCHFile();
665  return;
666  case Kind::InMemory:
667  asMemory().~InMemoryPreamble();
668  return;
669  }
670 }
671 
672 void PrecompiledPreamble::PCHStorage::setEmpty() {
673  destroy();
674  StorageKind = Kind::Empty;
675 }
676 
677 PrecompiledPreamble::PreambleFileHash
678 PrecompiledPreamble::PreambleFileHash::createForFile(off_t Size,
679  time_t ModTime) {
680  PreambleFileHash Result;
681  Result.Size = Size;
682  Result.ModTime = ModTime;
683  Result.MD5 = {};
684  return Result;
685 }
686 
687 PrecompiledPreamble::PreambleFileHash
688 PrecompiledPreamble::PreambleFileHash::createForMemoryBuffer(
689  const llvm::MemoryBuffer *Buffer) {
690  PreambleFileHash Result;
691  Result.Size = Buffer->getBufferSize();
692  Result.ModTime = 0;
693 
694  llvm::MD5 MD5Ctx;
695  MD5Ctx.update(Buffer->getBuffer().data());
696  MD5Ctx.final(Result.MD5);
697 
698  return Result;
699 }
700 
701 void PrecompiledPreamble::configurePreamble(
704  llvm::MemoryBuffer *MainFileBuffer) const {
705  assert(VFS);
706 
707  auto &PreprocessorOpts = CI.getPreprocessorOpts();
708 
709  // Remap main file to point to MainFileBuffer.
710  auto MainFilePath = CI.getFrontendOpts().Inputs[0].getFile();
711  PreprocessorOpts.addRemappedFile(MainFilePath, MainFileBuffer);
712 
713  // Configure ImpicitPCHInclude.
714  PreprocessorOpts.PrecompiledPreambleBytes.first = Bounds.Size;
715  PreprocessorOpts.PrecompiledPreambleBytes.second =
717  PreprocessorOpts.DisablePCHValidation = true;
718 
719  setupPreambleStorage(Storage, PreprocessorOpts, VFS);
720 }
721 
722 void PrecompiledPreamble::setupPreambleStorage(
723  const PCHStorage &Storage, PreprocessorOptions &PreprocessorOpts,
725  if (Storage.getKind() == PCHStorage::Kind::TempFile) {
726  const TempPCHFile &PCHFile = Storage.asFile();
727  PreprocessorOpts.ImplicitPCHInclude = PCHFile.getFilePath();
728 
729  // Make sure we can access the PCH file even if we're using a VFS
731  llvm::vfs::getRealFileSystem();
732  auto PCHPath = PCHFile.getFilePath();
733  if (VFS == RealFS || VFS->exists(PCHPath))
734  return;
735  auto Buf = RealFS->getBufferForFile(PCHPath);
736  if (!Buf) {
737  // We can't read the file even from RealFS, this is clearly an error,
738  // but we'll just leave the current VFS as is and let clang's code
739  // figure out what to do with missing PCH.
740  return;
741  }
742 
743  // We have a slight inconsistency here -- we're using the VFS to
744  // read files, but the PCH was generated in the real file system.
745  VFS = createVFSOverlayForPreamblePCH(PCHPath, std::move(*Buf), VFS);
746  } else {
747  assert(Storage.getKind() == PCHStorage::Kind::InMemory);
748  // For in-memory preamble, we have to provide a VFS overlay that makes it
749  // accessible.
750  StringRef PCHPath = getInMemoryPreamblePath();
751  PreprocessorOpts.ImplicitPCHInclude = PCHPath;
752 
753  auto Buf = llvm::MemoryBuffer::getMemBuffer(Storage.asMemory().Data);
754  VFS = createVFSOverlayForPreamblePCH(PCHPath, std::move(Buf), VFS);
755  }
756 }
757 
762 std::unique_ptr<PPCallbacks> PreambleCallbacks::createPPCallbacks() {
763  return nullptr;
764 }
766 
767 static llvm::ManagedStatic<BuildPreambleErrorCategory> BuildPreambleErrCategory;
768 
770  return std::error_code(static_cast<int>(Error), *BuildPreambleErrCategory);
771 }
772 
773 const char *BuildPreambleErrorCategory::name() const noexcept {
774  return "build-preamble.error";
775 }
776 
777 std::string BuildPreambleErrorCategory::message(int condition) const {
778  switch (static_cast<BuildPreambleError>(condition)) {
780  return "Could not create temporary file for PCH";
782  return "CreateTargetInfo() return null";
784  return "BeginSourceFile() return an error";
786  return "Could not emit PCH";
788  return "Command line arguments must contain exactly one source file";
789  }
790  llvm_unreachable("unexpected BuildPreambleError");
791 }
std::size_t getSize() const
Returns the size, in bytes, that preamble takes on disk or in memory.
Describes the bounds (start, size) of the preamble and a flag required by PreprocessorOptions::Precom...
Definition: Lexer.h:58
Implements support for file system lookup, file system caching, and directory search management...
Definition: FileManager.h:116
time_t getModificationTime() const
Definition: FileManager.h:89
bool CanReuse(const CompilerInvocation &Invocation, const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds, llvm::vfs::FileSystem *VFS) const
Check whether PrecompiledPreamble can be reused for the new contents(MainFileBuffer) of the main file...
An interface for collecting the dependencies of a compilation.
Definition: Utils.h:81
The translation unit is a prefix to a translation unit, and is not complete.
Definition: LangOptions.h:368
InMemoryModuleCache & getModuleCache() const
PreprocessorOptions - This class is used for passing the various options used in preprocessor initial...
void addRemappedFile(StringRef From, StringRef To)
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:154
void HandleTranslationUnit(ASTContext &Ctx) override
HandleTranslationUnit - This method is called when the ASTs for entire translation unit have been par...
Definition: GeneratePCH.cpp:41
Definition: Format.h:2274
static bool moveOnNoError(llvm::ErrorOr< T > Val, T &Output)
Definition: ASTUnit.cpp:146
__SIZE_TYPE__ size_t
The unsigned integer type of the result of the sizeof operator.
Definition: opencl-c-base.h:40
__DEVICE__ int max(int __a, int __b)
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:49
unsigned RelocatablePCH
When generating PCH files, instruct the AST writer to create relocatable PCH files.
static bool ComputeASTConsumerArguments(CompilerInstance &CI, std::string &Sysroot)
Compute the AST consumer arguments that will be used to create the PCHGenerator instance returned by ...
static llvm::ManagedStatic< BuildPreambleErrorCategory > BuildPreambleErrCategory
std::error_code make_error_code(BuildPreambleError Error)
FrontendOptions & getFrontendOpts()
Concrete class used by the front-end to report problems and issues.
Definition: Diagnostic.h:149
bool RetainRemappedFileBuffers
Whether the compiler instance should retain (i.e., not free) the buffers associated with remapped fil...
void OverridePreamble(CompilerInvocation &CI, IntrusiveRefCntPtr< llvm::vfs::FileSystem > &VFS, llvm::MemoryBuffer *MainFileBuffer) const
Configure CI to use this preamble.
void Reset()
Reset the state of the diagnostic object to its initial configuration.
Definition: Diagnostic.cpp:121
FrontendOptions & getFrontendOpts()
bool PreambleEndsAtStartOfLine
Whether the preamble ends at the start of a new line.
Definition: Lexer.h:66
A set of callbacks to gather useful information while building a preamble.
StringRef Filename
Definition: Format.cpp:1711
const char * name() const noexcept override
PreambleBounds getBounds() const
PreambleBounds used to build the preamble.
void AddImplicitPreamble(CompilerInvocation &CI, IntrusiveRefCntPtr< llvm::vfs::FileSystem > &VFS, llvm::MemoryBuffer *MainFileBuffer) const
Changes options inside CI to use PCH from this preamble.
static PreambleBounds ComputePreamble(StringRef Buffer, const LangOptions &LangOpts, unsigned MaxLines=0)
Compute the preamble of the given file.
Definition: Lexer.cpp:573
const FileEntry * getFileEntryForID(FileID FID) const
Returns the FileEntry record for the provided FileID.
Defines the clang::Preprocessor interface.
ASTEdit remove(RangeSelector S)
Removes the source selected by S.
Definition: Transformer.h:232
static TargetInfo * CreateTargetInfo(DiagnosticsEngine &Diags, const std::shared_ptr< TargetOptions > &Opts)
Construct a target for the given options.
Definition: Targets.cpp:602
bool GeneratePreamble
True indicates that a preamble is being generated.
PreambleBounds ComputePreambleBounds(const LangOptions &LangOpts, llvm::MemoryBuffer *Buffer, unsigned MaxLines)
Runs lexer to compute suggested preamble bounds.
The result type of a method or function.
In-memory cache for modules.
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
StringRef getName() const
Definition: FileManager.h:83
virtual CommentHandler * getCommentHandler()
The returned CommentHandler will be added to the preprocessor if not null.
std::string ImplicitPCHInclude
The implicit PCH included at the start of the translation unit, or empty.
LLVM IR: we accept this so that we can run the optimizer on it, and compile it to assembly or object ...
std::vector< FrontendInputFile > Inputs
The input files and their types.
Cached information about one file (either on disk or in the virtual file system). ...
Definition: FileManager.h:59
void ProcessWarningOptions(DiagnosticsEngine &Diags, const DiagnosticOptions &Opts, bool ReportDiags=true)
ProcessWarningOptions - Initialize the diagnostic client and process the warning options specified on...
Definition: Warnings.cpp:43
Abstract base class to use for AST consumer-based frontend actions.
virtual void BeforeExecute(CompilerInstance &CI)
Called before FrontendAction::BeginSourceFile.
virtual void AfterPCHEmitted(ASTWriter &Writer)
Called after PCH has been emitted.
PrecompiledPreamble(PrecompiledPreamble &&)=default
std::string message(int condition) const override
Dataflow Directional Tag Classes.
A class holding a PCH and all information to check whether it is valid to reuse the PCH for the subse...
PreprocessorOptions & getPreprocessorOpts()
off_t getSize() const
Definition: FileManager.h:86
IntrusiveRefCntPtr< llvm::vfs::FileSystem > createVFSFromCompilerInvocation(const CompilerInvocation &CI, DiagnosticsEngine &Diags)
const llvm::MemoryBuffer * getMemoryBufferForFile(const FileEntry *File, bool *Invalid=nullptr)
Retrieve the memory buffer associated with the given file.
FileID getMainFileID() const
Returns the FileID of the main source file.
Helper class for holding the data necessary to invoke the compiler.
FrontendOptions - Options for controlling the behavior of the frontend.
virtual void AfterExecute(CompilerInstance &CI)
Called after FrontendAction::Execute(), but before FrontendAction::EndSourceFile().
static llvm::ErrorOr< PrecompiledPreamble > Build(const CompilerInvocation &Invocation, const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds, DiagnosticsEngine &Diagnostics, IntrusiveRefCntPtr< llvm::vfs::FileSystem > VFS, std::shared_ptr< PCHContainerOperations > PCHContainerOps, bool StoreInMemory, PreambleCallbacks &Callbacks)
Try to build PrecompiledPreamble for Invocation.
Indicates that the tracking object is a descendant of a referenced-counted OSObject, used in the Darwin kernel.
unsigned Size
Size of the preamble in bytes.
Definition: Lexer.h:60
Generate pre-compiled header.
Preprocessor & getPreprocessor() const
Return the current preprocessor.
TranslationUnitKind
Describes the kind of translation unit being processed.
Definition: LangOptions.h:362
Writes an AST file containing the contents of a translation unit.
Definition: ASTWriter.h:103
std::pair< unsigned, bool > PrecompiledPreambleBytes
If non-zero, the implicit PCH include is actually a precompiled preamble that covers this number of b...
Defines the clang::TargetInfo interface.
static Decl::Kind getKind(const Decl *D)
Definition: DeclBase.cpp:944
Abstract base class that describes a handler that will receive source ranges for each of the comments...
An abstract superclass that describes a custom extension to the module/precompiled header file format...
AST and semantic-analysis consumer that generates a precompiled header from the parsed source code...
Definition: ASTWriter.h:972
static std::unique_ptr< llvm::raw_pwrite_stream > CreateOutputFile(CompilerInstance &CI, StringRef InFile, std::string &OutputFile)
Creates file to write the PCH into and returns a stream to write it into.
#define true
Definition: stdbool.h:16
virtual void HandleTopLevelDecl(DeclGroupRef DG)
Called for each TopLevelDecl.
This class handles loading and caching of source files into memory.
virtual std::unique_ptr< PPCallbacks > createPPCallbacks()
Creates wrapper class for PPCallbacks so we can also process information about includes that are insi...
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
Definition: Preprocessor.h:124