diff --git a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h new file mode 100644 --- /dev/null +++ b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h @@ -0,0 +1,48 @@ +//===- DependencyScanningTool.h - clang-scan-deps service ------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_DEPENDENCY_SCANNING_TOOL_H +#define LLVM_CLANG_TOOLING_DEPENDENCY_SCANNING_TOOL_H + +#include "clang/Tooling/DependencyScanning/DependencyScanningService.h" +#include "clang/Tooling/DependencyScanning/DependencyScanningWorker.h" +#include "clang/Tooling/JSONCompilationDatabase.h" +#include + +namespace clang{ +namespace tooling{ +namespace dependencies{ + +/// The high-level implementation of the dependency discovery tool that runs on +/// an individual worker thread. +class DependencyScanningTool { +public: + /// Construct a dependency scanning tool. + /// + /// \param Compilations The reference to the compilation database that's + /// used by the clang tool. + DependencyScanningTool(DependencyScanningService &Service, const clang::tooling::CompilationDatabase &Compilations); + + /// Print out the dependency information into a string using the dependency + /// file format that is specified in the options (-MD is the default) and + /// return it. + /// + /// \returns A \c StringError with the diagnostic output if clang errors + /// occurred, dependency file contents otherwise. + llvm::Expected getDependencyFile(const std::string &Input, StringRef CWD); + +private: + DependencyScanningWorker Worker; + const tooling::CompilationDatabase &Compilations; +}; + +} // end namespace dependencies +} // end namespace tooling +} // end namespace clang + +#endif LLVM_CLANG_TOOLING_DEPENDENCY_SCANNING_TOOL_H \ No newline at end of file diff --git a/clang/lib/Tooling/DependencyScanning/CMakeLists.txt b/clang/lib/Tooling/DependencyScanning/CMakeLists.txt --- a/clang/lib/Tooling/DependencyScanning/CMakeLists.txt +++ b/clang/lib/Tooling/DependencyScanning/CMakeLists.txt @@ -7,6 +7,7 @@ DependencyScanningFilesystem.cpp DependencyScanningService.cpp DependencyScanningWorker.cpp + DependencyScanningTool.cpp DEPENDS ClangDriverOptions diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp new file mode 100644 --- /dev/null +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp @@ -0,0 +1,71 @@ +//===- DependencyScanningTool.cpp - clang-scan-deps service ------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/Tooling/DependencyScanning/DependencyScanningTool.h" +#include "clang/Frontend/Utils.h" + +namespace clang{ +namespace tooling{ +namespace dependencies{ + +DependencyScanningTool::DependencyScanningTool(DependencyScanningService &Service, +const tooling::CompilationDatabase &Compilations) : Worker(Service), Compilations(Compilations) {} + +llvm::Expected DependencyScanningTool::getDependencyFile(const std::string &Input, + StringRef CWD) { + /// Prints out all of the gathered dependencies into a string. + class DependencyPrinterConsumer : public DependencyConsumer { + public: + void handleFileDependency(const DependencyOutputOptions &Opts, + StringRef File) override { + if (!this->Opts) + this->Opts = std::make_unique(Opts); + Dependencies.push_back(File); + } + + void printDependencies(std::string &S) { + if (!Opts) + return; + + class DependencyPrinter : public DependencyFileGenerator { + public: + DependencyPrinter(DependencyOutputOptions &Opts, + ArrayRef Dependencies) + : DependencyFileGenerator(Opts) { + for (const auto &Dep : Dependencies) + addDependency(Dep); + } + + void printDependencies(std::string &S) { + llvm::raw_string_ostream OS(S); + outputDependencyFile(OS); + } + }; + + DependencyPrinter Generator(*Opts, Dependencies); + Generator.printDependencies(S); + } + + private: + std::unique_ptr Opts; + std::vector Dependencies; + }; + + DependencyPrinterConsumer Consumer; + auto Result = + Worker.computeDependencies(Input, CWD, Compilations, Consumer); + if (Result) + return std::move(Result); + std::string Output; + Consumer.printDependencies(Output); + return Output; +} + +} // end namespace dependencies +} // end namespace tooling +} // end namespace clang \ No newline at end of file diff --git a/clang/tools/clang-scan-deps/ClangScanDeps.cpp b/clang/tools/clang-scan-deps/ClangScanDeps.cpp --- a/clang/tools/clang-scan-deps/ClangScanDeps.cpp +++ b/clang/tools/clang-scan-deps/ClangScanDeps.cpp @@ -10,6 +10,7 @@ #include "clang/Tooling/CommonOptionsParser.h" #include "clang/Tooling/DependencyScanning/DependencyScanningService.h" #include "clang/Tooling/DependencyScanning/DependencyScanningWorker.h" +#include "clang/Tooling/DependencyScanning/DependencyScanningTool.h" #include "clang/Tooling/JSONCompilationDatabase.h" #include "llvm/Support/InitLLVM.h" #include "llvm/Support/Options.h" @@ -38,101 +39,6 @@ raw_ostream &OS; }; -/// The high-level implementation of the dependency discovery tool that runs on -/// an individual worker thread. -class DependencyScanningTool { -public: - /// Construct a dependency scanning tool. - /// - /// \param Compilations The reference to the compilation database that's - /// used by the clang tool. - DependencyScanningTool(DependencyScanningService &Service, - const tooling::CompilationDatabase &Compilations, - SharedStream &OS, SharedStream &Errs) - : Worker(Service), Compilations(Compilations), OS(OS), Errs(Errs) {} - - /// Print out the dependency information into a string using the dependency - /// file format that is specified in the options (-MD is the default) and - /// return it. - /// - /// \returns A \c StringError with the diagnostic output if clang errors - /// occurred, dependency file contents otherwise. - llvm::Expected getDependencyFile(const std::string &Input, - StringRef CWD) { - /// Prints out all of the gathered dependencies into a string. - class DependencyPrinterConsumer : public DependencyConsumer { - public: - void handleFileDependency(const DependencyOutputOptions &Opts, - StringRef File) override { - if (!this->Opts) - this->Opts = std::make_unique(Opts); - Dependencies.push_back(File); - } - - void printDependencies(std::string &S) { - if (!Opts) - return; - - class DependencyPrinter : public DependencyFileGenerator { - public: - DependencyPrinter(DependencyOutputOptions &Opts, - ArrayRef Dependencies) - : DependencyFileGenerator(Opts) { - for (const auto &Dep : Dependencies) - addDependency(Dep); - } - - void printDependencies(std::string &S) { - llvm::raw_string_ostream OS(S); - outputDependencyFile(OS); - } - }; - - DependencyPrinter Generator(*Opts, Dependencies); - Generator.printDependencies(S); - } - - private: - std::unique_ptr Opts; - std::vector Dependencies; - }; - - DependencyPrinterConsumer Consumer; - auto Result = - Worker.computeDependencies(Input, CWD, Compilations, Consumer); - if (Result) - return std::move(Result); - std::string Output; - Consumer.printDependencies(Output); - return Output; - } - - /// Computes the dependencies for the given file and prints them out. - /// - /// \returns True on error. - bool runOnFile(const std::string &Input, StringRef CWD) { - auto MaybeFile = getDependencyFile(Input, CWD); - if (!MaybeFile) { - llvm::handleAllErrors( - MaybeFile.takeError(), [this, &Input](llvm::StringError &Err) { - Errs.applyLocked([&](raw_ostream &OS) { - OS << "Error while scanning dependencies for " << Input << ":\n"; - OS << Err.getMessage(); - }); - }); - return true; - } - OS.applyLocked([&](raw_ostream &OS) { OS << *MaybeFile; }); - return false; - } - -private: - DependencyScanningWorker Worker; - const tooling::CompilationDatabase &Compilations; - SharedStream &OS; - SharedStream &Errs; -}; - llvm::cl::opt Help("h", llvm::cl::desc("Alias for -help"), llvm::cl::Hidden); @@ -191,6 +97,28 @@ return ObjFileName.str(); } +/// Takes the result of a dependency scan and prints error / dependency files +/// based on the result. +/// +/// \returns True on error. +static bool handleDependencyResult(const std::string &Input, + llvm::Expected &MaybeFile, + SharedStream &OS, + SharedStream &Errs) { + if (!MaybeFile) { + llvm::handleAllErrors( + MaybeFile.takeError(), [&Input, &Errs](llvm::StringError &Err) { + Errs.applyLocked([&](raw_ostream &OS) { + OS << "Error while scanning dependencies for " << Input << ":\n"; + OS << Err.getMessage(); + }); + }); + return true; + } + OS.applyLocked([&](raw_ostream &OS) { OS << *MaybeFile; }); + return false; +} + int main(int argc, const char **argv) { llvm::InitLLVM X(argc, argv); llvm::cl::HideUnrelatedOptions(DependencyScannerCategory); @@ -284,7 +212,7 @@ std::vector> WorkerTools; for (unsigned I = 0; I < NumWorkers; ++I) WorkerTools.push_back(std::make_unique( - Service, *AdjustingCompilations, DependencyOS, Errs)); + Service, *AdjustingCompilations)); std::vector WorkerThreads; std::atomic HadErrors(false); @@ -296,7 +224,7 @@ << " files using " << NumWorkers << " workers\n"; } for (unsigned I = 0; I < NumWorkers; ++I) { - auto Worker = [I, &Lock, &Index, &Inputs, &HadErrors, &WorkerTools]() { + auto Worker = [I, &Lock, &Index, &Inputs, &HadErrors, &WorkerTools, &DependencyOS, &Errs]() { while (true) { std::string Input; StringRef CWD; @@ -310,7 +238,8 @@ CWD = Compilation.second; } // Run the tool on it. - if (WorkerTools[I]->runOnFile(Input, CWD)) + auto MaybeFile = WorkerTools[I]->getDependencyFile(Input, CWD); + if (handleDependencyResult(Input, MaybeFile, DependencyOS, Errs)) HadErrors = true; } };