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