clang  6.0.0
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  assert(VFS && "VFS must not be null");
489 
490  auto &PreprocessorOpts = CI.getPreprocessorOpts();
491 
492  // Remap main file to point to MainFileBuffer.
493  auto MainFilePath = CI.getFrontendOpts().Inputs[0].getFile();
494  PreprocessorOpts.addRemappedFile(MainFilePath, MainFileBuffer);
495 
496  // Configure ImpicitPCHInclude.
497  PreprocessorOpts.PrecompiledPreambleBytes.first = PreambleBytes.size();
498  PreprocessorOpts.PrecompiledPreambleBytes.second = PreambleEndsAtStartOfLine;
499  PreprocessorOpts.DisablePCHValidation = true;
500 
501  setupPreambleStorage(Storage, PreprocessorOpts, VFS);
502 }
503 
505  PCHStorage Storage, std::vector<char> PreambleBytes,
506  bool PreambleEndsAtStartOfLine,
507  llvm::StringMap<PreambleFileHash> FilesInPreamble)
508  : Storage(std::move(Storage)), FilesInPreamble(std::move(FilesInPreamble)),
509  PreambleBytes(std::move(PreambleBytes)),
510  PreambleEndsAtStartOfLine(PreambleEndsAtStartOfLine) {
511  assert(this->Storage.getKind() != PCHStorage::Kind::Empty);
512 }
513 
514 llvm::ErrorOr<PrecompiledPreamble::TempPCHFile>
515 PrecompiledPreamble::TempPCHFile::CreateNewPreamblePCHFile() {
516  // FIXME: This is a hack so that we can override the preamble file during
517  // crash-recovery testing, which is the only case where the preamble files
518  // are not necessarily cleaned up.
519  const char *TmpFile = ::getenv("CINDEXTEST_PREAMBLE_FILE");
520  if (TmpFile)
521  return TempPCHFile::createFromCustomPath(TmpFile);
522  return TempPCHFile::createInSystemTempDir("preamble", "pch");
523 }
524 
525 llvm::ErrorOr<PrecompiledPreamble::TempPCHFile>
526 PrecompiledPreamble::TempPCHFile::createInSystemTempDir(const Twine &Prefix,
527  StringRef Suffix) {
529  // Using a version of createTemporaryFile with a file descriptor guarantees
530  // that we would never get a race condition in a multi-threaded setting
531  // (i.e., multiple threads getting the same temporary path).
532  int FD;
533  auto EC = llvm::sys::fs::createTemporaryFile(Prefix, Suffix, FD, File);
534  if (EC)
535  return EC;
536  // We only needed to make sure the file exists, close the file right away.
537  llvm::sys::Process::SafelyCloseFileDescriptor(FD);
538  return TempPCHFile(std::move(File).str());
539 }
540 
541 llvm::ErrorOr<PrecompiledPreamble::TempPCHFile>
542 PrecompiledPreamble::TempPCHFile::createFromCustomPath(const Twine &Path) {
543  return TempPCHFile(Path.str());
544 }
545 
546 PrecompiledPreamble::TempPCHFile::TempPCHFile(std::string FilePath)
547  : FilePath(std::move(FilePath)) {
548  TemporaryFiles::getInstance().addFile(*this->FilePath);
549 }
550 
551 PrecompiledPreamble::TempPCHFile::TempPCHFile(TempPCHFile &&Other) {
552  FilePath = std::move(Other.FilePath);
553  Other.FilePath = None;
554 }
555 
556 PrecompiledPreamble::TempPCHFile &PrecompiledPreamble::TempPCHFile::
557 operator=(TempPCHFile &&Other) {
558  RemoveFileIfPresent();
559 
560  FilePath = std::move(Other.FilePath);
561  Other.FilePath = None;
562  return *this;
563 }
564 
565 PrecompiledPreamble::TempPCHFile::~TempPCHFile() { RemoveFileIfPresent(); }
566 
567 void PrecompiledPreamble::TempPCHFile::RemoveFileIfPresent() {
568  if (FilePath) {
569  TemporaryFiles::getInstance().removeFile(*FilePath);
570  FilePath = None;
571  }
572 }
573 
574 llvm::StringRef PrecompiledPreamble::TempPCHFile::getFilePath() const {
575  assert(FilePath && "TempPCHFile doesn't have a FilePath. Had it been moved?");
576  return *FilePath;
577 }
578 
579 PrecompiledPreamble::PCHStorage::PCHStorage(TempPCHFile File)
580  : StorageKind(Kind::TempFile) {
581  new (&asFile()) TempPCHFile(std::move(File));
582 }
583 
584 PrecompiledPreamble::PCHStorage::PCHStorage(InMemoryPreamble Memory)
585  : StorageKind(Kind::InMemory) {
586  new (&asMemory()) InMemoryPreamble(std::move(Memory));
587 }
588 
589 PrecompiledPreamble::PCHStorage::PCHStorage(PCHStorage &&Other) : PCHStorage() {
590  *this = std::move(Other);
591 }
592 
593 PrecompiledPreamble::PCHStorage &PrecompiledPreamble::PCHStorage::
594 operator=(PCHStorage &&Other) {
595  destroy();
596 
597  StorageKind = Other.StorageKind;
598  switch (StorageKind) {
599  case Kind::Empty:
600  // do nothing;
601  break;
602  case Kind::TempFile:
603  new (&asFile()) TempPCHFile(std::move(Other.asFile()));
604  break;
605  case Kind::InMemory:
606  new (&asMemory()) InMemoryPreamble(std::move(Other.asMemory()));
607  break;
608  }
609 
610  Other.setEmpty();
611  return *this;
612 }
613 
614 PrecompiledPreamble::PCHStorage::~PCHStorage() { destroy(); }
615 
616 PrecompiledPreamble::PCHStorage::Kind
618  return StorageKind;
619 }
620 
621 PrecompiledPreamble::TempPCHFile &PrecompiledPreamble::PCHStorage::asFile() {
622  assert(getKind() == Kind::TempFile);
623  return *reinterpret_cast<TempPCHFile *>(Storage.buffer);
624 }
625 
626 const PrecompiledPreamble::TempPCHFile &
627 PrecompiledPreamble::PCHStorage::asFile() const {
628  return const_cast<PCHStorage *>(this)->asFile();
629 }
630 
631 PrecompiledPreamble::InMemoryPreamble &
632 PrecompiledPreamble::PCHStorage::asMemory() {
633  assert(getKind() == Kind::InMemory);
634  return *reinterpret_cast<InMemoryPreamble *>(Storage.buffer);
635 }
636 
637 const PrecompiledPreamble::InMemoryPreamble &
638 PrecompiledPreamble::PCHStorage::asMemory() const {
639  return const_cast<PCHStorage *>(this)->asMemory();
640 }
641 
642 void PrecompiledPreamble::PCHStorage::destroy() {
643  switch (StorageKind) {
644  case Kind::Empty:
645  return;
646  case Kind::TempFile:
647  asFile().~TempPCHFile();
648  return;
649  case Kind::InMemory:
650  asMemory().~InMemoryPreamble();
651  return;
652  }
653 }
654 
655 void PrecompiledPreamble::PCHStorage::setEmpty() {
656  destroy();
657  StorageKind = Kind::Empty;
658 }
659 
660 PrecompiledPreamble::PreambleFileHash
661 PrecompiledPreamble::PreambleFileHash::createForFile(off_t Size,
662  time_t ModTime) {
663  PreambleFileHash Result;
664  Result.Size = Size;
665  Result.ModTime = ModTime;
666  Result.MD5 = {};
667  return Result;
668 }
669 
670 PrecompiledPreamble::PreambleFileHash
671 PrecompiledPreamble::PreambleFileHash::createForMemoryBuffer(
672  const llvm::MemoryBuffer *Buffer) {
673  PreambleFileHash Result;
674  Result.Size = Buffer->getBufferSize();
675  Result.ModTime = 0;
676 
677  llvm::MD5 MD5Ctx;
678  MD5Ctx.update(Buffer->getBuffer().data());
679  MD5Ctx.final(Result.MD5);
680 
681  return Result;
682 }
683 
684 void PrecompiledPreamble::setupPreambleStorage(
685  const PCHStorage &Storage, PreprocessorOptions &PreprocessorOpts,
687  if (Storage.getKind() == PCHStorage::Kind::TempFile) {
688  const TempPCHFile &PCHFile = Storage.asFile();
689  PreprocessorOpts.ImplicitPCHInclude = PCHFile.getFilePath();
690 
691  // Make sure we can access the PCH file even if we're using a VFS
693  auto PCHPath = PCHFile.getFilePath();
694  if (VFS == RealFS || VFS->exists(PCHPath))
695  return;
696  auto Buf = RealFS->getBufferForFile(PCHPath);
697  if (!Buf) {
698  // We can't read the file even from RealFS, this is clearly an error,
699  // but we'll just leave the current VFS as is and let clang's code
700  // figure out what to do with missing PCH.
701  return;
702  }
703 
704  // We have a slight inconsistency here -- we're using the VFS to
705  // read files, but the PCH was generated in the real file system.
706  VFS = createVFSOverlayForPreamblePCH(PCHPath, std::move(*Buf), VFS);
707  } else {
708  assert(Storage.getKind() == PCHStorage::Kind::InMemory);
709  // For in-memory preamble, we have to provide a VFS overlay that makes it
710  // accessible.
711  StringRef PCHPath = getInMemoryPreamblePath();
712  PreprocessorOpts.ImplicitPCHInclude = PCHPath;
713 
714  auto Buf = llvm::MemoryBuffer::getMemBuffer(Storage.asMemory().Data);
715  VFS = createVFSOverlayForPreamblePCH(PCHPath, std::move(Buf), VFS);
716  }
717 }
718 
723 std::unique_ptr<PPCallbacks> PreambleCallbacks::createPPCallbacks() {
724  return nullptr;
725 }
726 
728  return std::error_code(static_cast<int>(Error), BuildPreambleErrorCategory());
729 }
730 
731 const char *BuildPreambleErrorCategory::name() const noexcept {
732  return "build-preamble.error";
733 }
734 
735 std::string BuildPreambleErrorCategory::message(int condition) const {
736  switch (static_cast<BuildPreambleError>(condition)) {
738  return "Preamble is empty";
740  return "Could not create temporary file for PCH";
742  return "CreateTargetInfo() return null";
744  return "Could not create VFS Overlay";
746  return "BeginSourceFile() return an error";
748  return "Could not emit PCH";
749  }
750  llvm_unreachable("unexpected BuildPreambleError");
751 }
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:247
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:1900
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:48
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:147
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:113
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:1345
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:583
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().
unsigned Size
Size of the preamble in bytes.
Definition: Lexer.h:61
llvm::sys::fs::UniqueID getUniqueID() const
char __ovld __cnfn max(char x, char y)
Returns y if x < y, otherwise it returns x.
Generate pre-compiled header.
Preprocessor & getPreprocessor() const
Return the current preprocessor.
TranslationUnitKind
Describes the kind of translation unit being processed.
Definition: LangOptions.h:242
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.
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