1480093f4SDimitry Andric //===- DependencyScanningTool.cpp - clang-scan-deps service ---------------===// 2a7dea167SDimitry Andric // 3a7dea167SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4a7dea167SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5a7dea167SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6a7dea167SDimitry Andric // 7a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 8a7dea167SDimitry Andric 9a7dea167SDimitry Andric #include "clang/Tooling/DependencyScanning/DependencyScanningTool.h" 10a7dea167SDimitry Andric #include "clang/Frontend/Utils.h" 11a7dea167SDimitry Andric 12a7dea167SDimitry Andric namespace clang{ 13a7dea167SDimitry Andric namespace tooling{ 14a7dea167SDimitry Andric namespace dependencies{ 15a7dea167SDimitry Andric 16*fe6060f1SDimitry Andric std::vector<std::string> FullDependencies::getAdditionalArgs( 17*fe6060f1SDimitry Andric std::function<StringRef(ModuleID)> LookupPCMPath, 18*fe6060f1SDimitry Andric std::function<const ModuleDeps &(ModuleID)> LookupModuleDeps) const { 19*fe6060f1SDimitry Andric std::vector<std::string> Ret = getAdditionalArgsWithoutModulePaths(); 205ffd83dbSDimitry Andric 21*fe6060f1SDimitry Andric std::vector<std::string> PCMPaths; 22*fe6060f1SDimitry Andric std::vector<std::string> ModMapPaths; 23*fe6060f1SDimitry Andric dependencies::detail::collectPCMAndModuleMapPaths( 24*fe6060f1SDimitry Andric ClangModuleDeps, LookupPCMPath, LookupModuleDeps, PCMPaths, ModMapPaths); 25*fe6060f1SDimitry Andric for (const std::string &PCMPath : PCMPaths) 26*fe6060f1SDimitry Andric Ret.push_back("-fmodule-file=" + PCMPath); 27*fe6060f1SDimitry Andric for (const std::string &ModMapPath : ModMapPaths) 28*fe6060f1SDimitry Andric Ret.push_back("-fmodule-map-file=" + ModMapPath); 295ffd83dbSDimitry Andric 305ffd83dbSDimitry Andric return Ret; 315ffd83dbSDimitry Andric } 325ffd83dbSDimitry Andric 33*fe6060f1SDimitry Andric std::vector<std::string> 34*fe6060f1SDimitry Andric FullDependencies::getAdditionalArgsWithoutModulePaths() const { 35*fe6060f1SDimitry Andric std::vector<std::string> Args{ 36*fe6060f1SDimitry Andric "-fno-implicit-modules", 37*fe6060f1SDimitry Andric "-fno-implicit-module-maps", 38*fe6060f1SDimitry Andric }; 39*fe6060f1SDimitry Andric 40*fe6060f1SDimitry Andric for (const PrebuiltModuleDep &PMD : PrebuiltModuleDeps) { 41*fe6060f1SDimitry Andric Args.push_back("-fmodule-file=" + PMD.ModuleName + "=" + PMD.PCMFile); 42*fe6060f1SDimitry Andric Args.push_back("-fmodule-map-file=" + PMD.ModuleMapFile); 43*fe6060f1SDimitry Andric } 44*fe6060f1SDimitry Andric 45*fe6060f1SDimitry Andric return Args; 46*fe6060f1SDimitry Andric } 47*fe6060f1SDimitry Andric 48480093f4SDimitry Andric DependencyScanningTool::DependencyScanningTool( 49480093f4SDimitry Andric DependencyScanningService &Service) 505ffd83dbSDimitry Andric : Worker(Service) {} 51a7dea167SDimitry Andric 52480093f4SDimitry Andric llvm::Expected<std::string> DependencyScanningTool::getDependencyFile( 53480093f4SDimitry Andric const tooling::CompilationDatabase &Compilations, StringRef CWD) { 54a7dea167SDimitry Andric /// Prints out all of the gathered dependencies into a string. 55480093f4SDimitry Andric class MakeDependencyPrinterConsumer : public DependencyConsumer { 56a7dea167SDimitry Andric public: 57*fe6060f1SDimitry Andric void 58*fe6060f1SDimitry Andric handleDependencyOutputOpts(const DependencyOutputOptions &Opts) override { 59a7dea167SDimitry Andric this->Opts = std::make_unique<DependencyOutputOptions>(Opts); 60*fe6060f1SDimitry Andric } 61*fe6060f1SDimitry Andric 62*fe6060f1SDimitry Andric void handleFileDependency(StringRef File) override { 635ffd83dbSDimitry Andric Dependencies.push_back(std::string(File)); 64a7dea167SDimitry Andric } 65a7dea167SDimitry Andric 66*fe6060f1SDimitry Andric void handlePrebuiltModuleDependency(PrebuiltModuleDep PMD) override { 67*fe6060f1SDimitry Andric // Same as `handleModuleDependency`. 68*fe6060f1SDimitry Andric } 69*fe6060f1SDimitry Andric 70480093f4SDimitry Andric void handleModuleDependency(ModuleDeps MD) override { 71480093f4SDimitry Andric // These are ignored for the make format as it can't support the full 72480093f4SDimitry Andric // set of deps, and handleFileDependency handles enough for implicitly 73480093f4SDimitry Andric // built modules to work. 74480093f4SDimitry Andric } 75480093f4SDimitry Andric 76480093f4SDimitry Andric void handleContextHash(std::string Hash) override {} 77480093f4SDimitry Andric 78a7dea167SDimitry Andric void printDependencies(std::string &S) { 79*fe6060f1SDimitry Andric assert(Opts && "Handled dependency output options."); 80a7dea167SDimitry Andric 81a7dea167SDimitry Andric class DependencyPrinter : public DependencyFileGenerator { 82a7dea167SDimitry Andric public: 83a7dea167SDimitry Andric DependencyPrinter(DependencyOutputOptions &Opts, 84a7dea167SDimitry Andric ArrayRef<std::string> Dependencies) 85a7dea167SDimitry Andric : DependencyFileGenerator(Opts) { 86a7dea167SDimitry Andric for (const auto &Dep : Dependencies) 87a7dea167SDimitry Andric addDependency(Dep); 88a7dea167SDimitry Andric } 89a7dea167SDimitry Andric 90a7dea167SDimitry Andric void printDependencies(std::string &S) { 91a7dea167SDimitry Andric llvm::raw_string_ostream OS(S); 92a7dea167SDimitry Andric outputDependencyFile(OS); 93a7dea167SDimitry Andric } 94a7dea167SDimitry Andric }; 95a7dea167SDimitry Andric 96a7dea167SDimitry Andric DependencyPrinter Generator(*Opts, Dependencies); 97a7dea167SDimitry Andric Generator.printDependencies(S); 98a7dea167SDimitry Andric } 99a7dea167SDimitry Andric 100a7dea167SDimitry Andric private: 101a7dea167SDimitry Andric std::unique_ptr<DependencyOutputOptions> Opts; 102a7dea167SDimitry Andric std::vector<std::string> Dependencies; 103a7dea167SDimitry Andric }; 104a7dea167SDimitry Andric 1055ffd83dbSDimitry Andric // We expect a single command here because if a source file occurs multiple 1065ffd83dbSDimitry Andric // times in the original CDB, then `computeDependencies` would run the 1075ffd83dbSDimitry Andric // `DependencyScanningAction` once for every time the input occured in the 1085ffd83dbSDimitry Andric // CDB. Instead we split up the CDB into single command chunks to avoid this 1095ffd83dbSDimitry Andric // behavior. 1105ffd83dbSDimitry Andric assert(Compilations.getAllCompileCommands().size() == 1 && 1115ffd83dbSDimitry Andric "Expected a compilation database with a single command!"); 1125ffd83dbSDimitry Andric std::string Input = Compilations.getAllCompileCommands().front().Filename; 1135ffd83dbSDimitry Andric 1145ffd83dbSDimitry Andric MakeDependencyPrinterConsumer Consumer; 1155ffd83dbSDimitry Andric auto Result = Worker.computeDependencies(Input, CWD, Compilations, Consumer); 1165ffd83dbSDimitry Andric if (Result) 1175ffd83dbSDimitry Andric return std::move(Result); 1185ffd83dbSDimitry Andric std::string Output; 1195ffd83dbSDimitry Andric Consumer.printDependencies(Output); 1205ffd83dbSDimitry Andric return Output; 1215ffd83dbSDimitry Andric } 1225ffd83dbSDimitry Andric 1235ffd83dbSDimitry Andric llvm::Expected<FullDependenciesResult> 1245ffd83dbSDimitry Andric DependencyScanningTool::getFullDependencies( 1255ffd83dbSDimitry Andric const tooling::CompilationDatabase &Compilations, StringRef CWD, 1265ffd83dbSDimitry Andric const llvm::StringSet<> &AlreadySeen) { 127480093f4SDimitry Andric class FullDependencyPrinterConsumer : public DependencyConsumer { 128480093f4SDimitry Andric public: 1295ffd83dbSDimitry Andric FullDependencyPrinterConsumer(const llvm::StringSet<> &AlreadySeen) 1305ffd83dbSDimitry Andric : AlreadySeen(AlreadySeen) {} 1315ffd83dbSDimitry Andric 132*fe6060f1SDimitry Andric void 133*fe6060f1SDimitry Andric handleDependencyOutputOpts(const DependencyOutputOptions &Opts) override {} 134*fe6060f1SDimitry Andric 135*fe6060f1SDimitry Andric void handleFileDependency(StringRef File) override { 1365ffd83dbSDimitry Andric Dependencies.push_back(std::string(File)); 137480093f4SDimitry Andric } 138480093f4SDimitry Andric 139*fe6060f1SDimitry Andric void handlePrebuiltModuleDependency(PrebuiltModuleDep PMD) override { 140*fe6060f1SDimitry Andric PrebuiltModuleDeps.emplace_back(std::move(PMD)); 141*fe6060f1SDimitry Andric } 142*fe6060f1SDimitry Andric 143480093f4SDimitry Andric void handleModuleDependency(ModuleDeps MD) override { 144*fe6060f1SDimitry Andric ClangModuleDeps[MD.ID.ContextHash + MD.ID.ModuleName] = std::move(MD); 145480093f4SDimitry Andric } 146480093f4SDimitry Andric 147480093f4SDimitry Andric void handleContextHash(std::string Hash) override { 148480093f4SDimitry Andric ContextHash = std::move(Hash); 149480093f4SDimitry Andric } 150480093f4SDimitry Andric 1515ffd83dbSDimitry Andric FullDependenciesResult getFullDependencies() const { 1525ffd83dbSDimitry Andric FullDependencies FD; 153480093f4SDimitry Andric 154*fe6060f1SDimitry Andric FD.ID.ContextHash = std::move(ContextHash); 155480093f4SDimitry Andric 1565ffd83dbSDimitry Andric FD.FileDeps.assign(Dependencies.begin(), Dependencies.end()); 157480093f4SDimitry Andric 1585ffd83dbSDimitry Andric for (auto &&M : ClangModuleDeps) { 1595ffd83dbSDimitry Andric auto &MD = M.second; 160480093f4SDimitry Andric if (MD.ImportedByMainFile) 161*fe6060f1SDimitry Andric FD.ClangModuleDeps.push_back(MD.ID); 162480093f4SDimitry Andric } 163480093f4SDimitry Andric 164*fe6060f1SDimitry Andric FD.PrebuiltModuleDeps = std::move(PrebuiltModuleDeps); 165*fe6060f1SDimitry Andric 1665ffd83dbSDimitry Andric FullDependenciesResult FDR; 1675ffd83dbSDimitry Andric 1685ffd83dbSDimitry Andric for (auto &&M : ClangModuleDeps) { 1695ffd83dbSDimitry Andric // TODO: Avoid handleModuleDependency even being called for modules 1705ffd83dbSDimitry Andric // we've already seen. 1715ffd83dbSDimitry Andric if (AlreadySeen.count(M.first)) 1725ffd83dbSDimitry Andric continue; 1735ffd83dbSDimitry Andric FDR.DiscoveredModules.push_back(std::move(M.second)); 174480093f4SDimitry Andric } 175480093f4SDimitry Andric 1765ffd83dbSDimitry Andric FDR.FullDeps = std::move(FD); 1775ffd83dbSDimitry Andric return FDR; 178480093f4SDimitry Andric } 179480093f4SDimitry Andric 180480093f4SDimitry Andric private: 181480093f4SDimitry Andric std::vector<std::string> Dependencies; 182*fe6060f1SDimitry Andric std::vector<PrebuiltModuleDep> PrebuiltModuleDeps; 183480093f4SDimitry Andric std::unordered_map<std::string, ModuleDeps> ClangModuleDeps; 184480093f4SDimitry Andric std::string ContextHash; 1855ffd83dbSDimitry Andric std::vector<std::string> OutputPaths; 1865ffd83dbSDimitry Andric const llvm::StringSet<> &AlreadySeen; 187480093f4SDimitry Andric }; 188480093f4SDimitry Andric 189480093f4SDimitry Andric // We expect a single command here because if a source file occurs multiple 190480093f4SDimitry Andric // times in the original CDB, then `computeDependencies` would run the 191480093f4SDimitry Andric // `DependencyScanningAction` once for every time the input occured in the 192480093f4SDimitry Andric // CDB. Instead we split up the CDB into single command chunks to avoid this 193480093f4SDimitry Andric // behavior. 194480093f4SDimitry Andric assert(Compilations.getAllCompileCommands().size() == 1 && 195480093f4SDimitry Andric "Expected a compilation database with a single command!"); 196480093f4SDimitry Andric std::string Input = Compilations.getAllCompileCommands().front().Filename; 197480093f4SDimitry Andric 1985ffd83dbSDimitry Andric FullDependencyPrinterConsumer Consumer(AlreadySeen); 1995ffd83dbSDimitry Andric llvm::Error Result = 200a7dea167SDimitry Andric Worker.computeDependencies(Input, CWD, Compilations, Consumer); 201a7dea167SDimitry Andric if (Result) 202a7dea167SDimitry Andric return std::move(Result); 2035ffd83dbSDimitry Andric return Consumer.getFullDependencies(); 204a7dea167SDimitry Andric } 205a7dea167SDimitry Andric 206a7dea167SDimitry Andric } // end namespace dependencies 207a7dea167SDimitry Andric } // end namespace tooling 208a7dea167SDimitry Andric } // end namespace clang 209