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 
14 #include "clang/Frontend/Utils.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,
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;
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(
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,
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.
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) {
140  Compiler.addDependencyCollector(
141  std::make_shared<DependencyConsumerForwarder>(std::move(Opts),
142  Consumer));
143  break;
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;
164  ScanningOutputFormat Format;
165 };
166 
167 } // end anonymous namespace
168 
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>();
180  Service.getSharedCache(), RealFS, PPSkipMappings.get());
181  if (Service.canReuseFileManager())
182  Files = new FileManager(FileSystemOptions(), RealFS);
183 }
184 
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 
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);
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 }
HeaderSearchOptions & getHeaderSearchOpts()
Interface to process a clang::CompilerInvocation.
Definition: Tooling.h:73
void setDiagnosticConsumer(DiagnosticConsumer *DiagConsumer)
Set a DiagnosticConsumer to use during parsing.
Definition: Tooling.h:329
Implements support for file system lookup, file system caching, and directory search management...
Definition: FileManager.h:171
Utility to run a FrontendAction over a set of files.
Definition: Tooling.h:304
This mode is used to compute the dependencies by running the preprocessor over the source files that ...
Abstract interface, implemented by clients of the front-end, which formats and prints fully processed...
Definition: Diagnostic.h:1499
Definition: Format.h:2445
void clearArgumentsAdjusters()
Clear the command line arguments adjuster chain.
Definition: Tooling.cpp:432
std::vector< Entry > UserEntries
User specified include entries.
The dependency scanning service contains the shared state that is used by the invidual dependency sca...
A virtual file system optimized for the dependency discovery.
std::vector< std::string > VFSOverlayFiles
The set of user-provided virtual filesystem overlay files.
Concrete class used by the front-end to report problems and issues.
Definition: Diagnostic.h:149
Builds a dependency file when attached to a Preprocessor (for includes) and ASTReader (for module imp...
Definition: Utils.h:117
void setPrintErrorMessage(bool PrintErrorMessage)
Sets whether an error message should be printed out if an action fails.
Definition: Tooling.cpp:605
static llvm::Error runWithDiags(DiagnosticOptions *DiagOpts, llvm::function_ref< bool(DiagnosticConsumer &DC)> BodyShouldSucceed)
This outputs the full module dependency graph suitable for use for explicitly building modules...
std::string WorkingDir
If set, paths are resolved as if the working directory was set to the value of WorkingDir.
This is the Makefile compatible dep format.
DependencyScanningFilesystemSharedCache & getSharedCache()
Interface for compilation databases.
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
FileSystemOptions & getFileSystemOpts()
Returns the current file system options.
Definition: FileManager.h:352
Options for controlling the compiler diagnostics engine.
int run(ToolAction *Action)
Runs an action over all files specified in the command line.
Definition: Tooling.cpp:448
void setVirtualFileSystem(IntrusiveRefCntPtr< llvm::vfs::FileSystem > FS)
Definition: FileManager.h:357
Dataflow Directional Tag Classes.
void clearStatCache()
Removes the FileSystemStatCache object from the manager.
Definition: FileManager.cpp:68
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...
IntrusiveRefCntPtr< llvm::vfs::FileSystem > createVFSFromCompilerInvocation(const CompilerInvocation &CI, DiagnosticsEngine &Diags)
Helper class for holding the data necessary to invoke the compiler.
ScanningOutputFormat
The format that is output by the dependency scanner.
Keeps track of options that affect how file operations are performed.
void setRestoreWorkingDir(bool RestoreCWD)
Sets whether working directory should be restored after calling run().
Definition: Tooling.cpp:601
llvm::DenseMap< const llvm::MemoryBuffer *, const PreprocessorSkippedRangeMapping * > ExcludedPreprocessorDirectiveSkipMapping
The datastructure that holds the mapping between the active memory buffers and the individual skip ma...