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(_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 
307  // Create a file manager object to provide access to and cache the filesystem.
308  Clang->setFileManager(new FileManager(Clang->getFileSystemOpts(), VFS));
309 
310  // Create the source manager.
311  Clang->setSourceManager(
312  new SourceManager(Diagnostics, Clang->getFileManager()));
313 
314  auto PreambleDepCollector = std::make_shared<DependencyCollector>();
315  Clang->addDependencyCollector(PreambleDepCollector);
316 
317  // Remap the main source file to the preamble buffer.
318  StringRef MainFilePath = FrontendOpts.Inputs[0].getFile();
319  auto PreambleInputBuffer = llvm::MemoryBuffer::getMemBufferCopy(
320  MainFileBuffer->getBuffer().slice(0, Bounds.Size), MainFilePath);
321  if (PreprocessorOpts.RetainRemappedFileBuffers) {
322  // MainFileBuffer will be deleted by unique_ptr after leaving the method.
323  PreprocessorOpts.addRemappedFile(MainFilePath, PreambleInputBuffer.get());
324  } else {
325  // In that case, remapped buffer will be deleted by CompilerInstance on
326  // BeginSourceFile, so we call release() to avoid double deletion.
327  PreprocessorOpts.addRemappedFile(MainFilePath,
328  PreambleInputBuffer.release());
329  }
330 
331  std::unique_ptr<PrecompilePreambleAction> Act;
332  Act.reset(new PrecompilePreambleAction(
333  StoreInMemory ? &Storage.asMemory().Data : nullptr, Callbacks));
334  Callbacks.BeforeExecute(*Clang);
335  if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0]))
337 
338  std::unique_ptr<PPCallbacks> DelegatedPPCallbacks =
339  Callbacks.createPPCallbacks();
340  if (DelegatedPPCallbacks)
341  Clang->getPreprocessor().addPPCallbacks(std::move(DelegatedPPCallbacks));
342 
343  Act->Execute();
344 
345  // Run the callbacks.
346  Callbacks.AfterExecute(*Clang);
347 
348  Act->EndSourceFile();
349 
350  if (!Act->hasEmittedPreamblePCH())
352 
353  // Keep track of all of the files that the source manager knows about,
354  // so we can verify whether they have changed or not.
355  llvm::StringMap<PrecompiledPreamble::PreambleFileHash> FilesInPreamble;
356 
357  SourceManager &SourceMgr = Clang->getSourceManager();
358  for (auto &Filename : PreambleDepCollector->getDependencies()) {
359  const FileEntry *File = Clang->getFileManager().getFile(Filename);
360  if (!File || File == SourceMgr.getFileEntryForID(SourceMgr.getMainFileID()))
361  continue;
362  if (time_t ModTime = File->getModificationTime()) {
363  FilesInPreamble[File->getName()] =
364  PrecompiledPreamble::PreambleFileHash::createForFile(File->getSize(),
365  ModTime);
366  } else {
367  llvm::MemoryBuffer *Buffer = SourceMgr.getMemoryBufferForFile(File);
368  FilesInPreamble[File->getName()] =
369  PrecompiledPreamble::PreambleFileHash::createForMemoryBuffer(Buffer);
370  }
371  }
372 
373  return PrecompiledPreamble(std::move(Storage), std::move(PreambleBytes),
374  PreambleEndsAtStartOfLine,
375  std::move(FilesInPreamble));
376 }
377 
379  return PreambleBounds(PreambleBytes.size(), PreambleEndsAtStartOfLine);
380 }
381 
383  switch (Storage.getKind()) {
384  case PCHStorage::Kind::Empty:
385  assert(false && "Calling getSize() on invalid PrecompiledPreamble. "
386  "Was it std::moved?");
387  return 0;
388  case PCHStorage::Kind::InMemory:
389  return Storage.asMemory().Data.size();
390  case PCHStorage::Kind::TempFile: {
391  uint64_t Result;
392  if (llvm::sys::fs::file_size(Storage.asFile().getFilePath(), Result))
393  return 0;
394 
395  assert(Result <= std::numeric_limits<std::size_t>::max() &&
396  "file size did not fit into size_t");
397  return Result;
398  }
399  }
400  llvm_unreachable("Unhandled storage kind");
401 }
402 
404  const llvm::MemoryBuffer *MainFileBuffer,
405  PreambleBounds Bounds,
406  vfs::FileSystem *VFS) const {
407 
408  assert(
409  Bounds.Size <= MainFileBuffer->getBufferSize() &&
410  "Buffer is too large. Bounds were calculated from a different buffer?");
411 
412  auto PreambleInvocation = std::make_shared<CompilerInvocation>(Invocation);
413  PreprocessorOptions &PreprocessorOpts =
414  PreambleInvocation->getPreprocessorOpts();
415 
416  if (!Bounds.Size)
417  return false;
418 
419  // We've previously computed a preamble. Check whether we have the same
420  // preamble now that we did before, and that there's enough space in
421  // the main-file buffer within the precompiled preamble to fit the
422  // new main file.
423  if (PreambleBytes.size() != Bounds.Size ||
424  PreambleEndsAtStartOfLine != Bounds.PreambleEndsAtStartOfLine ||
425  memcmp(PreambleBytes.data(), MainFileBuffer->getBufferStart(),
426  Bounds.Size) != 0)
427  return false;
428  // The preamble has not changed. We may be able to re-use the precompiled
429  // preamble.
430 
431  // Check that none of the files used by the preamble have changed.
432  // First, make a record of those files that have been overridden via
433  // remapping or unsaved_files.
434  std::map<llvm::sys::fs::UniqueID, PreambleFileHash> OverriddenFiles;
435  for (const auto &R : PreprocessorOpts.RemappedFiles) {
436  vfs::Status Status;
437  if (!moveOnNoError(VFS->status(R.second), Status)) {
438  // If we can't stat the file we're remapping to, assume that something
439  // horrible happened.
440  return false;
441  }
442 
443  OverriddenFiles[Status.getUniqueID()] = PreambleFileHash::createForFile(
444  Status.getSize(), llvm::sys::toTimeT(Status.getLastModificationTime()));
445  }
446 
447  for (const auto &RB : PreprocessorOpts.RemappedFileBuffers) {
448  vfs::Status Status;
449  if (!moveOnNoError(VFS->status(RB.first), Status))
450  return false;
451 
452  OverriddenFiles[Status.getUniqueID()] =
453  PreambleFileHash::createForMemoryBuffer(RB.second);
454  }
455 
456  // Check whether anything has changed.
457  for (const auto &F : FilesInPreamble) {
458  vfs::Status Status;
459  if (!moveOnNoError(VFS->status(F.first()), Status)) {
460  // If we can't stat the file, assume that something horrible happened.
461  return false;
462  }
463 
464  std::map<llvm::sys::fs::UniqueID, PreambleFileHash>::iterator Overridden =
465  OverriddenFiles.find(Status.getUniqueID());
466  if (Overridden != OverriddenFiles.end()) {
467  // This file was remapped; check whether the newly-mapped file
468  // matches up with the previous mapping.
469  if (Overridden->second != F.second)
470  return false;
471  continue;
472  }
473 
474  // The file was not remapped; check whether it has changed on disk.
475  if (Status.getSize() != uint64_t(F.second.Size) ||
476  llvm::sys::toTimeT(Status.getLastModificationTime()) !=
477  F.second.ModTime)
478  return false;
479  }
480  return true;
481 }
482 
485  llvm::MemoryBuffer *MainFileBuffer) const {
486  PreambleBounds Bounds(PreambleBytes.size(), PreambleEndsAtStartOfLine);
487  configurePreamble(Bounds, CI, VFS, MainFileBuffer);
488 }
489 
492  llvm::MemoryBuffer *MainFileBuffer) const {
493  auto Bounds = ComputePreambleBounds(*CI.getLangOpts(), MainFileBuffer, 0);
494  configurePreamble(Bounds, CI, VFS, MainFileBuffer);
495 }
496 
498  PCHStorage Storage, std::vector<char> PreambleBytes,
499  bool PreambleEndsAtStartOfLine,
500  llvm::StringMap<PreambleFileHash> FilesInPreamble)
501  : Storage(std::move(Storage)), FilesInPreamble(std::move(FilesInPreamble)),
502  PreambleBytes(std::move(PreambleBytes)),
503  PreambleEndsAtStartOfLine(PreambleEndsAtStartOfLine) {
504  assert(this->Storage.getKind() != PCHStorage::Kind::Empty);
505 }
506 
507 llvm::ErrorOr<PrecompiledPreamble::TempPCHFile>
508 PrecompiledPreamble::TempPCHFile::CreateNewPreamblePCHFile() {
509  // FIXME: This is a hack so that we can override the preamble file during
510  // crash-recovery testing, which is the only case where the preamble files
511  // are not necessarily cleaned up.
512  const char *TmpFile = ::getenv("CINDEXTEST_PREAMBLE_FILE");
513  if (TmpFile)
514  return TempPCHFile::createFromCustomPath(TmpFile);
515  return TempPCHFile::createInSystemTempDir("preamble", "pch");
516 }
517 
518 llvm::ErrorOr<PrecompiledPreamble::TempPCHFile>
519 PrecompiledPreamble::TempPCHFile::createInSystemTempDir(const Twine &Prefix,
520  StringRef Suffix) {
522  // Using a version of createTemporaryFile with a file descriptor guarantees
523  // that we would never get a race condition in a multi-threaded setting
524  // (i.e., multiple threads getting the same temporary path).
525  int FD;
526  auto EC = llvm::sys::fs::createTemporaryFile(Prefix, Suffix, FD, File);
527  if (EC)
528  return EC;
529  // We only needed to make sure the file exists, close the file right away.
530  llvm::sys::Process::SafelyCloseFileDescriptor(FD);
531  return TempPCHFile(std::move(File).str());
532 }
533 
534 llvm::ErrorOr<PrecompiledPreamble::TempPCHFile>
535 PrecompiledPreamble::TempPCHFile::createFromCustomPath(const Twine &Path) {
536  return TempPCHFile(Path.str());
537 }
538 
539 PrecompiledPreamble::TempPCHFile::TempPCHFile(std::string FilePath)
540  : FilePath(std::move(FilePath)) {
541  TemporaryFiles::getInstance().addFile(*this->FilePath);
542 }
543 
544 PrecompiledPreamble::TempPCHFile::TempPCHFile(TempPCHFile &&Other) {
545  FilePath = std::move(Other.FilePath);
546  Other.FilePath = None;
547 }
548 
549 PrecompiledPreamble::TempPCHFile &PrecompiledPreamble::TempPCHFile::
550 operator=(TempPCHFile &&Other) {
551  RemoveFileIfPresent();
552 
553  FilePath = std::move(Other.FilePath);
554  Other.FilePath = None;
555  return *this;
556 }
557 
558 PrecompiledPreamble::TempPCHFile::~TempPCHFile() { RemoveFileIfPresent(); }
559 
560 void PrecompiledPreamble::TempPCHFile::RemoveFileIfPresent() {
561  if (FilePath) {
562  TemporaryFiles::getInstance().removeFile(*FilePath);
563  FilePath = None;
564  }
565 }
566 
567 llvm::StringRef PrecompiledPreamble::TempPCHFile::getFilePath() const {
568  assert(FilePath && "TempPCHFile doesn't have a FilePath. Had it been moved?");
569  return *FilePath;
570 }
571 
572 PrecompiledPreamble::PCHStorage::PCHStorage(TempPCHFile File)
573  : StorageKind(Kind::TempFile) {
574  new (&asFile()) TempPCHFile(std::move(File));
575 }
576 
577 PrecompiledPreamble::PCHStorage::PCHStorage(InMemoryPreamble Memory)
578  : StorageKind(Kind::InMemory) {
579  new (&asMemory()) InMemoryPreamble(std::move(Memory));
580 }
581 
582 PrecompiledPreamble::PCHStorage::PCHStorage(PCHStorage &&Other) : PCHStorage() {
583  *this = std::move(Other);
584 }
585 
586 PrecompiledPreamble::PCHStorage &PrecompiledPreamble::PCHStorage::
587 operator=(PCHStorage &&Other) {
588  destroy();
589 
590  StorageKind = Other.StorageKind;
591  switch (StorageKind) {
592  case Kind::Empty:
593  // do nothing;
594  break;
595  case Kind::TempFile:
596  new (&asFile()) TempPCHFile(std::move(Other.asFile()));
597  break;
598  case Kind::InMemory:
599  new (&asMemory()) InMemoryPreamble(std::move(Other.asMemory()));
600  break;
601  }
602 
603  Other.setEmpty();
604  return *this;
605 }
606 
607 PrecompiledPreamble::PCHStorage::~PCHStorage() { destroy(); }
608 
609 PrecompiledPreamble::PCHStorage::Kind
611  return StorageKind;
612 }
613 
614 PrecompiledPreamble::TempPCHFile &PrecompiledPreamble::PCHStorage::asFile() {
615  assert(getKind() == Kind::TempFile);
616  return *reinterpret_cast<TempPCHFile *>(Storage.buffer);
617 }
618 
619 const PrecompiledPreamble::TempPCHFile &
620 PrecompiledPreamble::PCHStorage::asFile() const {
621  return const_cast<PCHStorage *>(this)->asFile();
622 }
623 
624 PrecompiledPreamble::InMemoryPreamble &
625 PrecompiledPreamble::PCHStorage::asMemory() {
626  assert(getKind() == Kind::InMemory);
627  return *reinterpret_cast<InMemoryPreamble *>(Storage.buffer);
628 }
629 
630 const PrecompiledPreamble::InMemoryPreamble &
631 PrecompiledPreamble::PCHStorage::asMemory() const {
632  return const_cast<PCHStorage *>(this)->asMemory();
633 }
634 
635 void PrecompiledPreamble::PCHStorage::destroy() {
636  switch (StorageKind) {
637  case Kind::Empty:
638  return;
639  case Kind::TempFile:
640  asFile().~TempPCHFile();
641  return;
642  case Kind::InMemory:
643  asMemory().~InMemoryPreamble();
644  return;
645  }
646 }
647 
648 void PrecompiledPreamble::PCHStorage::setEmpty() {
649  destroy();
650  StorageKind = Kind::Empty;
651 }
652 
653 PrecompiledPreamble::PreambleFileHash
654 PrecompiledPreamble::PreambleFileHash::createForFile(off_t Size,
655  time_t ModTime) {
656  PreambleFileHash Result;
657  Result.Size = Size;
658  Result.ModTime = ModTime;
659  Result.MD5 = {};
660  return Result;
661 }
662 
663 PrecompiledPreamble::PreambleFileHash
664 PrecompiledPreamble::PreambleFileHash::createForMemoryBuffer(
665  const llvm::MemoryBuffer *Buffer) {
666  PreambleFileHash Result;
667  Result.Size = Buffer->getBufferSize();
668  Result.ModTime = 0;
669 
670  llvm::MD5 MD5Ctx;
671  MD5Ctx.update(Buffer->getBuffer().data());
672  MD5Ctx.final(Result.MD5);
673 
674  return Result;
675 }
676 
677 void PrecompiledPreamble::configurePreamble(
680  llvm::MemoryBuffer *MainFileBuffer) const {
681  assert(VFS);
682 
683  auto &PreprocessorOpts = CI.getPreprocessorOpts();
684 
685  // Remap main file to point to MainFileBuffer.
686  auto MainFilePath = CI.getFrontendOpts().Inputs[0].getFile();
687  PreprocessorOpts.addRemappedFile(MainFilePath, MainFileBuffer);
688 
689  // Configure ImpicitPCHInclude.
690  PreprocessorOpts.PrecompiledPreambleBytes.first = Bounds.Size;
691  PreprocessorOpts.PrecompiledPreambleBytes.second =
693  PreprocessorOpts.DisablePCHValidation = true;
694 
695  setupPreambleStorage(Storage, PreprocessorOpts, VFS);
696 }
697 
698 void PrecompiledPreamble::setupPreambleStorage(
699  const PCHStorage &Storage, PreprocessorOptions &PreprocessorOpts,
701  if (Storage.getKind() == PCHStorage::Kind::TempFile) {
702  const TempPCHFile &PCHFile = Storage.asFile();
703  PreprocessorOpts.ImplicitPCHInclude = PCHFile.getFilePath();
704 
705  // Make sure we can access the PCH file even if we're using a VFS
707  auto PCHPath = PCHFile.getFilePath();
708  if (VFS == RealFS || VFS->exists(PCHPath))
709  return;
710  auto Buf = RealFS->getBufferForFile(PCHPath);
711  if (!Buf) {
712  // We can't read the file even from RealFS, this is clearly an error,
713  // but we'll just leave the current VFS as is and let clang's code
714  // figure out what to do with missing PCH.
715  return;
716  }
717 
718  // We have a slight inconsistency here -- we're using the VFS to
719  // read files, but the PCH was generated in the real file system.
720  VFS = createVFSOverlayForPreamblePCH(PCHPath, std::move(*Buf), VFS);
721  } else {
722  assert(Storage.getKind() == PCHStorage::Kind::InMemory);
723  // For in-memory preamble, we have to provide a VFS overlay that makes it
724  // accessible.
725  StringRef PCHPath = getInMemoryPreamblePath();
726  PreprocessorOpts.ImplicitPCHInclude = PCHPath;
727 
728  auto Buf = llvm::MemoryBuffer::getMemBuffer(Storage.asMemory().Data);
729  VFS = createVFSOverlayForPreamblePCH(PCHPath, std::move(Buf), VFS);
730  }
731 }
732 
737 std::unique_ptr<PPCallbacks> PreambleCallbacks::createPPCallbacks() {
738  return nullptr;
739 }
740 
742  return std::error_code(static_cast<int>(Error), BuildPreambleErrorCategory());
743 }
744 
745 const char *BuildPreambleErrorCategory::name() const noexcept {
746  return "build-preamble.error";
747 }
748 
749 std::string BuildPreambleErrorCategory::message(int condition) const {
750  switch (static_cast<BuildPreambleError>(condition)) {
752  return "Preamble is empty";
754  return "Could not create temporary file for PCH";
756  return "CreateTargetInfo() return null";
758  return "BeginSourceFile() return an error";
760  return "Could not emit PCH";
761  }
762  llvm_unreachable("unexpected BuildPreambleError");
763 }
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:307
PreprocessorOptions - This class is used for passing the various options used in preprocessor initial...
void addRemappedFile(StringRef From, StringRef To)
void AddImplicitPreamble(CompilerInvocation &CI, IntrusiveRefCntPtr< vfs::FileSystem > &VFS, llvm::MemoryBuffer *MainFileBuffer) const
Changes options inside CI to use PCH from this preamble.
The virtual file system interface.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:150
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:1989
static bool moveOnNoError(llvm::ErrorOr< T > Val, T &Output)
Definition: ASTUnit.cpp:147
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:50
An in-memory file system.
unsigned RelocatablePCH
When generating PCH files, instruct the AST writer to create relocatable PCH files.
static bool ComputeASTConsumerArguments(CompilerInstance &CI, std::string &Sysroot)
Compute the AST consumer arguments that will be used to create the PCHGenerator instance returned by ...
A file system that allows overlaying one AbstractFileSystem on top of another.
virtual llvm::ErrorOr< Status > status(const Twine &Path)=0
Get the status of the entry at Path, if one exists.
std::error_code make_error_code(BuildPreambleError Error)
FrontendOptions & getFrontendOpts()
Concrete class used by the front-end to report problems and issues.
Definition: Diagnostic.h:149
bool RetainRemappedFileBuffers
Whether the compiler instance should retain (i.e., not free) the buffers associated with remapped fil...
The result of a status operation.
void Reset()
Reset the state of the diagnostic object to its initial configuration.
Definition: Diagnostic.cpp:114
FrontendOptions & getFrontendOpts()
bool PreambleEndsAtStartOfLine
Whether the preamble ends at the start of a new line.
Definition: Lexer.h:67
A set of callbacks to gather useful information while building a preamble.
StringRef Filename
Definition: Format.cpp:1572
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:301
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