clang  8.0.0svn
PrecompiledPreamble.cpp
Go to the documentation of this file.
1 //===--- PrecompiledPreamble.cpp - Build precompiled preambles --*- C++ -*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // Helper class to build precompiled preamble.
11 //
12 //===----------------------------------------------------------------------===//
13 
15 #include "clang/AST/DeclObjC.h"
16 #include "clang/Basic/TargetInfo.h"
22 #include "clang/Lex/Lexer.h"
25 #include "llvm/ADT/StringExtras.h"
26 #include "llvm/ADT/StringSet.h"
27 #include "llvm/Config/llvm-config.h"
28 #include "llvm/Support/CrashRecoveryContext.h"
29 #include "llvm/Support/FileSystem.h"
30 #include "llvm/Support/Mutex.h"
31 #include "llvm/Support/MutexGuard.h"
32 #include "llvm/Support/Process.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.
59  PCHFS->addFile(PCHFilename, 0, std::move(PCHBuffer));
61  new 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, StringRef isysroot,
161  std::unique_ptr<raw_ostream> Out)
162  : PCHGenerator(PP, "", isysroot, std::make_shared<PCHBuffer>(),
163  ArrayRef<std::shared_ptr<ModuleFileExtension>>(),
164  /*AllowASTWithErrors=*/true),
165  Action(Action), Out(std::move(Out)) {}
166 
167  bool HandleTopLevelDecl(DeclGroupRef DG) override {
168  Action.Callbacks.HandleTopLevelDecl(DG);
169  return true;
170  }
171 
172  void HandleTranslationUnit(ASTContext &Ctx) override {
174  if (!hasEmittedPCH())
175  return;
176 
177  // Write the generated bitstream to "Out".
178  *Out << getPCH();
179  // Make sure it hits disk now.
180  Out->flush();
181  // Free the buffer.
183  getPCH() = std::move(Empty);
184 
185  Action.setEmittedPreamblePCH(getWriter());
186  }
187 
188 private:
189  PrecompilePreambleAction &Action;
190  std::unique_ptr<raw_ostream> Out;
191 };
192 
193 std::unique_ptr<ASTConsumer>
194 PrecompilePreambleAction::CreateASTConsumer(CompilerInstance &CI,
195  StringRef InFile) {
196  std::string Sysroot;
198  return nullptr;
199 
200  std::unique_ptr<llvm::raw_ostream> OS;
201  if (InMemStorage) {
202  OS = llvm::make_unique<llvm::raw_string_ostream>(*InMemStorage);
203  } else {
204  std::string OutputFile;
205  OS = GeneratePCHAction::CreateOutputFile(CI, InFile, OutputFile);
206  }
207  if (!OS)
208  return nullptr;
209 
211  Sysroot.clear();
212 
213  return llvm::make_unique<PrecompilePreambleConsumer>(
214  *this, CI.getPreprocessor(), Sysroot, std::move(OS));
215 }
216 
217 template <class T> bool moveOnNoError(llvm::ErrorOr<T> Val, T &Output) {
218  if (!Val)
219  return false;
220  Output = std::move(*Val);
221  return true;
222 }
223 
224 } // namespace
225 
227  llvm::MemoryBuffer *Buffer,
228  unsigned MaxLines) {
229  return Lexer::ComputePreamble(Buffer->getBuffer(), LangOpts, MaxLines);
230 }
231 
232 llvm::ErrorOr<PrecompiledPreamble> PrecompiledPreamble::Build(
233  const CompilerInvocation &Invocation,
234  const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds,
236  std::shared_ptr<PCHContainerOperations> PCHContainerOps, bool StoreInMemory,
237  PreambleCallbacks &Callbacks) {
238  assert(VFS && "VFS is null");
239 
240  if (!Bounds.Size)
242 
243  auto PreambleInvocation = std::make_shared<CompilerInvocation>(Invocation);
244  FrontendOptions &FrontendOpts = PreambleInvocation->getFrontendOpts();
245  PreprocessorOptions &PreprocessorOpts =
246  PreambleInvocation->getPreprocessorOpts();
247 
249  if (!StoreInMemory) {
250  // Create a temporary file for the precompiled preamble. In rare
251  // circumstances, this can fail.
252  llvm::ErrorOr<PrecompiledPreamble::TempPCHFile> PreamblePCHFile =
253  PrecompiledPreamble::TempPCHFile::CreateNewPreamblePCHFile();
254  if (!PreamblePCHFile)
256  TempFile = std::move(*PreamblePCHFile);
257  }
258 
259  PCHStorage Storage = StoreInMemory ? PCHStorage(InMemoryPreamble())
260  : PCHStorage(std::move(*TempFile));
261 
262  // Save the preamble text for later; we'll need to compare against it for
263  // subsequent reparses.
264  std::vector<char> PreambleBytes(MainFileBuffer->getBufferStart(),
265  MainFileBuffer->getBufferStart() +
266  Bounds.Size);
267  bool PreambleEndsAtStartOfLine = Bounds.PreambleEndsAtStartOfLine;
268 
269  // Tell the compiler invocation to generate a temporary precompiled header.
270  FrontendOpts.ProgramAction = frontend::GeneratePCH;
271  FrontendOpts.OutputFile = StoreInMemory ? getInMemoryPreamblePath()
272  : Storage.asFile().getFilePath();
273  PreprocessorOpts.PrecompiledPreambleBytes.first = 0;
274  PreprocessorOpts.PrecompiledPreambleBytes.second = false;
275  // Inform preprocessor to record conditional stack when building the preamble.
276  PreprocessorOpts.GeneratePreamble = true;
277 
278  // Create the compiler instance to use for building the precompiled preamble.
279  std::unique_ptr<CompilerInstance> Clang(
280  new CompilerInstance(std::move(PCHContainerOps)));
281 
282  // Recover resources if we crash before exiting this method.
283  llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance> CICleanup(
284  Clang.get());
285 
286  Clang->setInvocation(std::move(PreambleInvocation));
287  Clang->setDiagnostics(&Diagnostics);
288 
289  // Create the target instance.
290  Clang->setTarget(TargetInfo::CreateTargetInfo(
291  Clang->getDiagnostics(), Clang->getInvocation().TargetOpts));
292  if (!Clang->hasTarget())
294 
295  // Inform the target of the language options.
296  //
297  // FIXME: We shouldn't need to do this, the target should be immutable once
298  // created. This complexity should be lifted elsewhere.
299  Clang->getTarget().adjust(Clang->getLangOpts());
300 
301  assert(Clang->getFrontendOpts().Inputs.size() == 1 &&
302  "Invocation must have exactly one source file!");
303  assert(Clang->getFrontendOpts().Inputs[0].getKind().getFormat() ==
305  "FIXME: AST inputs not yet supported here!");
306  assert(Clang->getFrontendOpts().Inputs[0].getKind().getLanguage() !=
308  "IR inputs not support here!");
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 
353  Act->Execute();
354 
355  // Run the callbacks.
356  Callbacks.AfterExecute(*Clang);
357 
358  Act->EndSourceFile();
359 
360  if (!Act->hasEmittedPreamblePCH())
362 
363  // Keep track of all of the files that the source manager knows about,
364  // so we can verify whether they have changed or not.
365  llvm::StringMap<PrecompiledPreamble::PreambleFileHash> FilesInPreamble;
366 
367  SourceManager &SourceMgr = Clang->getSourceManager();
368  for (auto &Filename : PreambleDepCollector->getDependencies()) {
369  const FileEntry *File = Clang->getFileManager().getFile(Filename);
370  if (!File || File == SourceMgr.getFileEntryForID(SourceMgr.getMainFileID()))
371  continue;
372  if (time_t ModTime = File->getModificationTime()) {
373  FilesInPreamble[File->getName()] =
374  PrecompiledPreamble::PreambleFileHash::createForFile(File->getSize(),
375  ModTime);
376  } else {
377  llvm::MemoryBuffer *Buffer = SourceMgr.getMemoryBufferForFile(File);
378  FilesInPreamble[File->getName()] =
379  PrecompiledPreamble::PreambleFileHash::createForMemoryBuffer(Buffer);
380  }
381  }
382 
383  return PrecompiledPreamble(std::move(Storage), std::move(PreambleBytes),
384  PreambleEndsAtStartOfLine,
385  std::move(FilesInPreamble));
386 }
387 
389  return PreambleBounds(PreambleBytes.size(), PreambleEndsAtStartOfLine);
390 }
391 
393  switch (Storage.getKind()) {
394  case PCHStorage::Kind::Empty:
395  assert(false && "Calling getSize() on invalid PrecompiledPreamble. "
396  "Was it std::moved?");
397  return 0;
398  case PCHStorage::Kind::InMemory:
399  return Storage.asMemory().Data.size();
400  case PCHStorage::Kind::TempFile: {
401  uint64_t Result;
402  if (llvm::sys::fs::file_size(Storage.asFile().getFilePath(), Result))
403  return 0;
404 
405  assert(Result <= std::numeric_limits<std::size_t>::max() &&
406  "file size did not fit into size_t");
407  return Result;
408  }
409  }
410  llvm_unreachable("Unhandled storage kind");
411 }
412 
414  const llvm::MemoryBuffer *MainFileBuffer,
415  PreambleBounds Bounds,
416  vfs::FileSystem *VFS) const {
417 
418  assert(
419  Bounds.Size <= MainFileBuffer->getBufferSize() &&
420  "Buffer is too large. Bounds were calculated from a different buffer?");
421 
422  auto PreambleInvocation = std::make_shared<CompilerInvocation>(Invocation);
423  PreprocessorOptions &PreprocessorOpts =
424  PreambleInvocation->getPreprocessorOpts();
425 
426  if (!Bounds.Size)
427  return false;
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  memcmp(PreambleBytes.data(), MainFileBuffer->getBufferStart(),
436  Bounds.Size) != 0)
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  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  for (const auto &RB : PreprocessorOpts.RemappedFileBuffers) {
458  vfs::Status Status;
459  if (!moveOnNoError(VFS->status(RB.first), Status))
460  return false;
461 
462  OverriddenFiles[Status.getUniqueID()] =
463  PreambleFileHash::createForMemoryBuffer(RB.second);
464  }
465 
466  // Check whether anything has changed.
467  for (const auto &F : FilesInPreamble) {
468  vfs::Status Status;
469  if (!moveOnNoError(VFS->status(F.first()), Status)) {
470  // If we can't stat the file, assume that something horrible happened.
471  return false;
472  }
473 
474  std::map<llvm::sys::fs::UniqueID, PreambleFileHash>::iterator Overridden =
475  OverriddenFiles.find(Status.getUniqueID());
476  if (Overridden != OverriddenFiles.end()) {
477  // This file was remapped; check whether the newly-mapped file
478  // matches up with the previous mapping.
479  if (Overridden->second != F.second)
480  return false;
481  continue;
482  }
483 
484  // The file was not remapped; check whether it has changed on disk.
485  if (Status.getSize() != uint64_t(F.second.Size) ||
486  llvm::sys::toTimeT(Status.getLastModificationTime()) !=
487  F.second.ModTime)
488  return false;
489  }
490  return true;
491 }
492 
495  llvm::MemoryBuffer *MainFileBuffer) const {
496  PreambleBounds Bounds(PreambleBytes.size(), PreambleEndsAtStartOfLine);
497  configurePreamble(Bounds, CI, VFS, MainFileBuffer);
498 }
499 
502  llvm::MemoryBuffer *MainFileBuffer) const {
503  auto Bounds = ComputePreambleBounds(*CI.getLangOpts(), MainFileBuffer, 0);
504  configurePreamble(Bounds, CI, VFS, MainFileBuffer);
505 }
506 
508  PCHStorage Storage, std::vector<char> PreambleBytes,
509  bool PreambleEndsAtStartOfLine,
510  llvm::StringMap<PreambleFileHash> FilesInPreamble)
511  : Storage(std::move(Storage)), FilesInPreamble(std::move(FilesInPreamble)),
512  PreambleBytes(std::move(PreambleBytes)),
513  PreambleEndsAtStartOfLine(PreambleEndsAtStartOfLine) {
514  assert(this->Storage.getKind() != PCHStorage::Kind::Empty);
515 }
516 
517 llvm::ErrorOr<PrecompiledPreamble::TempPCHFile>
518 PrecompiledPreamble::TempPCHFile::CreateNewPreamblePCHFile() {
519  // FIXME: This is a hack so that we can override the preamble file during
520  // crash-recovery testing, which is the only case where the preamble files
521  // are not necessarily cleaned up.
522  const char *TmpFile = ::getenv("CINDEXTEST_PREAMBLE_FILE");
523  if (TmpFile)
524  return TempPCHFile::createFromCustomPath(TmpFile);
525  return TempPCHFile::createInSystemTempDir("preamble", "pch");
526 }
527 
528 llvm::ErrorOr<PrecompiledPreamble::TempPCHFile>
529 PrecompiledPreamble::TempPCHFile::createInSystemTempDir(const Twine &Prefix,
530  StringRef Suffix) {
532  // Using a version of createTemporaryFile with a file descriptor guarantees
533  // that we would never get a race condition in a multi-threaded setting
534  // (i.e., multiple threads getting the same temporary path).
535  int FD;
536  auto EC = llvm::sys::fs::createTemporaryFile(Prefix, Suffix, FD, File);
537  if (EC)
538  return EC;
539  // We only needed to make sure the file exists, close the file right away.
540  llvm::sys::Process::SafelyCloseFileDescriptor(FD);
541  return TempPCHFile(std::move(File).str());
542 }
543 
544 llvm::ErrorOr<PrecompiledPreamble::TempPCHFile>
545 PrecompiledPreamble::TempPCHFile::createFromCustomPath(const Twine &Path) {
546  return TempPCHFile(Path.str());
547 }
548 
549 PrecompiledPreamble::TempPCHFile::TempPCHFile(std::string FilePath)
550  : FilePath(std::move(FilePath)) {
551  TemporaryFiles::getInstance().addFile(*this->FilePath);
552 }
553 
554 PrecompiledPreamble::TempPCHFile::TempPCHFile(TempPCHFile &&Other) {
555  FilePath = std::move(Other.FilePath);
556  Other.FilePath = None;
557 }
558 
559 PrecompiledPreamble::TempPCHFile &PrecompiledPreamble::TempPCHFile::
560 operator=(TempPCHFile &&Other) {
561  RemoveFileIfPresent();
562 
563  FilePath = std::move(Other.FilePath);
564  Other.FilePath = None;
565  return *this;
566 }
567 
568 PrecompiledPreamble::TempPCHFile::~TempPCHFile() { RemoveFileIfPresent(); }
569 
570 void PrecompiledPreamble::TempPCHFile::RemoveFileIfPresent() {
571  if (FilePath) {
572  TemporaryFiles::getInstance().removeFile(*FilePath);
573  FilePath = None;
574  }
575 }
576 
577 llvm::StringRef PrecompiledPreamble::TempPCHFile::getFilePath() const {
578  assert(FilePath && "TempPCHFile doesn't have a FilePath. Had it been moved?");
579  return *FilePath;
580 }
581 
582 PrecompiledPreamble::PCHStorage::PCHStorage(TempPCHFile File)
583  : StorageKind(Kind::TempFile) {
584  new (&asFile()) TempPCHFile(std::move(File));
585 }
586 
587 PrecompiledPreamble::PCHStorage::PCHStorage(InMemoryPreamble Memory)
588  : StorageKind(Kind::InMemory) {
589  new (&asMemory()) InMemoryPreamble(std::move(Memory));
590 }
591 
592 PrecompiledPreamble::PCHStorage::PCHStorage(PCHStorage &&Other) : PCHStorage() {
593  *this = std::move(Other);
594 }
595 
596 PrecompiledPreamble::PCHStorage &PrecompiledPreamble::PCHStorage::
597 operator=(PCHStorage &&Other) {
598  destroy();
599 
600  StorageKind = Other.StorageKind;
601  switch (StorageKind) {
602  case Kind::Empty:
603  // do nothing;
604  break;
605  case Kind::TempFile:
606  new (&asFile()) TempPCHFile(std::move(Other.asFile()));
607  break;
608  case Kind::InMemory:
609  new (&asMemory()) InMemoryPreamble(std::move(Other.asMemory()));
610  break;
611  }
612 
613  Other.setEmpty();
614  return *this;
615 }
616 
617 PrecompiledPreamble::PCHStorage::~PCHStorage() { destroy(); }
618 
619 PrecompiledPreamble::PCHStorage::Kind
621  return StorageKind;
622 }
623 
624 PrecompiledPreamble::TempPCHFile &PrecompiledPreamble::PCHStorage::asFile() {
625  assert(getKind() == Kind::TempFile);
626  return *reinterpret_cast<TempPCHFile *>(Storage.buffer);
627 }
628 
629 const PrecompiledPreamble::TempPCHFile &
630 PrecompiledPreamble::PCHStorage::asFile() const {
631  return const_cast<PCHStorage *>(this)->asFile();
632 }
633 
634 PrecompiledPreamble::InMemoryPreamble &
635 PrecompiledPreamble::PCHStorage::asMemory() {
636  assert(getKind() == Kind::InMemory);
637  return *reinterpret_cast<InMemoryPreamble *>(Storage.buffer);
638 }
639 
640 const PrecompiledPreamble::InMemoryPreamble &
641 PrecompiledPreamble::PCHStorage::asMemory() const {
642  return const_cast<PCHStorage *>(this)->asMemory();
643 }
644 
645 void PrecompiledPreamble::PCHStorage::destroy() {
646  switch (StorageKind) {
647  case Kind::Empty:
648  return;
649  case Kind::TempFile:
650  asFile().~TempPCHFile();
651  return;
652  case Kind::InMemory:
653  asMemory().~InMemoryPreamble();
654  return;
655  }
656 }
657 
658 void PrecompiledPreamble::PCHStorage::setEmpty() {
659  destroy();
660  StorageKind = Kind::Empty;
661 }
662 
663 PrecompiledPreamble::PreambleFileHash
664 PrecompiledPreamble::PreambleFileHash::createForFile(off_t Size,
665  time_t ModTime) {
666  PreambleFileHash Result;
667  Result.Size = Size;
668  Result.ModTime = ModTime;
669  Result.MD5 = {};
670  return Result;
671 }
672 
673 PrecompiledPreamble::PreambleFileHash
674 PrecompiledPreamble::PreambleFileHash::createForMemoryBuffer(
675  const llvm::MemoryBuffer *Buffer) {
676  PreambleFileHash Result;
677  Result.Size = Buffer->getBufferSize();
678  Result.ModTime = 0;
679 
680  llvm::MD5 MD5Ctx;
681  MD5Ctx.update(Buffer->getBuffer().data());
682  MD5Ctx.final(Result.MD5);
683 
684  return Result;
685 }
686 
687 void PrecompiledPreamble::configurePreamble(
690  llvm::MemoryBuffer *MainFileBuffer) const {
691  assert(VFS);
692 
693  auto &PreprocessorOpts = CI.getPreprocessorOpts();
694 
695  // Remap main file to point to MainFileBuffer.
696  auto MainFilePath = CI.getFrontendOpts().Inputs[0].getFile();
697  PreprocessorOpts.addRemappedFile(MainFilePath, MainFileBuffer);
698 
699  // Configure ImpicitPCHInclude.
700  PreprocessorOpts.PrecompiledPreambleBytes.first = Bounds.Size;
701  PreprocessorOpts.PrecompiledPreambleBytes.second =
703  PreprocessorOpts.DisablePCHValidation = true;
704 
705  setupPreambleStorage(Storage, PreprocessorOpts, VFS);
706 }
707 
708 void PrecompiledPreamble::setupPreambleStorage(
709  const PCHStorage &Storage, PreprocessorOptions &PreprocessorOpts,
711  if (Storage.getKind() == PCHStorage::Kind::TempFile) {
712  const TempPCHFile &PCHFile = Storage.asFile();
713  PreprocessorOpts.ImplicitPCHInclude = PCHFile.getFilePath();
714 
715  // Make sure we can access the PCH file even if we're using a VFS
717  auto PCHPath = PCHFile.getFilePath();
718  if (VFS == RealFS || VFS->exists(PCHPath))
719  return;
720  auto Buf = RealFS->getBufferForFile(PCHPath);
721  if (!Buf) {
722  // We can't read the file even from RealFS, this is clearly an error,
723  // but we'll just leave the current VFS as is and let clang's code
724  // figure out what to do with missing PCH.
725  return;
726  }
727 
728  // We have a slight inconsistency here -- we're using the VFS to
729  // read files, but the PCH was generated in the real file system.
730  VFS = createVFSOverlayForPreamblePCH(PCHPath, std::move(*Buf), VFS);
731  } else {
732  assert(Storage.getKind() == PCHStorage::Kind::InMemory);
733  // For in-memory preamble, we have to provide a VFS overlay that makes it
734  // accessible.
735  StringRef PCHPath = getInMemoryPreamblePath();
736  PreprocessorOpts.ImplicitPCHInclude = PCHPath;
737 
738  auto Buf = llvm::MemoryBuffer::getMemBuffer(Storage.asMemory().Data);
739  VFS = createVFSOverlayForPreamblePCH(PCHPath, std::move(Buf), VFS);
740  }
741 }
742 
747 std::unique_ptr<PPCallbacks> PreambleCallbacks::createPPCallbacks() {
748  return nullptr;
749 }
750 
752  return std::error_code(static_cast<int>(Error), BuildPreambleErrorCategory());
753 }
754 
755 const char *BuildPreambleErrorCategory::name() const noexcept {
756  return "build-preamble.error";
757 }
758 
759 std::string BuildPreambleErrorCategory::message(int condition) const {
760  switch (static_cast<BuildPreambleError>(condition)) {
762  return "Preamble is empty";
764  return "Could not create temporary file for PCH";
766  return "CreateTargetInfo() return null";
768  return "BeginSourceFile() return an error";
770  return "Could not emit PCH";
771  }
772  llvm_unreachable("unexpected BuildPreambleError");
773 }
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:59
Implements support for file system lookup, file system caching, and directory search management...
Definition: FileManager.h:116
__SIZE_TYPE__ size_t
The unsigned integer type of the result of the sizeof operator.
Definition: opencl-c.h:60
time_t getModificationTime() const
Definition: FileManager.h:91
An interface for collecting the dependencies of a compilation.
Definition: Utils.h:83
IntrusiveRefCntPtr< FileSystem > getRealFileSystem()
Gets an vfs::FileSystem for the &#39;real&#39; file system, as seen by the operating system.
The translation unit is a prefix to a translation unit, and is not complete.
Definition: LangOptions.h:307
PreprocessorOptions - This class is used for passing the various options used in preprocessor initial...
void addRemappedFile(StringRef From, StringRef To)
void AddImplicitPreamble(CompilerInvocation &CI, IntrusiveRefCntPtr< vfs::FileSystem > &VFS, llvm::MemoryBuffer *MainFileBuffer) const
Changes options inside CI to use PCH from this preamble.
The virtual file system interface.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:153
void HandleTranslationUnit(ASTContext &Ctx) override
HandleTranslationUnit - This method is called when the ASTs for entire translation unit have been par...
Definition: GeneratePCH.cpp:40
static llvm::ErrorOr< PrecompiledPreamble > Build(const CompilerInvocation &Invocation, const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds, DiagnosticsEngine &Diagnostics, IntrusiveRefCntPtr< vfs::FileSystem > VFS, std::shared_ptr< PCHContainerOperations > PCHContainerOps, bool StoreInMemory, PreambleCallbacks &Callbacks)
Try to build PrecompiledPreamble for Invocation.
Definition: Format.h:2031
static bool moveOnNoError(llvm::ErrorOr< T > Val, T &Output)
Definition: ASTUnit.cpp:147
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:50
An in-memory file system.
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 ...
A file system that allows overlaying one AbstractFileSystem on top of another.
virtual llvm::ErrorOr< Status > status(const Twine &Path)=0
Get the status of the entry at Path, if one exists.
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...
The result of a status operation.
void Reset()
Reset the state of the diagnostic object to its initial configuration.
Definition: Diagnostic.cpp:114
FrontendOptions & getFrontendOpts()
bool PreambleEndsAtStartOfLine
Whether the preamble ends at the start of a new line.
Definition: Lexer.h:67
A set of callbacks to gather useful information while building a preamble.
StringRef Filename
Definition: Format.cpp:1605
const char * name() const noexcept override
PreambleBounds getBounds() const
PreambleBounds used to build the preamble.
bool CanReuse(const CompilerInvocation &Invocation, const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds, vfs::FileSystem *VFS) const
Check whether PrecompiledPreamble can be reused for the new contents(MainFileBuffer) of the main file...
static PreambleBounds ComputePreamble(StringRef Buffer, const LangOptions &LangOpts, unsigned MaxLines=0)
Compute the preamble of the given file.
Definition: Lexer.cpp:574
const FileEntry * getFileEntryForID(FileID FID) const
Returns the FileEntry record for the provided FileID.
IntrusiveRefCntPtr< vfs::FileSystem > createVFSFromCompilerInvocation(const CompilerInvocation &CI, DiagnosticsEngine &Diags)
static TargetInfo * CreateTargetInfo(DiagnosticsEngine &Diags, const std::shared_ptr< TargetOptions > &Opts)
Construct a target for the given options.
Definition: Targets.cpp:596
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.
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
StringRef getName() const
Definition: FileManager.h:84
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
llvm::sys::TimePoint getLastModificationTime() const
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:44
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.
llvm::MemoryBuffer * getMemoryBufferForFile(const FileEntry *File, bool *Invalid=nullptr)
Retrieve the memory buffer associated with the given file.
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:87
uint64_t getSize() const
FileID getMainFileID() const
Returns the FileID of the main source file.
Helper class for holding the data necessary to invoke the compiler.
Defines the virtual file system interface vfs::FileSystem.
FrontendOptions - Options for controlling the behavior of the frontend.
virtual void AfterExecute(CompilerInstance &CI)
Called after FrontendAction::Execute(), but before FrontendAction::EndSourceFile().
void OverridePreamble(CompilerInvocation &CI, IntrusiveRefCntPtr< vfs::FileSystem > &VFS, llvm::MemoryBuffer *MainFileBuffer) const
Configure CI to use this preamble.
unsigned Size
Size of the preamble in bytes.
Definition: Lexer.h:61
llvm::sys::fs::UniqueID getUniqueID() const
Generate pre-compiled header.
Preprocessor & getPreprocessor() const
Return the current preprocessor.
TranslationUnitKind
Describes the kind of translation unit being processed.
Definition: LangOptions.h:301
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.
__DEVICE__ int max(int __a, int __b)
static Decl::Kind getKind(const Decl *D)
Definition: DeclBase.cpp:930
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:964
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:32
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:127