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 12*753f127fSDimitry Andric using namespace clang; 13*753f127fSDimitry Andric using namespace tooling; 14*753f127fSDimitry Andric using namespace dependencies; 15a7dea167SDimitry Andric 1681ad6265SDimitry Andric std::vector<std::string> FullDependencies::getCommandLine( 17*753f127fSDimitry Andric llvm::function_ref<std::string(const ModuleID &, ModuleOutputKind)> 18*753f127fSDimitry Andric LookupModuleOutput) const { 1981ad6265SDimitry Andric std::vector<std::string> Ret = getCommandLineWithoutModulePaths(); 205ffd83dbSDimitry Andric 21*753f127fSDimitry Andric for (ModuleID MID : ClangModuleDeps) { 22*753f127fSDimitry Andric auto PCM = LookupModuleOutput(MID, ModuleOutputKind::ModuleFile); 23*753f127fSDimitry Andric Ret.push_back("-fmodule-file=" + PCM); 24*753f127fSDimitry Andric } 255ffd83dbSDimitry Andric 265ffd83dbSDimitry Andric return Ret; 275ffd83dbSDimitry Andric } 285ffd83dbSDimitry Andric 29fe6060f1SDimitry Andric std::vector<std::string> 3081ad6265SDimitry Andric FullDependencies::getCommandLineWithoutModulePaths() const { 3181ad6265SDimitry Andric std::vector<std::string> Args = OriginalCommandLine; 32fe6060f1SDimitry Andric 3381ad6265SDimitry Andric Args.push_back("-fno-implicit-modules"); 3481ad6265SDimitry Andric Args.push_back("-fno-implicit-module-maps"); 35349cc55cSDimitry Andric for (const PrebuiltModuleDep &PMD : PrebuiltModuleDeps) 36349cc55cSDimitry Andric Args.push_back("-fmodule-file=" + PMD.PCMFile); 37fe6060f1SDimitry Andric 3881ad6265SDimitry Andric // These arguments are unused in explicit compiles. 3981ad6265SDimitry Andric llvm::erase_if(Args, [](StringRef Arg) { 4081ad6265SDimitry Andric if (Arg.consume_front("-fmodules-")) { 4181ad6265SDimitry Andric return Arg.startswith("cache-path=") || 4281ad6265SDimitry Andric Arg.startswith("prune-interval=") || 4381ad6265SDimitry Andric Arg.startswith("prune-after=") || 4481ad6265SDimitry Andric Arg == "validate-once-per-build-session"; 4581ad6265SDimitry Andric } 4681ad6265SDimitry Andric return Arg.startswith("-fbuild-session-file="); 4781ad6265SDimitry Andric }); 4881ad6265SDimitry Andric 49fe6060f1SDimitry Andric return Args; 50fe6060f1SDimitry Andric } 51fe6060f1SDimitry Andric 52480093f4SDimitry Andric DependencyScanningTool::DependencyScanningTool( 53480093f4SDimitry Andric DependencyScanningService &Service) 545ffd83dbSDimitry Andric : Worker(Service) {} 55a7dea167SDimitry Andric 56480093f4SDimitry Andric llvm::Expected<std::string> DependencyScanningTool::getDependencyFile( 57349cc55cSDimitry Andric const std::vector<std::string> &CommandLine, StringRef CWD, 58349cc55cSDimitry Andric llvm::Optional<StringRef> ModuleName) { 59a7dea167SDimitry Andric /// Prints out all of the gathered dependencies into a string. 60480093f4SDimitry Andric class MakeDependencyPrinterConsumer : public DependencyConsumer { 61a7dea167SDimitry Andric public: 62fe6060f1SDimitry Andric void 63fe6060f1SDimitry Andric handleDependencyOutputOpts(const DependencyOutputOptions &Opts) override { 64a7dea167SDimitry Andric this->Opts = std::make_unique<DependencyOutputOptions>(Opts); 65fe6060f1SDimitry Andric } 66fe6060f1SDimitry Andric 67fe6060f1SDimitry Andric void handleFileDependency(StringRef File) override { 685ffd83dbSDimitry Andric Dependencies.push_back(std::string(File)); 69a7dea167SDimitry Andric } 70a7dea167SDimitry Andric 71fe6060f1SDimitry Andric void handlePrebuiltModuleDependency(PrebuiltModuleDep PMD) override { 72fe6060f1SDimitry Andric // Same as `handleModuleDependency`. 73fe6060f1SDimitry Andric } 74fe6060f1SDimitry Andric 75480093f4SDimitry Andric void handleModuleDependency(ModuleDeps MD) override { 76480093f4SDimitry Andric // These are ignored for the make format as it can't support the full 77480093f4SDimitry Andric // set of deps, and handleFileDependency handles enough for implicitly 78480093f4SDimitry Andric // built modules to work. 79480093f4SDimitry Andric } 80480093f4SDimitry Andric 81480093f4SDimitry Andric void handleContextHash(std::string Hash) override {} 82480093f4SDimitry Andric 83a7dea167SDimitry Andric void printDependencies(std::string &S) { 84fe6060f1SDimitry Andric assert(Opts && "Handled dependency output options."); 85a7dea167SDimitry Andric 86a7dea167SDimitry Andric class DependencyPrinter : public DependencyFileGenerator { 87a7dea167SDimitry Andric public: 88a7dea167SDimitry Andric DependencyPrinter(DependencyOutputOptions &Opts, 89a7dea167SDimitry Andric ArrayRef<std::string> Dependencies) 90a7dea167SDimitry Andric : DependencyFileGenerator(Opts) { 91a7dea167SDimitry Andric for (const auto &Dep : Dependencies) 92a7dea167SDimitry Andric addDependency(Dep); 93a7dea167SDimitry Andric } 94a7dea167SDimitry Andric 95a7dea167SDimitry Andric void printDependencies(std::string &S) { 96a7dea167SDimitry Andric llvm::raw_string_ostream OS(S); 97a7dea167SDimitry Andric outputDependencyFile(OS); 98a7dea167SDimitry Andric } 99a7dea167SDimitry Andric }; 100a7dea167SDimitry Andric 101a7dea167SDimitry Andric DependencyPrinter Generator(*Opts, Dependencies); 102a7dea167SDimitry Andric Generator.printDependencies(S); 103a7dea167SDimitry Andric } 104a7dea167SDimitry Andric 105a7dea167SDimitry Andric private: 106a7dea167SDimitry Andric std::unique_ptr<DependencyOutputOptions> Opts; 107a7dea167SDimitry Andric std::vector<std::string> Dependencies; 108a7dea167SDimitry Andric }; 109a7dea167SDimitry Andric 1105ffd83dbSDimitry Andric MakeDependencyPrinterConsumer Consumer; 111349cc55cSDimitry Andric auto Result = 112349cc55cSDimitry Andric Worker.computeDependencies(CWD, CommandLine, Consumer, ModuleName); 1135ffd83dbSDimitry Andric if (Result) 1145ffd83dbSDimitry Andric return std::move(Result); 1155ffd83dbSDimitry Andric std::string Output; 1165ffd83dbSDimitry Andric Consumer.printDependencies(Output); 1175ffd83dbSDimitry Andric return Output; 1185ffd83dbSDimitry Andric } 1195ffd83dbSDimitry Andric 1205ffd83dbSDimitry Andric llvm::Expected<FullDependenciesResult> 1215ffd83dbSDimitry Andric DependencyScanningTool::getFullDependencies( 122349cc55cSDimitry Andric const std::vector<std::string> &CommandLine, StringRef CWD, 123349cc55cSDimitry Andric const llvm::StringSet<> &AlreadySeen, 124349cc55cSDimitry Andric llvm::Optional<StringRef> ModuleName) { 125480093f4SDimitry Andric class FullDependencyPrinterConsumer : public DependencyConsumer { 126480093f4SDimitry Andric public: 1275ffd83dbSDimitry Andric FullDependencyPrinterConsumer(const llvm::StringSet<> &AlreadySeen) 1285ffd83dbSDimitry Andric : AlreadySeen(AlreadySeen) {} 1295ffd83dbSDimitry Andric 130fe6060f1SDimitry Andric void 131fe6060f1SDimitry Andric handleDependencyOutputOpts(const DependencyOutputOptions &Opts) override {} 132fe6060f1SDimitry Andric 133fe6060f1SDimitry Andric void handleFileDependency(StringRef File) override { 1345ffd83dbSDimitry Andric Dependencies.push_back(std::string(File)); 135480093f4SDimitry Andric } 136480093f4SDimitry Andric 137fe6060f1SDimitry Andric void handlePrebuiltModuleDependency(PrebuiltModuleDep PMD) override { 138fe6060f1SDimitry Andric PrebuiltModuleDeps.emplace_back(std::move(PMD)); 139fe6060f1SDimitry Andric } 140fe6060f1SDimitry Andric 141480093f4SDimitry Andric void handleModuleDependency(ModuleDeps MD) override { 142fe6060f1SDimitry Andric ClangModuleDeps[MD.ID.ContextHash + MD.ID.ModuleName] = std::move(MD); 143480093f4SDimitry Andric } 144480093f4SDimitry Andric 145480093f4SDimitry Andric void handleContextHash(std::string Hash) override { 146480093f4SDimitry Andric ContextHash = std::move(Hash); 147480093f4SDimitry Andric } 148480093f4SDimitry Andric 14981ad6265SDimitry Andric FullDependenciesResult getFullDependencies( 15081ad6265SDimitry Andric const std::vector<std::string> &OriginalCommandLine) const { 1515ffd83dbSDimitry Andric FullDependencies FD; 152480093f4SDimitry Andric 15381ad6265SDimitry Andric FD.OriginalCommandLine = 15481ad6265SDimitry Andric ArrayRef<std::string>(OriginalCommandLine).slice(1); 15581ad6265SDimitry Andric 156fe6060f1SDimitry Andric FD.ID.ContextHash = std::move(ContextHash); 157480093f4SDimitry Andric 1585ffd83dbSDimitry Andric FD.FileDeps.assign(Dependencies.begin(), Dependencies.end()); 159480093f4SDimitry Andric 1605ffd83dbSDimitry Andric for (auto &&M : ClangModuleDeps) { 1615ffd83dbSDimitry Andric auto &MD = M.second; 162480093f4SDimitry Andric if (MD.ImportedByMainFile) 163fe6060f1SDimitry Andric FD.ClangModuleDeps.push_back(MD.ID); 164480093f4SDimitry Andric } 165480093f4SDimitry Andric 166fe6060f1SDimitry Andric FD.PrebuiltModuleDeps = std::move(PrebuiltModuleDeps); 167fe6060f1SDimitry Andric 1685ffd83dbSDimitry Andric FullDependenciesResult FDR; 1695ffd83dbSDimitry Andric 1705ffd83dbSDimitry Andric for (auto &&M : ClangModuleDeps) { 1715ffd83dbSDimitry Andric // TODO: Avoid handleModuleDependency even being called for modules 1725ffd83dbSDimitry Andric // we've already seen. 1735ffd83dbSDimitry Andric if (AlreadySeen.count(M.first)) 1745ffd83dbSDimitry Andric continue; 1755ffd83dbSDimitry Andric FDR.DiscoveredModules.push_back(std::move(M.second)); 176480093f4SDimitry Andric } 177480093f4SDimitry Andric 1785ffd83dbSDimitry Andric FDR.FullDeps = std::move(FD); 1795ffd83dbSDimitry Andric return FDR; 180480093f4SDimitry Andric } 181480093f4SDimitry Andric 182480093f4SDimitry Andric private: 183480093f4SDimitry Andric std::vector<std::string> Dependencies; 184fe6060f1SDimitry Andric std::vector<PrebuiltModuleDep> PrebuiltModuleDeps; 18581ad6265SDimitry Andric llvm::MapVector<std::string, ModuleDeps, llvm::StringMap<unsigned>> ClangModuleDeps; 186480093f4SDimitry Andric std::string ContextHash; 1875ffd83dbSDimitry Andric std::vector<std::string> OutputPaths; 1885ffd83dbSDimitry Andric const llvm::StringSet<> &AlreadySeen; 189480093f4SDimitry Andric }; 190480093f4SDimitry Andric 1915ffd83dbSDimitry Andric FullDependencyPrinterConsumer Consumer(AlreadySeen); 1925ffd83dbSDimitry Andric llvm::Error Result = 193349cc55cSDimitry Andric Worker.computeDependencies(CWD, CommandLine, Consumer, ModuleName); 194a7dea167SDimitry Andric if (Result) 195a7dea167SDimitry Andric return std::move(Result); 19681ad6265SDimitry Andric return Consumer.getFullDependencies(CommandLine); 197a7dea167SDimitry Andric } 198