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 12 namespace clang{ 13 namespace tooling{ 14 namespace dependencies{ 15 16 std::vector<std::string> FullDependencies::getAdditionalArgs( 17 std::function<StringRef(ModuleID)> LookupPCMPath, 18 std::function<const ModuleDeps &(ModuleID)> LookupModuleDeps) const { 19 std::vector<std::string> Ret = getAdditionalArgsWithoutModulePaths(); 20 21 std::vector<std::string> PCMPaths; 22 std::vector<std::string> ModMapPaths; 23 dependencies::detail::collectPCMAndModuleMapPaths( 24 ClangModuleDeps, LookupPCMPath, LookupModuleDeps, PCMPaths, ModMapPaths); 25 for (const std::string &PCMPath : PCMPaths) 26 Ret.push_back("-fmodule-file=" + PCMPath); 27 28 return Ret; 29 } 30 31 std::vector<std::string> 32 FullDependencies::getAdditionalArgsWithoutModulePaths() const { 33 std::vector<std::string> Args{ 34 "-fno-implicit-modules", 35 "-fno-implicit-module-maps", 36 }; 37 38 for (const PrebuiltModuleDep &PMD : PrebuiltModuleDeps) 39 Args.push_back("-fmodule-file=" + PMD.PCMFile); 40 41 return Args; 42 } 43 44 DependencyScanningTool::DependencyScanningTool( 45 DependencyScanningService &Service) 46 : Worker(Service) {} 47 48 llvm::Expected<std::string> DependencyScanningTool::getDependencyFile( 49 const std::vector<std::string> &CommandLine, StringRef CWD, 50 llvm::Optional<StringRef> ModuleName) { 51 /// Prints out all of the gathered dependencies into a string. 52 class MakeDependencyPrinterConsumer : public DependencyConsumer { 53 public: 54 void 55 handleDependencyOutputOpts(const DependencyOutputOptions &Opts) override { 56 this->Opts = std::make_unique<DependencyOutputOptions>(Opts); 57 } 58 59 void handleFileDependency(StringRef File) override { 60 Dependencies.push_back(std::string(File)); 61 } 62 63 void handlePrebuiltModuleDependency(PrebuiltModuleDep PMD) override { 64 // Same as `handleModuleDependency`. 65 } 66 67 void handleModuleDependency(ModuleDeps MD) override { 68 // These are ignored for the make format as it can't support the full 69 // set of deps, and handleFileDependency handles enough for implicitly 70 // built modules to work. 71 } 72 73 void handleContextHash(std::string Hash) override {} 74 75 void printDependencies(std::string &S) { 76 assert(Opts && "Handled dependency output options."); 77 78 class DependencyPrinter : public DependencyFileGenerator { 79 public: 80 DependencyPrinter(DependencyOutputOptions &Opts, 81 ArrayRef<std::string> Dependencies) 82 : DependencyFileGenerator(Opts) { 83 for (const auto &Dep : Dependencies) 84 addDependency(Dep); 85 } 86 87 void printDependencies(std::string &S) { 88 llvm::raw_string_ostream OS(S); 89 outputDependencyFile(OS); 90 } 91 }; 92 93 DependencyPrinter Generator(*Opts, Dependencies); 94 Generator.printDependencies(S); 95 } 96 97 private: 98 std::unique_ptr<DependencyOutputOptions> Opts; 99 std::vector<std::string> Dependencies; 100 }; 101 102 MakeDependencyPrinterConsumer Consumer; 103 auto Result = 104 Worker.computeDependencies(CWD, CommandLine, Consumer, ModuleName); 105 if (Result) 106 return std::move(Result); 107 std::string Output; 108 Consumer.printDependencies(Output); 109 return Output; 110 } 111 112 llvm::Expected<FullDependenciesResult> 113 DependencyScanningTool::getFullDependencies( 114 const std::vector<std::string> &CommandLine, StringRef CWD, 115 const llvm::StringSet<> &AlreadySeen, 116 llvm::Optional<StringRef> ModuleName) { 117 class FullDependencyPrinterConsumer : public DependencyConsumer { 118 public: 119 FullDependencyPrinterConsumer(const llvm::StringSet<> &AlreadySeen) 120 : AlreadySeen(AlreadySeen) {} 121 122 void 123 handleDependencyOutputOpts(const DependencyOutputOptions &Opts) override {} 124 125 void handleFileDependency(StringRef File) override { 126 Dependencies.push_back(std::string(File)); 127 } 128 129 void handlePrebuiltModuleDependency(PrebuiltModuleDep PMD) override { 130 PrebuiltModuleDeps.emplace_back(std::move(PMD)); 131 } 132 133 void handleModuleDependency(ModuleDeps MD) override { 134 ClangModuleDeps[MD.ID.ContextHash + MD.ID.ModuleName] = std::move(MD); 135 } 136 137 void handleContextHash(std::string Hash) override { 138 ContextHash = std::move(Hash); 139 } 140 141 FullDependenciesResult getFullDependencies() const { 142 FullDependencies FD; 143 144 FD.ID.ContextHash = std::move(ContextHash); 145 146 FD.FileDeps.assign(Dependencies.begin(), Dependencies.end()); 147 148 for (auto &&M : ClangModuleDeps) { 149 auto &MD = M.second; 150 if (MD.ImportedByMainFile) 151 FD.ClangModuleDeps.push_back(MD.ID); 152 } 153 154 FD.PrebuiltModuleDeps = std::move(PrebuiltModuleDeps); 155 156 FullDependenciesResult FDR; 157 158 for (auto &&M : ClangModuleDeps) { 159 // TODO: Avoid handleModuleDependency even being called for modules 160 // we've already seen. 161 if (AlreadySeen.count(M.first)) 162 continue; 163 FDR.DiscoveredModules.push_back(std::move(M.second)); 164 } 165 166 FDR.FullDeps = std::move(FD); 167 return FDR; 168 } 169 170 private: 171 std::vector<std::string> Dependencies; 172 std::vector<PrebuiltModuleDep> PrebuiltModuleDeps; 173 std::map<std::string, ModuleDeps> ClangModuleDeps; 174 std::string ContextHash; 175 std::vector<std::string> OutputPaths; 176 const llvm::StringSet<> &AlreadySeen; 177 }; 178 179 FullDependencyPrinterConsumer Consumer(AlreadySeen); 180 llvm::Error Result = 181 Worker.computeDependencies(CWD, CommandLine, Consumer, ModuleName); 182 if (Result) 183 return std::move(Result); 184 return Consumer.getFullDependencies(); 185 } 186 187 } // end namespace dependencies 188 } // end namespace tooling 189 } // end namespace clang 190