10b57cec5SDimitry Andric //===- DependencyScanningWorker.cpp - clang-scan-deps worker --------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "clang/Tooling/DependencyScanning/DependencyScanningWorker.h" 1006c3fb27SDimitry Andric #include "clang/Basic/DiagnosticDriver.h" 11bdd1243dSDimitry Andric #include "clang/Basic/DiagnosticFrontend.h" 12*0fca6ea1SDimitry Andric #include "clang/Basic/DiagnosticSerialization.h" 13fe6060f1SDimitry Andric #include "clang/CodeGen/ObjectFilePCHContainerOperations.h" 14bdd1243dSDimitry Andric #include "clang/Driver/Compilation.h" 15bdd1243dSDimitry Andric #include "clang/Driver/Driver.h" 16bdd1243dSDimitry Andric #include "clang/Driver/Job.h" 17bdd1243dSDimitry Andric #include "clang/Driver/Tool.h" 180b57cec5SDimitry Andric #include "clang/Frontend/CompilerInstance.h" 19a7dea167SDimitry Andric #include "clang/Frontend/CompilerInvocation.h" 200b57cec5SDimitry Andric #include "clang/Frontend/FrontendActions.h" 210b57cec5SDimitry Andric #include "clang/Frontend/TextDiagnosticPrinter.h" 220b57cec5SDimitry Andric #include "clang/Frontend/Utils.h" 23a7dea167SDimitry Andric #include "clang/Lex/PreprocessorOptions.h" 24a7dea167SDimitry Andric #include "clang/Tooling/DependencyScanning/DependencyScanningService.h" 25480093f4SDimitry Andric #include "clang/Tooling/DependencyScanning/ModuleDepCollector.h" 260b57cec5SDimitry Andric #include "clang/Tooling/Tooling.h" 27*0fca6ea1SDimitry Andric #include "llvm/ADT/ScopeExit.h" 2806c3fb27SDimitry Andric #include "llvm/Support/Allocator.h" 2906c3fb27SDimitry Andric #include "llvm/Support/Error.h" 3006c3fb27SDimitry Andric #include "llvm/TargetParser/Host.h" 31bdd1243dSDimitry Andric #include <optional> 320b57cec5SDimitry Andric 330b57cec5SDimitry Andric using namespace clang; 340b57cec5SDimitry Andric using namespace tooling; 350b57cec5SDimitry Andric using namespace dependencies; 360b57cec5SDimitry Andric 370b57cec5SDimitry Andric namespace { 380b57cec5SDimitry Andric 39a7dea167SDimitry Andric /// Forwards the gatherered dependencies to the consumer. 40a7dea167SDimitry Andric class DependencyConsumerForwarder : public DependencyFileGenerator { 410b57cec5SDimitry Andric public: 42a7dea167SDimitry Andric DependencyConsumerForwarder(std::unique_ptr<DependencyOutputOptions> Opts, 43bdd1243dSDimitry Andric StringRef WorkingDirectory, DependencyConsumer &C) 44bdd1243dSDimitry Andric : DependencyFileGenerator(*Opts), WorkingDirectory(WorkingDirectory), 45bdd1243dSDimitry Andric Opts(std::move(Opts)), C(C) {} 460b57cec5SDimitry Andric 470b57cec5SDimitry Andric void finishedMainFile(DiagnosticsEngine &Diags) override { 48fe6060f1SDimitry Andric C.handleDependencyOutputOpts(*Opts); 49a7dea167SDimitry Andric llvm::SmallString<256> CanonPath; 50a7dea167SDimitry Andric for (const auto &File : getDependencies()) { 51a7dea167SDimitry Andric CanonPath = File; 52a7dea167SDimitry Andric llvm::sys::path::remove_dots(CanonPath, /*remove_dot_dot=*/true); 53bdd1243dSDimitry Andric llvm::sys::fs::make_absolute(WorkingDirectory, CanonPath); 54fe6060f1SDimitry Andric C.handleFileDependency(CanonPath); 55a7dea167SDimitry Andric } 560b57cec5SDimitry Andric } 570b57cec5SDimitry Andric 580b57cec5SDimitry Andric private: 59bdd1243dSDimitry Andric StringRef WorkingDirectory; 600b57cec5SDimitry Andric std::unique_ptr<DependencyOutputOptions> Opts; 61a7dea167SDimitry Andric DependencyConsumer &C; 620b57cec5SDimitry Andric }; 630b57cec5SDimitry Andric 64*0fca6ea1SDimitry Andric static bool checkHeaderSearchPaths(const HeaderSearchOptions &HSOpts, 65*0fca6ea1SDimitry Andric const HeaderSearchOptions &ExistingHSOpts, 66*0fca6ea1SDimitry Andric DiagnosticsEngine *Diags, 67*0fca6ea1SDimitry Andric const LangOptions &LangOpts) { 68*0fca6ea1SDimitry Andric if (LangOpts.Modules) { 69*0fca6ea1SDimitry Andric if (HSOpts.VFSOverlayFiles != ExistingHSOpts.VFSOverlayFiles) { 70*0fca6ea1SDimitry Andric if (Diags) { 71*0fca6ea1SDimitry Andric Diags->Report(diag::warn_pch_vfsoverlay_mismatch); 72*0fca6ea1SDimitry Andric auto VFSNote = [&](int Type, ArrayRef<std::string> VFSOverlays) { 73*0fca6ea1SDimitry Andric if (VFSOverlays.empty()) { 74*0fca6ea1SDimitry Andric Diags->Report(diag::note_pch_vfsoverlay_empty) << Type; 75*0fca6ea1SDimitry Andric } else { 76*0fca6ea1SDimitry Andric std::string Files = llvm::join(VFSOverlays, "\n"); 77*0fca6ea1SDimitry Andric Diags->Report(diag::note_pch_vfsoverlay_files) << Type << Files; 78*0fca6ea1SDimitry Andric } 79*0fca6ea1SDimitry Andric }; 80*0fca6ea1SDimitry Andric VFSNote(0, HSOpts.VFSOverlayFiles); 81*0fca6ea1SDimitry Andric VFSNote(1, ExistingHSOpts.VFSOverlayFiles); 82*0fca6ea1SDimitry Andric } 83*0fca6ea1SDimitry Andric } 84*0fca6ea1SDimitry Andric } 85*0fca6ea1SDimitry Andric return false; 86*0fca6ea1SDimitry Andric } 87*0fca6ea1SDimitry Andric 8881ad6265SDimitry Andric using PrebuiltModuleFilesT = decltype(HeaderSearchOptions::PrebuiltModuleFiles); 8981ad6265SDimitry Andric 90fe6060f1SDimitry Andric /// A listener that collects the imported modules and optionally the input 91fe6060f1SDimitry Andric /// files. 92fe6060f1SDimitry Andric class PrebuiltModuleListener : public ASTReaderListener { 93fe6060f1SDimitry Andric public: 9481ad6265SDimitry Andric PrebuiltModuleListener(PrebuiltModuleFilesT &PrebuiltModuleFiles, 95*0fca6ea1SDimitry Andric llvm::SmallVector<std::string> &NewModuleFiles, 96*0fca6ea1SDimitry Andric PrebuiltModuleVFSMapT &PrebuiltModuleVFSMap, 97*0fca6ea1SDimitry Andric const HeaderSearchOptions &HSOpts, 98*0fca6ea1SDimitry Andric const LangOptions &LangOpts, DiagnosticsEngine &Diags) 9906c3fb27SDimitry Andric : PrebuiltModuleFiles(PrebuiltModuleFiles), 100*0fca6ea1SDimitry Andric NewModuleFiles(NewModuleFiles), 101*0fca6ea1SDimitry Andric PrebuiltModuleVFSMap(PrebuiltModuleVFSMap), ExistingHSOpts(HSOpts), 102*0fca6ea1SDimitry Andric ExistingLangOpts(LangOpts), Diags(Diags) {} 103fe6060f1SDimitry Andric 104fe6060f1SDimitry Andric bool needsImportVisitation() const override { return true; } 105fe6060f1SDimitry Andric 106fe6060f1SDimitry Andric void visitImport(StringRef ModuleName, StringRef Filename) override { 10781ad6265SDimitry Andric if (PrebuiltModuleFiles.insert({ModuleName.str(), Filename.str()}).second) 10881ad6265SDimitry Andric NewModuleFiles.push_back(Filename.str()); 109fe6060f1SDimitry Andric } 110fe6060f1SDimitry Andric 111*0fca6ea1SDimitry Andric void visitModuleFile(StringRef Filename, 112*0fca6ea1SDimitry Andric serialization::ModuleKind Kind) override { 113*0fca6ea1SDimitry Andric CurrentFile = Filename; 114*0fca6ea1SDimitry Andric } 115*0fca6ea1SDimitry Andric 116*0fca6ea1SDimitry Andric bool ReadHeaderSearchPaths(const HeaderSearchOptions &HSOpts, 117*0fca6ea1SDimitry Andric bool Complain) override { 118*0fca6ea1SDimitry Andric std::vector<std::string> VFSOverlayFiles = HSOpts.VFSOverlayFiles; 119*0fca6ea1SDimitry Andric PrebuiltModuleVFSMap.insert( 120*0fca6ea1SDimitry Andric {CurrentFile, llvm::StringSet<>(VFSOverlayFiles)}); 121*0fca6ea1SDimitry Andric return checkHeaderSearchPaths( 122*0fca6ea1SDimitry Andric HSOpts, ExistingHSOpts, Complain ? &Diags : nullptr, ExistingLangOpts); 123*0fca6ea1SDimitry Andric } 124*0fca6ea1SDimitry Andric 125fe6060f1SDimitry Andric private: 12681ad6265SDimitry Andric PrebuiltModuleFilesT &PrebuiltModuleFiles; 12781ad6265SDimitry Andric llvm::SmallVector<std::string> &NewModuleFiles; 128*0fca6ea1SDimitry Andric PrebuiltModuleVFSMapT &PrebuiltModuleVFSMap; 129*0fca6ea1SDimitry Andric const HeaderSearchOptions &ExistingHSOpts; 130*0fca6ea1SDimitry Andric const LangOptions &ExistingLangOpts; 131*0fca6ea1SDimitry Andric DiagnosticsEngine &Diags; 132*0fca6ea1SDimitry Andric std::string CurrentFile; 133fe6060f1SDimitry Andric }; 134fe6060f1SDimitry Andric 135fe6060f1SDimitry Andric /// Visit the given prebuilt module and collect all of the modules it 136fe6060f1SDimitry Andric /// transitively imports and contributing input files. 137*0fca6ea1SDimitry Andric static bool visitPrebuiltModule(StringRef PrebuiltModuleFilename, 138fe6060f1SDimitry Andric CompilerInstance &CI, 139*0fca6ea1SDimitry Andric PrebuiltModuleFilesT &ModuleFiles, 140*0fca6ea1SDimitry Andric PrebuiltModuleVFSMapT &PrebuiltModuleVFSMap, 141*0fca6ea1SDimitry Andric DiagnosticsEngine &Diags) { 14281ad6265SDimitry Andric // List of module files to be processed. 143*0fca6ea1SDimitry Andric llvm::SmallVector<std::string> Worklist; 144*0fca6ea1SDimitry Andric PrebuiltModuleListener Listener(ModuleFiles, Worklist, PrebuiltModuleVFSMap, 145*0fca6ea1SDimitry Andric CI.getHeaderSearchOpts(), CI.getLangOpts(), 146*0fca6ea1SDimitry Andric Diags); 147fe6060f1SDimitry Andric 148*0fca6ea1SDimitry Andric Listener.visitModuleFile(PrebuiltModuleFilename, 149*0fca6ea1SDimitry Andric serialization::MK_ExplicitModule); 150*0fca6ea1SDimitry Andric if (ASTReader::readASTFileControlBlock( 151*0fca6ea1SDimitry Andric PrebuiltModuleFilename, CI.getFileManager(), CI.getModuleCache(), 152*0fca6ea1SDimitry Andric CI.getPCHContainerReader(), 153*0fca6ea1SDimitry Andric /*FindModuleFileExtensions=*/false, Listener, 154*0fca6ea1SDimitry Andric /*ValidateDiagnosticOptions=*/false, ASTReader::ARR_OutOfDate)) 155*0fca6ea1SDimitry Andric return true; 156*0fca6ea1SDimitry Andric 157*0fca6ea1SDimitry Andric while (!Worklist.empty()) { 158*0fca6ea1SDimitry Andric Listener.visitModuleFile(Worklist.back(), serialization::MK_ExplicitModule); 159*0fca6ea1SDimitry Andric if (ASTReader::readASTFileControlBlock( 160bdd1243dSDimitry Andric Worklist.pop_back_val(), CI.getFileManager(), CI.getModuleCache(), 16181ad6265SDimitry Andric CI.getPCHContainerReader(), 162fe6060f1SDimitry Andric /*FindModuleFileExtensions=*/false, Listener, 163*0fca6ea1SDimitry Andric /*ValidateDiagnosticOptions=*/false)) 164*0fca6ea1SDimitry Andric return true; 165*0fca6ea1SDimitry Andric } 166*0fca6ea1SDimitry Andric return false; 167fe6060f1SDimitry Andric } 168fe6060f1SDimitry Andric 169fe6060f1SDimitry Andric /// Transform arbitrary file name into an object-like file name. 170fe6060f1SDimitry Andric static std::string makeObjFileName(StringRef FileName) { 171fe6060f1SDimitry Andric SmallString<128> ObjFileName(FileName); 172fe6060f1SDimitry Andric llvm::sys::path::replace_extension(ObjFileName, "o"); 1737a6dacacSDimitry Andric return std::string(ObjFileName); 174fe6060f1SDimitry Andric } 175fe6060f1SDimitry Andric 176fe6060f1SDimitry Andric /// Deduce the dependency target based on the output file and input files. 177fe6060f1SDimitry Andric static std::string 178fe6060f1SDimitry Andric deduceDepTarget(const std::string &OutputFile, 179fe6060f1SDimitry Andric const SmallVectorImpl<FrontendInputFile> &InputFiles) { 180fe6060f1SDimitry Andric if (OutputFile != "-") 181fe6060f1SDimitry Andric return OutputFile; 182fe6060f1SDimitry Andric 183fe6060f1SDimitry Andric if (InputFiles.empty() || !InputFiles.front().isFile()) 184fe6060f1SDimitry Andric return "clang-scan-deps\\ dependency"; 185fe6060f1SDimitry Andric 186fe6060f1SDimitry Andric return makeObjFileName(InputFiles.front().getFile()); 187fe6060f1SDimitry Andric } 188fe6060f1SDimitry Andric 189349cc55cSDimitry Andric /// Sanitize diagnostic options for dependency scan. 190349cc55cSDimitry Andric static void sanitizeDiagOpts(DiagnosticOptions &DiagOpts) { 191349cc55cSDimitry Andric // Don't print 'X warnings and Y errors generated'. 192349cc55cSDimitry Andric DiagOpts.ShowCarets = false; 193349cc55cSDimitry Andric // Don't write out diagnostic file. 194349cc55cSDimitry Andric DiagOpts.DiagnosticSerializationFile.clear(); 195*0fca6ea1SDimitry Andric // Don't emit warnings except for scanning specific warnings. 196*0fca6ea1SDimitry Andric // TODO: It would be useful to add a more principled way to ignore all 197*0fca6ea1SDimitry Andric // warnings that come from source code. The issue is that we need to 198*0fca6ea1SDimitry Andric // ignore warnings that could be surpressed by 199*0fca6ea1SDimitry Andric // `#pragma clang diagnostic`, while still allowing some scanning 200*0fca6ea1SDimitry Andric // warnings for things we're not ready to turn into errors yet. 201*0fca6ea1SDimitry Andric // See `test/ClangScanDeps/diagnostic-pragmas.c` for an example. 202*0fca6ea1SDimitry Andric llvm::erase_if(DiagOpts.Warnings, [](StringRef Warning) { 203*0fca6ea1SDimitry Andric return llvm::StringSwitch<bool>(Warning) 204*0fca6ea1SDimitry Andric .Cases("pch-vfs-diff", "error=pch-vfs-diff", false) 205*0fca6ea1SDimitry Andric .StartsWith("no-error=", false) 206*0fca6ea1SDimitry Andric .Default(true); 207*0fca6ea1SDimitry Andric }); 208*0fca6ea1SDimitry Andric } 209*0fca6ea1SDimitry Andric 210*0fca6ea1SDimitry Andric // Clang implements -D and -U by splatting text into a predefines buffer. This 211*0fca6ea1SDimitry Andric // allows constructs such as `-DFඞ=3 "-D F\u{0D9E} 4 3 2”` to be accepted and 212*0fca6ea1SDimitry Andric // define the same macro, or adding C++ style comments before the macro name. 213*0fca6ea1SDimitry Andric // 214*0fca6ea1SDimitry Andric // This function checks that the first non-space characters in the macro 215*0fca6ea1SDimitry Andric // obviously form an identifier that can be uniqued on without lexing. Failing 216*0fca6ea1SDimitry Andric // to do this could lead to changing the final definition of a macro. 217*0fca6ea1SDimitry Andric // 218*0fca6ea1SDimitry Andric // We could set up a preprocessor and actually lex the name, but that's very 219*0fca6ea1SDimitry Andric // heavyweight for a situation that will almost never happen in practice. 220*0fca6ea1SDimitry Andric static std::optional<StringRef> getSimpleMacroName(StringRef Macro) { 221*0fca6ea1SDimitry Andric StringRef Name = Macro.split("=").first.ltrim(" \t"); 222*0fca6ea1SDimitry Andric std::size_t I = 0; 223*0fca6ea1SDimitry Andric 224*0fca6ea1SDimitry Andric auto FinishName = [&]() -> std::optional<StringRef> { 225*0fca6ea1SDimitry Andric StringRef SimpleName = Name.slice(0, I); 226*0fca6ea1SDimitry Andric if (SimpleName.empty()) 227*0fca6ea1SDimitry Andric return std::nullopt; 228*0fca6ea1SDimitry Andric return SimpleName; 229*0fca6ea1SDimitry Andric }; 230*0fca6ea1SDimitry Andric 231*0fca6ea1SDimitry Andric for (; I != Name.size(); ++I) { 232*0fca6ea1SDimitry Andric switch (Name[I]) { 233*0fca6ea1SDimitry Andric case '(': // Start of macro parameter list 234*0fca6ea1SDimitry Andric case ' ': // End of macro name 235*0fca6ea1SDimitry Andric case '\t': 236*0fca6ea1SDimitry Andric return FinishName(); 237*0fca6ea1SDimitry Andric case '_': 238*0fca6ea1SDimitry Andric continue; 239*0fca6ea1SDimitry Andric default: 240*0fca6ea1SDimitry Andric if (llvm::isAlnum(Name[I])) 241*0fca6ea1SDimitry Andric continue; 242*0fca6ea1SDimitry Andric return std::nullopt; 243*0fca6ea1SDimitry Andric } 244*0fca6ea1SDimitry Andric } 245*0fca6ea1SDimitry Andric return FinishName(); 246*0fca6ea1SDimitry Andric } 247*0fca6ea1SDimitry Andric 248*0fca6ea1SDimitry Andric static void canonicalizeDefines(PreprocessorOptions &PPOpts) { 249*0fca6ea1SDimitry Andric using MacroOpt = std::pair<StringRef, std::size_t>; 250*0fca6ea1SDimitry Andric std::vector<MacroOpt> SimpleNames; 251*0fca6ea1SDimitry Andric SimpleNames.reserve(PPOpts.Macros.size()); 252*0fca6ea1SDimitry Andric std::size_t Index = 0; 253*0fca6ea1SDimitry Andric for (const auto &M : PPOpts.Macros) { 254*0fca6ea1SDimitry Andric auto SName = getSimpleMacroName(M.first); 255*0fca6ea1SDimitry Andric // Skip optimizing if we can't guarantee we can preserve relative order. 256*0fca6ea1SDimitry Andric if (!SName) 257*0fca6ea1SDimitry Andric return; 258*0fca6ea1SDimitry Andric SimpleNames.emplace_back(*SName, Index); 259*0fca6ea1SDimitry Andric ++Index; 260*0fca6ea1SDimitry Andric } 261*0fca6ea1SDimitry Andric 262*0fca6ea1SDimitry Andric llvm::stable_sort(SimpleNames, llvm::less_first()); 263*0fca6ea1SDimitry Andric // Keep the last instance of each macro name by going in reverse 264*0fca6ea1SDimitry Andric auto NewEnd = std::unique( 265*0fca6ea1SDimitry Andric SimpleNames.rbegin(), SimpleNames.rend(), 266*0fca6ea1SDimitry Andric [](const MacroOpt &A, const MacroOpt &B) { return A.first == B.first; }); 267*0fca6ea1SDimitry Andric SimpleNames.erase(SimpleNames.begin(), NewEnd.base()); 268*0fca6ea1SDimitry Andric 269*0fca6ea1SDimitry Andric // Apply permutation. 270*0fca6ea1SDimitry Andric decltype(PPOpts.Macros) NewMacros; 271*0fca6ea1SDimitry Andric NewMacros.reserve(SimpleNames.size()); 272*0fca6ea1SDimitry Andric for (std::size_t I = 0, E = SimpleNames.size(); I != E; ++I) { 273*0fca6ea1SDimitry Andric std::size_t OriginalIndex = SimpleNames[I].second; 274*0fca6ea1SDimitry Andric // We still emit undefines here as they may be undefining a predefined macro 275*0fca6ea1SDimitry Andric NewMacros.push_back(std::move(PPOpts.Macros[OriginalIndex])); 276*0fca6ea1SDimitry Andric } 277*0fca6ea1SDimitry Andric std::swap(PPOpts.Macros, NewMacros); 278349cc55cSDimitry Andric } 279349cc55cSDimitry Andric 2800b57cec5SDimitry Andric /// A clang tool that runs the preprocessor in a mode that's optimized for 2810b57cec5SDimitry Andric /// dependency scanning for the given compiler invocation. 2820b57cec5SDimitry Andric class DependencyScanningAction : public tooling::ToolAction { 2830b57cec5SDimitry Andric public: 284a7dea167SDimitry Andric DependencyScanningAction( 285a7dea167SDimitry Andric StringRef WorkingDirectory, DependencyConsumer &Consumer, 28606c3fb27SDimitry Andric DependencyActionController &Controller, 287a7dea167SDimitry Andric llvm::IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> DepFS, 2885f757f3fSDimitry Andric ScanningOutputFormat Format, ScanningOptimizations OptimizeArgs, 2895f757f3fSDimitry Andric bool EagerLoadModules, bool DisableFree, 2905f757f3fSDimitry Andric std::optional<StringRef> ModuleName = std::nullopt) 291a7dea167SDimitry Andric : WorkingDirectory(WorkingDirectory), Consumer(Consumer), 29206c3fb27SDimitry Andric Controller(Controller), DepFS(std::move(DepFS)), Format(Format), 29306c3fb27SDimitry Andric OptimizeArgs(OptimizeArgs), EagerLoadModules(EagerLoadModules), 29406c3fb27SDimitry Andric DisableFree(DisableFree), ModuleName(ModuleName) {} 2950b57cec5SDimitry Andric 2960b57cec5SDimitry Andric bool runInvocation(std::shared_ptr<CompilerInvocation> Invocation, 297*0fca6ea1SDimitry Andric FileManager *DriverFileMgr, 2980b57cec5SDimitry Andric std::shared_ptr<PCHContainerOperations> PCHContainerOps, 2990b57cec5SDimitry Andric DiagnosticConsumer *DiagConsumer) override { 300fe6060f1SDimitry Andric // Make a deep copy of the original Clang invocation. 301fe6060f1SDimitry Andric CompilerInvocation OriginalInvocation(*Invocation); 30281ad6265SDimitry Andric // Restore the value of DisableFree, which may be modified by Tooling. 30381ad6265SDimitry Andric OriginalInvocation.getFrontendOpts().DisableFree = DisableFree; 304*0fca6ea1SDimitry Andric if (any(OptimizeArgs & ScanningOptimizations::Macros)) 305*0fca6ea1SDimitry Andric canonicalizeDefines(OriginalInvocation.getPreprocessorOpts()); 306fe6060f1SDimitry Andric 307bdd1243dSDimitry Andric if (Scanned) { 308bdd1243dSDimitry Andric // Scanning runs once for the first -cc1 invocation in a chain of driver 309bdd1243dSDimitry Andric // jobs. For any dependent jobs, reuse the scanning result and just 310bdd1243dSDimitry Andric // update the LastCC1Arguments to correspond to the new invocation. 311bdd1243dSDimitry Andric // FIXME: to support multi-arch builds, each arch requires a separate scan 312bdd1243dSDimitry Andric setLastCC1Arguments(std::move(OriginalInvocation)); 313bdd1243dSDimitry Andric return true; 314bdd1243dSDimitry Andric } 315bdd1243dSDimitry Andric 316bdd1243dSDimitry Andric Scanned = true; 317bdd1243dSDimitry Andric 3180b57cec5SDimitry Andric // Create a compiler instance to handle the actual work. 319bdd1243dSDimitry Andric ScanInstanceStorage.emplace(std::move(PCHContainerOps)); 320bdd1243dSDimitry Andric CompilerInstance &ScanInstance = *ScanInstanceStorage; 321349cc55cSDimitry Andric ScanInstance.setInvocation(std::move(Invocation)); 3220b57cec5SDimitry Andric 3230b57cec5SDimitry Andric // Create the compiler's actual diagnostics engine. 324349cc55cSDimitry Andric sanitizeDiagOpts(ScanInstance.getDiagnosticOpts()); 325349cc55cSDimitry Andric ScanInstance.createDiagnostics(DiagConsumer, /*ShouldOwnClient=*/false); 326349cc55cSDimitry Andric if (!ScanInstance.hasDiagnostics()) 3270b57cec5SDimitry Andric return false; 3280b57cec5SDimitry Andric 329*0fca6ea1SDimitry Andric // Some DiagnosticConsumers require that finish() is called. 330*0fca6ea1SDimitry Andric auto DiagConsumerFinisher = 331*0fca6ea1SDimitry Andric llvm::make_scope_exit([DiagConsumer]() { DiagConsumer->finish(); }); 332*0fca6ea1SDimitry Andric 333349cc55cSDimitry Andric ScanInstance.getPreprocessorOpts().AllowPCHWithDifferentModulesCachePath = 334349cc55cSDimitry Andric true; 335fe6060f1SDimitry Andric 33681ad6265SDimitry Andric ScanInstance.getFrontendOpts().GenerateGlobalModuleIndex = false; 33781ad6265SDimitry Andric ScanInstance.getFrontendOpts().UseGlobalModuleIndex = false; 338bdd1243dSDimitry Andric ScanInstance.getFrontendOpts().ModulesShareFileManager = false; 33906c3fb27SDimitry Andric ScanInstance.getHeaderSearchOpts().ModuleFormat = "raw"; 340*0fca6ea1SDimitry Andric ScanInstance.getHeaderSearchOpts().ModulesIncludeVFSUsage = 341*0fca6ea1SDimitry Andric any(OptimizeArgs & ScanningOptimizations::VFS); 34281ad6265SDimitry Andric 343bdd1243dSDimitry Andric // Support for virtual file system overlays. 344*0fca6ea1SDimitry Andric auto FS = createVFSFromCompilerInvocation( 345bdd1243dSDimitry Andric ScanInstance.getInvocation(), ScanInstance.getDiagnostics(), 346*0fca6ea1SDimitry Andric DriverFileMgr->getVirtualFileSystemPtr()); 347bdd1243dSDimitry Andric 348*0fca6ea1SDimitry Andric // Create a new FileManager to match the invocation's FileSystemOptions. 349*0fca6ea1SDimitry Andric auto *FileMgr = ScanInstance.createFileManager(FS); 350349cc55cSDimitry Andric ScanInstance.createSourceManager(*FileMgr); 351fe6060f1SDimitry Andric 352fe6060f1SDimitry Andric // Store the list of prebuilt module files into header search options. This 353fe6060f1SDimitry Andric // will prevent the implicit build to create duplicate modules and will 354fe6060f1SDimitry Andric // force reuse of the existing prebuilt module files instead. 355*0fca6ea1SDimitry Andric PrebuiltModuleVFSMapT PrebuiltModuleVFSMap; 356349cc55cSDimitry Andric if (!ScanInstance.getPreprocessorOpts().ImplicitPCHInclude.empty()) 357*0fca6ea1SDimitry Andric if (visitPrebuiltModule( 358*0fca6ea1SDimitry Andric ScanInstance.getPreprocessorOpts().ImplicitPCHInclude, 359*0fca6ea1SDimitry Andric ScanInstance, 360*0fca6ea1SDimitry Andric ScanInstance.getHeaderSearchOpts().PrebuiltModuleFiles, 361*0fca6ea1SDimitry Andric PrebuiltModuleVFSMap, ScanInstance.getDiagnostics())) 362*0fca6ea1SDimitry Andric return false; 363fe6060f1SDimitry Andric 364fe6060f1SDimitry Andric // Use the dependency scanning optimized file system if requested to do so. 365*0fca6ea1SDimitry Andric if (DepFS) 36681ad6265SDimitry Andric ScanInstance.getPreprocessorOpts().DependencyDirectivesForFile = 367*0fca6ea1SDimitry Andric [LocalDepFS = DepFS](FileEntryRef File) 368bdd1243dSDimitry Andric -> std::optional<ArrayRef<dependency_directives_scan::Directive>> { 36981ad6265SDimitry Andric if (llvm::ErrorOr<EntryRef> Entry = 37081ad6265SDimitry Andric LocalDepFS->getOrCreateFileSystemEntry(File.getName())) 371*0fca6ea1SDimitry Andric if (LocalDepFS->ensureDirectiveTokensArePopulated(*Entry)) 37281ad6265SDimitry Andric return Entry->getDirectiveTokens(); 373bdd1243dSDimitry Andric return std::nullopt; 37481ad6265SDimitry Andric }; 375a7dea167SDimitry Andric 3760b57cec5SDimitry Andric // Create the dependency collector that will collect the produced 3770b57cec5SDimitry Andric // dependencies. 3780b57cec5SDimitry Andric // 3790b57cec5SDimitry Andric // This also moves the existing dependency output options from the 3800b57cec5SDimitry Andric // invocation to the collector. The options in the invocation are reset, 3810b57cec5SDimitry Andric // which ensures that the compiler won't create new dependency collectors, 3820b57cec5SDimitry Andric // and thus won't write out the extra '.d' files to disk. 383fe6060f1SDimitry Andric auto Opts = std::make_unique<DependencyOutputOptions>(); 384349cc55cSDimitry Andric std::swap(*Opts, ScanInstance.getInvocation().getDependencyOutputOpts()); 385fe6060f1SDimitry Andric // We need at least one -MT equivalent for the generator of make dependency 386fe6060f1SDimitry Andric // files to work. 3870b57cec5SDimitry Andric if (Opts->Targets.empty()) 388349cc55cSDimitry Andric Opts->Targets = { 389349cc55cSDimitry Andric deduceDepTarget(ScanInstance.getFrontendOpts().OutputFile, 390349cc55cSDimitry Andric ScanInstance.getFrontendOpts().Inputs)}; 391fe6060f1SDimitry Andric Opts->IncludeSystemHeaders = true; 392480093f4SDimitry Andric 393480093f4SDimitry Andric switch (Format) { 394480093f4SDimitry Andric case ScanningOutputFormat::Make: 395349cc55cSDimitry Andric ScanInstance.addDependencyCollector( 396bdd1243dSDimitry Andric std::make_shared<DependencyConsumerForwarder>( 397bdd1243dSDimitry Andric std::move(Opts), WorkingDirectory, Consumer)); 398480093f4SDimitry Andric break; 3991ac55f4cSDimitry Andric case ScanningOutputFormat::P1689: 400480093f4SDimitry Andric case ScanningOutputFormat::Full: 401bdd1243dSDimitry Andric MDC = std::make_shared<ModuleDepCollector>( 40206c3fb27SDimitry Andric std::move(Opts), ScanInstance, Consumer, Controller, 403*0fca6ea1SDimitry Andric OriginalInvocation, std::move(PrebuiltModuleVFSMap), OptimizeArgs, 404*0fca6ea1SDimitry Andric EagerLoadModules, Format == ScanningOutputFormat::P1689); 405bdd1243dSDimitry Andric ScanInstance.addDependencyCollector(MDC); 406480093f4SDimitry Andric break; 407480093f4SDimitry Andric } 408480093f4SDimitry Andric 4095ffd83dbSDimitry Andric // Consider different header search and diagnostic options to create 4105ffd83dbSDimitry Andric // different modules. This avoids the unsound aliasing of module PCMs. 4115ffd83dbSDimitry Andric // 412349cc55cSDimitry Andric // TODO: Implement diagnostic bucketing to reduce the impact of strict 413349cc55cSDimitry Andric // context hashing. 414349cc55cSDimitry Andric ScanInstance.getHeaderSearchOpts().ModulesStrictContextHash = true; 4155f757f3fSDimitry Andric ScanInstance.getHeaderSearchOpts().ModulesSkipDiagnosticOptions = true; 4165f757f3fSDimitry Andric ScanInstance.getHeaderSearchOpts().ModulesSkipHeaderSearchPaths = true; 4175f757f3fSDimitry Andric ScanInstance.getHeaderSearchOpts().ModulesSkipPragmaDiagnosticMappings = 4185f757f3fSDimitry Andric true; 4190b57cec5SDimitry Andric 42006c3fb27SDimitry Andric // Avoid some checks and module map parsing when loading PCM files. 42106c3fb27SDimitry Andric ScanInstance.getPreprocessorOpts().ModulesCheckRelocated = false; 42206c3fb27SDimitry Andric 423349cc55cSDimitry Andric std::unique_ptr<FrontendAction> Action; 424349cc55cSDimitry Andric 42581ad6265SDimitry Andric if (ModuleName) 426349cc55cSDimitry Andric Action = std::make_unique<GetDependenciesByModuleNameAction>(*ModuleName); 427349cc55cSDimitry Andric else 428349cc55cSDimitry Andric Action = std::make_unique<ReadPCHAndPreprocessAction>(); 429349cc55cSDimitry Andric 430*0fca6ea1SDimitry Andric if (ScanInstance.getDiagnostics().hasErrorOccurred()) 431*0fca6ea1SDimitry Andric return false; 432*0fca6ea1SDimitry Andric 433*0fca6ea1SDimitry Andric // Each action is responsible for calling finish. 434*0fca6ea1SDimitry Andric DiagConsumerFinisher.release(); 435349cc55cSDimitry Andric const bool Result = ScanInstance.ExecuteAction(*Action); 436bdd1243dSDimitry Andric 437bdd1243dSDimitry Andric if (Result) 438bdd1243dSDimitry Andric setLastCC1Arguments(std::move(OriginalInvocation)); 439bdd1243dSDimitry Andric 440*0fca6ea1SDimitry Andric // Propagate the statistics to the parent FileManager. 441*0fca6ea1SDimitry Andric DriverFileMgr->AddStats(ScanInstance.getFileManager()); 442*0fca6ea1SDimitry Andric 4430b57cec5SDimitry Andric return Result; 4440b57cec5SDimitry Andric } 4450b57cec5SDimitry Andric 446bdd1243dSDimitry Andric bool hasScanned() const { return Scanned; } 447bdd1243dSDimitry Andric 448bdd1243dSDimitry Andric /// Take the cc1 arguments corresponding to the most recent invocation used 449bdd1243dSDimitry Andric /// with this action. Any modifications implied by the discovered dependencies 450bdd1243dSDimitry Andric /// will have already been applied. 451bdd1243dSDimitry Andric std::vector<std::string> takeLastCC1Arguments() { 452bdd1243dSDimitry Andric std::vector<std::string> Result; 453bdd1243dSDimitry Andric std::swap(Result, LastCC1Arguments); // Reset LastCC1Arguments to empty. 454bdd1243dSDimitry Andric return Result; 455bdd1243dSDimitry Andric } 456bdd1243dSDimitry Andric 457bdd1243dSDimitry Andric private: 458bdd1243dSDimitry Andric void setLastCC1Arguments(CompilerInvocation &&CI) { 459bdd1243dSDimitry Andric if (MDC) 460bdd1243dSDimitry Andric MDC->applyDiscoveredDependencies(CI); 461bdd1243dSDimitry Andric LastCC1Arguments = CI.getCC1CommandLine(); 462bdd1243dSDimitry Andric } 463bdd1243dSDimitry Andric 4640b57cec5SDimitry Andric private: 4650b57cec5SDimitry Andric StringRef WorkingDirectory; 466a7dea167SDimitry Andric DependencyConsumer &Consumer; 46706c3fb27SDimitry Andric DependencyActionController &Controller; 468a7dea167SDimitry Andric llvm::IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> DepFS; 469480093f4SDimitry Andric ScanningOutputFormat Format; 4705f757f3fSDimitry Andric ScanningOptimizations OptimizeArgs; 471bdd1243dSDimitry Andric bool EagerLoadModules; 47281ad6265SDimitry Andric bool DisableFree; 473bdd1243dSDimitry Andric std::optional<StringRef> ModuleName; 474bdd1243dSDimitry Andric std::optional<CompilerInstance> ScanInstanceStorage; 475bdd1243dSDimitry Andric std::shared_ptr<ModuleDepCollector> MDC; 476bdd1243dSDimitry Andric std::vector<std::string> LastCC1Arguments; 477bdd1243dSDimitry Andric bool Scanned = false; 4780b57cec5SDimitry Andric }; 4790b57cec5SDimitry Andric 4800b57cec5SDimitry Andric } // end anonymous namespace 4810b57cec5SDimitry Andric 482a7dea167SDimitry Andric DependencyScanningWorker::DependencyScanningWorker( 483fcaf7f86SDimitry Andric DependencyScanningService &Service, 484fcaf7f86SDimitry Andric llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS) 4855f757f3fSDimitry Andric : Format(Service.getFormat()), OptimizeArgs(Service.getOptimizeArgs()), 486bdd1243dSDimitry Andric EagerLoadModules(Service.shouldEagerLoadModules()) { 4870b57cec5SDimitry Andric PCHContainerOps = std::make_shared<PCHContainerOperations>(); 48806c3fb27SDimitry Andric // We need to read object files from PCH built outside the scanner. 489fe6060f1SDimitry Andric PCHContainerOps->registerReader( 490fe6060f1SDimitry Andric std::make_unique<ObjectFilePCHContainerReader>()); 49106c3fb27SDimitry Andric // The scanner itself writes only raw ast files. 49206c3fb27SDimitry Andric PCHContainerOps->registerWriter(std::make_unique<RawPCHContainerWriter>()); 493fe6060f1SDimitry Andric 494bdd1243dSDimitry Andric switch (Service.getMode()) { 495bdd1243dSDimitry Andric case ScanningMode::DependencyDirectivesScan: 496bdd1243dSDimitry Andric DepFS = 497bdd1243dSDimitry Andric new DependencyScanningWorkerFilesystem(Service.getSharedCache(), FS); 498bdd1243dSDimitry Andric BaseFS = DepFS; 499bdd1243dSDimitry Andric break; 500bdd1243dSDimitry Andric case ScanningMode::CanonicalPreprocessing: 501bdd1243dSDimitry Andric DepFS = nullptr; 502bdd1243dSDimitry Andric BaseFS = FS; 503bdd1243dSDimitry Andric break; 504bdd1243dSDimitry Andric } 5050b57cec5SDimitry Andric } 5060b57cec5SDimitry Andric 507bdd1243dSDimitry Andric llvm::Error DependencyScanningWorker::computeDependencies( 508bdd1243dSDimitry Andric StringRef WorkingDirectory, const std::vector<std::string> &CommandLine, 50906c3fb27SDimitry Andric DependencyConsumer &Consumer, DependencyActionController &Controller, 51006c3fb27SDimitry Andric std::optional<StringRef> ModuleName) { 511bdd1243dSDimitry Andric std::vector<const char *> CLI; 512bdd1243dSDimitry Andric for (const std::string &Arg : CommandLine) 513bdd1243dSDimitry Andric CLI.push_back(Arg.c_str()); 514bdd1243dSDimitry Andric auto DiagOpts = CreateAndPopulateDiagOpts(CLI); 515349cc55cSDimitry Andric sanitizeDiagOpts(*DiagOpts); 516349cc55cSDimitry Andric 5170b57cec5SDimitry Andric // Capture the emitted diagnostics and report them to the client 5180b57cec5SDimitry Andric // in the case of a failure. 5190b57cec5SDimitry Andric std::string DiagnosticOutput; 5200b57cec5SDimitry Andric llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput); 521bdd1243dSDimitry Andric TextDiagnosticPrinter DiagPrinter(DiagnosticsOS, DiagOpts.release()); 5220b57cec5SDimitry Andric 52306c3fb27SDimitry Andric if (computeDependencies(WorkingDirectory, CommandLine, Consumer, Controller, 52406c3fb27SDimitry Andric DiagPrinter, ModuleName)) 525a7dea167SDimitry Andric return llvm::Error::success(); 5260b57cec5SDimitry Andric return llvm::make_error<llvm::StringError>(DiagnosticsOS.str(), 5270b57cec5SDimitry Andric llvm::inconvertibleErrorCode()); 5280b57cec5SDimitry Andric } 529a7dea167SDimitry Andric 530bdd1243dSDimitry Andric static bool forEachDriverJob( 53106c3fb27SDimitry Andric ArrayRef<std::string> ArgStrs, DiagnosticsEngine &Diags, FileManager &FM, 532bdd1243dSDimitry Andric llvm::function_ref<bool(const driver::Command &Cmd)> Callback) { 53306c3fb27SDimitry Andric SmallVector<const char *, 256> Argv; 53406c3fb27SDimitry Andric Argv.reserve(ArgStrs.size()); 53506c3fb27SDimitry Andric for (const std::string &Arg : ArgStrs) 53606c3fb27SDimitry Andric Argv.push_back(Arg.c_str()); 53706c3fb27SDimitry Andric 53806c3fb27SDimitry Andric llvm::vfs::FileSystem *FS = &FM.getVirtualFileSystem(); 53906c3fb27SDimitry Andric 540bdd1243dSDimitry Andric std::unique_ptr<driver::Driver> Driver = std::make_unique<driver::Driver>( 54106c3fb27SDimitry Andric Argv[0], llvm::sys::getDefaultTargetTriple(), Diags, 54206c3fb27SDimitry Andric "clang LLVM compiler", FS); 543bdd1243dSDimitry Andric Driver->setTitle("clang_based_tool"); 544bdd1243dSDimitry Andric 54506c3fb27SDimitry Andric llvm::BumpPtrAllocator Alloc; 54606c3fb27SDimitry Andric bool CLMode = driver::IsClangCL( 54706c3fb27SDimitry Andric driver::getDriverMode(Argv[0], ArrayRef(Argv).slice(1))); 54806c3fb27SDimitry Andric 54906c3fb27SDimitry Andric if (llvm::Error E = driver::expandResponseFiles(Argv, CLMode, Alloc, FS)) { 55006c3fb27SDimitry Andric Diags.Report(diag::err_drv_expand_response_file) 55106c3fb27SDimitry Andric << llvm::toString(std::move(E)); 55206c3fb27SDimitry Andric return false; 55306c3fb27SDimitry Andric } 554bdd1243dSDimitry Andric 555bdd1243dSDimitry Andric const std::unique_ptr<driver::Compilation> Compilation( 556bdd1243dSDimitry Andric Driver->BuildCompilation(llvm::ArrayRef(Argv))); 557bdd1243dSDimitry Andric if (!Compilation) 558bdd1243dSDimitry Andric return false; 559bdd1243dSDimitry Andric 5605f757f3fSDimitry Andric if (Compilation->containsError()) 5615f757f3fSDimitry Andric return false; 5625f757f3fSDimitry Andric 563bdd1243dSDimitry Andric for (const driver::Command &Job : Compilation->getJobs()) { 564bdd1243dSDimitry Andric if (!Callback(Job)) 565bdd1243dSDimitry Andric return false; 566bdd1243dSDimitry Andric } 567bdd1243dSDimitry Andric return true; 568bdd1243dSDimitry Andric } 569bdd1243dSDimitry Andric 5705f757f3fSDimitry Andric static bool createAndRunToolInvocation( 5715f757f3fSDimitry Andric std::vector<std::string> CommandLine, DependencyScanningAction &Action, 5725f757f3fSDimitry Andric FileManager &FM, 5735f757f3fSDimitry Andric std::shared_ptr<clang::PCHContainerOperations> &PCHContainerOps, 5745f757f3fSDimitry Andric DiagnosticsEngine &Diags, DependencyConsumer &Consumer) { 5755f757f3fSDimitry Andric 5765f757f3fSDimitry Andric // Save executable path before providing CommandLine to ToolInvocation 5775f757f3fSDimitry Andric std::string Executable = CommandLine[0]; 5785f757f3fSDimitry Andric ToolInvocation Invocation(std::move(CommandLine), &Action, &FM, 5795f757f3fSDimitry Andric PCHContainerOps); 5805f757f3fSDimitry Andric Invocation.setDiagnosticConsumer(Diags.getClient()); 5815f757f3fSDimitry Andric Invocation.setDiagnosticOptions(&Diags.getDiagnosticOptions()); 5825f757f3fSDimitry Andric if (!Invocation.run()) 5835f757f3fSDimitry Andric return false; 5845f757f3fSDimitry Andric 5855f757f3fSDimitry Andric std::vector<std::string> Args = Action.takeLastCC1Arguments(); 5865f757f3fSDimitry Andric Consumer.handleBuildCommand({std::move(Executable), std::move(Args)}); 5875f757f3fSDimitry Andric return true; 5885f757f3fSDimitry Andric } 5895f757f3fSDimitry Andric 590bdd1243dSDimitry Andric bool DependencyScanningWorker::computeDependencies( 591349cc55cSDimitry Andric StringRef WorkingDirectory, const std::vector<std::string> &CommandLine, 59206c3fb27SDimitry Andric DependencyConsumer &Consumer, DependencyActionController &Controller, 59306c3fb27SDimitry Andric DiagnosticConsumer &DC, std::optional<StringRef> ModuleName) { 594349cc55cSDimitry Andric // Reset what might have been modified in the previous worker invocation. 595bdd1243dSDimitry Andric BaseFS->setCurrentWorkingDirectory(WorkingDirectory); 596349cc55cSDimitry Andric 597bdd1243dSDimitry Andric std::optional<std::vector<std::string>> ModifiedCommandLine; 598bdd1243dSDimitry Andric llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> ModifiedFS; 599bdd1243dSDimitry Andric 60006c3fb27SDimitry Andric // If we're scanning based on a module name alone, we don't expect the client 60106c3fb27SDimitry Andric // to provide us with an input file. However, the driver really wants to have 60206c3fb27SDimitry Andric // one. Let's just make it up to make the driver happy. 60306c3fb27SDimitry Andric if (ModuleName) { 604bdd1243dSDimitry Andric auto OverlayFS = 605bdd1243dSDimitry Andric llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(BaseFS); 606bdd1243dSDimitry Andric auto InMemoryFS = 607bdd1243dSDimitry Andric llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>(); 608bdd1243dSDimitry Andric InMemoryFS->setCurrentWorkingDirectory(WorkingDirectory); 609bdd1243dSDimitry Andric OverlayFS->pushOverlay(InMemoryFS); 610bdd1243dSDimitry Andric ModifiedFS = OverlayFS; 61106c3fb27SDimitry Andric 61206c3fb27SDimitry Andric SmallString<128> FakeInputPath; 61306c3fb27SDimitry Andric // TODO: We should retry the creation if the path already exists. 61406c3fb27SDimitry Andric llvm::sys::fs::createUniquePath(*ModuleName + "-%%%%%%%%.input", 61506c3fb27SDimitry Andric FakeInputPath, 61606c3fb27SDimitry Andric /*MakeAbsolute=*/false); 61706c3fb27SDimitry Andric InMemoryFS->addFile(FakeInputPath, 0, llvm::MemoryBuffer::getMemBuffer("")); 61806c3fb27SDimitry Andric 61906c3fb27SDimitry Andric ModifiedCommandLine = CommandLine; 62006c3fb27SDimitry Andric ModifiedCommandLine->emplace_back(FakeInputPath); 621349cc55cSDimitry Andric } 622349cc55cSDimitry Andric 623349cc55cSDimitry Andric const std::vector<std::string> &FinalCommandLine = 624349cc55cSDimitry Andric ModifiedCommandLine ? *ModifiedCommandLine : CommandLine; 62506c3fb27SDimitry Andric auto &FinalFS = ModifiedFS ? ModifiedFS : BaseFS; 626349cc55cSDimitry Andric 627*0fca6ea1SDimitry Andric auto FileMgr = 628*0fca6ea1SDimitry Andric llvm::makeIntrusiveRefCnt<FileManager>(FileSystemOptions{}, FinalFS); 629bdd1243dSDimitry Andric 63006c3fb27SDimitry Andric std::vector<const char *> FinalCCommandLine(FinalCommandLine.size(), nullptr); 63106c3fb27SDimitry Andric llvm::transform(FinalCommandLine, FinalCCommandLine.begin(), 632349cc55cSDimitry Andric [](const std::string &Str) { return Str.c_str(); }); 633349cc55cSDimitry Andric 634bdd1243dSDimitry Andric auto DiagOpts = CreateAndPopulateDiagOpts(FinalCCommandLine); 635bdd1243dSDimitry Andric sanitizeDiagOpts(*DiagOpts); 636bdd1243dSDimitry Andric IntrusiveRefCntPtr<DiagnosticsEngine> Diags = 637bdd1243dSDimitry Andric CompilerInstance::createDiagnostics(DiagOpts.release(), &DC, 638bdd1243dSDimitry Andric /*ShouldOwnClient=*/false); 639bdd1243dSDimitry Andric 640bdd1243dSDimitry Andric // Although `Diagnostics` are used only for command-line parsing, the 641bdd1243dSDimitry Andric // custom `DiagConsumer` might expect a `SourceManager` to be present. 642bdd1243dSDimitry Andric SourceManager SrcMgr(*Diags, *FileMgr); 643bdd1243dSDimitry Andric Diags->setSourceManager(&SrcMgr); 64481ad6265SDimitry Andric // DisableFree is modified by Tooling for running 64581ad6265SDimitry Andric // in-process; preserve the original value, which is 64681ad6265SDimitry Andric // always true for a driver invocation. 64781ad6265SDimitry Andric bool DisableFree = true; 64806c3fb27SDimitry Andric DependencyScanningAction Action(WorkingDirectory, Consumer, Controller, DepFS, 64906c3fb27SDimitry Andric Format, OptimizeArgs, EagerLoadModules, 65006c3fb27SDimitry Andric DisableFree, ModuleName); 6515f757f3fSDimitry Andric 6525f757f3fSDimitry Andric bool Success = false; 6535f757f3fSDimitry Andric if (FinalCommandLine[1] == "-cc1") { 6545f757f3fSDimitry Andric Success = createAndRunToolInvocation(FinalCommandLine, Action, *FileMgr, 6555f757f3fSDimitry Andric PCHContainerOps, *Diags, Consumer); 6565f757f3fSDimitry Andric } else { 6575f757f3fSDimitry Andric Success = forEachDriverJob( 658bdd1243dSDimitry Andric FinalCommandLine, *Diags, *FileMgr, [&](const driver::Command &Cmd) { 659bdd1243dSDimitry Andric if (StringRef(Cmd.getCreator().getName()) != "clang") { 660bdd1243dSDimitry Andric // Non-clang command. Just pass through to the dependency 661bdd1243dSDimitry Andric // consumer. 662bdd1243dSDimitry Andric Consumer.handleBuildCommand( 663bdd1243dSDimitry Andric {Cmd.getExecutable(), 664bdd1243dSDimitry Andric {Cmd.getArguments().begin(), Cmd.getArguments().end()}}); 665bdd1243dSDimitry Andric return true; 666bdd1243dSDimitry Andric } 667bdd1243dSDimitry Andric 6685f757f3fSDimitry Andric // Insert -cc1 comand line options into Argv 669bdd1243dSDimitry Andric std::vector<std::string> Argv; 670bdd1243dSDimitry Andric Argv.push_back(Cmd.getExecutable()); 671bdd1243dSDimitry Andric Argv.insert(Argv.end(), Cmd.getArguments().begin(), 672bdd1243dSDimitry Andric Cmd.getArguments().end()); 673bdd1243dSDimitry Andric 674349cc55cSDimitry Andric // Create an invocation that uses the underlying file 675349cc55cSDimitry Andric // system to ensure that any file system requests that 676349cc55cSDimitry Andric // are made by the driver do not go through the 677349cc55cSDimitry Andric // dependency scanning filesystem. 6785f757f3fSDimitry Andric return createAndRunToolInvocation(std::move(Argv), Action, *FileMgr, 6795f757f3fSDimitry Andric PCHContainerOps, *Diags, Consumer); 680a7dea167SDimitry Andric }); 6815f757f3fSDimitry Andric } 682bdd1243dSDimitry Andric 683bdd1243dSDimitry Andric if (Success && !Action.hasScanned()) 684bdd1243dSDimitry Andric Diags->Report(diag::err_fe_expected_compiler_job) 685bdd1243dSDimitry Andric << llvm::join(FinalCommandLine, " "); 686bdd1243dSDimitry Andric return Success && Action.hasScanned(); 6870b57cec5SDimitry Andric } 68806c3fb27SDimitry Andric 68906c3fb27SDimitry Andric DependencyActionController::~DependencyActionController() {} 690