diff options
author | Alex Lorenz <arphaman@gmail.com> | 2019-06-26 21:11:51 +0000 |
---|---|---|
committer | Alex Lorenz <arphaman@gmail.com> | 2019-06-26 21:11:51 +0000 |
commit | 24d531c5bb2b8946ebe2253e24194fd63f3acbe7 (patch) | |
tree | c0f86ec8c2dfc5949e6b533bfe8ff81a2c2c0a02 /lib | |
parent | a057056821e096990964f3416835c8477eb1b6bf (diff) | |
download | clang-24d531c5bb2b8946ebe2253e24194fd63f3acbe7.tar.gz |
[clang-scan-deps] Introduce the DependencyScanning library with the
thread worker code and better error handling
This commit extracts out the code that will powers the fast scanning
worker into a new file in a new DependencyScanning library. The error
and output handling is improved so that the clients can gather
errors/results from the worker directly.
Differential Revision: https://reviews.llvm.org/D63681
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@364474 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Tooling/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lib/Tooling/DependencyScanning/CMakeLists.txt | 22 | ||||
-rw-r--r-- | lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp | 149 | ||||
-rw-r--r-- | lib/Tooling/Tooling.cpp | 7 |
4 files changed, 178 insertions, 1 deletions
diff --git a/lib/Tooling/CMakeLists.txt b/lib/Tooling/CMakeLists.txt index 5a380fb8cc..81185d7417 100644 --- a/lib/Tooling/CMakeLists.txt +++ b/lib/Tooling/CMakeLists.txt @@ -8,6 +8,7 @@ add_subdirectory(Inclusions) add_subdirectory(Refactoring) add_subdirectory(ASTDiff) add_subdirectory(Syntax) +add_subdirectory(DependencyScanning) add_clang_library(clangTooling AllTUsExecution.cpp diff --git a/lib/Tooling/DependencyScanning/CMakeLists.txt b/lib/Tooling/DependencyScanning/CMakeLists.txt new file mode 100644 index 0000000000..699954d26d --- /dev/null +++ b/lib/Tooling/DependencyScanning/CMakeLists.txt @@ -0,0 +1,22 @@ +set(LLVM_LINK_COMPONENTS + Core + Support + ) + +add_clang_library(clangDependencyScanning + DependencyScanningWorker.cpp + + DEPENDS + ClangDriverOptions + + LINK_LIBS + clangAST + clangBasic + clangDriver + clangFrontend + clangFrontendTool + clangLex + clangParse + clangSerialization + clangTooling +) diff --git a/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp b/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp new file mode 100644 index 0000000000..4868f26637 --- /dev/null +++ b/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp @@ -0,0 +1,149 @@ +//===- DependencyScanningWorker.cpp - clang-scan-deps worker --------------===// +// +// 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/DependencyScanningWorker.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/FrontendActions.h" +#include "clang/Frontend/TextDiagnosticPrinter.h" +#include "clang/Frontend/Utils.h" +#include "clang/Tooling/Tooling.h" + +using namespace clang; +using namespace tooling; +using namespace dependencies; + +namespace { + +/// Prints out all of the gathered dependencies into a string. +class DependencyPrinter : public DependencyFileGenerator { +public: + DependencyPrinter(std::unique_ptr<DependencyOutputOptions> Opts, + std::string &S) + : DependencyFileGenerator(*Opts), Opts(std::move(Opts)), S(S) {} + + void finishedMainFile(DiagnosticsEngine &Diags) override { + llvm::raw_string_ostream OS(S); + outputDependencyFile(OS); + } + +private: + std::unique_ptr<DependencyOutputOptions> Opts; + std::string &S; +}; + +/// A proxy file system that doesn't call `chdir` when changing the working +/// directory of a clang tool. +class ProxyFileSystemWithoutChdir : public llvm::vfs::ProxyFileSystem { +public: + ProxyFileSystemWithoutChdir( + llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS) + : ProxyFileSystem(std::move(FS)) {} + + llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override { + assert(!CWD.empty() && "empty CWD"); + return CWD; + } + + std::error_code setCurrentWorkingDirectory(const Twine &Path) override { + CWD = Path.str(); + return {}; + } + +private: + std::string CWD; +}; + +/// A clang tool that runs the preprocessor in a mode that's optimized for +/// dependency scanning for the given compiler invocation. +class DependencyScanningAction : public tooling::ToolAction { +public: + DependencyScanningAction(StringRef WorkingDirectory, + std::string &DependencyFileContents) + : WorkingDirectory(WorkingDirectory), + DependencyFileContents(DependencyFileContents) {} + + bool runInvocation(std::shared_ptr<CompilerInvocation> Invocation, + FileManager *FileMgr, + std::shared_ptr<PCHContainerOperations> PCHContainerOps, + DiagnosticConsumer *DiagConsumer) override { + // Create a compiler instance to handle the actual work. + CompilerInstance Compiler(std::move(PCHContainerOps)); + Compiler.setInvocation(std::move(Invocation)); + FileMgr->getFileSystemOpts().WorkingDir = WorkingDirectory; + Compiler.setFileManager(FileMgr); + + // Don't print 'X warnings and Y errors generated'. + Compiler.getDiagnosticOpts().ShowCarets = false; + // Create the compiler's actual diagnostics engine. + Compiler.createDiagnostics(DiagConsumer, /*ShouldOwnClient=*/false); + if (!Compiler.hasDiagnostics()) + return false; + + Compiler.createSourceManager(*FileMgr); + + // Create the dependency collector that will collect the produced + // dependencies. + // + // This also moves the existing dependency output options from the + // invocation to the collector. The options in the invocation are reset, + // which ensures that the compiler won't create new dependency collectors, + // and thus won't write out the extra '.d' files to disk. + auto Opts = llvm::make_unique<DependencyOutputOptions>( + std::move(Compiler.getInvocation().getDependencyOutputOpts())); + // We need at least one -MT equivalent for the generator to work. + if (Opts->Targets.empty()) + Opts->Targets = {"clang-scan-deps dependency"}; + Compiler.addDependencyCollector(std::make_shared<DependencyPrinter>( + std::move(Opts), DependencyFileContents)); + + auto Action = llvm::make_unique<PreprocessOnlyAction>(); + const bool Result = Compiler.ExecuteAction(*Action); + FileMgr->clearStatCache(); + return Result; + } + +private: + StringRef WorkingDirectory; + /// The dependency file will be written to this string. + std::string &DependencyFileContents; +}; + +} // end anonymous namespace + +DependencyScanningWorker::DependencyScanningWorker() { + DiagOpts = new DiagnosticOptions(); + PCHContainerOps = std::make_shared<PCHContainerOperations>(); + /// FIXME: Use the shared file system from the service for fast scanning + /// mode. + WorkerFS = new ProxyFileSystemWithoutChdir(llvm::vfs::getRealFileSystem()); +} + +llvm::Expected<std::string> +DependencyScanningWorker::getDependencyFile(const std::string &Input, + StringRef WorkingDirectory, + const CompilationDatabase &CDB) { + // Capture the emitted diagnostics and report them to the client + // in the case of a failure. + std::string DiagnosticOutput; + llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput); + TextDiagnosticPrinter DiagPrinter(DiagnosticsOS, DiagOpts.get()); + + WorkerFS->setCurrentWorkingDirectory(WorkingDirectory); + tooling::ClangTool Tool(CDB, Input, PCHContainerOps, WorkerFS); + Tool.clearArgumentsAdjusters(); + Tool.setRestoreWorkingDir(false); + Tool.setPrintErrorMessage(false); + Tool.setDiagnosticConsumer(&DiagPrinter); + std::string Output; + DependencyScanningAction Action(WorkingDirectory, Output); + if (Tool.run(&Action)) { + return llvm::make_error<llvm::StringError>(DiagnosticsOS.str(), + llvm::inconvertibleErrorCode()); + } + return Output; +} diff --git a/lib/Tooling/Tooling.cpp b/lib/Tooling/Tooling.cpp index a7c64866a4..291df0ae33 100644 --- a/lib/Tooling/Tooling.cpp +++ b/lib/Tooling/Tooling.cpp @@ -517,7 +517,8 @@ int ClangTool::run(ToolAction *Action) { if (!Invocation.run()) { // FIXME: Diagnostics should be used instead. - llvm::errs() << "Error while processing " << File << ".\n"; + if (PrintErrorMessage) + llvm::errs() << "Error while processing " << File << ".\n"; ProcessingFailed = true; } } @@ -569,6 +570,10 @@ void ClangTool::setRestoreWorkingDir(bool RestoreCWD) { this->RestoreCWD = RestoreCWD; } +void ClangTool::setPrintErrorMessage(bool PrintErrorMessage) { + this->PrintErrorMessage = PrintErrorMessage; +} + namespace clang { namespace tooling { |