1200b3289SIlya Biryukov //===--- PrecompiledPreamble.cpp - Build precompiled preambles --*- C++ -*-===// 2200b3289SIlya Biryukov // 3200b3289SIlya Biryukov // The LLVM Compiler Infrastructure 4200b3289SIlya Biryukov // 5200b3289SIlya Biryukov // This file is distributed under the University of Illinois Open Source 6200b3289SIlya Biryukov // License. See LICENSE.TXT for details. 7200b3289SIlya Biryukov // 8200b3289SIlya Biryukov //===----------------------------------------------------------------------===// 9200b3289SIlya Biryukov // 10200b3289SIlya Biryukov // Helper class to build precompiled preamble. 11200b3289SIlya Biryukov // 12200b3289SIlya Biryukov //===----------------------------------------------------------------------===// 13200b3289SIlya Biryukov 14200b3289SIlya Biryukov #include "clang/Frontend/PrecompiledPreamble.h" 15200b3289SIlya Biryukov #include "clang/AST/DeclObjC.h" 16200b3289SIlya Biryukov #include "clang/Basic/TargetInfo.h" 17200b3289SIlya Biryukov #include "clang/Basic/VirtualFileSystem.h" 18200b3289SIlya Biryukov #include "clang/Frontend/CompilerInstance.h" 19200b3289SIlya Biryukov #include "clang/Frontend/CompilerInvocation.h" 20200b3289SIlya Biryukov #include "clang/Frontend/FrontendActions.h" 21200b3289SIlya Biryukov #include "clang/Frontend/FrontendOptions.h" 22200b3289SIlya Biryukov #include "clang/Lex/Lexer.h" 23200b3289SIlya Biryukov #include "clang/Lex/PreprocessorOptions.h" 24200b3289SIlya Biryukov #include "clang/Serialization/ASTWriter.h" 25200b3289SIlya Biryukov #include "llvm/ADT/StringExtras.h" 26200b3289SIlya Biryukov #include "llvm/ADT/StringSet.h" 27200b3289SIlya Biryukov #include "llvm/Support/CrashRecoveryContext.h" 28200b3289SIlya Biryukov #include "llvm/Support/FileSystem.h" 29200b3289SIlya Biryukov #include "llvm/Support/Mutex.h" 30200b3289SIlya Biryukov #include "llvm/Support/MutexGuard.h" 31*b88de416SIlya Biryukov #include "llvm/Support/Process.h" 32200b3289SIlya Biryukov 33200b3289SIlya Biryukov using namespace clang; 34200b3289SIlya Biryukov 35200b3289SIlya Biryukov namespace { 36200b3289SIlya Biryukov 37200b3289SIlya Biryukov /// Keeps a track of files to be deleted in destructor. 38200b3289SIlya Biryukov class TemporaryFiles { 39200b3289SIlya Biryukov public: 40200b3289SIlya Biryukov // A static instance to be used by all clients. 41200b3289SIlya Biryukov static TemporaryFiles &getInstance(); 42200b3289SIlya Biryukov 43200b3289SIlya Biryukov private: 44200b3289SIlya Biryukov // Disallow constructing the class directly. 45200b3289SIlya Biryukov TemporaryFiles() = default; 46200b3289SIlya Biryukov // Disallow copy. 47200b3289SIlya Biryukov TemporaryFiles(const TemporaryFiles &) = delete; 48200b3289SIlya Biryukov 49200b3289SIlya Biryukov public: 50200b3289SIlya Biryukov ~TemporaryFiles(); 51200b3289SIlya Biryukov 52200b3289SIlya Biryukov /// Adds \p File to a set of tracked files. 53200b3289SIlya Biryukov void addFile(StringRef File); 54200b3289SIlya Biryukov 55200b3289SIlya Biryukov /// Remove \p File from disk and from the set of tracked files. 56200b3289SIlya Biryukov void removeFile(StringRef File); 57200b3289SIlya Biryukov 58200b3289SIlya Biryukov private: 59200b3289SIlya Biryukov llvm::sys::SmartMutex<false> Mutex; 60200b3289SIlya Biryukov llvm::StringSet<> Files; 61200b3289SIlya Biryukov }; 62200b3289SIlya Biryukov 63200b3289SIlya Biryukov TemporaryFiles &TemporaryFiles::getInstance() { 64200b3289SIlya Biryukov static TemporaryFiles Instance; 65200b3289SIlya Biryukov return Instance; 66200b3289SIlya Biryukov } 67200b3289SIlya Biryukov 68200b3289SIlya Biryukov TemporaryFiles::~TemporaryFiles() { 69200b3289SIlya Biryukov llvm::MutexGuard Guard(Mutex); 70200b3289SIlya Biryukov for (const auto &File : Files) 71200b3289SIlya Biryukov llvm::sys::fs::remove(File.getKey()); 72200b3289SIlya Biryukov } 73200b3289SIlya Biryukov 74200b3289SIlya Biryukov void TemporaryFiles::addFile(StringRef File) { 75200b3289SIlya Biryukov llvm::MutexGuard Guard(Mutex); 76200b3289SIlya Biryukov auto IsInserted = Files.insert(File).second; 7753dd644cSHaojian Wu (void)IsInserted; 78200b3289SIlya Biryukov assert(IsInserted && "File has already been added"); 79200b3289SIlya Biryukov } 80200b3289SIlya Biryukov 81200b3289SIlya Biryukov void TemporaryFiles::removeFile(StringRef File) { 82200b3289SIlya Biryukov llvm::MutexGuard Guard(Mutex); 83200b3289SIlya Biryukov auto WasPresent = Files.erase(File); 8453dd644cSHaojian Wu (void)WasPresent; 85200b3289SIlya Biryukov assert(WasPresent && "File was not tracked"); 86200b3289SIlya Biryukov llvm::sys::fs::remove(File); 87200b3289SIlya Biryukov } 88200b3289SIlya Biryukov 89200b3289SIlya Biryukov class PreambleMacroCallbacks : public PPCallbacks { 90200b3289SIlya Biryukov public: 91200b3289SIlya Biryukov PreambleMacroCallbacks(PreambleCallbacks &Callbacks) : Callbacks(Callbacks) {} 92200b3289SIlya Biryukov 93200b3289SIlya Biryukov void MacroDefined(const Token &MacroNameTok, 94200b3289SIlya Biryukov const MacroDirective *MD) override { 95200b3289SIlya Biryukov Callbacks.HandleMacroDefined(MacroNameTok, MD); 96200b3289SIlya Biryukov } 97200b3289SIlya Biryukov 98200b3289SIlya Biryukov private: 99200b3289SIlya Biryukov PreambleCallbacks &Callbacks; 100200b3289SIlya Biryukov }; 101200b3289SIlya Biryukov 102200b3289SIlya Biryukov class PrecompilePreambleAction : public ASTFrontendAction { 103200b3289SIlya Biryukov public: 104200b3289SIlya Biryukov PrecompilePreambleAction(PreambleCallbacks &Callbacks) 105200b3289SIlya Biryukov : Callbacks(Callbacks) {} 106200b3289SIlya Biryukov 107200b3289SIlya Biryukov std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, 108200b3289SIlya Biryukov StringRef InFile) override; 109200b3289SIlya Biryukov 110200b3289SIlya Biryukov bool hasEmittedPreamblePCH() const { return HasEmittedPreamblePCH; } 111200b3289SIlya Biryukov 112200b3289SIlya Biryukov void setEmittedPreamblePCH(ASTWriter &Writer) { 113200b3289SIlya Biryukov this->HasEmittedPreamblePCH = true; 114200b3289SIlya Biryukov Callbacks.AfterPCHEmitted(Writer); 115200b3289SIlya Biryukov } 116200b3289SIlya Biryukov 117200b3289SIlya Biryukov bool shouldEraseOutputFiles() override { return !hasEmittedPreamblePCH(); } 118200b3289SIlya Biryukov bool hasCodeCompletionSupport() const override { return false; } 119200b3289SIlya Biryukov bool hasASTFileSupport() const override { return false; } 120200b3289SIlya Biryukov TranslationUnitKind getTranslationUnitKind() override { return TU_Prefix; } 121200b3289SIlya Biryukov 122200b3289SIlya Biryukov private: 123200b3289SIlya Biryukov friend class PrecompilePreambleConsumer; 124200b3289SIlya Biryukov 125200b3289SIlya Biryukov bool HasEmittedPreamblePCH = false; 126200b3289SIlya Biryukov PreambleCallbacks &Callbacks; 127200b3289SIlya Biryukov }; 128200b3289SIlya Biryukov 129200b3289SIlya Biryukov class PrecompilePreambleConsumer : public PCHGenerator { 130200b3289SIlya Biryukov public: 131200b3289SIlya Biryukov PrecompilePreambleConsumer(PrecompilePreambleAction &Action, 132200b3289SIlya Biryukov const Preprocessor &PP, StringRef isysroot, 133200b3289SIlya Biryukov std::unique_ptr<raw_ostream> Out) 134200b3289SIlya Biryukov : PCHGenerator(PP, "", isysroot, std::make_shared<PCHBuffer>(), 135200b3289SIlya Biryukov ArrayRef<std::shared_ptr<ModuleFileExtension>>(), 136200b3289SIlya Biryukov /*AllowASTWithErrors=*/true), 137200b3289SIlya Biryukov Action(Action), Out(std::move(Out)) {} 138200b3289SIlya Biryukov 139200b3289SIlya Biryukov bool HandleTopLevelDecl(DeclGroupRef DG) override { 140200b3289SIlya Biryukov Action.Callbacks.HandleTopLevelDecl(DG); 141200b3289SIlya Biryukov return true; 142200b3289SIlya Biryukov } 143200b3289SIlya Biryukov 144200b3289SIlya Biryukov void HandleTranslationUnit(ASTContext &Ctx) override { 145200b3289SIlya Biryukov PCHGenerator::HandleTranslationUnit(Ctx); 146200b3289SIlya Biryukov if (!hasEmittedPCH()) 147200b3289SIlya Biryukov return; 148200b3289SIlya Biryukov 149200b3289SIlya Biryukov // Write the generated bitstream to "Out". 150200b3289SIlya Biryukov *Out << getPCH(); 151200b3289SIlya Biryukov // Make sure it hits disk now. 152200b3289SIlya Biryukov Out->flush(); 153200b3289SIlya Biryukov // Free the buffer. 154200b3289SIlya Biryukov llvm::SmallVector<char, 0> Empty; 155200b3289SIlya Biryukov getPCH() = std::move(Empty); 156200b3289SIlya Biryukov 157200b3289SIlya Biryukov Action.setEmittedPreamblePCH(getWriter()); 158200b3289SIlya Biryukov } 159200b3289SIlya Biryukov 160200b3289SIlya Biryukov private: 161200b3289SIlya Biryukov PrecompilePreambleAction &Action; 162200b3289SIlya Biryukov std::unique_ptr<raw_ostream> Out; 163200b3289SIlya Biryukov }; 164200b3289SIlya Biryukov 165200b3289SIlya Biryukov std::unique_ptr<ASTConsumer> 166200b3289SIlya Biryukov PrecompilePreambleAction::CreateASTConsumer(CompilerInstance &CI, 167200b3289SIlya Biryukov 168200b3289SIlya Biryukov StringRef InFile) { 169200b3289SIlya Biryukov std::string Sysroot; 170200b3289SIlya Biryukov std::string OutputFile; 171200b3289SIlya Biryukov std::unique_ptr<raw_ostream> OS = 172200b3289SIlya Biryukov GeneratePCHAction::ComputeASTConsumerArguments(CI, InFile, Sysroot, 173200b3289SIlya Biryukov OutputFile); 174200b3289SIlya Biryukov if (!OS) 175200b3289SIlya Biryukov return nullptr; 176200b3289SIlya Biryukov 177200b3289SIlya Biryukov if (!CI.getFrontendOpts().RelocatablePCH) 178200b3289SIlya Biryukov Sysroot.clear(); 179200b3289SIlya Biryukov 180200b3289SIlya Biryukov CI.getPreprocessor().addPPCallbacks( 181200b3289SIlya Biryukov llvm::make_unique<PreambleMacroCallbacks>(Callbacks)); 182200b3289SIlya Biryukov return llvm::make_unique<PrecompilePreambleConsumer>( 183200b3289SIlya Biryukov *this, CI.getPreprocessor(), Sysroot, std::move(OS)); 184200b3289SIlya Biryukov } 185200b3289SIlya Biryukov 186200b3289SIlya Biryukov template <class T> bool moveOnNoError(llvm::ErrorOr<T> Val, T &Output) { 187200b3289SIlya Biryukov if (!Val) 188200b3289SIlya Biryukov return false; 189200b3289SIlya Biryukov Output = std::move(*Val); 190200b3289SIlya Biryukov return true; 191200b3289SIlya Biryukov } 192200b3289SIlya Biryukov 193200b3289SIlya Biryukov } // namespace 194200b3289SIlya Biryukov 195200b3289SIlya Biryukov PreambleBounds clang::ComputePreambleBounds(const LangOptions &LangOpts, 196200b3289SIlya Biryukov llvm::MemoryBuffer *Buffer, 197200b3289SIlya Biryukov unsigned MaxLines) { 198200b3289SIlya Biryukov auto Pre = Lexer::ComputePreamble(Buffer->getBuffer(), LangOpts, MaxLines); 199200b3289SIlya Biryukov return PreambleBounds(Pre.first, Pre.second); 200200b3289SIlya Biryukov } 201200b3289SIlya Biryukov 202200b3289SIlya Biryukov llvm::ErrorOr<PrecompiledPreamble> PrecompiledPreamble::Build( 203200b3289SIlya Biryukov const CompilerInvocation &Invocation, 204200b3289SIlya Biryukov const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds, 205200b3289SIlya Biryukov DiagnosticsEngine &Diagnostics, IntrusiveRefCntPtr<vfs::FileSystem> VFS, 206200b3289SIlya Biryukov std::shared_ptr<PCHContainerOperations> PCHContainerOps, 207200b3289SIlya Biryukov PreambleCallbacks &Callbacks) { 208200b3289SIlya Biryukov assert(VFS && "VFS is null"); 209200b3289SIlya Biryukov 210200b3289SIlya Biryukov if (!Bounds.Size) 211200b3289SIlya Biryukov return BuildPreambleError::PreambleIsEmpty; 212200b3289SIlya Biryukov 213200b3289SIlya Biryukov auto PreambleInvocation = std::make_shared<CompilerInvocation>(Invocation); 214200b3289SIlya Biryukov FrontendOptions &FrontendOpts = PreambleInvocation->getFrontendOpts(); 215200b3289SIlya Biryukov PreprocessorOptions &PreprocessorOpts = 216200b3289SIlya Biryukov PreambleInvocation->getPreprocessorOpts(); 217200b3289SIlya Biryukov 218200b3289SIlya Biryukov // Create a temporary file for the precompiled preamble. In rare 219200b3289SIlya Biryukov // circumstances, this can fail. 220200b3289SIlya Biryukov llvm::ErrorOr<PrecompiledPreamble::TempPCHFile> PreamblePCHFile = 221200b3289SIlya Biryukov PrecompiledPreamble::TempPCHFile::CreateNewPreamblePCHFile(); 222200b3289SIlya Biryukov if (!PreamblePCHFile) 223200b3289SIlya Biryukov return BuildPreambleError::CouldntCreateTempFile; 224200b3289SIlya Biryukov 225200b3289SIlya Biryukov // Save the preamble text for later; we'll need to compare against it for 226200b3289SIlya Biryukov // subsequent reparses. 227200b3289SIlya Biryukov std::vector<char> PreambleBytes(MainFileBuffer->getBufferStart(), 228200b3289SIlya Biryukov MainFileBuffer->getBufferStart() + 229200b3289SIlya Biryukov Bounds.Size); 230200b3289SIlya Biryukov bool PreambleEndsAtStartOfLine = Bounds.PreambleEndsAtStartOfLine; 231200b3289SIlya Biryukov 232200b3289SIlya Biryukov // Tell the compiler invocation to generate a temporary precompiled header. 233200b3289SIlya Biryukov FrontendOpts.ProgramAction = frontend::GeneratePCH; 234200b3289SIlya Biryukov // FIXME: Generate the precompiled header into memory? 235200b3289SIlya Biryukov FrontendOpts.OutputFile = PreamblePCHFile->getFilePath(); 236200b3289SIlya Biryukov PreprocessorOpts.PrecompiledPreambleBytes.first = 0; 237200b3289SIlya Biryukov PreprocessorOpts.PrecompiledPreambleBytes.second = false; 238200b3289SIlya Biryukov 239200b3289SIlya Biryukov // Create the compiler instance to use for building the precompiled preamble. 240200b3289SIlya Biryukov std::unique_ptr<CompilerInstance> Clang( 241200b3289SIlya Biryukov new CompilerInstance(std::move(PCHContainerOps))); 242200b3289SIlya Biryukov 243200b3289SIlya Biryukov // Recover resources if we crash before exiting this method. 244200b3289SIlya Biryukov llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance> CICleanup( 245200b3289SIlya Biryukov Clang.get()); 246200b3289SIlya Biryukov 247200b3289SIlya Biryukov Clang->setInvocation(std::move(PreambleInvocation)); 248200b3289SIlya Biryukov Clang->setDiagnostics(&Diagnostics); 249200b3289SIlya Biryukov 250200b3289SIlya Biryukov // Create the target instance. 251200b3289SIlya Biryukov Clang->setTarget(TargetInfo::CreateTargetInfo( 252200b3289SIlya Biryukov Clang->getDiagnostics(), Clang->getInvocation().TargetOpts)); 253200b3289SIlya Biryukov if (!Clang->hasTarget()) 254200b3289SIlya Biryukov return BuildPreambleError::CouldntCreateTargetInfo; 255200b3289SIlya Biryukov 256200b3289SIlya Biryukov // Inform the target of the language options. 257200b3289SIlya Biryukov // 258200b3289SIlya Biryukov // FIXME: We shouldn't need to do this, the target should be immutable once 259200b3289SIlya Biryukov // created. This complexity should be lifted elsewhere. 260200b3289SIlya Biryukov Clang->getTarget().adjust(Clang->getLangOpts()); 261200b3289SIlya Biryukov 262200b3289SIlya Biryukov assert(Clang->getFrontendOpts().Inputs.size() == 1 && 263200b3289SIlya Biryukov "Invocation must have exactly one source file!"); 264200b3289SIlya Biryukov assert(Clang->getFrontendOpts().Inputs[0].getKind().getFormat() == 265200b3289SIlya Biryukov InputKind::Source && 266200b3289SIlya Biryukov "FIXME: AST inputs not yet supported here!"); 267200b3289SIlya Biryukov assert(Clang->getFrontendOpts().Inputs[0].getKind().getLanguage() != 268200b3289SIlya Biryukov InputKind::LLVM_IR && 269200b3289SIlya Biryukov "IR inputs not support here!"); 270200b3289SIlya Biryukov 271200b3289SIlya Biryukov // Clear out old caches and data. 272200b3289SIlya Biryukov Diagnostics.Reset(); 273200b3289SIlya Biryukov ProcessWarningOptions(Diagnostics, Clang->getDiagnosticOpts()); 274200b3289SIlya Biryukov 275200b3289SIlya Biryukov VFS = 276200b3289SIlya Biryukov createVFSFromCompilerInvocation(Clang->getInvocation(), Diagnostics, VFS); 277200b3289SIlya Biryukov if (!VFS) 278200b3289SIlya Biryukov return BuildPreambleError::CouldntCreateVFSOverlay; 279200b3289SIlya Biryukov 280200b3289SIlya Biryukov // Create a file manager object to provide access to and cache the filesystem. 281200b3289SIlya Biryukov Clang->setFileManager(new FileManager(Clang->getFileSystemOpts(), VFS)); 282200b3289SIlya Biryukov 283200b3289SIlya Biryukov // Create the source manager. 284200b3289SIlya Biryukov Clang->setSourceManager( 285200b3289SIlya Biryukov new SourceManager(Diagnostics, Clang->getFileManager())); 286200b3289SIlya Biryukov 287200b3289SIlya Biryukov auto PreambleDepCollector = std::make_shared<DependencyCollector>(); 288200b3289SIlya Biryukov Clang->addDependencyCollector(PreambleDepCollector); 289200b3289SIlya Biryukov 290200b3289SIlya Biryukov // Remap the main source file to the preamble buffer. 291200b3289SIlya Biryukov StringRef MainFilePath = FrontendOpts.Inputs[0].getFile(); 292200b3289SIlya Biryukov auto PreambleInputBuffer = llvm::MemoryBuffer::getMemBufferCopy( 293200b3289SIlya Biryukov MainFileBuffer->getBuffer().slice(0, Bounds.Size), MainFilePath); 294200b3289SIlya Biryukov if (PreprocessorOpts.RetainRemappedFileBuffers) { 295200b3289SIlya Biryukov // MainFileBuffer will be deleted by unique_ptr after leaving the method. 296200b3289SIlya Biryukov PreprocessorOpts.addRemappedFile(MainFilePath, PreambleInputBuffer.get()); 297200b3289SIlya Biryukov } else { 298200b3289SIlya Biryukov // In that case, remapped buffer will be deleted by CompilerInstance on 299200b3289SIlya Biryukov // BeginSourceFile, so we call release() to avoid double deletion. 300200b3289SIlya Biryukov PreprocessorOpts.addRemappedFile(MainFilePath, 301200b3289SIlya Biryukov PreambleInputBuffer.release()); 302200b3289SIlya Biryukov } 303200b3289SIlya Biryukov 304200b3289SIlya Biryukov std::unique_ptr<PrecompilePreambleAction> Act; 305200b3289SIlya Biryukov Act.reset(new PrecompilePreambleAction(Callbacks)); 306200b3289SIlya Biryukov if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0])) 307200b3289SIlya Biryukov return BuildPreambleError::BeginSourceFileFailed; 308200b3289SIlya Biryukov 309200b3289SIlya Biryukov Act->Execute(); 310200b3289SIlya Biryukov 311200b3289SIlya Biryukov // Run the callbacks. 312200b3289SIlya Biryukov Callbacks.AfterExecute(*Clang); 313200b3289SIlya Biryukov 314200b3289SIlya Biryukov Act->EndSourceFile(); 315200b3289SIlya Biryukov 316200b3289SIlya Biryukov if (!Act->hasEmittedPreamblePCH()) 317200b3289SIlya Biryukov return BuildPreambleError::CouldntEmitPCH; 318200b3289SIlya Biryukov 319200b3289SIlya Biryukov // Keep track of all of the files that the source manager knows about, 320200b3289SIlya Biryukov // so we can verify whether they have changed or not. 321200b3289SIlya Biryukov llvm::StringMap<PrecompiledPreamble::PreambleFileHash> FilesInPreamble; 322200b3289SIlya Biryukov 323200b3289SIlya Biryukov SourceManager &SourceMgr = Clang->getSourceManager(); 324200b3289SIlya Biryukov for (auto &Filename : PreambleDepCollector->getDependencies()) { 325200b3289SIlya Biryukov const FileEntry *File = Clang->getFileManager().getFile(Filename); 326200b3289SIlya Biryukov if (!File || File == SourceMgr.getFileEntryForID(SourceMgr.getMainFileID())) 327200b3289SIlya Biryukov continue; 328200b3289SIlya Biryukov if (time_t ModTime = File->getModificationTime()) { 329200b3289SIlya Biryukov FilesInPreamble[File->getName()] = 330200b3289SIlya Biryukov PrecompiledPreamble::PreambleFileHash::createForFile(File->getSize(), 331200b3289SIlya Biryukov ModTime); 332200b3289SIlya Biryukov } else { 333200b3289SIlya Biryukov llvm::MemoryBuffer *Buffer = SourceMgr.getMemoryBufferForFile(File); 334200b3289SIlya Biryukov FilesInPreamble[File->getName()] = 335200b3289SIlya Biryukov PrecompiledPreamble::PreambleFileHash::createForMemoryBuffer(Buffer); 336200b3289SIlya Biryukov } 337200b3289SIlya Biryukov } 338200b3289SIlya Biryukov 339200b3289SIlya Biryukov return PrecompiledPreamble( 340200b3289SIlya Biryukov std::move(*PreamblePCHFile), std::move(PreambleBytes), 341200b3289SIlya Biryukov PreambleEndsAtStartOfLine, std::move(FilesInPreamble)); 342200b3289SIlya Biryukov } 343200b3289SIlya Biryukov 344200b3289SIlya Biryukov PreambleBounds PrecompiledPreamble::getBounds() const { 345200b3289SIlya Biryukov return PreambleBounds(PreambleBytes.size(), PreambleEndsAtStartOfLine); 346200b3289SIlya Biryukov } 347200b3289SIlya Biryukov 348200b3289SIlya Biryukov bool PrecompiledPreamble::CanReuse(const CompilerInvocation &Invocation, 349200b3289SIlya Biryukov const llvm::MemoryBuffer *MainFileBuffer, 350200b3289SIlya Biryukov PreambleBounds Bounds, 351200b3289SIlya Biryukov vfs::FileSystem *VFS) const { 352200b3289SIlya Biryukov 353200b3289SIlya Biryukov assert( 354200b3289SIlya Biryukov Bounds.Size <= MainFileBuffer->getBufferSize() && 355200b3289SIlya Biryukov "Buffer is too large. Bounds were calculated from a different buffer?"); 356200b3289SIlya Biryukov 357200b3289SIlya Biryukov auto PreambleInvocation = std::make_shared<CompilerInvocation>(Invocation); 358200b3289SIlya Biryukov PreprocessorOptions &PreprocessorOpts = 359200b3289SIlya Biryukov PreambleInvocation->getPreprocessorOpts(); 360200b3289SIlya Biryukov 361200b3289SIlya Biryukov if (!Bounds.Size) 362200b3289SIlya Biryukov return false; 363200b3289SIlya Biryukov 364200b3289SIlya Biryukov // We've previously computed a preamble. Check whether we have the same 365200b3289SIlya Biryukov // preamble now that we did before, and that there's enough space in 366200b3289SIlya Biryukov // the main-file buffer within the precompiled preamble to fit the 367200b3289SIlya Biryukov // new main file. 368200b3289SIlya Biryukov if (PreambleBytes.size() != Bounds.Size || 369200b3289SIlya Biryukov PreambleEndsAtStartOfLine != Bounds.PreambleEndsAtStartOfLine || 370200b3289SIlya Biryukov memcmp(PreambleBytes.data(), MainFileBuffer->getBufferStart(), 371200b3289SIlya Biryukov Bounds.Size) != 0) 372200b3289SIlya Biryukov return false; 373200b3289SIlya Biryukov // The preamble has not changed. We may be able to re-use the precompiled 374200b3289SIlya Biryukov // preamble. 375200b3289SIlya Biryukov 376200b3289SIlya Biryukov // Check that none of the files used by the preamble have changed. 377200b3289SIlya Biryukov // First, make a record of those files that have been overridden via 378200b3289SIlya Biryukov // remapping or unsaved_files. 379200b3289SIlya Biryukov std::map<llvm::sys::fs::UniqueID, PreambleFileHash> OverriddenFiles; 380200b3289SIlya Biryukov for (const auto &R : PreprocessorOpts.RemappedFiles) { 381200b3289SIlya Biryukov vfs::Status Status; 382200b3289SIlya Biryukov if (!moveOnNoError(VFS->status(R.second), Status)) { 383200b3289SIlya Biryukov // If we can't stat the file we're remapping to, assume that something 384200b3289SIlya Biryukov // horrible happened. 385200b3289SIlya Biryukov return false; 386200b3289SIlya Biryukov } 387200b3289SIlya Biryukov 388200b3289SIlya Biryukov OverriddenFiles[Status.getUniqueID()] = PreambleFileHash::createForFile( 389200b3289SIlya Biryukov Status.getSize(), llvm::sys::toTimeT(Status.getLastModificationTime())); 390200b3289SIlya Biryukov } 391200b3289SIlya Biryukov 392200b3289SIlya Biryukov for (const auto &RB : PreprocessorOpts.RemappedFileBuffers) { 393200b3289SIlya Biryukov vfs::Status Status; 394200b3289SIlya Biryukov if (!moveOnNoError(VFS->status(RB.first), Status)) 395200b3289SIlya Biryukov return false; 396200b3289SIlya Biryukov 397200b3289SIlya Biryukov OverriddenFiles[Status.getUniqueID()] = 398200b3289SIlya Biryukov PreambleFileHash::createForMemoryBuffer(RB.second); 399200b3289SIlya Biryukov } 400200b3289SIlya Biryukov 401200b3289SIlya Biryukov // Check whether anything has changed. 402200b3289SIlya Biryukov for (const auto &F : FilesInPreamble) { 403200b3289SIlya Biryukov vfs::Status Status; 404200b3289SIlya Biryukov if (!moveOnNoError(VFS->status(F.first()), Status)) { 405200b3289SIlya Biryukov // If we can't stat the file, assume that something horrible happened. 406200b3289SIlya Biryukov return false; 407200b3289SIlya Biryukov } 408200b3289SIlya Biryukov 409200b3289SIlya Biryukov std::map<llvm::sys::fs::UniqueID, PreambleFileHash>::iterator Overridden = 410200b3289SIlya Biryukov OverriddenFiles.find(Status.getUniqueID()); 411200b3289SIlya Biryukov if (Overridden != OverriddenFiles.end()) { 412200b3289SIlya Biryukov // This file was remapped; check whether the newly-mapped file 413200b3289SIlya Biryukov // matches up with the previous mapping. 414200b3289SIlya Biryukov if (Overridden->second != F.second) 415200b3289SIlya Biryukov return false; 416200b3289SIlya Biryukov continue; 417200b3289SIlya Biryukov } 418200b3289SIlya Biryukov 419200b3289SIlya Biryukov // The file was not remapped; check whether it has changed on disk. 420200b3289SIlya Biryukov if (Status.getSize() != uint64_t(F.second.Size) || 421200b3289SIlya Biryukov llvm::sys::toTimeT(Status.getLastModificationTime()) != 422200b3289SIlya Biryukov F.second.ModTime) 423200b3289SIlya Biryukov return false; 424200b3289SIlya Biryukov } 425200b3289SIlya Biryukov return true; 426200b3289SIlya Biryukov } 427200b3289SIlya Biryukov 428200b3289SIlya Biryukov void PrecompiledPreamble::AddImplicitPreamble( 429200b3289SIlya Biryukov CompilerInvocation &CI, llvm::MemoryBuffer *MainFileBuffer) const { 430200b3289SIlya Biryukov auto &PreprocessorOpts = CI.getPreprocessorOpts(); 431200b3289SIlya Biryukov 432200b3289SIlya Biryukov // Configure ImpicitPCHInclude. 433200b3289SIlya Biryukov PreprocessorOpts.PrecompiledPreambleBytes.first = PreambleBytes.size(); 434200b3289SIlya Biryukov PreprocessorOpts.PrecompiledPreambleBytes.second = PreambleEndsAtStartOfLine; 435200b3289SIlya Biryukov PreprocessorOpts.ImplicitPCHInclude = PCHFile.getFilePath(); 436200b3289SIlya Biryukov PreprocessorOpts.DisablePCHValidation = true; 437200b3289SIlya Biryukov 438200b3289SIlya Biryukov // Remap main file to point to MainFileBuffer. 439200b3289SIlya Biryukov auto MainFilePath = CI.getFrontendOpts().Inputs[0].getFile(); 440200b3289SIlya Biryukov PreprocessorOpts.addRemappedFile(MainFilePath, MainFileBuffer); 441200b3289SIlya Biryukov } 442200b3289SIlya Biryukov 443200b3289SIlya Biryukov PrecompiledPreamble::PrecompiledPreamble( 444200b3289SIlya Biryukov TempPCHFile PCHFile, std::vector<char> PreambleBytes, 445200b3289SIlya Biryukov bool PreambleEndsAtStartOfLine, 446200b3289SIlya Biryukov llvm::StringMap<PreambleFileHash> FilesInPreamble) 447200b3289SIlya Biryukov : PCHFile(std::move(PCHFile)), FilesInPreamble(FilesInPreamble), 448200b3289SIlya Biryukov PreambleBytes(std::move(PreambleBytes)), 449200b3289SIlya Biryukov PreambleEndsAtStartOfLine(PreambleEndsAtStartOfLine) {} 450200b3289SIlya Biryukov 451200b3289SIlya Biryukov llvm::ErrorOr<PrecompiledPreamble::TempPCHFile> 452200b3289SIlya Biryukov PrecompiledPreamble::TempPCHFile::CreateNewPreamblePCHFile() { 453200b3289SIlya Biryukov // FIXME: This is a hack so that we can override the preamble file during 454200b3289SIlya Biryukov // crash-recovery testing, which is the only case where the preamble files 455200b3289SIlya Biryukov // are not necessarily cleaned up. 456200b3289SIlya Biryukov const char *TmpFile = ::getenv("CINDEXTEST_PREAMBLE_FILE"); 457200b3289SIlya Biryukov if (TmpFile) 458200b3289SIlya Biryukov return TempPCHFile::createFromCustomPath(TmpFile); 459200b3289SIlya Biryukov return TempPCHFile::createInSystemTempDir("preamble", "pch"); 460200b3289SIlya Biryukov } 461200b3289SIlya Biryukov 462200b3289SIlya Biryukov llvm::ErrorOr<PrecompiledPreamble::TempPCHFile> 463200b3289SIlya Biryukov PrecompiledPreamble::TempPCHFile::createInSystemTempDir(const Twine &Prefix, 464200b3289SIlya Biryukov StringRef Suffix) { 465200b3289SIlya Biryukov llvm::SmallString<64> File; 466*b88de416SIlya Biryukov // Using a version of createTemporaryFile with a file descriptor guarantees 467*b88de416SIlya Biryukov // that we would never get a race condition in a multi-threaded setting (i.e., 468*b88de416SIlya Biryukov // multiple threads getting the same temporary path). 469*b88de416SIlya Biryukov int FD; 470*b88de416SIlya Biryukov auto EC = llvm::sys::fs::createTemporaryFile(Prefix, Suffix, /*ref*/ FD, 471*b88de416SIlya Biryukov /*ref*/ File); 472200b3289SIlya Biryukov if (EC) 473200b3289SIlya Biryukov return EC; 474*b88de416SIlya Biryukov // We only needed to make sure the file exists, close the file right away. 475*b88de416SIlya Biryukov llvm::sys::Process::SafelyCloseFileDescriptor(FD); 476200b3289SIlya Biryukov return TempPCHFile(std::move(File).str()); 477200b3289SIlya Biryukov } 478200b3289SIlya Biryukov 479200b3289SIlya Biryukov llvm::ErrorOr<PrecompiledPreamble::TempPCHFile> 480200b3289SIlya Biryukov PrecompiledPreamble::TempPCHFile::createFromCustomPath(const Twine &Path) { 481200b3289SIlya Biryukov return TempPCHFile(Path.str()); 482200b3289SIlya Biryukov } 483200b3289SIlya Biryukov 484200b3289SIlya Biryukov PrecompiledPreamble::TempPCHFile::TempPCHFile(std::string FilePath) 485200b3289SIlya Biryukov : FilePath(std::move(FilePath)) { 486200b3289SIlya Biryukov TemporaryFiles::getInstance().addFile(*this->FilePath); 487200b3289SIlya Biryukov } 488200b3289SIlya Biryukov 489200b3289SIlya Biryukov PrecompiledPreamble::TempPCHFile::TempPCHFile(TempPCHFile &&Other) { 490200b3289SIlya Biryukov FilePath = std::move(Other.FilePath); 491200b3289SIlya Biryukov Other.FilePath = None; 492200b3289SIlya Biryukov } 493200b3289SIlya Biryukov 494200b3289SIlya Biryukov PrecompiledPreamble::TempPCHFile &PrecompiledPreamble::TempPCHFile:: 495200b3289SIlya Biryukov operator=(TempPCHFile &&Other) { 496200b3289SIlya Biryukov RemoveFileIfPresent(); 497200b3289SIlya Biryukov 498200b3289SIlya Biryukov FilePath = std::move(Other.FilePath); 499200b3289SIlya Biryukov Other.FilePath = None; 500200b3289SIlya Biryukov return *this; 501200b3289SIlya Biryukov } 502200b3289SIlya Biryukov 503200b3289SIlya Biryukov PrecompiledPreamble::TempPCHFile::~TempPCHFile() { RemoveFileIfPresent(); } 504200b3289SIlya Biryukov 505200b3289SIlya Biryukov void PrecompiledPreamble::TempPCHFile::RemoveFileIfPresent() { 506200b3289SIlya Biryukov if (FilePath) { 507200b3289SIlya Biryukov TemporaryFiles::getInstance().removeFile(*FilePath); 508200b3289SIlya Biryukov FilePath = None; 509200b3289SIlya Biryukov } 510200b3289SIlya Biryukov } 511200b3289SIlya Biryukov 512200b3289SIlya Biryukov llvm::StringRef PrecompiledPreamble::TempPCHFile::getFilePath() const { 513200b3289SIlya Biryukov assert(FilePath && "TempPCHFile doesn't have a FilePath. Had it been moved?"); 514200b3289SIlya Biryukov return *FilePath; 515200b3289SIlya Biryukov } 516200b3289SIlya Biryukov 517200b3289SIlya Biryukov PrecompiledPreamble::PreambleFileHash 518200b3289SIlya Biryukov PrecompiledPreamble::PreambleFileHash::createForFile(off_t Size, 519200b3289SIlya Biryukov time_t ModTime) { 520200b3289SIlya Biryukov PreambleFileHash Result; 521200b3289SIlya Biryukov Result.Size = Size; 522200b3289SIlya Biryukov Result.ModTime = ModTime; 523200b3289SIlya Biryukov Result.MD5 = {}; 524200b3289SIlya Biryukov return Result; 525200b3289SIlya Biryukov } 526200b3289SIlya Biryukov 527200b3289SIlya Biryukov PrecompiledPreamble::PreambleFileHash 528200b3289SIlya Biryukov PrecompiledPreamble::PreambleFileHash::createForMemoryBuffer( 529200b3289SIlya Biryukov const llvm::MemoryBuffer *Buffer) { 530200b3289SIlya Biryukov PreambleFileHash Result; 531200b3289SIlya Biryukov Result.Size = Buffer->getBufferSize(); 532200b3289SIlya Biryukov Result.ModTime = 0; 533200b3289SIlya Biryukov 534200b3289SIlya Biryukov llvm::MD5 MD5Ctx; 535200b3289SIlya Biryukov MD5Ctx.update(Buffer->getBuffer().data()); 536200b3289SIlya Biryukov MD5Ctx.final(Result.MD5); 537200b3289SIlya Biryukov 538200b3289SIlya Biryukov return Result; 539200b3289SIlya Biryukov } 540200b3289SIlya Biryukov 541200b3289SIlya Biryukov void PreambleCallbacks::AfterExecute(CompilerInstance &CI) {} 542200b3289SIlya Biryukov void PreambleCallbacks::AfterPCHEmitted(ASTWriter &Writer) {} 543200b3289SIlya Biryukov void PreambleCallbacks::HandleTopLevelDecl(DeclGroupRef DG) {} 544200b3289SIlya Biryukov void PreambleCallbacks::HandleMacroDefined(const Token &MacroNameTok, 545200b3289SIlya Biryukov const MacroDirective *MD) {} 546200b3289SIlya Biryukov 547200b3289SIlya Biryukov std::error_code clang::make_error_code(BuildPreambleError Error) { 548200b3289SIlya Biryukov return std::error_code(static_cast<int>(Error), BuildPreambleErrorCategory()); 549200b3289SIlya Biryukov } 550200b3289SIlya Biryukov 551200b3289SIlya Biryukov const char *BuildPreambleErrorCategory::name() const noexcept { 552200b3289SIlya Biryukov return "build-preamble.error"; 553200b3289SIlya Biryukov } 554200b3289SIlya Biryukov 555200b3289SIlya Biryukov std::string BuildPreambleErrorCategory::message(int condition) const { 556200b3289SIlya Biryukov switch (static_cast<BuildPreambleError>(condition)) { 557200b3289SIlya Biryukov case BuildPreambleError::PreambleIsEmpty: 558200b3289SIlya Biryukov return "Preamble is empty"; 559200b3289SIlya Biryukov case BuildPreambleError::CouldntCreateTempFile: 560200b3289SIlya Biryukov return "Could not create temporary file for PCH"; 561200b3289SIlya Biryukov case BuildPreambleError::CouldntCreateTargetInfo: 562200b3289SIlya Biryukov return "CreateTargetInfo() return null"; 563200b3289SIlya Biryukov case BuildPreambleError::CouldntCreateVFSOverlay: 564200b3289SIlya Biryukov return "Could not create VFS Overlay"; 565200b3289SIlya Biryukov case BuildPreambleError::BeginSourceFileFailed: 566200b3289SIlya Biryukov return "BeginSourceFile() return an error"; 567200b3289SIlya Biryukov case BuildPreambleError::CouldntEmitPCH: 568200b3289SIlya Biryukov return "Could not emit PCH"; 569200b3289SIlya Biryukov } 570200b3289SIlya Biryukov llvm_unreachable("unexpected BuildPreambleError"); 571200b3289SIlya Biryukov } 572