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 handleContextHash(std::string Hash) override {} 44 45 void printDependencies(std::string &S) { 46 assert(Opts && "Handled dependency output options."); 47 48 class DependencyPrinter : public DependencyFileGenerator { 49 public: 50 DependencyPrinter(DependencyOutputOptions &Opts, 51 ArrayRef<std::string> Dependencies) 52 : DependencyFileGenerator(Opts) { 53 for (const auto &Dep : Dependencies) 54 addDependency(Dep); 55 } 56 57 void printDependencies(std::string &S) { 58 llvm::raw_string_ostream OS(S); 59 outputDependencyFile(OS); 60 } 61 }; 62 63 DependencyPrinter Generator(*Opts, Dependencies); 64 Generator.printDependencies(S); 65 } 66 67 protected: 68 std::unique_ptr<DependencyOutputOptions> Opts; 69 std::vector<std::string> Dependencies; 70 }; 71 } // anonymous namespace 72 73 llvm::Expected<std::string> DependencyScanningTool::getDependencyFile( 74 const std::vector<std::string> &CommandLine, StringRef CWD) { 75 MakeDependencyPrinterConsumer Consumer; 76 CallbackActionController Controller(nullptr); 77 auto Result = 78 Worker.computeDependencies(CWD, CommandLine, Consumer, Controller); 79 if (Result) 80 return std::move(Result); 81 std::string Output; 82 Consumer.printDependencies(Output); 83 return Output; 84 } 85 86 llvm::Expected<P1689Rule> DependencyScanningTool::getP1689ModuleDependencyFile( 87 const CompileCommand &Command, StringRef CWD, std::string &MakeformatOutput, 88 std::string &MakeformatOutputPath) { 89 class P1689ModuleDependencyPrinterConsumer 90 : public MakeDependencyPrinterConsumer { 91 public: 92 P1689ModuleDependencyPrinterConsumer(P1689Rule &Rule, 93 const CompileCommand &Command) 94 : Filename(Command.Filename), Rule(Rule) { 95 Rule.PrimaryOutput = Command.Output; 96 } 97 98 void handleProvidedAndRequiredStdCXXModules( 99 std::optional<P1689ModuleInfo> Provided, 100 std::vector<P1689ModuleInfo> Requires) override { 101 Rule.Provides = Provided; 102 if (Rule.Provides) 103 Rule.Provides->SourcePath = Filename.str(); 104 Rule.Requires = Requires; 105 } 106 107 StringRef getMakeFormatDependencyOutputPath() { 108 if (Opts->OutputFormat != DependencyOutputFormat::Make) 109 return {}; 110 return Opts->OutputFile; 111 } 112 113 private: 114 StringRef Filename; 115 P1689Rule &Rule; 116 }; 117 118 class P1689ActionController : public DependencyActionController { 119 public: 120 // The lookupModuleOutput is for clang modules. P1689 format don't need it. 121 std::string lookupModuleOutput(const ModuleID &, 122 ModuleOutputKind Kind) override { 123 return ""; 124 } 125 }; 126 127 P1689Rule Rule; 128 P1689ModuleDependencyPrinterConsumer Consumer(Rule, Command); 129 P1689ActionController Controller; 130 auto Result = Worker.computeDependencies(CWD, Command.CommandLine, Consumer, 131 Controller); 132 if (Result) 133 return std::move(Result); 134 135 MakeformatOutputPath = Consumer.getMakeFormatDependencyOutputPath(); 136 if (!MakeformatOutputPath.empty()) 137 Consumer.printDependencies(MakeformatOutput); 138 return Rule; 139 } 140 141 llvm::Expected<TranslationUnitDeps> 142 DependencyScanningTool::getTranslationUnitDependencies( 143 const std::vector<std::string> &CommandLine, StringRef CWD, 144 const llvm::DenseSet<ModuleID> &AlreadySeen, 145 LookupModuleOutputCallback LookupModuleOutput) { 146 FullDependencyConsumer Consumer(AlreadySeen); 147 CallbackActionController Controller(LookupModuleOutput); 148 llvm::Error Result = 149 Worker.computeDependencies(CWD, CommandLine, Consumer, Controller); 150 if (Result) 151 return std::move(Result); 152 return Consumer.takeTranslationUnitDeps(); 153 } 154 155 llvm::Expected<ModuleDepsGraph> DependencyScanningTool::getModuleDependencies( 156 StringRef ModuleName, const std::vector<std::string> &CommandLine, 157 StringRef CWD, const llvm::DenseSet<ModuleID> &AlreadySeen, 158 LookupModuleOutputCallback LookupModuleOutput) { 159 FullDependencyConsumer Consumer(AlreadySeen); 160 CallbackActionController Controller(LookupModuleOutput); 161 llvm::Error Result = Worker.computeDependencies(CWD, CommandLine, Consumer, 162 Controller, ModuleName); 163 if (Result) 164 return std::move(Result); 165 return Consumer.takeModuleGraphDeps(); 166 } 167 168 TranslationUnitDeps FullDependencyConsumer::takeTranslationUnitDeps() { 169 TranslationUnitDeps TU; 170 171 TU.ID.ContextHash = std::move(ContextHash); 172 TU.FileDeps = std::move(Dependencies); 173 TU.PrebuiltModuleDeps = std::move(PrebuiltModuleDeps); 174 TU.Commands = std::move(Commands); 175 176 for (auto &&M : ClangModuleDeps) { 177 auto &MD = M.second; 178 // TODO: Avoid handleModuleDependency even being called for modules 179 // we've already seen. 180 if (AlreadySeen.count(M.first)) 181 continue; 182 TU.ModuleGraph.push_back(std::move(MD)); 183 } 184 TU.ClangModuleDeps = std::move(DirectModuleDeps); 185 186 return TU; 187 } 188 189 ModuleDepsGraph FullDependencyConsumer::takeModuleGraphDeps() { 190 ModuleDepsGraph ModuleGraph; 191 192 for (auto &&M : ClangModuleDeps) { 193 auto &MD = M.second; 194 // TODO: Avoid handleModuleDependency even being called for modules 195 // we've already seen. 196 if (AlreadySeen.count(M.first)) 197 continue; 198 ModuleGraph.push_back(std::move(MD)); 199 } 200 201 return ModuleGraph; 202 } 203 204 CallbackActionController::~CallbackActionController() {} 205