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*81ad6265SDimitry Andric std::vector<std::string> FullDependencies::getCommandLine( 17*81ad6265SDimitry Andric std::function<StringRef(ModuleID)> LookupPCMPath) const { 18*81ad6265SDimitry Andric std::vector<std::string> Ret = getCommandLineWithoutModulePaths(); 195ffd83dbSDimitry Andric 20*81ad6265SDimitry Andric for (ModuleID MID : ClangModuleDeps) 21*81ad6265SDimitry Andric Ret.push_back(("-fmodule-file=" + LookupPCMPath(MID)).str()); 225ffd83dbSDimitry Andric 235ffd83dbSDimitry Andric return Ret; 245ffd83dbSDimitry Andric } 255ffd83dbSDimitry Andric 26fe6060f1SDimitry Andric std::vector<std::string> 27*81ad6265SDimitry Andric FullDependencies::getCommandLineWithoutModulePaths() const { 28*81ad6265SDimitry Andric std::vector<std::string> Args = OriginalCommandLine; 29fe6060f1SDimitry Andric 30*81ad6265SDimitry Andric Args.push_back("-fno-implicit-modules"); 31*81ad6265SDimitry Andric Args.push_back("-fno-implicit-module-maps"); 32349cc55cSDimitry Andric for (const PrebuiltModuleDep &PMD : PrebuiltModuleDeps) 33349cc55cSDimitry Andric Args.push_back("-fmodule-file=" + PMD.PCMFile); 34fe6060f1SDimitry Andric 35*81ad6265SDimitry Andric // These arguments are unused in explicit compiles. 36*81ad6265SDimitry Andric llvm::erase_if(Args, [](StringRef Arg) { 37*81ad6265SDimitry Andric if (Arg.consume_front("-fmodules-")) { 38*81ad6265SDimitry Andric return Arg.startswith("cache-path=") || 39*81ad6265SDimitry Andric Arg.startswith("prune-interval=") || 40*81ad6265SDimitry Andric Arg.startswith("prune-after=") || 41*81ad6265SDimitry Andric Arg == "validate-once-per-build-session"; 42*81ad6265SDimitry Andric } 43*81ad6265SDimitry Andric return Arg.startswith("-fbuild-session-file="); 44*81ad6265SDimitry Andric }); 45*81ad6265SDimitry Andric 46fe6060f1SDimitry Andric return Args; 47fe6060f1SDimitry Andric } 48fe6060f1SDimitry Andric 49480093f4SDimitry Andric DependencyScanningTool::DependencyScanningTool( 50480093f4SDimitry Andric DependencyScanningService &Service) 515ffd83dbSDimitry Andric : Worker(Service) {} 52a7dea167SDimitry Andric 53480093f4SDimitry Andric llvm::Expected<std::string> DependencyScanningTool::getDependencyFile( 54349cc55cSDimitry Andric const std::vector<std::string> &CommandLine, StringRef CWD, 55349cc55cSDimitry Andric llvm::Optional<StringRef> ModuleName) { 56a7dea167SDimitry Andric /// Prints out all of the gathered dependencies into a string. 57480093f4SDimitry Andric class MakeDependencyPrinterConsumer : public DependencyConsumer { 58a7dea167SDimitry Andric public: 59fe6060f1SDimitry Andric void 60fe6060f1SDimitry Andric handleDependencyOutputOpts(const DependencyOutputOptions &Opts) override { 61a7dea167SDimitry Andric this->Opts = std::make_unique<DependencyOutputOptions>(Opts); 62fe6060f1SDimitry Andric } 63fe6060f1SDimitry Andric 64fe6060f1SDimitry Andric void handleFileDependency(StringRef File) override { 655ffd83dbSDimitry Andric Dependencies.push_back(std::string(File)); 66a7dea167SDimitry Andric } 67a7dea167SDimitry Andric 68fe6060f1SDimitry Andric void handlePrebuiltModuleDependency(PrebuiltModuleDep PMD) override { 69fe6060f1SDimitry Andric // Same as `handleModuleDependency`. 70fe6060f1SDimitry Andric } 71fe6060f1SDimitry Andric 72480093f4SDimitry Andric void handleModuleDependency(ModuleDeps MD) override { 73480093f4SDimitry Andric // These are ignored for the make format as it can't support the full 74480093f4SDimitry Andric // set of deps, and handleFileDependency handles enough for implicitly 75480093f4SDimitry Andric // built modules to work. 76480093f4SDimitry Andric } 77480093f4SDimitry Andric 78480093f4SDimitry Andric void handleContextHash(std::string Hash) override {} 79480093f4SDimitry Andric 80a7dea167SDimitry Andric void printDependencies(std::string &S) { 81fe6060f1SDimitry Andric assert(Opts && "Handled dependency output options."); 82a7dea167SDimitry Andric 83a7dea167SDimitry Andric class DependencyPrinter : public DependencyFileGenerator { 84a7dea167SDimitry Andric public: 85a7dea167SDimitry Andric DependencyPrinter(DependencyOutputOptions &Opts, 86a7dea167SDimitry Andric ArrayRef<std::string> Dependencies) 87a7dea167SDimitry Andric : DependencyFileGenerator(Opts) { 88a7dea167SDimitry Andric for (const auto &Dep : Dependencies) 89a7dea167SDimitry Andric addDependency(Dep); 90a7dea167SDimitry Andric } 91a7dea167SDimitry Andric 92a7dea167SDimitry Andric void printDependencies(std::string &S) { 93a7dea167SDimitry Andric llvm::raw_string_ostream OS(S); 94a7dea167SDimitry Andric outputDependencyFile(OS); 95a7dea167SDimitry Andric } 96a7dea167SDimitry Andric }; 97a7dea167SDimitry Andric 98a7dea167SDimitry Andric DependencyPrinter Generator(*Opts, Dependencies); 99a7dea167SDimitry Andric Generator.printDependencies(S); 100a7dea167SDimitry Andric } 101a7dea167SDimitry Andric 102a7dea167SDimitry Andric private: 103a7dea167SDimitry Andric std::unique_ptr<DependencyOutputOptions> Opts; 104a7dea167SDimitry Andric std::vector<std::string> Dependencies; 105a7dea167SDimitry Andric }; 106a7dea167SDimitry Andric 1075ffd83dbSDimitry Andric MakeDependencyPrinterConsumer Consumer; 108349cc55cSDimitry Andric auto Result = 109349cc55cSDimitry Andric Worker.computeDependencies(CWD, CommandLine, Consumer, ModuleName); 1105ffd83dbSDimitry Andric if (Result) 1115ffd83dbSDimitry Andric return std::move(Result); 1125ffd83dbSDimitry Andric std::string Output; 1135ffd83dbSDimitry Andric Consumer.printDependencies(Output); 1145ffd83dbSDimitry Andric return Output; 1155ffd83dbSDimitry Andric } 1165ffd83dbSDimitry Andric 1175ffd83dbSDimitry Andric llvm::Expected<FullDependenciesResult> 1185ffd83dbSDimitry Andric DependencyScanningTool::getFullDependencies( 119349cc55cSDimitry Andric const std::vector<std::string> &CommandLine, StringRef CWD, 120349cc55cSDimitry Andric const llvm::StringSet<> &AlreadySeen, 121349cc55cSDimitry Andric llvm::Optional<StringRef> ModuleName) { 122480093f4SDimitry Andric class FullDependencyPrinterConsumer : public DependencyConsumer { 123480093f4SDimitry Andric public: 1245ffd83dbSDimitry Andric FullDependencyPrinterConsumer(const llvm::StringSet<> &AlreadySeen) 1255ffd83dbSDimitry Andric : AlreadySeen(AlreadySeen) {} 1265ffd83dbSDimitry Andric 127fe6060f1SDimitry Andric void 128fe6060f1SDimitry Andric handleDependencyOutputOpts(const DependencyOutputOptions &Opts) override {} 129fe6060f1SDimitry Andric 130fe6060f1SDimitry Andric void handleFileDependency(StringRef File) override { 1315ffd83dbSDimitry Andric Dependencies.push_back(std::string(File)); 132480093f4SDimitry Andric } 133480093f4SDimitry Andric 134fe6060f1SDimitry Andric void handlePrebuiltModuleDependency(PrebuiltModuleDep PMD) override { 135fe6060f1SDimitry Andric PrebuiltModuleDeps.emplace_back(std::move(PMD)); 136fe6060f1SDimitry Andric } 137fe6060f1SDimitry Andric 138480093f4SDimitry Andric void handleModuleDependency(ModuleDeps MD) override { 139fe6060f1SDimitry Andric ClangModuleDeps[MD.ID.ContextHash + MD.ID.ModuleName] = std::move(MD); 140480093f4SDimitry Andric } 141480093f4SDimitry Andric 142480093f4SDimitry Andric void handleContextHash(std::string Hash) override { 143480093f4SDimitry Andric ContextHash = std::move(Hash); 144480093f4SDimitry Andric } 145480093f4SDimitry Andric 146*81ad6265SDimitry Andric FullDependenciesResult getFullDependencies( 147*81ad6265SDimitry Andric const std::vector<std::string> &OriginalCommandLine) const { 1485ffd83dbSDimitry Andric FullDependencies FD; 149480093f4SDimitry Andric 150*81ad6265SDimitry Andric FD.OriginalCommandLine = 151*81ad6265SDimitry Andric ArrayRef<std::string>(OriginalCommandLine).slice(1); 152*81ad6265SDimitry Andric 153fe6060f1SDimitry Andric FD.ID.ContextHash = std::move(ContextHash); 154480093f4SDimitry Andric 1555ffd83dbSDimitry Andric FD.FileDeps.assign(Dependencies.begin(), Dependencies.end()); 156480093f4SDimitry Andric 1575ffd83dbSDimitry Andric for (auto &&M : ClangModuleDeps) { 1585ffd83dbSDimitry Andric auto &MD = M.second; 159480093f4SDimitry Andric if (MD.ImportedByMainFile) 160fe6060f1SDimitry Andric FD.ClangModuleDeps.push_back(MD.ID); 161480093f4SDimitry Andric } 162480093f4SDimitry Andric 163fe6060f1SDimitry Andric FD.PrebuiltModuleDeps = std::move(PrebuiltModuleDeps); 164fe6060f1SDimitry Andric 1655ffd83dbSDimitry Andric FullDependenciesResult FDR; 1665ffd83dbSDimitry Andric 1675ffd83dbSDimitry Andric for (auto &&M : ClangModuleDeps) { 1685ffd83dbSDimitry Andric // TODO: Avoid handleModuleDependency even being called for modules 1695ffd83dbSDimitry Andric // we've already seen. 1705ffd83dbSDimitry Andric if (AlreadySeen.count(M.first)) 1715ffd83dbSDimitry Andric continue; 1725ffd83dbSDimitry Andric FDR.DiscoveredModules.push_back(std::move(M.second)); 173480093f4SDimitry Andric } 174480093f4SDimitry Andric 1755ffd83dbSDimitry Andric FDR.FullDeps = std::move(FD); 1765ffd83dbSDimitry Andric return FDR; 177480093f4SDimitry Andric } 178480093f4SDimitry Andric 179480093f4SDimitry Andric private: 180480093f4SDimitry Andric std::vector<std::string> Dependencies; 181fe6060f1SDimitry Andric std::vector<PrebuiltModuleDep> PrebuiltModuleDeps; 182*81ad6265SDimitry Andric llvm::MapVector<std::string, ModuleDeps, llvm::StringMap<unsigned>> ClangModuleDeps; 183480093f4SDimitry Andric std::string ContextHash; 1845ffd83dbSDimitry Andric std::vector<std::string> OutputPaths; 1855ffd83dbSDimitry Andric const llvm::StringSet<> &AlreadySeen; 186480093f4SDimitry Andric }; 187480093f4SDimitry Andric 1885ffd83dbSDimitry Andric FullDependencyPrinterConsumer Consumer(AlreadySeen); 1895ffd83dbSDimitry Andric llvm::Error Result = 190349cc55cSDimitry Andric Worker.computeDependencies(CWD, CommandLine, Consumer, ModuleName); 191a7dea167SDimitry Andric if (Result) 192a7dea167SDimitry Andric return std::move(Result); 193*81ad6265SDimitry Andric return Consumer.getFullDependencies(CommandLine); 194a7dea167SDimitry Andric } 195a7dea167SDimitry Andric 196a7dea167SDimitry Andric } // end namespace dependencies 197a7dea167SDimitry Andric } // end namespace tooling 198a7dea167SDimitry Andric } // end namespace clang 199