clang  7.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(LLVM_ON_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 /// Keeps a track of files to be deleted in destructor.
67 class TemporaryFiles {
68 public:
69  // A static instance to be used by all clients.
70  static TemporaryFiles &getInstance();
71 
72 private:
73  // Disallow constructing the class directly.
74  TemporaryFiles() = default;
75  // Disallow copy.
76  TemporaryFiles(const TemporaryFiles &) = delete;
77 
78 public:
79  ~TemporaryFiles();
80 
81  /// Adds \p File to a set of tracked files.
82  void addFile(StringRef File);
83 
84  /// Remove \p File from disk and from the set of tracked files.
85  void removeFile(StringRef File);
86 
87 private:
88  llvm::sys::SmartMutex<false> Mutex;
89  llvm::StringSet<> Files;
90 };
91 
92 TemporaryFiles &TemporaryFiles::getInstance() {
93  static TemporaryFiles Instance;
94  return Instance;
95 }
96 
97 TemporaryFiles::~TemporaryFiles() {
98  llvm::MutexGuard Guard(Mutex);
99  for (const auto &File : Files)
100  llvm::sys::fs::remove(File.getKey());
101 }
102 
103 void TemporaryFiles::addFile(StringRef File) {
104  llvm::MutexGuard Guard(Mutex);
105  auto IsInserted = Files.insert(File).second;
106  (void)IsInserted;
107  assert(IsInserted && "File has already been added");
108 }
109 
110 void TemporaryFiles::removeFile(StringRef File) {
111  llvm::MutexGuard Guard(Mutex);
112  auto WasPresent = Files.erase(File);
113  (void)WasPresent;
114  assert(WasPresent && "File was not tracked");
115  llvm::sys::fs::remove(File);
116 }
117 
118 class PrecompilePreambleAction : public ASTFrontendAction {
119 public:
120  PrecompilePreambleAction(std::string *InMemStorage,
121  PreambleCallbacks &Callbacks)
122  : InMemStorage(InMemStorage), Callbacks(Callbacks) {}
123 
124  std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
125  StringRef InFile) override;
126 
127  bool hasEmittedPreamblePCH() const { return HasEmittedPreamblePCH; }
128 
129  void setEmittedPreamblePCH(ASTWriter &Writer) {
130  this->HasEmittedPreamblePCH = true;
131  Callbacks.AfterPCHEmitted(Writer);
132  }
133 
134  bool shouldEraseOutputFiles() override { return !hasEmittedPreamblePCH(); }
135  bool hasCodeCompletionSupport() const override { return false; }
136  bool hasASTFileSupport() const override { return false; }
137  TranslationUnitKind getTranslationUnitKind() override { return TU_Prefix; }
138 
139 private:
140  friend class PrecompilePreambleConsumer;
141 
142  bool HasEmittedPreamblePCH = false;
143  std::string *InMemStorage;
144  PreambleCallbacks &Callbacks;
145 };
146 
147 class PrecompilePreambleConsumer : public PCHGenerator {
148 public:
149  PrecompilePreambleConsumer(PrecompilePreambleAction &Action,
150  const Preprocessor &PP, StringRef isysroot,
151  std::unique_ptr<raw_ostream> Out)
152  : PCHGenerator(PP, "", isysroot, std::make_shared<PCHBuffer>(),
153  ArrayRef<std::shared_ptr<ModuleFileExtension>>(),
154  /*AllowASTWithErrors=*/true),
155  Action(Action), Out(std::move(Out)) {}
156 
157  bool HandleTopLevelDecl(DeclGroupRef DG) override {
158  Action.Callbacks.HandleTopLevelDecl(DG);
159  return true;
160  }
161 
162  void HandleTranslationUnit(ASTContext &Ctx) override {
164  if (!hasEmittedPCH())
165  return;
166 
167  // Write the generated bitstream to "Out".
168  *Out << getPCH();
169  // Make sure it hits disk now.
170  Out->flush();
171  // Free the buffer.
173  getPCH() = std::move(Empty);
174 
175  Action.setEmittedPreamblePCH(getWriter());
176  }
177 
178 private:
179  PrecompilePreambleAction &Action;
180  std::unique_ptr<raw_ostream> Out;
181 };
182 
183 std::unique_ptr<ASTConsumer>
184 PrecompilePreambleAction::CreateASTConsumer(CompilerInstance &CI,
185  StringRef InFile) {
186  std::string Sysroot;
188  return nullptr;
189 
190  std::unique_ptr<llvm::raw_ostream> OS;
191  if (InMemStorage) {
192  OS = llvm::make_unique<llvm::raw_string_ostream>(*InMemStorage);
193  } else {
194  std::string OutputFile;
195  OS = GeneratePCHAction::CreateOutputFile(CI, InFile, OutputFile);
196  }
197  if (!OS)
198  return nullptr;
199 
201  Sysroot.clear();
202 
203  return llvm::make_unique<PrecompilePreambleConsumer>(
204  *this, CI.getPreprocessor(), Sysroot, std::move(OS));
205 }
206 
207 template <class T> bool moveOnNoError(llvm::ErrorOr<T> Val, T &Output) {
208  if (!Val)
209  return false;
210  Output = std::move(*Val);
211  return true;
212 }
213 
214 } // namespace
215 
217  llvm::MemoryBuffer *Buffer,
218  unsigned MaxLines) {
219  return Lexer::ComputePreamble(Buffer->getBuffer(), LangOpts, MaxLines);
220 }
221 
222 llvm::ErrorOr<PrecompiledPreamble> PrecompiledPreamble::Build(
223  const CompilerInvocation &Invocation,
224  const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds,
226  std::shared_ptr<PCHContainerOperations> PCHContainerOps, bool StoreInMemory,
227  PreambleCallbacks &Callbacks) {
228  assert(VFS && "VFS is null");
229 
230  if (!Bounds.Size)
232 
233  auto PreambleInvocation = std::make_shared<CompilerInvocation>(Invocation);
234  FrontendOptions &FrontendOpts = PreambleInvocation->getFrontendOpts();
235  PreprocessorOptions &PreprocessorOpts =
236  PreambleInvocation->getPreprocessorOpts();
237 
239  if (!StoreInMemory) {
240  // Create a temporary file for the precompiled preamble. In rare
241  // circumstances, this can fail.
242  llvm::ErrorOr<PrecompiledPreamble::TempPCHFile> PreamblePCHFile =
243  PrecompiledPreamble::TempPCHFile::CreateNewPreamblePCHFile();
244  if (!PreamblePCHFile)
246  TempFile = std::move(*PreamblePCHFile);
247  }
248 
249  PCHStorage Storage = StoreInMemory ? PCHStorage(InMemoryPreamble())
250  : PCHStorage(std::move(*TempFile));
251 
252  // Save the preamble text for later; we'll need to compare against it for
253  // subsequent reparses.
254  std::vector<char> PreambleBytes(MainFileBuffer->getBufferStart(),
255  MainFileBuffer->getBufferStart() +
256  Bounds.Size);
257  bool PreambleEndsAtStartOfLine = Bounds.PreambleEndsAtStartOfLine;
258 
259  // Tell the compiler invocation to generate a temporary precompiled header.
260  FrontendOpts.ProgramAction = frontend::GeneratePCH;
261  FrontendOpts.OutputFile = StoreInMemory ? getInMemoryPreamblePath()
262  : Storage.asFile().getFilePath();
263  PreprocessorOpts.PrecompiledPreambleBytes.first = 0;
264  PreprocessorOpts.PrecompiledPreambleBytes.second = false;
265  // Inform preprocessor to record conditional stack when building the preamble.
266  PreprocessorOpts.GeneratePreamble = true;
267 
268  // Create the compiler instance to use for building the precompiled preamble.
269  std::unique_ptr<CompilerInstance> Clang(
270  new CompilerInstance(std::move(PCHContainerOps)));
271 
272  // Recover resources if we crash before exiting this method.
273  llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance> CICleanup(
274  Clang.get());
275 
276  Clang->setInvocation(std::move(PreambleInvocation));
277  Clang->setDiagnostics(&Diagnostics);
278 
279  // Create the target instance.
280  Clang->setTarget(TargetInfo::CreateTargetInfo(
281  Clang->getDiagnostics(), Clang->getInvocation().TargetOpts));
282  if (!Clang->hasTarget())
284 
285  // Inform the target of the language options.
286  //
287  // FIXME: We shouldn't need to do this, the target should be immutable once
288  // created. This complexity should be lifted elsewhere.
289  Clang->getTarget().adjust(Clang->getLangOpts());
290 
291  assert(Clang->getFrontendOpts().Inputs.size() == 1 &&
292  "Invocation must have exactly one source file!");
293  assert(Clang->getFrontendOpts().Inputs[0].getKind().getFormat() ==
295  "FIXME: AST inputs not yet supported here!");
296  assert(Clang->getFrontendOpts().Inputs[0].getKind().getLanguage() !=
298  "IR inputs not support here!");
299 
300  // Clear out old caches and data.
301  Diagnostics.Reset();
302  ProcessWarningOptions(Diagnostics, Clang->getDiagnosticOpts());
303 
304  VFS =
305  createVFSFromCompilerInvocation(Clang->getInvocation(), Diagnostics, VFS);
306  if (!VFS)
308 
309  // Create a file manager object to provide access to and cache the filesystem.
310  Clang->setFileManager(new FileManager(Clang->getFileSystemOpts(), VFS));
311 
312  // Create the source manager.
313  Clang->setSourceManager(
314  new SourceManager(Diagnostics, Clang->getFileManager()));
315 
316  auto PreambleDepCollector = std::make_shared<DependencyCollector>();
317  Clang->addDependencyCollector(PreambleDepCollector);
318 
319  // Remap the main source file to the preamble buffer.
320  StringRef MainFilePath = FrontendOpts.Inputs[0].getFile();
321  auto PreambleInputBuffer = llvm::MemoryBuffer::getMemBufferCopy(
322  MainFileBuffer->getBuffer().slice(0, Bounds.Size), MainFilePath);
323  if (PreprocessorOpts.RetainRemappedFileBuffers) {
324  // MainFileBuffer will be deleted by unique_ptr after leaving the method.
325  PreprocessorOpts.addRemappedFile(MainFilePath, PreambleInputBuffer.get());
326  } else {
327  // In that case, remapped buffer will be deleted by CompilerInstance on
328  // BeginSourceFile, so we call release() to avoid double deletion.
329  PreprocessorOpts.addRemappedFile(MainFilePath,
330  PreambleInputBuffer.release());
331  }
332 
333  std::unique_ptr<PrecompilePreambleAction> Act;
334  Act.reset(new PrecompilePreambleAction(
335  StoreInMemory ? &Storage.asMemory().Data : nullptr, Callbacks));
336  Callbacks.BeforeExecute(*Clang);
337  if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0]))
339 
340  std::unique_ptr<PPCallbacks> DelegatedPPCallbacks =
341  Callbacks.createPPCallbacks();
342  if (DelegatedPPCallbacks)
343  Clang->getPreprocessor().addPPCallbacks(std::move(DelegatedPPCallbacks));
344 
345  Act->Execute();
346 
347  // Run the callbacks.
348  Callbacks.AfterExecute(*Clang);
349 
350  Act->EndSourceFile();
351 
352  if (!Act->hasEmittedPreamblePCH())
354 
355  // Keep track of all of the files that the source manager knows about,
356  // so we can verify whether they have changed or not.
357  llvm::StringMap<PrecompiledPreamble::PreambleFileHash> FilesInPreamble;
358 
359  SourceManager &SourceMgr = Clang->getSourceManager();
360  for (auto &Filename : PreambleDepCollector->getDependencies()) {
361  const FileEntry *File = Clang->getFileManager().getFile(Filename);
362  if (!File || File == SourceMgr.getFileEntryForID(SourceMgr.getMainFileID()))
363  continue;
364  if (time_t ModTime = File->getModificationTime()) {
365  FilesInPreamble[File->getName()] =
366  PrecompiledPreamble::PreambleFileHash::createForFile(File->getSize(),
367  ModTime);
368  } else {
369  llvm::MemoryBuffer *Buffer = SourceMgr.getMemoryBufferForFile(File);
370  FilesInPreamble[File->getName()] =
371  PrecompiledPreamble::PreambleFileHash::createForMemoryBuffer(Buffer);
372  }
373  }
374 
375  return PrecompiledPreamble(std::move(Storage), std::move(PreambleBytes),
376  PreambleEndsAtStartOfLine,
377  std::move(FilesInPreamble));
378 }
379 
381  return PreambleBounds(PreambleBytes.size(), PreambleEndsAtStartOfLine);
382 }
383 
385  switch (Storage.getKind()) {
386  case PCHStorage::Kind::Empty:
387  assert(false && "Calling getSize() on invalid PrecompiledPreamble. "
388  "Was it std::moved?");
389  return 0;
390  case PCHStorage::Kind::InMemory:
391  return Storage.asMemory().Data.size();
392  case PCHStorage::Kind::TempFile: {
393  uint64_t Result;
394  if (llvm::sys::fs::file_size(Storage.asFile().getFilePath(), Result))
395  return 0;
396 
397  assert(Result <= std::numeric_limits<std::size_t>::max() &&
398  "file size did not fit into size_t");
399  return Result;
400  }
401  }
402  llvm_unreachable("Unhandled storage kind");
403 }
404 
406  const llvm::MemoryBuffer *MainFileBuffer,
407  PreambleBounds Bounds,
408  vfs::FileSystem *VFS) const {
409 
410  assert(
411  Bounds.Size <= MainFileBuffer->getBufferSize() &&
412  "Buffer is too large. Bounds were calculated from a different buffer?");
413 
414  auto PreambleInvocation = std::make_shared<CompilerInvocation>(Invocation);
415  PreprocessorOptions &PreprocessorOpts =
416  PreambleInvocation->getPreprocessorOpts();
417 
418  if (!Bounds.Size)
419  return false;
420 
421  // We've previously computed a preamble. Check whether we have the same
422  // preamble now that we did before, and that there's enough space in
423  // the main-file buffer within the precompiled preamble to fit the
424  // new main file.
425  if (PreambleBytes.size() != Bounds.Size ||
426  PreambleEndsAtStartOfLine != Bounds.PreambleEndsAtStartOfLine ||
427  memcmp(PreambleBytes.data(), MainFileBuffer->getBufferStart(),
428  Bounds.Size) != 0)
429  return false;
430  // The preamble has not changed. We may be able to re-use the precompiled
431  // preamble.
432 
433  // Check that none of the files used by the preamble have changed.
434  // First, make a record of those files that have been overridden via
435  // remapping or unsaved_files.
436  std::map<llvm::sys::fs::UniqueID, PreambleFileHash> OverriddenFiles;
437  for (const auto &R : PreprocessorOpts.RemappedFiles) {
438  vfs::Status Status;
439  if (!moveOnNoError(VFS->status(R.second), Status)) {
440  // If we can't stat the file we're remapping to, assume that something
441  // horrible happened.
442  return false;
443  }
444 
445  OverriddenFiles[Status.getUniqueID()] = PreambleFileHash::createForFile(
446  Status.getSize(), llvm::sys::toTimeT(Status.getLastModificationTime()));
447  }
448 
449  for (const auto &RB : PreprocessorOpts.RemappedFileBuffers) {
450  vfs::Status Status;
451  if (!moveOnNoError(VFS->status(RB.first), Status))
452  return false;
453 
454  OverriddenFiles[Status.getUniqueID()] =
455  PreambleFileHash::createForMemoryBuffer(RB.second);
456  }
457 
458  // Check whether anything has changed.
459  for (const auto &F : FilesInPreamble) {
460  vfs::Status Status;
461  if (!moveOnNoError(VFS->status(F.first()), Status)) {
462  // If we can't stat the file, assume that something horrible happened.
463  return false;
464  }
465 
466  std::map<llvm::sys::fs::UniqueID, PreambleFileHash>::iterator Overridden =
467  OverriddenFiles.find(Status.getUniqueID());
468  if (Overridden != OverriddenFiles.end()) {
469  // This file was remapped; check whether the newly-mapped file
470  // matches up with the previous mapping.
471  if (Overridden->second != F.second)
472  return false;
473  continue;
474  }
475 
476  // The file was not remapped; check whether it has changed on disk.
477  if (Status.getSize() != uint64_t(F.second.Size) ||
478  llvm::sys::toTimeT(Status.getLastModificationTime()) !=
479  F.second.ModTime)
480  return false;
481  }
482  return true;
483 }
484 
487  llvm::MemoryBuffer *MainFileBuffer) const {
488  PreambleBounds Bounds(PreambleBytes.size(), PreambleEndsAtStartOfLine);
489  configurePreamble(Bounds, CI, VFS, MainFileBuffer);
490 }
491 
494  llvm::MemoryBuffer *MainFileBuffer) const {
495  auto Bounds = ComputePreambleBounds(*CI.getLangOpts(), MainFileBuffer, 0);
496  configurePreamble(Bounds, CI, VFS, MainFileBuffer);
497 }
498 
500  PCHStorage Storage, std::vector<char> PreambleBytes,
501  bool PreambleEndsAtStartOfLine,
502  llvm::StringMap<PreambleFileHash> FilesInPreamble)
503  : Storage(std::move(Storage)), FilesInPreamble(std::move(FilesInPreamble)),
504  PreambleBytes(std::move(PreambleBytes)),
505  PreambleEndsAtStartOfLine(PreambleEndsAtStartOfLine) {
506  assert(this->Storage.getKind() != PCHStorage::Kind::Empty);
507 }
508 
509 llvm::ErrorOr<PrecompiledPreamble::TempPCHFile>
510 PrecompiledPreamble::TempPCHFile::CreateNewPreamblePCHFile() {
511  // FIXME: This is a hack so that we can override the preamble file during
512  // crash-recovery testing, which is the only case where the preamble files
513  // are not necessarily cleaned up.
514  const char *TmpFile = ::getenv("CINDEXTEST_PREAMBLE_FILE");
515  if (TmpFile)
516  return TempPCHFile::createFromCustomPath(TmpFile);
517  return TempPCHFile::createInSystemTempDir("preamble", "pch");
518 }
519 
520 llvm::ErrorOr<PrecompiledPreamble::TempPCHFile>
521 PrecompiledPreamble::TempPCHFile::createInSystemTempDir(const Twine &Prefix,
522  StringRef Suffix) {
524  // Using a version of createTemporaryFile with a file descriptor guarantees
525  // that we would never get a race condition in a multi-threaded setting
526  // (i.e., multiple threads getting the same temporary path).
527  int FD;
528  auto EC = llvm::sys::fs::createTemporaryFile(Prefix, Suffix, FD, File);
529  if (EC)
530  return EC;
531  // We only needed to make sure the file exists, close the file right away.
532  llvm::sys::Process::SafelyCloseFileDescriptor(FD);
533  return TempPCHFile(std::move(File).str());
534 }
535 
536 llvm::ErrorOr<PrecompiledPreamble::TempPCHFile>
537 PrecompiledPreamble::TempPCHFile::createFromCustomPath(const Twine &Path) {
538  return TempPCHFile(Path.str());
539 }
540 
541 PrecompiledPreamble::TempPCHFile::TempPCHFile(std::string FilePath)
542  : FilePath(std::move(FilePath)) {
543  TemporaryFiles::getInstance().addFile(*this->FilePath);
544 }
545 
546 PrecompiledPreamble::TempPCHFile::TempPCHFile(TempPCHFile &&Other) {
547  FilePath = std::move(Other.FilePath);
548  Other.FilePath = None;
549 }
550 
551 PrecompiledPreamble::TempPCHFile &PrecompiledPreamble::TempPCHFile::
552 operator=(TempPCHFile &&Other) {
553  RemoveFileIfPresent();
554 
555  FilePath = std::move(Other.FilePath);
556  Other.FilePath = None;
557  return *this;
558 }
559 
560 PrecompiledPreamble::TempPCHFile::~TempPCHFile() { RemoveFileIfPresent(); }
561 
562 void PrecompiledPreamble::TempPCHFile::RemoveFileIfPresent() {
563  if (FilePath) {
564  TemporaryFiles::getInstance().removeFile(*FilePath);
565  FilePath = None;
566  }
567 }
568 
569 llvm::StringRef PrecompiledPreamble::TempPCHFile::getFilePath() const {
570  assert(FilePath && "TempPCHFile doesn't have a FilePath. Had it been moved?");
571  return *FilePath;
572 }
573 
574 PrecompiledPreamble::PCHStorage::PCHStorage(TempPCHFile File)
575  : StorageKind(Kind::TempFile) {
576  new (&asFile()) TempPCHFile(std::move(File));
577 }
578 
579 PrecompiledPreamble::PCHStorage::PCHStorage(InMemoryPreamble Memory)
580  : StorageKind(Kind::InMemory) {
581  new (&asMemory()) InMemoryPreamble(std::move(Memory));
582 }
583 
584 PrecompiledPreamble::PCHStorage::PCHStorage(PCHStorage &&Other) : PCHStorage() {
585  *this = std::move(Other);
586 }
587 
588 PrecompiledPreamble::PCHStorage &PrecompiledPreamble::PCHStorage::
589 operator=(PCHStorage &&Other) {
590  destroy();
591 
592  StorageKind = Other.StorageKind;
593  switch (StorageKind) {
594  case Kind::Empty:
595  // do nothing;
596  break;
597  case Kind::TempFile:
598  new (&asFile()) TempPCHFile(std::move(Other.asFile()));
599  break;
600  case Kind::InMemory:
601  new (&asMemory()) InMemoryPreamble(std::move(Other.asMemory()));
602  break;
603  }
604 
605  Other.setEmpty();
606  return *this;
607 }
608 
609 PrecompiledPreamble::PCHStorage::~PCHStorage() { destroy(); }
610 
611 PrecompiledPreamble::PCHStorage::Kind
613  return StorageKind;
614 }
615 
616 PrecompiledPreamble::TempPCHFile &PrecompiledPreamble::PCHStorage::asFile() {
617  assert(getKind() == Kind::TempFile);
618  return *reinterpret_cast<TempPCHFile *>(Storage.buffer);
619 }
620 
621 const PrecompiledPreamble::TempPCHFile &
622 PrecompiledPreamble::PCHStorage::asFile() const {
623  return const_cast<PCHStorage *>(this)->asFile();
624 }
625 
626 PrecompiledPreamble::InMemoryPreamble &
627 PrecompiledPreamble::PCHStorage::asMemory() {
628  assert(getKind() == Kind::InMemory);
629  return *reinterpret_cast<InMemoryPreamble *>(Storage.buffer);
630 }
631 
632 const PrecompiledPreamble::InMemoryPreamble &
633 PrecompiledPreamble::PCHStorage::asMemory() const {
634  return const_cast<PCHStorage *>(this)->asMemory();
635 }
636 
637 void PrecompiledPreamble::PCHStorage::destroy() {
638  switch (StorageKind) {
639  case Kind::Empty:
640  return;
641  case Kind::TempFile:
642  asFile().~TempPCHFile();
643  return;
644  case Kind::InMemory:
645  asMemory().~InMemoryPreamble();
646  return;
647  }
648 }
649 
650 void PrecompiledPreamble::PCHStorage::setEmpty() {
651  destroy();
652  StorageKind = Kind::Empty;
653 }
654 
655 PrecompiledPreamble::PreambleFileHash
656 PrecompiledPreamble::PreambleFileHash::createForFile(off_t Size,
657  time_t ModTime) {
658  PreambleFileHash Result;
659  Result.Size = Size;
660  Result.ModTime = ModTime;
661  Result.MD5 = {};
662  return Result;
663 }
664 
665 PrecompiledPreamble::PreambleFileHash
666 PrecompiledPreamble::PreambleFileHash::createForMemoryBuffer(
667  const llvm::MemoryBuffer *Buffer) {
668  PreambleFileHash Result;
669  Result.Size = Buffer->getBufferSize();
670  Result.ModTime = 0;
671 
672  llvm::MD5 MD5Ctx;
673  MD5Ctx.update(Buffer->getBuffer().data());
674  MD5Ctx.final(Result.MD5);
675 
676  return Result;
677 }
678 
679 void PrecompiledPreamble::configurePreamble(
682  llvm::MemoryBuffer *MainFileBuffer) const {
683  assert(VFS);
684 
685  auto &PreprocessorOpts = CI.getPreprocessorOpts();
686 
687  // Remap main file to point to MainFileBuffer.
688  auto MainFilePath = CI.getFrontendOpts().Inputs[0].getFile();
689  PreprocessorOpts.addRemappedFile(MainFilePath, MainFileBuffer);
690 
691  // Configure ImpicitPCHInclude.
692  PreprocessorOpts.PrecompiledPreambleBytes.first = Bounds.Size;
693  PreprocessorOpts.PrecompiledPreambleBytes.second =
695  PreprocessorOpts.DisablePCHValidation = true;
696 
697  setupPreambleStorage(Storage, PreprocessorOpts, VFS);
698 }
699 
700 void PrecompiledPreamble::setupPreambleStorage(
701  const PCHStorage &Storage, PreprocessorOptions &PreprocessorOpts,
703  if (Storage.getKind() == PCHStorage::Kind::TempFile) {
704  const TempPCHFile &PCHFile = Storage.asFile();
705  PreprocessorOpts.ImplicitPCHInclude = PCHFile.getFilePath();
706 
707  // Make sure we can access the PCH file even if we're using a VFS
709  auto PCHPath = PCHFile.getFilePath();
710  if (VFS == RealFS || VFS->exists(PCHPath))
711  return;
712  auto Buf = RealFS->getBufferForFile(PCHPath);
713  if (!Buf) {
714  // We can't read the file even from RealFS, this is clearly an error,
715  // but we'll just leave the current VFS as is and let clang's code
716  // figure out what to do with missing PCH.
717  return;
718  }
719 
720  // We have a slight inconsistency here -- we're using the VFS to
721  // read files, but the PCH was generated in the real file system.
722  VFS = createVFSOverlayForPreamblePCH(PCHPath, std::move(*Buf), VFS);
723  } else {
724  assert(Storage.getKind() == PCHStorage::Kind::InMemory);
725  // For in-memory preamble, we have to provide a VFS overlay that makes it
726  // accessible.
727  StringRef PCHPath = getInMemoryPreamblePath();
728  PreprocessorOpts.ImplicitPCHInclude = PCHPath;
729 
730  auto Buf = llvm::MemoryBuffer::getMemBuffer(Storage.asMemory().Data);
731  VFS = createVFSOverlayForPreamblePCH(PCHPath, std::move(Buf), VFS);
732  }
733 }
734 
739 std::unique_ptr<PPCallbacks> PreambleCallbacks::createPPCallbacks() {
740  return nullptr;
741 }
742 
744  return std::error_code(static_cast<int>(Error), BuildPreambleErrorCategory());
745 }
746 
747 const char *BuildPreambleErrorCategory::name() const noexcept {
748  return "build-preamble.error";
749 }
750 
751 std::string BuildPreambleErrorCategory::message(int condition) const {
752  switch (static_cast<BuildPreambleError>(condition)) {
754  return "Preamble is empty";
756  return "Could not create temporary file for PCH";
758  return "CreateTargetInfo() return null";
760  return "Could not create VFS Overlay";
762  return "BeginSourceFile() return an error";
764  return "Could not emit PCH";
765  }
766  llvm_unreachable("unexpected BuildPreambleError");
767 }
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
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:269
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:149
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:2007
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:1522
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.
const FunctionProtoType * T
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:263
Writes an AST file containing the contents of a translation unit.
Definition: ASTWriter.h:104
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:965
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