//===- DependencyScanningWorker.cpp - Thread-Safe Scanning 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/DependencyScanning/DependencyScanningWorker.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/DiagnosticFrontend.h" #include "clang/DependencyScanning/DependencyConsumer.h" #include "clang/DependencyScanning/DependencyScannerImpl.h" #include "clang/Serialization/ObjectFilePCHContainerReader.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/Support/VirtualFileSystem.h" using namespace clang; using namespace dependencies; DependencyScanningWorker::DependencyScanningWorker( DependencyScanningService &Service) : Service(Service) { PCHContainerOps = std::make_shared(); // We need to read object files from PCH built outside the scanner. PCHContainerOps->registerReader( std::make_unique()); // The scanner itself writes only raw ast files. PCHContainerOps->registerWriter(std::make_unique()); auto BaseFS = Service.getOpts().MakeVFS(); if (Service.getOpts().TraceVFS) { TracingFS = llvm::makeIntrusiveRefCnt( std::move(BaseFS)); BaseFS = TracingFS; } DepFS = llvm::makeIntrusiveRefCnt( Service, std::move(BaseFS)); } DependencyScanningWorker::~DependencyScanningWorker() = default; static bool createAndRunToolInvocation( ArrayRef CommandLine, DependencyScanningAction &Action, IntrusiveRefCntPtr FS, std::shared_ptr &PCHContainerOps, DiagnosticsEngine &Diags) { auto Invocation = createCompilerInvocation(CommandLine, Diags); if (!Invocation) return false; return Action.runInvocation(CommandLine[0], std::move(Invocation), std::move(FS), PCHContainerOps, Diags.getClient()); } IntrusiveRefCntPtr DependencyScanningWorker::makeEffectiveVFS( StringRef WorkingDirectory, IntrusiveRefCntPtr OverlayFS) const { IntrusiveRefCntPtr FS = DepFS; if (OverlayFS) { auto NewFS = llvm::makeIntrusiveRefCnt(std::move(FS)); NewFS->pushOverlay(std::move(OverlayFS)); FS = std::move(NewFS); } FS->setCurrentWorkingDirectory(WorkingDirectory); return FS; } bool DependencyScanningWorker::computeDependencies( StringRef WorkingDirectory, ArrayRef> CommandLines, DependencyConsumer &DepConsumer, DependencyActionController &Controller, DiagnosticConsumer &DiagConsumer, IntrusiveRefCntPtr OverlayFS) { auto FS = makeEffectiveVFS(WorkingDirectory, std::move(OverlayFS)); DependencyScanningAction Action(Service, WorkingDirectory, DepConsumer, Controller, DepFS); const bool Success = llvm::all_of(CommandLines, [&](const auto &Cmd) { if (StringRef(Cmd[1]) != "-cc1") { // Non-clang command. Just pass through to the dependency consumer. DepConsumer.handleBuildCommand( {Cmd.front(), {Cmd.begin() + 1, Cmd.end()}}); return true; } auto DiagEngineWithDiagOpts = DiagnosticsEngineWithDiagOpts(Cmd, FS, DiagConsumer); auto &Diags = *DiagEngineWithDiagOpts.DiagEngine; // Create an invocation that uses the underlying file system to ensure that // any file system requests that are made by the driver do not go through // the dependency scanning filesystem. return createAndRunToolInvocation(Cmd, Action, FS, PCHContainerOps, Diags); }); return Success && Action.hasScanned(); }