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  auto PreambleInvocation = std::make_shared<CompilerInvocation>(Invocation);
241  FrontendOptions &FrontendOpts = PreambleInvocation->getFrontendOpts();
242  PreprocessorOptions &PreprocessorOpts =
243  PreambleInvocation->getPreprocessorOpts();
244 
246  if (!StoreInMemory) {
247  // Create a temporary file for the precompiled preamble. In rare
248  // circumstances, this can fail.
249  llvm::ErrorOr<PrecompiledPreamble::TempPCHFile> PreamblePCHFile =
250  PrecompiledPreamble::TempPCHFile::CreateNewPreamblePCHFile();
251  if (!PreamblePCHFile)
253  TempFile = std::move(*PreamblePCHFile);
254  }
255 
256  PCHStorage Storage = StoreInMemory ? PCHStorage(InMemoryPreamble())
257  : PCHStorage(std::move(*TempFile));
258 
259  // Save the preamble text for later; we'll need to compare against it for
260  // subsequent reparses.
261  std::vector<char> PreambleBytes(MainFileBuffer->getBufferStart(),
262  MainFileBuffer->getBufferStart() +
263  Bounds.Size);
264  bool PreambleEndsAtStartOfLine = Bounds.PreambleEndsAtStartOfLine;
265 
266  // Tell the compiler invocation to generate a temporary precompiled header.
267  FrontendOpts.ProgramAction = frontend::GeneratePCH;
268  FrontendOpts.OutputFile = StoreInMemory ? getInMemoryPreamblePath()
269  : Storage.asFile().getFilePath();
270  PreprocessorOpts.PrecompiledPreambleBytes.first = 0;
271  PreprocessorOpts.PrecompiledPreambleBytes.second = false;
272  // Inform preprocessor to record conditional stack when building the preamble.
273  PreprocessorOpts.GeneratePreamble = true;
274 
275  // Create the compiler instance to use for building the precompiled preamble.
276  std::unique_ptr<CompilerInstance> Clang(
277  new CompilerInstance(std::move(PCHContainerOps)));
278 
279  // Recover resources if we crash before exiting this method.
280  llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance> CICleanup(
281  Clang.get());
282 
283  Clang->setInvocation(std::move(PreambleInvocation));
284  Clang->setDiagnostics(&Diagnostics);
285 
286  // Create the target instance.
287  Clang->setTarget(TargetInfo::CreateTargetInfo(
288  Clang->getDiagnostics(), Clang->getInvocation().TargetOpts));
289  if (!Clang->hasTarget())
291 
292  // Inform the target of the language options.
293  //
294  // FIXME: We shouldn't need to do this, the target should be immutable once
295  // created. This complexity should be lifted elsewhere.
296  Clang->getTarget().adjust(Clang->getLangOpts());
297 
298  assert(Clang->getFrontendOpts().Inputs.size() == 1 &&
299  "Invocation must have exactly one source file!");
300  assert(Clang->getFrontendOpts().Inputs[0].getKind().getFormat() ==
302  "FIXME: AST inputs not yet supported here!");
303  assert(Clang->getFrontendOpts().Inputs[0].getKind().getLanguage() !=
305  "IR inputs not support here!");
306 
307  // Clear out old caches and data.
308  Diagnostics.Reset();
309  ProcessWarningOptions(Diagnostics, Clang->getDiagnosticOpts());
310 
311  VFS =
312  createVFSFromCompilerInvocation(Clang->getInvocation(), Diagnostics, VFS);
313 
314  // Create a file manager object to provide access to and cache the filesystem.
315  Clang->setFileManager(new FileManager(Clang->getFileSystemOpts(), VFS));
316 
317  // Create the source manager.
318  Clang->setSourceManager(
319  new SourceManager(Diagnostics, Clang->getFileManager()));
320 
321  auto PreambleDepCollector = std::make_shared<PreambleDependencyCollector>();
322  Clang->addDependencyCollector(PreambleDepCollector);
323 
324  // Remap the main source file to the preamble buffer.
325  StringRef MainFilePath = FrontendOpts.Inputs[0].getFile();
326  auto PreambleInputBuffer = llvm::MemoryBuffer::getMemBufferCopy(
327  MainFileBuffer->getBuffer().slice(0, Bounds.Size), MainFilePath);
328  if (PreprocessorOpts.RetainRemappedFileBuffers) {
329  // MainFileBuffer will be deleted by unique_ptr after leaving the method.
330  PreprocessorOpts.addRemappedFile(MainFilePath, PreambleInputBuffer.get());
331  } else {
332  // In that case, remapped buffer will be deleted by CompilerInstance on
333  // BeginSourceFile, so we call release() to avoid double deletion.
334  PreprocessorOpts.addRemappedFile(MainFilePath,
335  PreambleInputBuffer.release());
336  }
337 
338  std::unique_ptr<PrecompilePreambleAction> Act;
339  Act.reset(new PrecompilePreambleAction(
340  StoreInMemory ? &Storage.asMemory().Data : nullptr, Callbacks));
341  Callbacks.BeforeExecute(*Clang);
342  if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0]))
344 
345  std::unique_ptr<PPCallbacks> DelegatedPPCallbacks =
346  Callbacks.createPPCallbacks();
347  if (DelegatedPPCallbacks)
348  Clang->getPreprocessor().addPPCallbacks(std::move(DelegatedPPCallbacks));
349 
350  Act->Execute();
351 
352  // Run the callbacks.
353  Callbacks.AfterExecute(*Clang);
354 
355  Act->EndSourceFile();
356 
357  if (!Act->hasEmittedPreamblePCH())
359 
360  // Keep track of all of the files that the source manager knows about,
361  // so we can verify whether they have changed or not.
362  llvm::StringMap<PrecompiledPreamble::PreambleFileHash> FilesInPreamble;
363 
364  SourceManager &SourceMgr = Clang->getSourceManager();
365  for (auto &Filename : PreambleDepCollector->getDependencies()) {
366  const FileEntry *File = Clang->getFileManager().getFile(Filename);
367  if (!File || File == SourceMgr.getFileEntryForID(SourceMgr.getMainFileID()))
368  continue;
369  if (time_t ModTime = File->getModificationTime()) {
370  FilesInPreamble[File->getName()] =
371  PrecompiledPreamble::PreambleFileHash::createForFile(File->getSize(),
372  ModTime);
373  } else {
374  llvm::MemoryBuffer *Buffer = SourceMgr.getMemoryBufferForFile(File);
375  FilesInPreamble[File->getName()] =
376  PrecompiledPreamble::PreambleFileHash::createForMemoryBuffer(Buffer);
377  }
378  }
379 
380  return PrecompiledPreamble(std::move(Storage), std::move(PreambleBytes),
381  PreambleEndsAtStartOfLine,
382  std::move(FilesInPreamble));
383 }
384 
386  return PreambleBounds(PreambleBytes.size(), PreambleEndsAtStartOfLine);
387 }
388 
390  switch (Storage.getKind()) {
391  case PCHStorage::Kind::Empty:
392  assert(false && "Calling getSize() on invalid PrecompiledPreamble. "
393  "Was it std::moved?");
394  return 0;
395  case PCHStorage::Kind::InMemory:
396  return Storage.asMemory().Data.size();
397  case PCHStorage::Kind::TempFile: {
398  uint64_t Result;
399  if (llvm::sys::fs::file_size(Storage.asFile().getFilePath(), Result))
400  return 0;
401 
402  assert(Result <= std::numeric_limits<std::size_t>::max() &&
403  "file size did not fit into size_t");
404  return Result;
405  }
406  }
407  llvm_unreachable("Unhandled storage kind");
408 }
409 
411  const llvm::MemoryBuffer *MainFileBuffer,
412  PreambleBounds Bounds,
413  vfs::FileSystem *VFS) const {
414 
415  assert(
416  Bounds.Size <= MainFileBuffer->getBufferSize() &&
417  "Buffer is too large. Bounds were calculated from a different buffer?");
418 
419  auto PreambleInvocation = std::make_shared<CompilerInvocation>(Invocation);
420  PreprocessorOptions &PreprocessorOpts =
421  PreambleInvocation->getPreprocessorOpts();
422 
423  // We've previously computed a preamble. Check whether we have the same
424  // preamble now that we did before, and that there's enough space in
425  // the main-file buffer within the precompiled preamble to fit the
426  // new main file.
427  if (PreambleBytes.size() != Bounds.Size ||
428  PreambleEndsAtStartOfLine != Bounds.PreambleEndsAtStartOfLine ||
429  memcmp(PreambleBytes.data(), MainFileBuffer->getBufferStart(),
430  Bounds.Size) != 0)
431  return false;
432  // The preamble has not changed. We may be able to re-use the precompiled
433  // preamble.
434 
435  // Check that none of the files used by the preamble have changed.
436  // First, make a record of those files that have been overridden via
437  // remapping or unsaved_files.
438  std::map<llvm::sys::fs::UniqueID, PreambleFileHash> OverriddenFiles;
439  for (const auto &R : PreprocessorOpts.RemappedFiles) {
440  vfs::Status Status;
441  if (!moveOnNoError(VFS->status(R.second), Status)) {
442  // If we can't stat the file we're remapping to, assume that something
443  // horrible happened.
444  return false;
445  }
446 
447  OverriddenFiles[Status.getUniqueID()] = PreambleFileHash::createForFile(
448  Status.getSize(), llvm::sys::toTimeT(Status.getLastModificationTime()));
449  }
450 
451  for (const auto &RB : PreprocessorOpts.RemappedFileBuffers) {
452  vfs::Status Status;
453  if (!moveOnNoError(VFS->status(RB.first), Status))
454  return false;
455 
456  OverriddenFiles[Status.getUniqueID()] =
457  PreambleFileHash::createForMemoryBuffer(RB.second);
458  }
459 
460  // Check whether anything has changed.
461  for (const auto &F : FilesInPreamble) {
462  vfs::Status Status;
463  if (!moveOnNoError(VFS->status(F.first()), Status)) {
464  // If we can't stat the file, assume that something horrible happened.
465  return false;
466  }
467 
468  std::map<llvm::sys::fs::UniqueID, PreambleFileHash>::iterator Overridden =
469  OverriddenFiles.find(Status.getUniqueID());
470  if (Overridden != OverriddenFiles.end()) {
471  // This file was remapped; check whether the newly-mapped file
472  // matches up with the previous mapping.
473  if (Overridden->second != F.second)
474  return false;
475  continue;
476  }
477 
478  // The file was not remapped; check whether it has changed on disk.
479  if (Status.getSize() != uint64_t(F.second.Size) ||
480  llvm::sys::toTimeT(Status.getLastModificationTime()) !=
481  F.second.ModTime)
482  return false;
483  }
484  return true;
485 }
486 
489  llvm::MemoryBuffer *MainFileBuffer) const {
490  PreambleBounds Bounds(PreambleBytes.size(), PreambleEndsAtStartOfLine);
491  configurePreamble(Bounds, CI, VFS, MainFileBuffer);
492 }
493 
496  llvm::MemoryBuffer *MainFileBuffer) const {
497  auto Bounds = ComputePreambleBounds(*CI.getLangOpts(), MainFileBuffer, 0);
498  configurePreamble(Bounds, CI, VFS, MainFileBuffer);
499 }
500 
502  PCHStorage Storage, std::vector<char> PreambleBytes,
503  bool PreambleEndsAtStartOfLine,
504  llvm::StringMap<PreambleFileHash> FilesInPreamble)
505  : Storage(std::move(Storage)), FilesInPreamble(std::move(FilesInPreamble)),
506  PreambleBytes(std::move(PreambleBytes)),
507  PreambleEndsAtStartOfLine(PreambleEndsAtStartOfLine) {
508  assert(this->Storage.getKind() != PCHStorage::Kind::Empty);
509 }
510 
511 llvm::ErrorOr<PrecompiledPreamble::TempPCHFile>
512 PrecompiledPreamble::TempPCHFile::CreateNewPreamblePCHFile() {
513  // FIXME: This is a hack so that we can override the preamble file during
514  // crash-recovery testing, which is the only case where the preamble files
515  // are not necessarily cleaned up.
516  const char *TmpFile = ::getenv("CINDEXTEST_PREAMBLE_FILE");
517  if (TmpFile)
518  return TempPCHFile::createFromCustomPath(TmpFile);
519  return TempPCHFile::createInSystemTempDir("preamble", "pch");
520 }
521 
522 llvm::ErrorOr<PrecompiledPreamble::TempPCHFile>
523 PrecompiledPreamble::TempPCHFile::createInSystemTempDir(const Twine &Prefix,
524  StringRef Suffix) {
526  // Using a version of createTemporaryFile with a file descriptor guarantees
527  // that we would never get a race condition in a multi-threaded setting
528  // (i.e., multiple threads getting the same temporary path).
529  int FD;
530  auto EC = llvm::sys::fs::createTemporaryFile(Prefix, Suffix, FD, File);
531  if (EC)
532  return EC;
533  // We only needed to make sure the file exists, close the file right away.
534  llvm::sys::Process::SafelyCloseFileDescriptor(FD);
535  return TempPCHFile(std::move(File).str());
536 }
537 
538 llvm::ErrorOr<PrecompiledPreamble::TempPCHFile>
539 PrecompiledPreamble::TempPCHFile::createFromCustomPath(const Twine &Path) {
540  return TempPCHFile(Path.str());
541 }
542 
543 PrecompiledPreamble::TempPCHFile::TempPCHFile(std::string FilePath)
544  : FilePath(std::move(FilePath)) {
545  TemporaryFiles::getInstance().addFile(*this->FilePath);
546 }
547 
548 PrecompiledPreamble::TempPCHFile::TempPCHFile(TempPCHFile &&Other) {
549  FilePath = std::move(Other.FilePath);
550  Other.FilePath = None;
551 }
552 
553 PrecompiledPreamble::TempPCHFile &PrecompiledPreamble::TempPCHFile::
554 operator=(TempPCHFile &&Other) {
555  RemoveFileIfPresent();
556 
557  FilePath = std::move(Other.FilePath);
558  Other.FilePath = None;
559  return *this;
560 }
561 
562 PrecompiledPreamble::TempPCHFile::~TempPCHFile() { RemoveFileIfPresent(); }
563 
564 void PrecompiledPreamble::TempPCHFile::RemoveFileIfPresent() {
565  if (FilePath) {
566  TemporaryFiles::getInstance().removeFile(*FilePath);
567  FilePath = None;
568  }
569 }
570 
571 llvm::StringRef PrecompiledPreamble::TempPCHFile::getFilePath() const {
572  assert(FilePath && "TempPCHFile doesn't have a FilePath. Had it been moved?");
573  return *FilePath;
574 }
575 
576 PrecompiledPreamble::PCHStorage::PCHStorage(TempPCHFile File)
577  : StorageKind(Kind::TempFile) {
578  new (&asFile()) TempPCHFile(std::move(File));
579 }
580 
581 PrecompiledPreamble::PCHStorage::PCHStorage(InMemoryPreamble Memory)
582  : StorageKind(Kind::InMemory) {
583  new (&asMemory()) InMemoryPreamble(std::move(Memory));
584 }
585 
586 PrecompiledPreamble::PCHStorage::PCHStorage(PCHStorage &&Other) : PCHStorage() {
587  *this = std::move(Other);
588 }
589 
590 PrecompiledPreamble::PCHStorage &PrecompiledPreamble::PCHStorage::
591 operator=(PCHStorage &&Other) {
592  destroy();
593 
594  StorageKind = Other.StorageKind;
595  switch (StorageKind) {
596  case Kind::Empty:
597  // do nothing;
598  break;
599  case Kind::TempFile:
600  new (&asFile()) TempPCHFile(std::move(Other.asFile()));
601  break;
602  case Kind::InMemory:
603  new (&asMemory()) InMemoryPreamble(std::move(Other.asMemory()));
604  break;
605  }
606 
607  Other.setEmpty();
608  return *this;
609 }
610 
611 PrecompiledPreamble::PCHStorage::~PCHStorage() { destroy(); }
612 
613 PrecompiledPreamble::PCHStorage::Kind
615  return StorageKind;
616 }
617 
618 PrecompiledPreamble::TempPCHFile &PrecompiledPreamble::PCHStorage::asFile() {
619  assert(getKind() == Kind::TempFile);
620  return *reinterpret_cast<TempPCHFile *>(Storage.buffer);
621 }
622 
623 const PrecompiledPreamble::TempPCHFile &
624 PrecompiledPreamble::PCHStorage::asFile() const {
625  return const_cast<PCHStorage *>(this)->asFile();
626 }
627 
628 PrecompiledPreamble::InMemoryPreamble &
629 PrecompiledPreamble::PCHStorage::asMemory() {
630  assert(getKind() == Kind::InMemory);
631  return *reinterpret_cast<InMemoryPreamble *>(Storage.buffer);
632 }
633 
634 const PrecompiledPreamble::InMemoryPreamble &
635 PrecompiledPreamble::PCHStorage::asMemory() const {
636  return const_cast<PCHStorage *>(this)->asMemory();
637 }
638 
639 void PrecompiledPreamble::PCHStorage::destroy() {
640  switch (StorageKind) {
641  case Kind::Empty:
642  return;
643  case Kind::TempFile:
644  asFile().~TempPCHFile();
645  return;
646  case Kind::InMemory:
647  asMemory().~InMemoryPreamble();
648  return;
649  }
650 }
651 
652 void PrecompiledPreamble::PCHStorage::setEmpty() {
653  destroy();
654  StorageKind = Kind::Empty;
655 }
656 
657 PrecompiledPreamble::PreambleFileHash
658 PrecompiledPreamble::PreambleFileHash::createForFile(off_t Size,
659  time_t ModTime) {
660  PreambleFileHash Result;
661  Result.Size = Size;
662  Result.ModTime = ModTime;
663  Result.MD5 = {};
664  return Result;
665 }
666 
667 PrecompiledPreamble::PreambleFileHash
668 PrecompiledPreamble::PreambleFileHash::createForMemoryBuffer(
669  const llvm::MemoryBuffer *Buffer) {
670  PreambleFileHash Result;
671  Result.Size = Buffer->getBufferSize();
672  Result.ModTime = 0;
673 
674  llvm::MD5 MD5Ctx;
675  MD5Ctx.update(Buffer->getBuffer().data());
676  MD5Ctx.final(Result.MD5);
677 
678  return Result;
679 }
680 
681 void PrecompiledPreamble::configurePreamble(
684  llvm::MemoryBuffer *MainFileBuffer) const {
685  assert(VFS);
686 
687  auto &PreprocessorOpts = CI.getPreprocessorOpts();
688 
689  // Remap main file to point to MainFileBuffer.
690  auto MainFilePath = CI.getFrontendOpts().Inputs[0].getFile();
691  PreprocessorOpts.addRemappedFile(MainFilePath, MainFileBuffer);
692 
693  // Configure ImpicitPCHInclude.
694  PreprocessorOpts.PrecompiledPreambleBytes.first = Bounds.Size;
695  PreprocessorOpts.PrecompiledPreambleBytes.second =
697  PreprocessorOpts.DisablePCHValidation = true;
698 
699  setupPreambleStorage(Storage, PreprocessorOpts, VFS);
700 }
701 
702 void PrecompiledPreamble::setupPreambleStorage(
703  const PCHStorage &Storage, PreprocessorOptions &PreprocessorOpts,
705  if (Storage.getKind() == PCHStorage::Kind::TempFile) {
706  const TempPCHFile &PCHFile = Storage.asFile();
707  PreprocessorOpts.ImplicitPCHInclude = PCHFile.getFilePath();
708 
709  // Make sure we can access the PCH file even if we're using a VFS
711  auto PCHPath = PCHFile.getFilePath();
712  if (VFS == RealFS || VFS->exists(PCHPath))
713  return;
714  auto Buf = RealFS->getBufferForFile(PCHPath);
715  if (!Buf) {
716  // We can't read the file even from RealFS, this is clearly an error,
717  // but we'll just leave the current VFS as is and let clang's code
718  // figure out what to do with missing PCH.
719  return;
720  }
721 
722  // We have a slight inconsistency here -- we're using the VFS to
723  // read files, but the PCH was generated in the real file system.
724  VFS = createVFSOverlayForPreamblePCH(PCHPath, std::move(*Buf), VFS);
725  } else {
726  assert(Storage.getKind() == PCHStorage::Kind::InMemory);
727  // For in-memory preamble, we have to provide a VFS overlay that makes it
728  // accessible.
729  StringRef PCHPath = getInMemoryPreamblePath();
730  PreprocessorOpts.ImplicitPCHInclude = PCHPath;
731 
732  auto Buf = llvm::MemoryBuffer::getMemBuffer(Storage.asMemory().Data);
733  VFS = createVFSOverlayForPreamblePCH(PCHPath, std::move(Buf), VFS);
734  }
735 }
736 
741 std::unique_ptr<PPCallbacks> PreambleCallbacks::createPPCallbacks() {
742  return nullptr;
743 }
744 
746  return std::error_code(static_cast<int>(Error), BuildPreambleErrorCategory());
747 }
748 
749 const char *BuildPreambleErrorCategory::name() const noexcept {
750  return "build-preamble.error";
751 }
752 
753 std::string BuildPreambleErrorCategory::message(int condition) const {
754  switch (static_cast<BuildPreambleError>(condition)) {
756  return "Could not create temporary file for PCH";
758  return "CreateTargetInfo() return null";
760  return "BeginSourceFile() return an error";
762  return "Could not emit PCH";
763  }
764  llvm_unreachable("unexpected BuildPreambleError");
765 }
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:332
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:326
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