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 12753f127fSDimitry Andric using namespace clang; 13753f127fSDimitry Andric using namespace tooling; 14753f127fSDimitry Andric using namespace dependencies; 15a7dea167SDimitry Andric 1681ad6265SDimitry Andric std::vector<std::string> FullDependencies::getCommandLine( 17753f127fSDimitry Andric llvm::function_ref<std::string(const ModuleID &, ModuleOutputKind)> 18753f127fSDimitry Andric LookupModuleOutput) const { 1981ad6265SDimitry Andric std::vector<std::string> Ret = getCommandLineWithoutModulePaths(); 205ffd83dbSDimitry Andric 21753f127fSDimitry Andric for (ModuleID MID : ClangModuleDeps) { 22753f127fSDimitry Andric auto PCM = LookupModuleOutput(MID, ModuleOutputKind::ModuleFile); 23753f127fSDimitry Andric Ret.push_back("-fmodule-file=" + PCM); 24753f127fSDimitry 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( 53*fcaf7f86SDimitry Andric DependencyScanningService &Service, 54*fcaf7f86SDimitry Andric llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS) 55*fcaf7f86SDimitry Andric : Worker(Service, std::move(FS)) {} 56a7dea167SDimitry Andric 57480093f4SDimitry Andric llvm::Expected<std::string> DependencyScanningTool::getDependencyFile( 58349cc55cSDimitry Andric const std::vector<std::string> &CommandLine, StringRef CWD, 59349cc55cSDimitry Andric llvm::Optional<StringRef> ModuleName) { 60a7dea167SDimitry Andric /// Prints out all of the gathered dependencies into a string. 61480093f4SDimitry Andric class MakeDependencyPrinterConsumer : public DependencyConsumer { 62a7dea167SDimitry Andric public: 63fe6060f1SDimitry Andric void 64fe6060f1SDimitry Andric handleDependencyOutputOpts(const DependencyOutputOptions &Opts) override { 65a7dea167SDimitry Andric this->Opts = std::make_unique<DependencyOutputOptions>(Opts); 66fe6060f1SDimitry Andric } 67fe6060f1SDimitry Andric 68fe6060f1SDimitry Andric void handleFileDependency(StringRef File) override { 695ffd83dbSDimitry Andric Dependencies.push_back(std::string(File)); 70a7dea167SDimitry Andric } 71a7dea167SDimitry Andric 72fe6060f1SDimitry Andric void handlePrebuiltModuleDependency(PrebuiltModuleDep PMD) override { 73fe6060f1SDimitry Andric // Same as `handleModuleDependency`. 74fe6060f1SDimitry Andric } 75fe6060f1SDimitry Andric 76480093f4SDimitry Andric void handleModuleDependency(ModuleDeps MD) override { 77480093f4SDimitry Andric // These are ignored for the make format as it can't support the full 78480093f4SDimitry Andric // set of deps, and handleFileDependency handles enough for implicitly 79480093f4SDimitry Andric // built modules to work. 80480093f4SDimitry Andric } 81480093f4SDimitry Andric 82480093f4SDimitry Andric void handleContextHash(std::string Hash) override {} 83480093f4SDimitry Andric 84a7dea167SDimitry Andric void printDependencies(std::string &S) { 85fe6060f1SDimitry Andric assert(Opts && "Handled dependency output options."); 86a7dea167SDimitry Andric 87a7dea167SDimitry Andric class DependencyPrinter : public DependencyFileGenerator { 88a7dea167SDimitry Andric public: 89a7dea167SDimitry Andric DependencyPrinter(DependencyOutputOptions &Opts, 90a7dea167SDimitry Andric ArrayRef<std::string> Dependencies) 91a7dea167SDimitry Andric : DependencyFileGenerator(Opts) { 92a7dea167SDimitry Andric for (const auto &Dep : Dependencies) 93a7dea167SDimitry Andric addDependency(Dep); 94a7dea167SDimitry Andric } 95a7dea167SDimitry Andric 96a7dea167SDimitry Andric void printDependencies(std::string &S) { 97a7dea167SDimitry Andric llvm::raw_string_ostream OS(S); 98a7dea167SDimitry Andric outputDependencyFile(OS); 99a7dea167SDimitry Andric } 100a7dea167SDimitry Andric }; 101a7dea167SDimitry Andric 102a7dea167SDimitry Andric DependencyPrinter Generator(*Opts, Dependencies); 103a7dea167SDimitry Andric Generator.printDependencies(S); 104a7dea167SDimitry Andric } 105a7dea167SDimitry Andric 106a7dea167SDimitry Andric private: 107a7dea167SDimitry Andric std::unique_ptr<DependencyOutputOptions> Opts; 108a7dea167SDimitry Andric std::vector<std::string> Dependencies; 109a7dea167SDimitry Andric }; 110a7dea167SDimitry Andric 1115ffd83dbSDimitry Andric MakeDependencyPrinterConsumer Consumer; 112349cc55cSDimitry Andric auto Result = 113349cc55cSDimitry Andric Worker.computeDependencies(CWD, CommandLine, Consumer, ModuleName); 1145ffd83dbSDimitry Andric if (Result) 1155ffd83dbSDimitry Andric return std::move(Result); 1165ffd83dbSDimitry Andric std::string Output; 1175ffd83dbSDimitry Andric Consumer.printDependencies(Output); 1185ffd83dbSDimitry Andric return Output; 1195ffd83dbSDimitry Andric } 1205ffd83dbSDimitry Andric 1215ffd83dbSDimitry Andric llvm::Expected<FullDependenciesResult> 1225ffd83dbSDimitry Andric DependencyScanningTool::getFullDependencies( 123349cc55cSDimitry Andric const std::vector<std::string> &CommandLine, StringRef CWD, 124349cc55cSDimitry Andric const llvm::StringSet<> &AlreadySeen, 125349cc55cSDimitry Andric llvm::Optional<StringRef> ModuleName) { 126480093f4SDimitry Andric class FullDependencyPrinterConsumer : public DependencyConsumer { 127480093f4SDimitry Andric public: 1285ffd83dbSDimitry Andric FullDependencyPrinterConsumer(const llvm::StringSet<> &AlreadySeen) 1295ffd83dbSDimitry Andric : AlreadySeen(AlreadySeen) {} 1305ffd83dbSDimitry Andric 131fe6060f1SDimitry Andric void 132fe6060f1SDimitry Andric handleDependencyOutputOpts(const DependencyOutputOptions &Opts) override {} 133fe6060f1SDimitry Andric 134fe6060f1SDimitry Andric void handleFileDependency(StringRef File) override { 1355ffd83dbSDimitry Andric Dependencies.push_back(std::string(File)); 136480093f4SDimitry Andric } 137480093f4SDimitry Andric 138fe6060f1SDimitry Andric void handlePrebuiltModuleDependency(PrebuiltModuleDep PMD) override { 139fe6060f1SDimitry Andric PrebuiltModuleDeps.emplace_back(std::move(PMD)); 140fe6060f1SDimitry Andric } 141fe6060f1SDimitry Andric 142480093f4SDimitry Andric void handleModuleDependency(ModuleDeps MD) override { 143fe6060f1SDimitry Andric ClangModuleDeps[MD.ID.ContextHash + MD.ID.ModuleName] = std::move(MD); 144480093f4SDimitry Andric } 145480093f4SDimitry Andric 146480093f4SDimitry Andric void handleContextHash(std::string Hash) override { 147480093f4SDimitry Andric ContextHash = std::move(Hash); 148480093f4SDimitry Andric } 149480093f4SDimitry Andric 15081ad6265SDimitry Andric FullDependenciesResult getFullDependencies( 15181ad6265SDimitry Andric const std::vector<std::string> &OriginalCommandLine) const { 1525ffd83dbSDimitry Andric FullDependencies FD; 153480093f4SDimitry Andric 15481ad6265SDimitry Andric FD.OriginalCommandLine = 15581ad6265SDimitry Andric ArrayRef<std::string>(OriginalCommandLine).slice(1); 15681ad6265SDimitry Andric 157fe6060f1SDimitry Andric FD.ID.ContextHash = std::move(ContextHash); 158480093f4SDimitry Andric 1595ffd83dbSDimitry Andric FD.FileDeps.assign(Dependencies.begin(), Dependencies.end()); 160480093f4SDimitry Andric 1615ffd83dbSDimitry Andric for (auto &&M : ClangModuleDeps) { 1625ffd83dbSDimitry Andric auto &MD = M.second; 163480093f4SDimitry Andric if (MD.ImportedByMainFile) 164fe6060f1SDimitry Andric FD.ClangModuleDeps.push_back(MD.ID); 165480093f4SDimitry Andric } 166480093f4SDimitry Andric 167fe6060f1SDimitry Andric FD.PrebuiltModuleDeps = std::move(PrebuiltModuleDeps); 168fe6060f1SDimitry Andric 1695ffd83dbSDimitry Andric FullDependenciesResult FDR; 1705ffd83dbSDimitry Andric 1715ffd83dbSDimitry Andric for (auto &&M : ClangModuleDeps) { 1725ffd83dbSDimitry Andric // TODO: Avoid handleModuleDependency even being called for modules 1735ffd83dbSDimitry Andric // we've already seen. 1745ffd83dbSDimitry Andric if (AlreadySeen.count(M.first)) 1755ffd83dbSDimitry Andric continue; 1765ffd83dbSDimitry Andric FDR.DiscoveredModules.push_back(std::move(M.second)); 177480093f4SDimitry Andric } 178480093f4SDimitry Andric 1795ffd83dbSDimitry Andric FDR.FullDeps = std::move(FD); 1805ffd83dbSDimitry Andric return FDR; 181480093f4SDimitry Andric } 182480093f4SDimitry Andric 183480093f4SDimitry Andric private: 184480093f4SDimitry Andric std::vector<std::string> Dependencies; 185fe6060f1SDimitry Andric std::vector<PrebuiltModuleDep> PrebuiltModuleDeps; 18681ad6265SDimitry Andric llvm::MapVector<std::string, ModuleDeps, llvm::StringMap<unsigned>> ClangModuleDeps; 187480093f4SDimitry Andric std::string ContextHash; 1885ffd83dbSDimitry Andric std::vector<std::string> OutputPaths; 1895ffd83dbSDimitry Andric const llvm::StringSet<> &AlreadySeen; 190480093f4SDimitry Andric }; 191480093f4SDimitry Andric 1925ffd83dbSDimitry Andric FullDependencyPrinterConsumer Consumer(AlreadySeen); 1935ffd83dbSDimitry Andric llvm::Error Result = 194349cc55cSDimitry Andric Worker.computeDependencies(CWD, CommandLine, Consumer, ModuleName); 195a7dea167SDimitry Andric if (Result) 196a7dea167SDimitry Andric return std::move(Result); 19781ad6265SDimitry Andric return Consumer.getFullDependencies(CommandLine); 198a7dea167SDimitry Andric } 199