clang 10.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
9 #include "clang/Tooling/DependencyScanning/DependencyScanningWorker.h"
10 #include "clang/Frontend/CompilerInstance.h"
11 #include "clang/Frontend/CompilerInvocation.h"
12 #include "clang/Frontend/FrontendActions.h"
13 #include "clang/Frontend/TextDiagnosticPrinter.h"
14 #include "clang/Frontend/Utils.h"
15 #include "clang/Lex/PreprocessorOptions.h"
16 #include "clang/Tooling/DependencyScanning/DependencyScanningService.h"
17 #include "clang/Tooling/DependencyScanning/ModuleDepCollector.h"
18 #include "clang/Tooling/Tooling.h"
19
20 using namespace clang;
21 using namespace tooling;
22 using namespace dependencies;
23
24 namespace {
25
26 /// Forwards the gatherered dependencies to the consumer.
27 class DependencyConsumerForwarder : public DependencyFileGenerator {
28 public:
29 DependencyConsumerForwarder(std::unique_ptr<DependencyOutputOptions> Opts,
30 DependencyConsumer &C)
31 : DependencyFileGenerator(*Opts), Opts(std::move(Opts)), C(C) {}
32
33 void finishedMainFile(DiagnosticsEngine &Diags) override {
34 llvm::SmallString<256> CanonPath;
35 for (const auto &File : getDependencies()) {
36 CanonPath = File;
37 llvm::sys::path::remove_dots(CanonPath, /*remove_dot_dot=*/true);
38 C.handleFileDependency(*Opts, CanonPath);
39 }
40 }
41
42 private:
43 std::unique_ptr<DependencyOutputOptions> Opts;
44 DependencyConsumer &C;
45 };
46
47 /// A proxy file system that doesn't call `chdir` when changing the working
48 /// directory of a clang tool.
49 class ProxyFileSystemWithoutChdir : public llvm::vfs::ProxyFileSystem {
50 public:
51 ProxyFileSystemWithoutChdir(
52 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS)
53 : ProxyFileSystem(std::move(FS)) {}
54
55 llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override {
56 assert(!CWD.empty() && "empty CWD");
57 return CWD;
58 }
59
60 std::error_code setCurrentWorkingDirectory(const Twine &Path) override {
61 CWD = Path.str();
62 return {};
63 }
64
65 private:
66 std::string CWD;
67 };
68
69 /// A clang tool that runs the preprocessor in a mode that's optimized for
70 /// dependency scanning for the given compiler invocation.
71 class DependencyScanningAction : public tooling::ToolAction {
72 public:
73 DependencyScanningAction(
74 StringRef WorkingDirectory, DependencyConsumer &Consumer,
75 llvm::IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> DepFS,
76 ExcludedPreprocessorDirectiveSkipMapping *PPSkipMappings,
77 ScanningOutputFormat Format)
78 : WorkingDirectory(WorkingDirectory), Consumer(Consumer),
79 DepFS(std::move(DepFS)), PPSkipMappings(PPSkipMappings),
80 Format(Format) {}
81
82 bool runInvocation(std::shared_ptr<CompilerInvocation> Invocation,
83 FileManager *FileMgr,
84 std::shared_ptr<PCHContainerOperations> PCHContainerOps,
85 DiagnosticConsumer *DiagConsumer) override {
86 // Create a compiler instance to handle the actual work.
87 CompilerInstance Compiler(std::move(PCHContainerOps));
88 Compiler.setInvocation(std::move(Invocation));
89
90 // Don't print 'X warnings and Y errors generated'.
91 Compiler.getDiagnosticOpts().ShowCarets = false;
92 // Create the compiler's actual diagnostics engine.
93 Compiler.createDiagnostics(DiagConsumer, /*ShouldOwnClient=*/false);
94 if (!Compiler.hasDiagnostics())
95 return false;
96
97 // Use the dependency scanning optimized file system if we can.
98 if (DepFS) {
99 const CompilerInvocation &CI = Compiler.getInvocation();
100 // Add any filenames that were explicity passed in the build settings and
101 // that might be opened, as we want to ensure we don't run source
102 // minimization on them.
103 DepFS->IgnoredFiles.clear();
104 for (const auto &Entry : CI.getHeaderSearchOpts().UserEntries)
105 DepFS->IgnoredFiles.insert(Entry.Path);
106 for (const auto &Entry : CI.getHeaderSearchOpts().VFSOverlayFiles)
107 DepFS->IgnoredFiles.insert(Entry);
108
109 // Support for virtual file system overlays on top of the caching
110 // filesystem.
111 FileMgr->setVirtualFileSystem(createVFSFromCompilerInvocation(
112 CI, Compiler.getDiagnostics(), DepFS));
113
114 // Pass the skip mappings which should speed up excluded conditional block
115 // skipping in the preprocessor.
116 if (PPSkipMappings)
117 Compiler.getPreprocessorOpts()
118 .ExcludedConditionalDirectiveSkipMappings = PPSkipMappings;
119 }
120
121 FileMgr->getFileSystemOpts().WorkingDir = WorkingDirectory;
122 Compiler.setFileManager(FileMgr);
123 Compiler.createSourceManager(*FileMgr);
124
125 // Create the dependency collector that will collect the produced
126 // dependencies.
127 //
128 // This also moves the existing dependency output options from the
129 // invocation to the collector. The options in the invocation are reset,
130 // which ensures that the compiler won't create new dependency collectors,
131 // and thus won't write out the extra '.d' files to disk.
132 auto Opts = std::make_unique<DependencyOutputOptions>(
133 std::move(Compiler.getInvocation().getDependencyOutputOpts()));
134 // We need at least one -MT equivalent for the generator to work.
135 if (Opts->Targets.empty())
136 Opts->Targets = {"clang-scan-deps dependency"};
137
138 switch (Format) {
139 case ScanningOutputFormat::Make:
140 Compiler.addDependencyCollector(
141 std::make_shared<DependencyConsumerForwarder>(std::move(Opts),
142 Consumer));
143 break;
144 case ScanningOutputFormat::Full:
145 Compiler.addDependencyCollector(
146 std::make_shared<ModuleDepCollector>(Compiler, Consumer));
147 break;
148 }
149
150 Consumer.handleContextHash(Compiler.getInvocation().getModuleHash());
151
152 auto Action = std::make_unique<PreprocessOnlyAction>();
153 const bool Result = Compiler.ExecuteAction(*Action);
154 if (!DepFS)
155 FileMgr->clearStatCache();
156 return Result;
157 }
158
159 private:
160 StringRef WorkingDirectory;
161 DependencyConsumer &Consumer;
162 llvm::IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> DepFS;
163 ExcludedPreprocessorDirectiveSkipMapping *PPSkipMappings;
164 ScanningOutputFormat Format;
165 };
166
167 } // end anonymous namespace
168
169 DependencyScanningWorker::DependencyScanningWorker(
170 DependencyScanningService &Service)
171 : Format(Service.getFormat()) {
172 DiagOpts = new DiagnosticOptions();
173 PCHContainerOps = std::make_shared<PCHContainerOperations>();
174 RealFS = new ProxyFileSystemWithoutChdir(llvm::vfs::getRealFileSystem());
175 if (Service.canSkipExcludedPPRanges())
176 PPSkipMappings =
177 std::make_unique<ExcludedPreprocessorDirectiveSkipMapping>();
178 if (Service.getMode() == ScanningMode::MinimizedSourcePreprocessing)
179 DepFS = new DependencyScanningWorkerFilesystem(
180 Service.getSharedCache(), RealFS, PPSkipMappings.get());
181 if (Service.canReuseFileManager())
182 Files = new FileManager(FileSystemOptions(), RealFS);
183 }
184
185 static llvm::Error runWithDiags(
186 DiagnosticOptions *DiagOpts,
187 llvm::function_ref<bool(DiagnosticConsumer &DC)> BodyShouldSucceed) {
188 // Capture the emitted diagnostics and report them to the client
189 // in the case of a failure.
190 std::string DiagnosticOutput;
191 llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput);
192 TextDiagnosticPrinter DiagPrinter(DiagnosticsOS, DiagOpts);
193
194 if (BodyShouldSucceed(DiagPrinter))
195 return llvm::Error::success();
196 return llvm::make_error<llvm::StringError>(DiagnosticsOS.str(),
197 llvm::inconvertibleErrorCode());
198 }
199
200 llvm::Error DependencyScanningWorker::computeDependencies(
201 const std::string &Input, StringRef WorkingDirectory,
202 const CompilationDatabase &CDB, DependencyConsumer &Consumer) {
203 RealFS->setCurrentWorkingDirectory(WorkingDirectory);
204 return runWithDiags(DiagOpts.get(), [&](DiagnosticConsumer &DC) {
205 /// Create the tool that uses the underlying file system to ensure that any
206 /// file system requests that are made by the driver do not go through the
207 /// dependency scanning filesystem.
208 tooling::ClangTool Tool(CDB, Input, PCHContainerOps, RealFS, Files);
209 Tool.clearArgumentsAdjusters();
210 Tool.setRestoreWorkingDir(false);
211 Tool.setPrintErrorMessage(false);
212 Tool.setDiagnosticConsumer(&DC);
213 DependencyScanningAction Action(WorkingDirectory, Consumer, DepFS,
214 PPSkipMappings.get(), Format);
215 return !Tool.run(&Action);
216 });
217 }
clang::CompilerInvocationBase::getHeaderSearchOpts
HeaderSearchOptions & getHeaderSearchOpts()
Definition: CompilerInvocation.h:95
clang::tooling::ToolAction
Interface to process a clang::CompilerInvocation.
Definition: Tooling.h:73
FrontendActions.h
clang::tooling::ClangTool::setDiagnosticConsumer
void setDiagnosticConsumer(DiagnosticConsumer *DiagConsumer)
Set a DiagnosticConsumer to use during parsing.
Definition: Tooling.h:329
clang::FileManager
Implements support for file system lookup, file system caching, and directory search management...
Definition: FileManager.h:171
clang::tooling::dependencies::DependencyScanningService::getMode
ScanningMode getMode() const
Definition: DependencyScanningService.h:53
clang::tooling::ClangTool
Utility to run a FrontendAction over a set of files.
Definition: Tooling.h:304
clang::tooling::dependencies::ScanningMode::MinimizedSourcePreprocessing
This mode is used to compute the dependencies by running the preprocessor over the source files that ...
clang::tooling::dependencies::DependencyScanningWorker::DependencyScanningWorker
DependencyScanningWorker(DependencyScanningService &Service)
Definition: DependencyScanningWorker.cpp:169
clang::DiagnosticConsumer
Abstract interface, implemented by clients of the front-end, which formats and prints fully processed...
Definition: Diagnostic.h:1499
std
Definition: Format.h:2445
clang::tooling::ClangTool::clearArgumentsAdjusters
void clearArgumentsAdjusters()
Clear the command line arguments adjuster chain.
Definition: Tooling.cpp:432
clang::HeaderSearchOptions::UserEntries
std::vector< Entry > UserEntries
User specified include entries.
Definition: HeaderSearchOptions.h:102
clang::tooling::dependencies::DependencyScanningService
The dependency scanning service contains the shared state that is used by the invidual dependency sca...
Definition: DependencyScanningService.h:47
clang::tooling::dependencies::DependencyScanningWorkerFilesystem
A virtual file system optimized for the dependency discovery.
Definition: DependencyScanningFilesystem.h:143
DependencyScanningService.h
clang::HeaderSearchOptions::VFSOverlayFiles
std::vector< std::string > VFSOverlayFiles
The set of user-provided virtual filesystem overlay files.
Definition: HeaderSearchOptions.h:174
clang::DiagnosticsEngine
Concrete class used by the front-end to report problems and issues.
Definition: Diagnostic.h:149
Utils.h
llvm::SmallString
Definition: LLVM.h:34
clang::DependencyFileGenerator
Builds a dependency file when attached to a Preprocessor (for includes) and ASTReader (for module imp...
Definition: Utils.h:117
clang::tooling::ClangTool::setPrintErrorMessage
void setPrintErrorMessage(bool PrintErrorMessage)
Sets whether an error message should be printed out if an action fails.
Definition: Tooling.cpp:605
CompilerInstance.h
clang::tooling::dependencies::DependencyConsumer
Definition: DependencyScanningWorker.h:33
runWithDiags
static llvm::Error runWithDiags(DiagnosticOptions *DiagOpts, llvm::function_ref< bool(DiagnosticConsumer &DC)> BodyShouldSucceed)
Definition: DependencyScanningWorker.cpp:185
clang::tooling::dependencies::ScanningOutputFormat::Full
This outputs the full module dependency graph suitable for use for explicitly building modules...
clang::FileSystemOptions::WorkingDir
std::string WorkingDir
If set, paths are resolved as if the working directory was set to the value of WorkingDir.
Definition: FileSystemOptions.h:26
clang::tooling::dependencies::ScanningOutputFormat::Make
This is the Makefile compatible dep format.
clang::tooling::dependencies::DependencyScanningService::getSharedCache
DependencyScanningFilesystemSharedCache & getSharedCache()
Definition: DependencyScanningService.h:61
clang::DiagnosticLevelMask::Error
CompilerInvocation.h
ModuleDepCollector.h
ProxyFileSystem
clang::tooling::CompilationDatabase
Interface for compilation databases.
Definition: CompilationDatabase.h:87
llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem >
clang::CompilerInstance
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
Definition: CompilerInstance.h:72
clang::FileManager::getFileSystemOpts
FileSystemOptions & getFileSystemOpts()
Returns the current file system options.
Definition: FileManager.h:352
PreprocessorOptions.h
clang::DiagnosticOptions
Options for controlling the compiler diagnostics engine.
Definition: DiagnosticOptions.h:63
clang::tooling::dependencies::DependencyScanningService::canSkipExcludedPPRanges
bool canSkipExcludedPPRanges() const
Definition: DependencyScanningService.h:59
clang::tooling::ClangTool::run
int run(ToolAction *Action)
Runs an action over all files specified in the command line.
Definition: Tooling.cpp:448
clang::FileManager::setVirtualFileSystem
void setVirtualFileSystem(IntrusiveRefCntPtr< llvm::vfs::FileSystem > FS)
Definition: FileManager.h:357
Tooling.h
clang
Dataflow Directional Tag Classes.
Definition: CFGReachabilityAnalysis.h:21
clang::FileManager::clearStatCache
void clearStatCache()
Removes the FileSystemStatCache object from the manager.
Definition: FileManager.cpp:68
clang::tooling::dependencies::DependencyScanningWorker::computeDependencies
llvm::Error computeDependencies(const std::string &Input, StringRef WorkingDirectory, const CompilationDatabase &CDB, DependencyConsumer &Consumer)
Run the dependency scanning tool for a given clang driver invocation (as specified for the given Inpu...
Definition: DependencyScanningWorker.cpp:200
clang::TextDiagnosticPrinter
Definition: TextDiagnosticPrinter.h:27
DependencyScanningWorker.h
clang::createVFSFromCompilerInvocation
IntrusiveRefCntPtr< llvm::vfs::FileSystem > createVFSFromCompilerInvocation(const CompilerInvocation &CI, DiagnosticsEngine &Diags)
Definition: CompilerInvocation.cpp:3737
clang::CompilerInvocation
Helper class for holding the data necessary to invoke the compiler.
Definition: CompilerInvocation.h:121
TextDiagnosticPrinter.h
clang::tooling::dependencies::ScanningOutputFormat
ScanningOutputFormat
The format that is output by the dependency scanner.
Definition: DependencyScanningService.h:34
clang::FileSystemOptions
Keeps track of options that affect how file operations are performed.
Definition: FileSystemOptions.h:22
clang::tooling::dependencies::DependencyScanningService::canReuseFileManager
bool canReuseFileManager() const
Definition: DependencyScanningService.h:57
clang::tooling::ClangTool::setRestoreWorkingDir
void setRestoreWorkingDir(bool RestoreCWD)
Sets whether working directory should be restored after calling run().
Definition: Tooling.cpp:601
clang::ExcludedPreprocessorDirectiveSkipMapping
llvm::DenseMap< const llvm::MemoryBuffer *, const PreprocessorSkippedRangeMapping * > ExcludedPreprocessorDirectiveSkipMapping
The datastructure that holds the mapping between the active memory buffers and the individual skip ma...
Definition: PreprocessorExcludedConditionalDirectiveSkipMapping.h:27
AttributeLangSupport::C
Definition: SemaDeclAttr.cpp:45