clang 22.0.0git
DependencyScanningWorker.cpp
Go to the documentation of this file.
1//===- DependencyScanningWorker.cpp - clang-scan-deps worker --------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
12#include "clang/Driver/Driver.h"
13#include "clang/Driver/Tool.h"
14
15using namespace clang;
16using namespace tooling;
17using namespace dependencies;
18
22 : Service(Service) {
23 PCHContainerOps = std::make_shared<PCHContainerOperations>();
24 // We need to read object files from PCH built outside the scanner.
25 PCHContainerOps->registerReader(
26 std::make_unique<ObjectFilePCHContainerReader>());
27 // The scanner itself writes only raw ast files.
28 PCHContainerOps->registerWriter(std::make_unique<RawPCHContainerWriter>());
29
30 if (Service.shouldTraceVFS())
31 FS = llvm::makeIntrusiveRefCnt<llvm::vfs::TracingFileSystem>(std::move(FS));
32
33 switch (Service.getMode()) {
35 DepFS = llvm::makeIntrusiveRefCnt<DependencyScanningWorkerFilesystem>(
36 Service.getSharedCache(), FS);
37 BaseFS = DepFS;
38 break;
40 DepFS = nullptr;
41 BaseFS = FS;
42 break;
43 }
44}
45
48
50 StringRef WorkingDirectory, const std::vector<std::string> &CommandLine,
52 std::optional<llvm::MemoryBufferRef> TUBuffer) {
53 // Capture the emitted diagnostics and report them to the client
54 // in the case of a failure.
55 TextDiagnosticsPrinterWithOutput DiagPrinterWithOS(CommandLine);
56
57 if (computeDependencies(WorkingDirectory, CommandLine, Consumer, Controller,
58 DiagPrinterWithOS.DiagPrinter, TUBuffer))
59 return llvm::Error::success();
60 return llvm::make_error<llvm::StringError>(
61 DiagPrinterWithOS.DiagnosticsOS.str(), llvm::inconvertibleErrorCode());
62}
63
64static bool forEachDriverJob(
67 llvm::function_ref<bool(const driver::Command &Cmd)> Callback) {
68 // Compilation holds a non-owning a reference to the Driver, hence we need to
69 // keep the Driver alive when we use Compilation. Arguments to commands may be
70 // owned by Alloc when expanded from response files.
71 llvm::BumpPtrAllocator Alloc;
72 auto [Driver, Compilation] = buildCompilation(ArgStrs, Diags, FS, Alloc);
73 if (!Compilation)
74 return false;
75 for (const driver::Command &Job : Compilation->getJobs()) {
76 if (!Callback(Job))
77 return false;
78 }
79 return true;
80}
81
83 const std::vector<std::string> &CommandLine,
86 std::shared_ptr<clang::PCHContainerOperations> &PCHContainerOps,
87 DiagnosticsEngine &Diags, DependencyConsumer &Consumer) {
88 auto Invocation = createCompilerInvocation(CommandLine, Diags);
89 if (!Invocation)
90 return false;
91
92 if (!Action.runInvocation(std::move(Invocation), std::move(FS),
93 PCHContainerOps, Diags.getClient()))
94 return false;
95
96 std::vector<std::string> Args = Action.takeLastCC1Arguments();
97 Consumer.handleBuildCommand({CommandLine[0], std::move(Args)});
98 return true;
99}
100
101bool DependencyScanningWorker::scanDependencies(
102 StringRef WorkingDirectory, const std::vector<std::string> &CommandLine,
103 DependencyConsumer &Consumer, DependencyActionController &Controller,
104 DiagnosticConsumer &DC,
105 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS) {
106 DignosticsEngineWithDiagOpts DiagEngineWithCmdAndOpts(CommandLine, FS, DC);
107 DependencyScanningAction Action(Service, WorkingDirectory, Consumer,
108 Controller, DepFS);
109
110 bool Success = false;
111 if (CommandLine[1] == "-cc1") {
113 CommandLine, Action, FS, PCHContainerOps,
114 *DiagEngineWithCmdAndOpts.DiagEngine, Consumer);
115 } else {
117 CommandLine, *DiagEngineWithCmdAndOpts.DiagEngine, FS,
118 [&](const driver::Command &Cmd) {
119 if (StringRef(Cmd.getCreator().getName()) != "clang") {
120 // Non-clang command. Just pass through to the dependency
121 // consumer.
122 Consumer.handleBuildCommand(
123 {Cmd.getExecutable(),
124 {Cmd.getArguments().begin(), Cmd.getArguments().end()}});
125 return true;
126 }
127
128 // Insert -cc1 comand line options into Argv
129 std::vector<std::string> Argv;
130 Argv.push_back(Cmd.getExecutable());
131 llvm::append_range(Argv, Cmd.getArguments());
132
133 // Create an invocation that uses the underlying file
134 // system to ensure that any file system requests that
135 // are made by the driver do not go through the
136 // dependency scanning filesystem.
138 std::move(Argv), Action, FS, PCHContainerOps,
139 *DiagEngineWithCmdAndOpts.DiagEngine, Consumer);
140 });
141 }
142
143 if (Success && !Action.hasScanned())
144 DiagEngineWithCmdAndOpts.DiagEngine->Report(
145 diag::err_fe_expected_compiler_job)
146 << llvm::join(CommandLine, " ");
147
148 // Ensure finish() is called even if we never reached ExecuteAction().
149 if (!Action.hasDiagConsumerFinished())
150 DC.finish();
151
152 return Success && Action.hasScanned();
153}
154
156 StringRef WorkingDirectory, const std::vector<std::string> &CommandLine,
157 DependencyConsumer &Consumer, DependencyActionController &Controller,
158 DiagnosticConsumer &DC, std::optional<llvm::MemoryBufferRef> TUBuffer) {
159 if (TUBuffer) {
160 auto [FinalFS, FinalCommandLine] = initVFSForTUBuferScanning(
161 BaseFS, CommandLine, WorkingDirectory, *TUBuffer);
162 return scanDependencies(WorkingDirectory, FinalCommandLine, Consumer,
163 Controller, DC, FinalFS);
164 } else {
165 BaseFS->setCurrentWorkingDirectory(WorkingDirectory);
166 return scanDependencies(WorkingDirectory, CommandLine, Consumer, Controller,
167 DC, BaseFS);
168 }
169}
170
171llvm::Error
173 StringRef CWD, const std::vector<std::string> &CommandLine) {
174 bool Success = initializeCompilerInstanceWithContext(CWD, CommandLine);
175 return CIWithContext->handleReturnStatus(Success);
176}
177
178llvm::Error
180 StringRef ModuleName, DependencyConsumer &Consumer,
181 DependencyActionController &Controller) {
182 bool Success =
183 computeDependenciesByNameWithContext(ModuleName, Consumer, Controller);
184 return CIWithContext->handleReturnStatus(Success);
185}
186
187llvm::Error
190 return CIWithContext->handleReturnStatus(Success);
191}
192
194 StringRef CWD, const std::vector<std::string> &CommandLine,
195 DiagnosticConsumer *DC) {
196 CIWithContext =
197 std::make_unique<CompilerInstanceWithContext>(*this, CWD, CommandLine);
198 return CIWithContext->initialize(DC);
199}
200
202 StringRef ModuleName, DependencyConsumer &Consumer,
203 DependencyActionController &Controller) {
204 assert(CIWithContext && "CompilerInstance with context required!");
205 return CIWithContext->computeDependencies(ModuleName, Consumer, Controller);
206}
207
209 return CIWithContext->finalize();
210}
static bool forEachDriverJob(ArrayRef< std::string > ArgStrs, DiagnosticsEngine &Diags, IntrusiveRefCntPtr< llvm::vfs::FileSystem > FS, llvm::function_ref< bool(const driver::Command &Cmd)> Callback)
static bool createAndRunToolInvocation(const std::vector< std::string > &CommandLine, DependencyScanningAction &Action, IntrusiveRefCntPtr< llvm::vfs::FileSystem > FS, std::shared_ptr< clang::PCHContainerOperations > &PCHContainerOps, DiagnosticsEngine &Diags, DependencyConsumer &Consumer)
Abstract interface, implemented by clients of the front-end, which formats and prints fully processed...
virtual void finish()
Callback to inform the diagnostic client that processing of all source files has ended.
Concrete class used by the front-end to report problems and issues.
Definition Diagnostic.h:232
DiagnosticConsumer * getClient()
Definition Diagnostic.h:607
Command - An executable path/name and argument vector to execute.
Definition Job.h:106
const llvm::opt::ArgStringList & getArguments() const
Definition Job.h:224
const char * getExecutable() const
Definition Job.h:222
Dependency scanner callbacks that are used during scanning to influence the behaviour of the scan - f...
bool runInvocation(std::unique_ptr< CompilerInvocation > Invocation, IntrusiveRefCntPtr< llvm::vfs::FileSystem > FS, std::shared_ptr< PCHContainerOperations > PCHContainerOps, DiagnosticConsumer *DiagConsumer)
std::vector< std::string > takeLastCC1Arguments()
Take the cc1 arguments corresponding to the most recent invocation used with this action.
The dependency scanning service contains shared configuration and state that is used by the individua...
bool computeDependenciesByNameWithContext(StringRef ModuleName, DependencyConsumer &Consumer, DependencyActionController &Controller)
llvm::Error finalizeCompilerInstanceWithContextOrError()
Finalizes the diagnostics engine and deletes the compiler instance.
bool initializeCompilerInstanceWithContext(StringRef CWD, const std::vector< std::string > &CommandLine, DiagnosticConsumer *DC=nullptr)
The three methods below provides the same functionality as the three methods above.
bool computeDependencies(StringRef WorkingDirectory, const std::vector< std::string > &CommandLine, DependencyConsumer &DepConsumer, DependencyActionController &Controller, DiagnosticConsumer &DiagConsumer, std::optional< llvm::MemoryBufferRef > TUBuffer=std::nullopt)
Run the dependency scanning tool for a given clang driver command-line, and report the discovered dep...
llvm::Error initializeCompilerInstanceWithContextOrError(StringRef CWD, const std::vector< std::string > &CommandLine)
The three method below implements a new interface for by name dependency scanning.
llvm::Error computeDependenciesByNameWithContextOrError(StringRef ModuleName, DependencyConsumer &Consumer, DependencyActionController &Controller)
Performaces dependency scanning for the module whose name is specified.
DependencyScanningWorker(DependencyScanningService &Service, llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > FS)
Construct a dependency scanning worker.
@ DependencyDirectivesScan
This mode is used to compute the dependencies by running the preprocessor with special kind of lexing...
@ CanonicalPreprocessing
This mode is used to compute the dependencies by running the preprocessor over the source files.
std::unique_ptr< CompilerInvocation > createCompilerInvocation(ArrayRef< std::string > CommandLine, DiagnosticsEngine &Diags)
std::pair< IntrusiveRefCntPtr< llvm::vfs::FileSystem >, std::vector< std::string > > initVFSForTUBuferScanning(IntrusiveRefCntPtr< llvm::vfs::FileSystem > BaseFS, ArrayRef< std::string > CommandLine, StringRef WorkingDirectory, llvm::MemoryBufferRef TUBuffer)
std::pair< std::unique_ptr< driver::Driver >, std::unique_ptr< driver::Compilation > > buildCompilation(ArrayRef< std::string > ArgStrs, DiagnosticsEngine &Diags, IntrusiveRefCntPtr< llvm::vfs::FileSystem > FS, llvm::BumpPtrAllocator &Alloc)
The JSON file list parser is used to communicate input to InstallAPI.
@ Success
Annotation was successful.
Definition Parser.h:65