1 //===- DependencyScanningTool.cpp - clang-scan-deps service ---------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "clang/Tooling/DependencyScanning/DependencyScanningTool.h" 10 #include "clang/Frontend/Utils.h" 11 #include <optional> 12 13 using namespace clang; 14 using namespace tooling; 15 using namespace dependencies; 16 17 DependencyScanningTool::DependencyScanningTool( 18 DependencyScanningService &Service, 19 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS) 20 : Worker(Service, std::move(FS)) {} 21 22 namespace { 23 /// Prints out all of the gathered dependencies into a string. 24 class MakeDependencyPrinterConsumer : public DependencyConsumer { 25 public: 26 void handleBuildCommand(Command) override {} 27 28 void 29 handleDependencyOutputOpts(const DependencyOutputOptions &Opts) override { 30 this->Opts = std::make_unique<DependencyOutputOptions>(Opts); 31 } 32 33 void handleFileDependency(StringRef File) override { 34 Dependencies.push_back(std::string(File)); 35 } 36 37 // These are ignored for the make format as it can't support the full 38 // set of deps, and handleFileDependency handles enough for implicitly 39 // built modules to work. 40 void handlePrebuiltModuleDependency(PrebuiltModuleDep PMD) override {} 41 void handleModuleDependency(ModuleDeps MD) override {} 42 void handleDirectModuleDependency(ModuleID ID) override {} 43 void handleVisibleModule(std::string ModuleName) override {} 44 void handleContextHash(std::string Hash) override {} 45 46 void printDependencies(std::string &S) { 47 assert(Opts && "Handled dependency output options."); 48 49 class DependencyPrinter : public DependencyFileGenerator { 50 public: 51 DependencyPrinter(DependencyOutputOptions &Opts, 52 ArrayRef<std::string> Dependencies) 53 : DependencyFileGenerator(Opts) { 54 for (const auto &Dep : Dependencies) 55 addDependency(Dep); 56 } 57 58 void printDependencies(std::string &S) { 59 llvm::raw_string_ostream OS(S); 60 outputDependencyFile(OS); 61 } 62 }; 63 64 DependencyPrinter Generator(*Opts, Dependencies); 65 Generator.printDependencies(S); 66 } 67 68 protected: 69 std::unique_ptr<DependencyOutputOptions> Opts; 70 std::vector<std::string> Dependencies; 71 }; 72 } // anonymous namespace 73 74 llvm::Expected<std::string> DependencyScanningTool::getDependencyFile( 75 const std::vector<std::string> &CommandLine, StringRef CWD) { 76 MakeDependencyPrinterConsumer Consumer; 77 CallbackActionController Controller(nullptr); 78 auto Result = 79 Worker.computeDependencies(CWD, CommandLine, Consumer, Controller); 80 if (Result) 81 return std::move(Result); 82 std::string Output; 83 Consumer.printDependencies(Output); 84 return Output; 85 } 86 87 llvm::Expected<P1689Rule> DependencyScanningTool::getP1689ModuleDependencyFile( 88 const CompileCommand &Command, StringRef CWD, std::string &MakeformatOutput, 89 std::string &MakeformatOutputPath) { 90 class P1689ModuleDependencyPrinterConsumer 91 : public MakeDependencyPrinterConsumer { 92 public: 93 P1689ModuleDependencyPrinterConsumer(P1689Rule &Rule, 94 const CompileCommand &Command) 95 : Filename(Command.Filename), Rule(Rule) { 96 Rule.PrimaryOutput = Command.Output; 97 } 98 99 void handleProvidedAndRequiredStdCXXModules( 100 std::optional<P1689ModuleInfo> Provided, 101 std::vector<P1689ModuleInfo> Requires) override { 102 Rule.Provides = Provided; 103 if (Rule.Provides) 104 Rule.Provides->SourcePath = Filename.str(); 105 Rule.Requires = Requires; 106 } 107 108 StringRef getMakeFormatDependencyOutputPath() { 109 if (Opts->OutputFormat != DependencyOutputFormat::Make) 110 return {}; 111 return Opts->OutputFile; 112 } 113 114 private: 115 StringRef Filename; 116 P1689Rule &Rule; 117 }; 118 119 class P1689ActionController : public DependencyActionController { 120 public: 121 // The lookupModuleOutput is for clang modules. P1689 format don't need it. 122 std::string lookupModuleOutput(const ModuleDeps &, 123 ModuleOutputKind Kind) override { 124 return ""; 125 } 126 }; 127 128 P1689Rule Rule; 129 P1689ModuleDependencyPrinterConsumer Consumer(Rule, Command); 130 P1689ActionController Controller; 131 auto Result = Worker.computeDependencies(CWD, Command.CommandLine, Consumer, 132 Controller); 133 if (Result) 134 return std::move(Result); 135 136 MakeformatOutputPath = Consumer.getMakeFormatDependencyOutputPath(); 137 if (!MakeformatOutputPath.empty()) 138 Consumer.printDependencies(MakeformatOutput); 139 return Rule; 140 } 141 142 llvm::Expected<TranslationUnitDeps> 143 DependencyScanningTool::getTranslationUnitDependencies( 144 const std::vector<std::string> &CommandLine, StringRef CWD, 145 const llvm::DenseSet<ModuleID> &AlreadySeen, 146 LookupModuleOutputCallback LookupModuleOutput, 147 std::optional<llvm::MemoryBufferRef> TUBuffer) { 148 FullDependencyConsumer Consumer(AlreadySeen); 149 CallbackActionController Controller(LookupModuleOutput); 150 llvm::Error Result = Worker.computeDependencies(CWD, CommandLine, Consumer, 151 Controller, TUBuffer); 152 153 if (Result) 154 return std::move(Result); 155 return Consumer.takeTranslationUnitDeps(); 156 } 157 158 llvm::Expected<TranslationUnitDeps> 159 DependencyScanningTool::getModuleDependencies( 160 StringRef ModuleName, const std::vector<std::string> &CommandLine, 161 StringRef CWD, const llvm::DenseSet<ModuleID> &AlreadySeen, 162 LookupModuleOutputCallback LookupModuleOutput) { 163 FullDependencyConsumer Consumer(AlreadySeen); 164 CallbackActionController Controller(LookupModuleOutput); 165 llvm::Error Result = Worker.computeDependencies(CWD, CommandLine, Consumer, 166 Controller, ModuleName); 167 if (Result) 168 return std::move(Result); 169 return Consumer.takeTranslationUnitDeps(); 170 } 171 172 TranslationUnitDeps FullDependencyConsumer::takeTranslationUnitDeps() { 173 TranslationUnitDeps TU; 174 175 TU.ID.ContextHash = std::move(ContextHash); 176 TU.ID.ModuleName = std::move(ModuleName); 177 TU.NamedModuleDeps = std::move(NamedModuleDeps); 178 TU.FileDeps = std::move(Dependencies); 179 TU.PrebuiltModuleDeps = std::move(PrebuiltModuleDeps); 180 TU.VisibleModules = std::move(VisibleModules); 181 TU.Commands = std::move(Commands); 182 183 for (auto &&M : ClangModuleDeps) { 184 auto &MD = M.second; 185 // TODO: Avoid handleModuleDependency even being called for modules 186 // we've already seen. 187 if (AlreadySeen.count(M.first)) 188 continue; 189 TU.ModuleGraph.push_back(std::move(MD)); 190 } 191 TU.ClangModuleDeps = std::move(DirectModuleDeps); 192 193 return TU; 194 } 195 196 CallbackActionController::~CallbackActionController() {} 197