clang 22.0.0git
DependencyScanningWorker.cpp
Go to the documentation of this file.
1//===- DependencyScanningWorker.cpp - Thread-Safe Scanning 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
13#include "clang/Driver/Driver.h"
14#include "clang/Driver/Tool.h"
16#include "llvm/Support/VirtualFileSystem.h"
17
18using namespace clang;
19using namespace dependencies;
20
24 : Service(Service) {
25 PCHContainerOps = std::make_shared<PCHContainerOperations>();
26 // We need to read object files from PCH built outside the scanner.
27 PCHContainerOps->registerReader(
28 std::make_unique<ObjectFilePCHContainerReader>());
29 // The scanner itself writes only raw ast files.
30 PCHContainerOps->registerWriter(std::make_unique<RawPCHContainerWriter>());
31
32 if (Service.shouldTraceVFS())
33 BaseFS = llvm::makeIntrusiveRefCnt<llvm::vfs::TracingFileSystem>(
34 std::move(BaseFS));
35
36 DepFS = llvm::makeIntrusiveRefCnt<DependencyScanningWorkerFilesystem>(
37 Service.getSharedCache(), std::move(BaseFS));
38}
39
42
44 StringRef WorkingDirectory, ArrayRef<std::string> CommandLine,
46 std::optional<llvm::MemoryBufferRef> TUBuffer) {
47 // Capture the emitted diagnostics and report them to the client
48 // in the case of a failure.
49 TextDiagnosticsPrinterWithOutput DiagPrinterWithOS(CommandLine);
50
51 if (computeDependencies(WorkingDirectory, CommandLine, Consumer, Controller,
52 DiagPrinterWithOS.DiagPrinter, TUBuffer))
53 return llvm::Error::success();
54 return llvm::make_error<llvm::StringError>(
55 DiagPrinterWithOS.DiagnosticsOS.str(), llvm::inconvertibleErrorCode());
56}
57
58static bool forEachDriverJob(
61 llvm::function_ref<bool(const driver::Command &Cmd)> Callback) {
62 // Compilation holds a non-owning a reference to the Driver, hence we need to
63 // keep the Driver alive when we use Compilation. Arguments to commands may be
64 // owned by Alloc when expanded from response files.
65 llvm::BumpPtrAllocator Alloc;
66 auto [Driver, Compilation] = buildCompilation(ArgStrs, Diags, FS, Alloc);
67 if (!Compilation)
68 return false;
69 for (const driver::Command &Job : Compilation->getJobs()) {
70 if (!Callback(Job))
71 return false;
72 }
73 return true;
74}
75
79 std::shared_ptr<clang::PCHContainerOperations> &PCHContainerOps,
80 DiagnosticsEngine &Diags) {
81 auto Invocation = createCompilerInvocation(CommandLine, Diags);
82 if (!Invocation)
83 return false;
84
85 return Action.runInvocation(CommandLine[0], std::move(Invocation),
86 std::move(FS), PCHContainerOps,
87 Diags.getClient());
88}
89
90bool DependencyScanningWorker::scanDependencies(
91 StringRef WorkingDirectory, ArrayRef<std::string> CommandLine,
93 DiagnosticConsumer &DC,
94 IntrusiveRefCntPtr<llvm::vfs::FileSystem> OverlayFS) {
95 IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS = DepFS;
96 if (OverlayFS) {
97#ifndef NDEBUG
98 bool SawDepFS = false;
99 OverlayFS->visit(
100 [&](llvm::vfs::FileSystem &VFS) { SawDepFS |= &VFS == DepFS.get(); });
101 assert(SawDepFS && "OverlayFS not based on DepFS");
102#endif
103 FS = std::move(OverlayFS);
104 }
105
106 DiagnosticsEngineWithDiagOpts DiagEngineWithCmdAndOpts(CommandLine, FS, DC);
107 DependencyScanningAction Action(Service, WorkingDirectory, Consumer,
108 Controller, DepFS);
109
110 bool Success = false;
111 if (CommandLine[1] == "-cc1") {
112 Success =
113 createAndRunToolInvocation(CommandLine, Action, FS, PCHContainerOps,
114 *DiagEngineWithCmdAndOpts.DiagEngine);
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 command 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);
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, ArrayRef<std::string> CommandLine,
157 DependencyConsumer &Consumer, DependencyActionController &Controller,
158 DiagnosticConsumer &DC, std::optional<llvm::MemoryBufferRef> TUBuffer) {
159 if (TUBuffer) {
160 auto [FinalFS, FinalCommandLine] = initVFSForTUBufferScanning(
161 DepFS, CommandLine, WorkingDirectory, *TUBuffer);
162 return scanDependencies(WorkingDirectory, FinalCommandLine, Consumer,
163 Controller, DC, FinalFS);
164 }
165
166 DepFS->setCurrentWorkingDirectory(WorkingDirectory);
167 return scanDependencies(WorkingDirectory, CommandLine, Consumer, Controller,
168 DC);
169}
170
172 StringRef CWD, ArrayRef<std::string> CommandLine, DiagnosticConsumer &DC) {
173 auto OverlayFSAndArgs =
174 initVFSForByNameScanning(DepFS, CommandLine, CWD, "ScanningByName");
175 auto &OverlayFS = OverlayFSAndArgs.first;
176 const auto &ModifiedCommandLine = OverlayFSAndArgs.second;
177
178 auto DiagEngineWithCmdAndOpts =
179 std::make_unique<DiagnosticsEngineWithDiagOpts>(ModifiedCommandLine,
180 OverlayFS, DC);
181
183 CWD, ModifiedCommandLine, std::move(DiagEngineWithCmdAndOpts), OverlayFS);
184}
185
187 StringRef CWD, ArrayRef<std::string> CommandLine,
188 std::unique_ptr<DiagnosticsEngineWithDiagOpts> DiagEngineWithDiagOpts,
190 CIWithContext =
191 std::make_unique<CompilerInstanceWithContext>(*this, CWD, CommandLine);
192 return CIWithContext->initialize(std::move(DiagEngineWithDiagOpts),
193 OverlayFS);
194}
195
197 StringRef ModuleName, DependencyConsumer &Consumer,
198 DependencyActionController &Controller) {
199 assert(CIWithContext && "CompilerInstance with context required!");
200 return CIWithContext->computeDependencies(ModuleName, Consumer, Controller);
201}
202
204 return CIWithContext->finalize();
205}
Defines the Diagnostic-related interfaces.
static bool createAndRunToolInvocation(ArrayRef< std::string > CommandLine, DependencyScanningAction &Action, IntrusiveRefCntPtr< llvm::vfs::FileSystem > FS, std::shared_ptr< clang::PCHContainerOperations > &PCHContainerOps, DiagnosticsEngine &Diags)
static bool forEachDriverJob(ArrayRef< std::string > ArgStrs, DiagnosticsEngine &Diags, IntrusiveRefCntPtr< llvm::vfs::FileSystem > FS, llvm::function_ref< bool(const driver::Command &Cmd)> Callback)
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
Dependency scanner callbacks that are used during scanning to influence the behaviour of the scan - f...
bool runInvocation(std::string Executable, std::unique_ptr< CompilerInvocation > Invocation, IntrusiveRefCntPtr< llvm::vfs::FileSystem > FS, std::shared_ptr< PCHContainerOperations > PCHContainerOps, DiagnosticConsumer *DiagConsumer)
The dependency scanning service contains shared configuration and state that is used by the individua...
bool computeDependenciesByNameWithContext(StringRef ModuleName, DependencyConsumer &Consumer, DependencyActionController &Controller)
Performaces dependency scanning for the module whose name is specified.
DependencyScanningWorker(DependencyScanningService &Service, IntrusiveRefCntPtr< llvm::vfs::FileSystem > BaseFS)
Construct a dependency scanning worker.
bool computeDependencies(StringRef WorkingDirectory, ArrayRef< 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...
bool initializeCompilerInstanceWithContext(StringRef CWD, ArrayRef< std::string > CommandLine, DiagnosticConsumer &DC)
The three method below implements a new interface for by name dependency scanning.
bool finalizeCompilerInstanceWithContext()
Finalizes the diagnostics engine and deletes the compiler instance.
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
std::pair< IntrusiveRefCntPtr< llvm::vfs::FileSystem >, std::vector< std::string > > initVFSForTUBufferScanning(IntrusiveRefCntPtr< llvm::vfs::FileSystem > BaseFS, ArrayRef< std::string > CommandLine, StringRef WorkingDirectory, llvm::MemoryBufferRef TUBuffer)
@ VFS
Remove unused -ivfsoverlay arguments.
std::unique_ptr< CompilerInvocation > createCompilerInvocation(ArrayRef< std::string > CommandLine, DiagnosticsEngine &Diags)
std::pair< IntrusiveRefCntPtr< llvm::vfs::OverlayFileSystem >, std::vector< std::string > > initVFSForByNameScanning(IntrusiveRefCntPtr< llvm::vfs::FileSystem > BaseFS, ArrayRef< std::string > CommandLine, StringRef WorkingDirectory, StringRef ModuleName)
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