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 16fe6060f1SDimitry Andric std::vector<std::string> FullDependencies::getAdditionalArgs( 17fe6060f1SDimitry Andric std::function<StringRef(ModuleID)> LookupPCMPath, 18fe6060f1SDimitry Andric std::function<const ModuleDeps &(ModuleID)> LookupModuleDeps) const { 19fe6060f1SDimitry Andric std::vector<std::string> Ret = getAdditionalArgsWithoutModulePaths(); 205ffd83dbSDimitry Andric 21fe6060f1SDimitry Andric std::vector<std::string> PCMPaths; 22fe6060f1SDimitry Andric std::vector<std::string> ModMapPaths; 23fe6060f1SDimitry Andric dependencies::detail::collectPCMAndModuleMapPaths( 24fe6060f1SDimitry Andric ClangModuleDeps, LookupPCMPath, LookupModuleDeps, PCMPaths, ModMapPaths); 25fe6060f1SDimitry Andric for (const std::string &PCMPath : PCMPaths) 26fe6060f1SDimitry Andric Ret.push_back("-fmodule-file=" + PCMPath); 275ffd83dbSDimitry Andric 285ffd83dbSDimitry Andric return Ret; 295ffd83dbSDimitry Andric } 305ffd83dbSDimitry Andric 31fe6060f1SDimitry Andric std::vector<std::string> 32fe6060f1SDimitry Andric FullDependencies::getAdditionalArgsWithoutModulePaths() const { 33fe6060f1SDimitry Andric std::vector<std::string> Args{ 34fe6060f1SDimitry Andric "-fno-implicit-modules", 35fe6060f1SDimitry Andric "-fno-implicit-module-maps", 36fe6060f1SDimitry Andric }; 37fe6060f1SDimitry Andric 38*349cc55cSDimitry Andric for (const PrebuiltModuleDep &PMD : PrebuiltModuleDeps) 39*349cc55cSDimitry Andric Args.push_back("-fmodule-file=" + PMD.PCMFile); 40fe6060f1SDimitry Andric 41fe6060f1SDimitry Andric return Args; 42fe6060f1SDimitry Andric } 43fe6060f1SDimitry Andric 44480093f4SDimitry Andric DependencyScanningTool::DependencyScanningTool( 45480093f4SDimitry Andric DependencyScanningService &Service) 465ffd83dbSDimitry Andric : Worker(Service) {} 47a7dea167SDimitry Andric 48480093f4SDimitry Andric llvm::Expected<std::string> DependencyScanningTool::getDependencyFile( 49*349cc55cSDimitry Andric const std::vector<std::string> &CommandLine, StringRef CWD, 50*349cc55cSDimitry Andric llvm::Optional<StringRef> ModuleName) { 51a7dea167SDimitry Andric /// Prints out all of the gathered dependencies into a string. 52480093f4SDimitry Andric class MakeDependencyPrinterConsumer : public DependencyConsumer { 53a7dea167SDimitry Andric public: 54fe6060f1SDimitry Andric void 55fe6060f1SDimitry Andric handleDependencyOutputOpts(const DependencyOutputOptions &Opts) override { 56a7dea167SDimitry Andric this->Opts = std::make_unique<DependencyOutputOptions>(Opts); 57fe6060f1SDimitry Andric } 58fe6060f1SDimitry Andric 59fe6060f1SDimitry Andric void handleFileDependency(StringRef File) override { 605ffd83dbSDimitry Andric Dependencies.push_back(std::string(File)); 61a7dea167SDimitry Andric } 62a7dea167SDimitry Andric 63fe6060f1SDimitry Andric void handlePrebuiltModuleDependency(PrebuiltModuleDep PMD) override { 64fe6060f1SDimitry Andric // Same as `handleModuleDependency`. 65fe6060f1SDimitry Andric } 66fe6060f1SDimitry Andric 67480093f4SDimitry Andric void handleModuleDependency(ModuleDeps MD) override { 68480093f4SDimitry Andric // These are ignored for the make format as it can't support the full 69480093f4SDimitry Andric // set of deps, and handleFileDependency handles enough for implicitly 70480093f4SDimitry Andric // built modules to work. 71480093f4SDimitry Andric } 72480093f4SDimitry Andric 73480093f4SDimitry Andric void handleContextHash(std::string Hash) override {} 74480093f4SDimitry Andric 75a7dea167SDimitry Andric void printDependencies(std::string &S) { 76fe6060f1SDimitry Andric assert(Opts && "Handled dependency output options."); 77a7dea167SDimitry Andric 78a7dea167SDimitry Andric class DependencyPrinter : public DependencyFileGenerator { 79a7dea167SDimitry Andric public: 80a7dea167SDimitry Andric DependencyPrinter(DependencyOutputOptions &Opts, 81a7dea167SDimitry Andric ArrayRef<std::string> Dependencies) 82a7dea167SDimitry Andric : DependencyFileGenerator(Opts) { 83a7dea167SDimitry Andric for (const auto &Dep : Dependencies) 84a7dea167SDimitry Andric addDependency(Dep); 85a7dea167SDimitry Andric } 86a7dea167SDimitry Andric 87a7dea167SDimitry Andric void printDependencies(std::string &S) { 88a7dea167SDimitry Andric llvm::raw_string_ostream OS(S); 89a7dea167SDimitry Andric outputDependencyFile(OS); 90a7dea167SDimitry Andric } 91a7dea167SDimitry Andric }; 92a7dea167SDimitry Andric 93a7dea167SDimitry Andric DependencyPrinter Generator(*Opts, Dependencies); 94a7dea167SDimitry Andric Generator.printDependencies(S); 95a7dea167SDimitry Andric } 96a7dea167SDimitry Andric 97a7dea167SDimitry Andric private: 98a7dea167SDimitry Andric std::unique_ptr<DependencyOutputOptions> Opts; 99a7dea167SDimitry Andric std::vector<std::string> Dependencies; 100a7dea167SDimitry Andric }; 101a7dea167SDimitry Andric 1025ffd83dbSDimitry Andric MakeDependencyPrinterConsumer Consumer; 103*349cc55cSDimitry Andric auto Result = 104*349cc55cSDimitry Andric Worker.computeDependencies(CWD, CommandLine, Consumer, ModuleName); 1055ffd83dbSDimitry Andric if (Result) 1065ffd83dbSDimitry Andric return std::move(Result); 1075ffd83dbSDimitry Andric std::string Output; 1085ffd83dbSDimitry Andric Consumer.printDependencies(Output); 1095ffd83dbSDimitry Andric return Output; 1105ffd83dbSDimitry Andric } 1115ffd83dbSDimitry Andric 1125ffd83dbSDimitry Andric llvm::Expected<FullDependenciesResult> 1135ffd83dbSDimitry Andric DependencyScanningTool::getFullDependencies( 114*349cc55cSDimitry Andric const std::vector<std::string> &CommandLine, StringRef CWD, 115*349cc55cSDimitry Andric const llvm::StringSet<> &AlreadySeen, 116*349cc55cSDimitry Andric llvm::Optional<StringRef> ModuleName) { 117480093f4SDimitry Andric class FullDependencyPrinterConsumer : public DependencyConsumer { 118480093f4SDimitry Andric public: 1195ffd83dbSDimitry Andric FullDependencyPrinterConsumer(const llvm::StringSet<> &AlreadySeen) 1205ffd83dbSDimitry Andric : AlreadySeen(AlreadySeen) {} 1215ffd83dbSDimitry Andric 122fe6060f1SDimitry Andric void 123fe6060f1SDimitry Andric handleDependencyOutputOpts(const DependencyOutputOptions &Opts) override {} 124fe6060f1SDimitry Andric 125fe6060f1SDimitry Andric void handleFileDependency(StringRef File) override { 1265ffd83dbSDimitry Andric Dependencies.push_back(std::string(File)); 127480093f4SDimitry Andric } 128480093f4SDimitry Andric 129fe6060f1SDimitry Andric void handlePrebuiltModuleDependency(PrebuiltModuleDep PMD) override { 130fe6060f1SDimitry Andric PrebuiltModuleDeps.emplace_back(std::move(PMD)); 131fe6060f1SDimitry Andric } 132fe6060f1SDimitry Andric 133480093f4SDimitry Andric void handleModuleDependency(ModuleDeps MD) override { 134fe6060f1SDimitry Andric ClangModuleDeps[MD.ID.ContextHash + MD.ID.ModuleName] = std::move(MD); 135480093f4SDimitry Andric } 136480093f4SDimitry Andric 137480093f4SDimitry Andric void handleContextHash(std::string Hash) override { 138480093f4SDimitry Andric ContextHash = std::move(Hash); 139480093f4SDimitry Andric } 140480093f4SDimitry Andric 1415ffd83dbSDimitry Andric FullDependenciesResult getFullDependencies() const { 1425ffd83dbSDimitry Andric FullDependencies FD; 143480093f4SDimitry Andric 144fe6060f1SDimitry Andric FD.ID.ContextHash = std::move(ContextHash); 145480093f4SDimitry Andric 1465ffd83dbSDimitry Andric FD.FileDeps.assign(Dependencies.begin(), Dependencies.end()); 147480093f4SDimitry Andric 1485ffd83dbSDimitry Andric for (auto &&M : ClangModuleDeps) { 1495ffd83dbSDimitry Andric auto &MD = M.second; 150480093f4SDimitry Andric if (MD.ImportedByMainFile) 151fe6060f1SDimitry Andric FD.ClangModuleDeps.push_back(MD.ID); 152480093f4SDimitry Andric } 153480093f4SDimitry Andric 154fe6060f1SDimitry Andric FD.PrebuiltModuleDeps = std::move(PrebuiltModuleDeps); 155fe6060f1SDimitry Andric 1565ffd83dbSDimitry Andric FullDependenciesResult FDR; 1575ffd83dbSDimitry Andric 1585ffd83dbSDimitry Andric for (auto &&M : ClangModuleDeps) { 1595ffd83dbSDimitry Andric // TODO: Avoid handleModuleDependency even being called for modules 1605ffd83dbSDimitry Andric // we've already seen. 1615ffd83dbSDimitry Andric if (AlreadySeen.count(M.first)) 1625ffd83dbSDimitry Andric continue; 1635ffd83dbSDimitry Andric FDR.DiscoveredModules.push_back(std::move(M.second)); 164480093f4SDimitry Andric } 165480093f4SDimitry Andric 1665ffd83dbSDimitry Andric FDR.FullDeps = std::move(FD); 1675ffd83dbSDimitry Andric return FDR; 168480093f4SDimitry Andric } 169480093f4SDimitry Andric 170480093f4SDimitry Andric private: 171480093f4SDimitry Andric std::vector<std::string> Dependencies; 172fe6060f1SDimitry Andric std::vector<PrebuiltModuleDep> PrebuiltModuleDeps; 173*349cc55cSDimitry Andric std::map<std::string, ModuleDeps> ClangModuleDeps; 174480093f4SDimitry Andric std::string ContextHash; 1755ffd83dbSDimitry Andric std::vector<std::string> OutputPaths; 1765ffd83dbSDimitry Andric const llvm::StringSet<> &AlreadySeen; 177480093f4SDimitry Andric }; 178480093f4SDimitry Andric 1795ffd83dbSDimitry Andric FullDependencyPrinterConsumer Consumer(AlreadySeen); 1805ffd83dbSDimitry Andric llvm::Error Result = 181*349cc55cSDimitry Andric Worker.computeDependencies(CWD, CommandLine, Consumer, ModuleName); 182a7dea167SDimitry Andric if (Result) 183a7dea167SDimitry Andric return std::move(Result); 1845ffd83dbSDimitry Andric return Consumer.getFullDependencies(); 185a7dea167SDimitry Andric } 186a7dea167SDimitry Andric 187a7dea167SDimitry Andric } // end namespace dependencies 188a7dea167SDimitry Andric } // end namespace tooling 189a7dea167SDimitry Andric } // end namespace clang 190