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/ADT/IntrusiveRefCntPtr.h"
17#include "llvm/Support/VirtualFileSystem.h"
18
19using namespace clang;
20using namespace dependencies;
21
25 : Service(Service) {
26 PCHContainerOps = std::make_shared<PCHContainerOperations>();
27 // We need to read object files from PCH built outside the scanner.
28 PCHContainerOps->registerReader(
29 std::make_unique<ObjectFilePCHContainerReader>());
30 // The scanner itself writes only raw ast files.
31 PCHContainerOps->registerWriter(std::make_unique<RawPCHContainerWriter>());
32
33 if (Service.shouldTraceVFS())
34 BaseFS = llvm::makeIntrusiveRefCnt<llvm::vfs::TracingFileSystem>(
35 std::move(BaseFS));
36
37 DepFS = llvm::makeIntrusiveRefCnt<DependencyScanningWorkerFilesystem>(
38 Service.getSharedCache(), std::move(BaseFS));
39}
40
43
47 std::shared_ptr<clang::PCHContainerOperations> &PCHContainerOps,
48 DiagnosticsEngine &Diags) {
49 auto Invocation = createCompilerInvocation(CommandLine, Diags);
50 if (!Invocation)
51 return false;
52
53 return Action.runInvocation(CommandLine[0], std::move(Invocation),
54 std::move(FS), PCHContainerOps,
55 Diags.getClient());
56}
57
59 StringRef WorkingDirectory, ArrayRef<std::string> CommandLine,
60 DependencyConsumer &DepConsumer, DependencyActionController &Controller,
61 DiagnosticConsumer &DiagConsumer,
63 return computeDependencies(WorkingDirectory,
64 ArrayRef<ArrayRef<std::string>>(CommandLine),
65 DepConsumer, Controller, DiagConsumer, OverlayFS);
66}
67
69 StringRef WorkingDirectory, ArrayRef<ArrayRef<std::string>> CommandLines,
70 DependencyConsumer &DepConsumer, DependencyActionController &Controller,
71 DiagnosticConsumer &DiagConsumer,
74 if (OverlayFS) {
75#ifndef NDEBUG
76 bool SawDepFS = false;
77 OverlayFS->visit(
78 [&](llvm::vfs::FileSystem &VFS) { SawDepFS |= &VFS == DepFS.get(); });
79 assert(SawDepFS && "OverlayFS not based on DepFS");
80#endif
81 FS = std::move(OverlayFS);
82 } else {
83 FS = DepFS;
84 FS->setCurrentWorkingDirectory(WorkingDirectory);
85 }
86
87 DependencyScanningAction Action(Service, WorkingDirectory, DepConsumer,
88 Controller, DepFS);
89
90 const bool Success = llvm::all_of(CommandLines, [&](const auto &Cmd) {
91 if (StringRef(Cmd[1]) != "-cc1") {
92 // Non-clang command. Just pass through to the dependency consumer.
93 DepConsumer.handleBuildCommand(
94 {Cmd.front(), {Cmd.begin() + 1, Cmd.end()}});
95 return true;
96 }
97
98 auto DiagEngineWithDiagOpts =
99 DiagnosticsEngineWithDiagOpts(Cmd, FS, DiagConsumer);
100 auto &Diags = *DiagEngineWithDiagOpts.DiagEngine;
101
102 // Create an invocation that uses the underlying file system to ensure that
103 // any file system requests that are made by the driver do not go through
104 // the dependency scanning filesystem.
105 return createAndRunToolInvocation(Cmd, Action, FS, PCHContainerOps, Diags);
106 });
107
108 // Ensure finish() is called even if we never reached ExecuteAction().
109 if (!Action.hasDiagConsumerFinished())
110 DiagConsumer.finish();
111
112 return Success && Action.hasScanned();
113}
114
116 StringRef CWD, ArrayRef<std::string> CommandLine, DiagnosticConsumer &DC) {
117 auto [OverlayFS, ModifiedCommandLine] =
118 initVFSForByNameScanning(DepFS, CommandLine, CWD, "ScanningByName");
119 auto DiagEngineWithCmdAndOpts =
120 std::make_unique<DiagnosticsEngineWithDiagOpts>(ModifiedCommandLine,
121 OverlayFS, DC);
123 CWD, ModifiedCommandLine, std::move(DiagEngineWithCmdAndOpts), OverlayFS);
124}
125
127 StringRef CWD, ArrayRef<std::string> CommandLine,
128 std::unique_ptr<DiagnosticsEngineWithDiagOpts> DiagEngineWithDiagOpts,
130 CIWithContext =
131 std::make_unique<CompilerInstanceWithContext>(*this, CWD, CommandLine);
132 return CIWithContext->initialize(std::move(DiagEngineWithDiagOpts),
133 OverlayFS);
134}
135
137 StringRef ModuleName, DependencyConsumer &Consumer,
138 DependencyActionController &Controller) {
139 assert(CIWithContext && "CompilerInstance with context required!");
140 return CIWithContext->computeDependencies(ModuleName, Consumer, Controller);
141}
142
144 return CIWithContext->finalize();
145}
146
147std::pair<IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem>,
148 std::vector<std::string>>
151 ArrayRef<std::string> CommandLine, StringRef WorkingDirectory,
152 llvm::MemoryBufferRef TUBuffer) {
153 // Reset what might have been modified in the previous worker invocation.
154 BaseFS->setCurrentWorkingDirectory(WorkingDirectory);
155
156 auto OverlayFS =
157 llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(BaseFS);
158 auto InMemoryFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
159 InMemoryFS->setCurrentWorkingDirectory(WorkingDirectory);
160 auto InputPath = TUBuffer.getBufferIdentifier();
161 InMemoryFS->addFile(
162 InputPath, 0, llvm::MemoryBuffer::getMemBufferCopy(TUBuffer.getBuffer()));
163 IntrusiveRefCntPtr<llvm::vfs::FileSystem> InMemoryOverlay = InMemoryFS;
164
165 OverlayFS->pushOverlay(InMemoryOverlay);
166 std::vector<std::string> ModifiedCommandLine(CommandLine);
167 ModifiedCommandLine.emplace_back(InputPath);
168
169 return std::make_pair(OverlayFS, ModifiedCommandLine);
170}
171
172std::pair<IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem>,
173 std::vector<std::string>>
176 ArrayRef<std::string> CommandLine, StringRef WorkingDirectory,
177 StringRef ModuleName) {
178 // Reset what might have been modified in the previous worker invocation.
179 BaseFS->setCurrentWorkingDirectory(WorkingDirectory);
180
181 // If we're scanning based on a module name alone, we don't expect the client
182 // to provide us with an input file. However, the driver really wants to have
183 // one. Let's just make it up to make the driver happy.
184 auto OverlayFS =
185 llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(BaseFS);
186 auto InMemoryFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
187 InMemoryFS->setCurrentWorkingDirectory(WorkingDirectory);
188 SmallString<128> FakeInputPath;
189 // TODO: We should retry the creation if the path already exists.
190 llvm::sys::fs::createUniquePath(ModuleName + "-%%%%%%%%.input", FakeInputPath,
191 /*MakeAbsolute=*/false);
192 InMemoryFS->addFile(FakeInputPath, 0, llvm::MemoryBuffer::getMemBuffer(""));
193 IntrusiveRefCntPtr<llvm::vfs::FileSystem> InMemoryOverlay = InMemoryFS;
194 OverlayFS->pushOverlay(InMemoryOverlay);
195
196 std::vector<std::string> ModifiedCommandLine(CommandLine);
197 ModifiedCommandLine.emplace_back(FakeInputPath);
198
199 return std::make_pair(OverlayFS, ModifiedCommandLine);
200}
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)
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, llvm::IntrusiveRefCntPtr< llvm::vfs::OverlayFileSystem > OverlayFS=nullptr)
Run the dependency scanning worker for the given frontend 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.
@ VFS
Remove unused -ivfsoverlay arguments.
std::pair< IntrusiveRefCntPtr< llvm::vfs::OverlayFileSystem >, std::vector< std::string > > initVFSForTUBufferScanning(IntrusiveRefCntPtr< llvm::vfs::FileSystem > BaseFS, ArrayRef< std::string > CommandLine, StringRef WorkingDirectory, llvm::MemoryBufferRef TUBuffer)
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)
The JSON file list parser is used to communicate input to InstallAPI.
@ Success
Annotation was successful.
Definition Parser.h:65