clang  6.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 
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  if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0]))
338 
339  std::unique_ptr<PPCallbacks> DelegatedPPCallbacks =
340  Callbacks.createPPCallbacks();
341  if (DelegatedPPCallbacks)
342  Clang->getPreprocessor().addPPCallbacks(std::move(DelegatedPPCallbacks));
343 
344  Act->Execute();
345 
346  // Run the callbacks.
347  Callbacks.AfterExecute(*Clang);
348 
349  Act->EndSourceFile();
350 
351  if (!Act->hasEmittedPreamblePCH())
353 
354  // Keep track of all of the files that the source manager knows about,
355  // so we can verify whether they have changed or not.
356  llvm::StringMap<PrecompiledPreamble::PreambleFileHash> FilesInPreamble;
357 
358  SourceManager &SourceMgr = Clang->getSourceManager();
359  for (auto &Filename : PreambleDepCollector->getDependencies()) {
360  const FileEntry *File = Clang->getFileManager().getFile(Filename);
361  if (!File || File == SourceMgr.getFileEntryForID(SourceMgr.getMainFileID()))
362  continue;
363  if (time_t ModTime = File->getModificationTime()) {
364  FilesInPreamble[File->getName()] =
365  PrecompiledPreamble::PreambleFileHash::createForFile(File->getSize(),
366  ModTime);
367  } else {
368  llvm::MemoryBuffer *Buffer = SourceMgr.getMemoryBufferForFile(File);
369  FilesInPreamble[File->getName()] =
370  PrecompiledPreamble::PreambleFileHash::createForMemoryBuffer(Buffer);
371  }
372  }
373 
374  return PrecompiledPreamble(std::move(Storage), std::move(PreambleBytes),
375  PreambleEndsAtStartOfLine,
376  std::move(FilesInPreamble));
377 }
378 
380  return PreambleBounds(PreambleBytes.size(), PreambleEndsAtStartOfLine);
381 }
382 
384  const llvm::MemoryBuffer *MainFileBuffer,
385  PreambleBounds Bounds,
386  vfs::FileSystem *VFS) const {
387 
388  assert(
389  Bounds.Size <= MainFileBuffer->getBufferSize() &&
390  "Buffer is too large. Bounds were calculated from a different buffer?");
391 
392  auto PreambleInvocation = std::make_shared<CompilerInvocation>(Invocation);
393  PreprocessorOptions &PreprocessorOpts =
394  PreambleInvocation->getPreprocessorOpts();
395 
396  if (!Bounds.Size)
397  return false;
398 
399  // We've previously computed a preamble. Check whether we have the same
400  // preamble now that we did before, and that there's enough space in
401  // the main-file buffer within the precompiled preamble to fit the
402  // new main file.
403  if (PreambleBytes.size() != Bounds.Size ||
404  PreambleEndsAtStartOfLine != Bounds.PreambleEndsAtStartOfLine ||
405  memcmp(PreambleBytes.data(), MainFileBuffer->getBufferStart(),
406  Bounds.Size) != 0)
407  return false;
408  // The preamble has not changed. We may be able to re-use the precompiled
409  // preamble.
410 
411  // Check that none of the files used by the preamble have changed.
412  // First, make a record of those files that have been overridden via
413  // remapping or unsaved_files.
414  std::map<llvm::sys::fs::UniqueID, PreambleFileHash> OverriddenFiles;
415  for (const auto &R : PreprocessorOpts.RemappedFiles) {
416  vfs::Status Status;
417  if (!moveOnNoError(VFS->status(R.second), Status)) {
418  // If we can't stat the file we're remapping to, assume that something
419  // horrible happened.
420  return false;
421  }
422 
423  OverriddenFiles[Status.getUniqueID()] = PreambleFileHash::createForFile(
424  Status.getSize(), llvm::sys::toTimeT(Status.getLastModificationTime()));
425  }
426 
427  for (const auto &RB : PreprocessorOpts.RemappedFileBuffers) {
428  vfs::Status Status;
429  if (!moveOnNoError(VFS->status(RB.first), Status))
430  return false;
431 
432  OverriddenFiles[Status.getUniqueID()] =
433  PreambleFileHash::createForMemoryBuffer(RB.second);
434  }
435 
436  // Check whether anything has changed.
437  for (const auto &F : FilesInPreamble) {
438  vfs::Status Status;
439  if (!moveOnNoError(VFS->status(F.first()), Status)) {
440  // If we can't stat the file, assume that something horrible happened.
441  return false;
442  }
443 
444  std::map<llvm::sys::fs::UniqueID, PreambleFileHash>::iterator Overridden =
445  OverriddenFiles.find(Status.getUniqueID());
446  if (Overridden != OverriddenFiles.end()) {
447  // This file was remapped; check whether the newly-mapped file
448  // matches up with the previous mapping.
449  if (Overridden->second != F.second)
450  return false;
451  continue;
452  }
453 
454  // The file was not remapped; check whether it has changed on disk.
455  if (Status.getSize() != uint64_t(F.second.Size) ||
456  llvm::sys::toTimeT(Status.getLastModificationTime()) !=
457  F.second.ModTime)
458  return false;
459  }
460  return true;
461 }
462 
465  llvm::MemoryBuffer *MainFileBuffer) const {
466  assert(VFS && "VFS must not be null");
467 
468  auto &PreprocessorOpts = CI.getPreprocessorOpts();
469 
470  // Remap main file to point to MainFileBuffer.
471  auto MainFilePath = CI.getFrontendOpts().Inputs[0].getFile();
472  PreprocessorOpts.addRemappedFile(MainFilePath, MainFileBuffer);
473 
474  // Configure ImpicitPCHInclude.
475  PreprocessorOpts.PrecompiledPreambleBytes.first = PreambleBytes.size();
476  PreprocessorOpts.PrecompiledPreambleBytes.second = PreambleEndsAtStartOfLine;
477  PreprocessorOpts.DisablePCHValidation = true;
478 
479  setupPreambleStorage(Storage, PreprocessorOpts, VFS);
480 }
481 
483  PCHStorage Storage, std::vector<char> PreambleBytes,
484  bool PreambleEndsAtStartOfLine,
485  llvm::StringMap<PreambleFileHash> FilesInPreamble)
486  : Storage(std::move(Storage)), FilesInPreamble(std::move(FilesInPreamble)),
487  PreambleBytes(std::move(PreambleBytes)),
488  PreambleEndsAtStartOfLine(PreambleEndsAtStartOfLine) {
489  assert(this->Storage.getKind() != PCHStorage::Kind::Empty);
490 }
491 
492 llvm::ErrorOr<PrecompiledPreamble::TempPCHFile>
493 PrecompiledPreamble::TempPCHFile::CreateNewPreamblePCHFile() {
494  // FIXME: This is a hack so that we can override the preamble file during
495  // crash-recovery testing, which is the only case where the preamble files
496  // are not necessarily cleaned up.
497  const char *TmpFile = ::getenv("CINDEXTEST_PREAMBLE_FILE");
498  if (TmpFile)
499  return TempPCHFile::createFromCustomPath(TmpFile);
500  return TempPCHFile::createInSystemTempDir("preamble", "pch");
501 }
502 
503 llvm::ErrorOr<PrecompiledPreamble::TempPCHFile>
504 PrecompiledPreamble::TempPCHFile::createInSystemTempDir(const Twine &Prefix,
505  StringRef Suffix) {
507  // Using a version of createTemporaryFile with a file descriptor guarantees
508  // that we would never get a race condition in a multi-threaded setting (i.e.,
509  // multiple threads getting the same temporary path).
510  int FD;
511  auto EC = llvm::sys::fs::createTemporaryFile(Prefix, Suffix, FD, File);
512  if (EC)
513  return EC;
514  // We only needed to make sure the file exists, close the file right away.
515  llvm::sys::Process::SafelyCloseFileDescriptor(FD);
516  return TempPCHFile(std::move(File).str());
517 }
518 
519 llvm::ErrorOr<PrecompiledPreamble::TempPCHFile>
520 PrecompiledPreamble::TempPCHFile::createFromCustomPath(const Twine &Path) {
521  return TempPCHFile(Path.str());
522 }
523 
524 PrecompiledPreamble::TempPCHFile::TempPCHFile(std::string FilePath)
525  : FilePath(std::move(FilePath)) {
526  TemporaryFiles::getInstance().addFile(*this->FilePath);
527 }
528 
529 PrecompiledPreamble::TempPCHFile::TempPCHFile(TempPCHFile &&Other) {
530  FilePath = std::move(Other.FilePath);
531  Other.FilePath = None;
532 }
533 
534 PrecompiledPreamble::TempPCHFile &PrecompiledPreamble::TempPCHFile::
535 operator=(TempPCHFile &&Other) {
536  RemoveFileIfPresent();
537 
538  FilePath = std::move(Other.FilePath);
539  Other.FilePath = None;
540  return *this;
541 }
542 
543 PrecompiledPreamble::TempPCHFile::~TempPCHFile() { RemoveFileIfPresent(); }
544 
545 void PrecompiledPreamble::TempPCHFile::RemoveFileIfPresent() {
546  if (FilePath) {
547  TemporaryFiles::getInstance().removeFile(*FilePath);
548  FilePath = None;
549  }
550 }
551 
552 llvm::StringRef PrecompiledPreamble::TempPCHFile::getFilePath() const {
553  assert(FilePath && "TempPCHFile doesn't have a FilePath. Had it been moved?");
554  return *FilePath;
555 }
556 
557 PrecompiledPreamble::PCHStorage::PCHStorage(TempPCHFile File)
558  : StorageKind(Kind::TempFile) {
559  new (&asFile()) TempPCHFile(std::move(File));
560 }
561 
562 PrecompiledPreamble::PCHStorage::PCHStorage(InMemoryPreamble Memory)
563  : StorageKind(Kind::InMemory) {
564  new (&asMemory()) InMemoryPreamble(std::move(Memory));
565 }
566 
567 PrecompiledPreamble::PCHStorage::PCHStorage(PCHStorage &&Other) : PCHStorage() {
568  *this = std::move(Other);
569 }
570 
571 PrecompiledPreamble::PCHStorage &PrecompiledPreamble::PCHStorage::
572 operator=(PCHStorage &&Other) {
573  destroy();
574 
575  StorageKind = Other.StorageKind;
576  switch (StorageKind) {
577  case Kind::Empty:
578  // do nothing;
579  break;
580  case Kind::TempFile:
581  new (&asFile()) TempPCHFile(std::move(Other.asFile()));
582  break;
583  case Kind::InMemory:
584  new (&asMemory()) InMemoryPreamble(std::move(Other.asMemory()));
585  break;
586  }
587 
588  Other.setEmpty();
589  return *this;
590 }
591 
592 PrecompiledPreamble::PCHStorage::~PCHStorage() { destroy(); }
593 
594 PrecompiledPreamble::PCHStorage::Kind
596  return StorageKind;
597 }
598 
599 PrecompiledPreamble::TempPCHFile &PrecompiledPreamble::PCHStorage::asFile() {
600  assert(getKind() == Kind::TempFile);
601  return *reinterpret_cast<TempPCHFile *>(Storage.buffer);
602 }
603 
604 const PrecompiledPreamble::TempPCHFile &
605 PrecompiledPreamble::PCHStorage::asFile() const {
606  return const_cast<PCHStorage *>(this)->asFile();
607 }
608 
609 PrecompiledPreamble::InMemoryPreamble &
610 PrecompiledPreamble::PCHStorage::asMemory() {
611  assert(getKind() == Kind::InMemory);
612  return *reinterpret_cast<InMemoryPreamble *>(Storage.buffer);
613 }
614 
615 const PrecompiledPreamble::InMemoryPreamble &
616 PrecompiledPreamble::PCHStorage::asMemory() const {
617  return const_cast<PCHStorage *>(this)->asMemory();
618 }
619 
620 void PrecompiledPreamble::PCHStorage::destroy() {
621  switch (StorageKind) {
622  case Kind::Empty:
623  return;
624  case Kind::TempFile:
625  asFile().~TempPCHFile();
626  return;
627  case Kind::InMemory:
628  asMemory().~InMemoryPreamble();
629  return;
630  }
631 }
632 
633 void PrecompiledPreamble::PCHStorage::setEmpty() {
634  destroy();
635  StorageKind = Kind::Empty;
636 }
637 
638 PrecompiledPreamble::PreambleFileHash
639 PrecompiledPreamble::PreambleFileHash::createForFile(off_t Size,
640  time_t ModTime) {
641  PreambleFileHash Result;
642  Result.Size = Size;
643  Result.ModTime = ModTime;
644  Result.MD5 = {};
645  return Result;
646 }
647 
648 PrecompiledPreamble::PreambleFileHash
649 PrecompiledPreamble::PreambleFileHash::createForMemoryBuffer(
650  const llvm::MemoryBuffer *Buffer) {
651  PreambleFileHash Result;
652  Result.Size = Buffer->getBufferSize();
653  Result.ModTime = 0;
654 
655  llvm::MD5 MD5Ctx;
656  MD5Ctx.update(Buffer->getBuffer().data());
657  MD5Ctx.final(Result.MD5);
658 
659  return Result;
660 }
661 
662 void PrecompiledPreamble::setupPreambleStorage(
663  const PCHStorage &Storage, PreprocessorOptions &PreprocessorOpts,
665  if (Storage.getKind() == PCHStorage::Kind::TempFile) {
666  const TempPCHFile &PCHFile = Storage.asFile();
667  PreprocessorOpts.ImplicitPCHInclude = PCHFile.getFilePath();
668 
669  // Make sure we can access the PCH file even if we're using a VFS
671  auto PCHPath = PCHFile.getFilePath();
672  if (VFS == RealFS || VFS->exists(PCHPath))
673  return;
674  auto Buf = RealFS->getBufferForFile(PCHPath);
675  if (!Buf) {
676  // We can't read the file even from RealFS, this is clearly an error,
677  // but we'll just leave the current VFS as is and let clang's code
678  // figure out what to do with missing PCH.
679  return;
680  }
681 
682  // We have a slight inconsistency here -- we're using the VFS to
683  // read files, but the PCH was generated in the real file system.
684  VFS = createVFSOverlayForPreamblePCH(PCHPath, std::move(*Buf), VFS);
685  } else {
686  assert(Storage.getKind() == PCHStorage::Kind::InMemory);
687  // For in-memory preamble, we have to provide a VFS overlay that makes it
688  // accessible.
689  StringRef PCHPath = getInMemoryPreamblePath();
690  PreprocessorOpts.ImplicitPCHInclude = PCHPath;
691 
692  auto Buf = llvm::MemoryBuffer::getMemBuffer(Storage.asMemory().Data);
693  VFS = createVFSOverlayForPreamblePCH(PCHPath, std::move(Buf), VFS);
694  }
695 }
696 
700 std::unique_ptr<PPCallbacks> PreambleCallbacks::createPPCallbacks() {
701  return nullptr;
702 }
703 
705  return std::error_code(static_cast<int>(Error), BuildPreambleErrorCategory());
706 }
707 
708 const char *BuildPreambleErrorCategory::name() const noexcept {
709  return "build-preamble.error";
710 }
711 
712 std::string BuildPreambleErrorCategory::message(int condition) const {
713  switch (static_cast<BuildPreambleError>(condition)) {
715  return "Preamble is empty";
717  return "Could not create temporary file for PCH";
719  return "CreateTargetInfo() return null";
721  return "Could not create VFS Overlay";
723  return "BeginSourceFile() return an error";
725  return "Could not emit PCH";
726  }
727  llvm_unreachable("unexpected BuildPreambleError");
728 }
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
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 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
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:915
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