DependencyScanningTool.cpp revision 360784
160484Sobrien//===- DependencyScanningTool.cpp - clang-scan-deps service ---------------===// 278828Sobrien// 378828Sobrien// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 460484Sobrien// See https://llvm.org/LICENSE.txt for license information. 560484Sobrien// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 660484Sobrien// 760484Sobrien//===----------------------------------------------------------------------===// 860484Sobrien 960484Sobrien#include "clang/Tooling/DependencyScanning/DependencyScanningTool.h" 1060484Sobrien#include "clang/Frontend/Utils.h" 1160484Sobrien#include "llvm/Support/JSON.h" 1260484Sobrien 1360484Sobrienstatic llvm::json::Array toJSONSorted(const llvm::StringSet<> &Set) { 1460484Sobrien std::vector<llvm::StringRef> Strings; 1560484Sobrien for (auto &&I : Set) 1660484Sobrien Strings.push_back(I.getKey()); 1760484Sobrien std::sort(Strings.begin(), Strings.end()); 1860484Sobrien return llvm::json::Array(Strings); 1960484Sobrien} 2060484Sobrien 2160484Sobriennamespace clang{ 2260484Sobriennamespace tooling{ 2360484Sobriennamespace dependencies{ 2460484Sobrien 2560484SobrienDependencyScanningTool::DependencyScanningTool( 2660484Sobrien DependencyScanningService &Service) 2760484Sobrien : Format(Service.getFormat()), Worker(Service) { 2860484Sobrien} 2960484Sobrien 3060484Sobrienllvm::Expected<std::string> DependencyScanningTool::getDependencyFile( 3160484Sobrien const tooling::CompilationDatabase &Compilations, StringRef CWD) { 3260484Sobrien /// Prints out all of the gathered dependencies into a string. 3360484Sobrien class MakeDependencyPrinterConsumer : public DependencyConsumer { 3460484Sobrien public: 3560484Sobrien void handleFileDependency(const DependencyOutputOptions &Opts, 3660484Sobrien StringRef File) override { 3760484Sobrien if (!this->Opts) 3860484Sobrien this->Opts = std::make_unique<DependencyOutputOptions>(Opts); 3989857Sobrien Dependencies.push_back(File); 4089857Sobrien } 4160484Sobrien 4289857Sobrien void handleModuleDependency(ModuleDeps MD) override { 4389857Sobrien // These are ignored for the make format as it can't support the full 4489857Sobrien // set of deps, and handleFileDependency handles enough for implicitly 4589857Sobrien // built modules to work. 4689857Sobrien } 4789857Sobrien 4889857Sobrien void handleContextHash(std::string Hash) override {} 4989857Sobrien 5089857Sobrien void printDependencies(std::string &S) { 5189857Sobrien if (!Opts) 5289857Sobrien return; 5389857Sobrien 5489857Sobrien class DependencyPrinter : public DependencyFileGenerator { 5589857Sobrien public: 5689857Sobrien DependencyPrinter(DependencyOutputOptions &Opts, 5789857Sobrien ArrayRef<std::string> Dependencies) 5889857Sobrien : DependencyFileGenerator(Opts) { 5989857Sobrien for (const auto &Dep : Dependencies) 6089857Sobrien addDependency(Dep); 6189857Sobrien } 6289857Sobrien 6389857Sobrien void printDependencies(std::string &S) { 6489857Sobrien llvm::raw_string_ostream OS(S); 6589857Sobrien outputDependencyFile(OS); 6689857Sobrien } 6789857Sobrien }; 6889857Sobrien 6989857Sobrien DependencyPrinter Generator(*Opts, Dependencies); 7089857Sobrien Generator.printDependencies(S); 7189857Sobrien } 7289857Sobrien 7360484Sobrien private: 7460484Sobrien std::unique_ptr<DependencyOutputOptions> Opts; 7560484Sobrien std::vector<std::string> Dependencies; 7677298Sobrien }; 7760484Sobrien 7860484Sobrien class FullDependencyPrinterConsumer : public DependencyConsumer { 7960484Sobrien public: 8060484Sobrien void handleFileDependency(const DependencyOutputOptions &Opts, 8160484Sobrien StringRef File) override { 8260484Sobrien Dependencies.push_back(File); 8360484Sobrien } 8460484Sobrien 8560484Sobrien void handleModuleDependency(ModuleDeps MD) override { 8660484Sobrien ClangModuleDeps[MD.ContextHash + MD.ModuleName] = std::move(MD); 8760484Sobrien } 8860484Sobrien 8960484Sobrien void handleContextHash(std::string Hash) override { 9060484Sobrien ContextHash = std::move(Hash); 9160484Sobrien } 9260484Sobrien 9360484Sobrien void printDependencies(std::string &S, StringRef MainFile) { 9460484Sobrien // Sort the modules by name to get a deterministic order. 9560484Sobrien std::vector<StringRef> Modules; 9660484Sobrien for (auto &&Dep : ClangModuleDeps) 9760484Sobrien Modules.push_back(Dep.first); 9860484Sobrien std::sort(Modules.begin(), Modules.end()); 9960484Sobrien 10060484Sobrien llvm::raw_string_ostream OS(S); 10177298Sobrien 10260484Sobrien using namespace llvm::json; 10389857Sobrien 10489857Sobrien Array Imports; 10560484Sobrien for (auto &&ModName : Modules) { 10660484Sobrien auto &MD = ClangModuleDeps[ModName]; 10760484Sobrien if (MD.ImportedByMainFile) 10889857Sobrien Imports.push_back(MD.ModuleName); 10960484Sobrien } 11060484Sobrien 11160484Sobrien Array Mods; 11260484Sobrien for (auto &&ModName : Modules) { 11360484Sobrien auto &MD = ClangModuleDeps[ModName]; 11460484Sobrien Object Mod{ 11589857Sobrien {"name", MD.ModuleName}, 11660484Sobrien {"file-deps", toJSONSorted(MD.FileDeps)}, 11789857Sobrien {"clang-module-deps", toJSONSorted(MD.ClangModuleDeps)}, 11860484Sobrien {"clang-modulemap-file", MD.ClangModuleMapFile}, 11960484Sobrien }; 12060484Sobrien Mods.push_back(std::move(Mod)); 12160484Sobrien } 12260484Sobrien 12360484Sobrien Object O{ 12460484Sobrien {"input-file", MainFile}, 12560484Sobrien {"clang-context-hash", ContextHash}, 12660484Sobrien {"file-deps", Dependencies}, 12760484Sobrien {"clang-module-deps", std::move(Imports)}, 12860484Sobrien {"clang-modules", std::move(Mods)}, 12960484Sobrien }; 13060484Sobrien 13160484Sobrien S = llvm::formatv("{0:2},\n", Value(std::move(O))).str(); 13260484Sobrien return; 13360484Sobrien } 13460484Sobrien 13560484Sobrien private: 13660484Sobrien std::vector<std::string> Dependencies; 13760484Sobrien std::unordered_map<std::string, ModuleDeps> ClangModuleDeps; 13889857Sobrien std::string ContextHash; 13989857Sobrien }; 14060484Sobrien 14160484Sobrien 14260484Sobrien // We expect a single command here because if a source file occurs multiple 14360484Sobrien // times in the original CDB, then `computeDependencies` would run the 14489857Sobrien // `DependencyScanningAction` once for every time the input occured in the 14577298Sobrien // CDB. Instead we split up the CDB into single command chunks to avoid this 14660484Sobrien // behavior. 14760484Sobrien assert(Compilations.getAllCompileCommands().size() == 1 && 14860484Sobrien "Expected a compilation database with a single command!"); 14960484Sobrien std::string Input = Compilations.getAllCompileCommands().front().Filename; 15060484Sobrien 15160484Sobrien if (Format == ScanningOutputFormat::Make) { 15277298Sobrien MakeDependencyPrinterConsumer Consumer; 15389857Sobrien auto Result = 15460484Sobrien Worker.computeDependencies(Input, CWD, Compilations, Consumer); 15560484Sobrien if (Result) 15660484Sobrien return std::move(Result); 15760484Sobrien std::string Output; 15860484Sobrien Consumer.printDependencies(Output); 15960484Sobrien return Output; 16060484Sobrien } else { 16160484Sobrien FullDependencyPrinterConsumer Consumer; 16260484Sobrien auto Result = 16360484Sobrien Worker.computeDependencies(Input, CWD, Compilations, Consumer); 16460484Sobrien if (Result) 16560484Sobrien return std::move(Result); 16660484Sobrien std::string Output; 16760484Sobrien Consumer.printDependencies(Output, Input); 16860484Sobrien return Output; 16960484Sobrien } 17060484Sobrien} 17189857Sobrien 17289857Sobrien} // end namespace dependencies 17389857Sobrien} // end namespace tooling 17460484Sobrien} // end namespace clang 17560484Sobrien