clang 19.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
15#include "clang/Driver/Driver.h"
16#include "clang/Driver/Job.h"
17#include "clang/Driver/Tool.h"
27#include "llvm/ADT/ScopeExit.h"
28#include "llvm/Support/Allocator.h"
29#include "llvm/Support/Error.h"
30#include "llvm/TargetParser/Host.h"
31#include <optional>
32
33using namespace clang;
34using namespace tooling;
35using namespace dependencies;
36
37namespace {
38
39/// Forwards the gatherered dependencies to the consumer.
40class DependencyConsumerForwarder : public DependencyFileGenerator {
41public:
42 DependencyConsumerForwarder(std::unique_ptr<DependencyOutputOptions> Opts,
43 StringRef WorkingDirectory, DependencyConsumer &C)
44 : DependencyFileGenerator(*Opts), WorkingDirectory(WorkingDirectory),
45 Opts(std::move(Opts)), C(C) {}
46
47 void finishedMainFile(DiagnosticsEngine &Diags) override {
48 C.handleDependencyOutputOpts(*Opts);
49 llvm::SmallString<256> CanonPath;
50 for (const auto &File : getDependencies()) {
51 CanonPath = File;
52 llvm::sys::path::remove_dots(CanonPath, /*remove_dot_dot=*/true);
53 llvm::sys::fs::make_absolute(WorkingDirectory, CanonPath);
54 C.handleFileDependency(CanonPath);
55 }
56 }
57
58private:
59 StringRef WorkingDirectory;
60 std::unique_ptr<DependencyOutputOptions> Opts;
62};
63
64static bool checkHeaderSearchPaths(const HeaderSearchOptions &HSOpts,
65 const HeaderSearchOptions &ExistingHSOpts,
66 DiagnosticsEngine *Diags,
67 const LangOptions &LangOpts) {
68 if (LangOpts.Modules) {
69 if (HSOpts.VFSOverlayFiles != ExistingHSOpts.VFSOverlayFiles) {
70 if (Diags) {
71 Diags->Report(diag::warn_pch_vfsoverlay_mismatch);
72 auto VFSNote = [&](int Type, ArrayRef<std::string> VFSOverlays) {
73 if (VFSOverlays.empty()) {
74 Diags->Report(diag::note_pch_vfsoverlay_empty) << Type;
75 } else {
76 std::string Files = llvm::join(VFSOverlays, "\n");
77 Diags->Report(diag::note_pch_vfsoverlay_files) << Type << Files;
78 }
79 };
80 VFSNote(0, HSOpts.VFSOverlayFiles);
81 VFSNote(1, ExistingHSOpts.VFSOverlayFiles);
82 }
83 }
84 }
85 return false;
86}
87
88using PrebuiltModuleFilesT = decltype(HeaderSearchOptions::PrebuiltModuleFiles);
89
90/// A listener that collects the imported modules and optionally the input
91/// files.
92class PrebuiltModuleListener : public ASTReaderListener {
93public:
94 PrebuiltModuleListener(PrebuiltModuleFilesT &PrebuiltModuleFiles,
95 llvm::SmallVector<std::string> &NewModuleFiles,
96 PrebuiltModuleVFSMapT &PrebuiltModuleVFSMap,
97 const HeaderSearchOptions &HSOpts,
98 const LangOptions &LangOpts, DiagnosticsEngine &Diags)
99 : PrebuiltModuleFiles(PrebuiltModuleFiles),
100 NewModuleFiles(NewModuleFiles),
101 PrebuiltModuleVFSMap(PrebuiltModuleVFSMap), ExistingHSOpts(HSOpts),
102 ExistingLangOpts(LangOpts), Diags(Diags) {}
103
104 bool needsImportVisitation() const override { return true; }
105
106 void visitImport(StringRef ModuleName, StringRef Filename) override {
107 if (PrebuiltModuleFiles.insert({ModuleName.str(), Filename.str()}).second)
108 NewModuleFiles.push_back(Filename.str());
109 }
110
111 void visitModuleFile(StringRef Filename,
112 serialization::ModuleKind Kind) override {
113 CurrentFile = Filename;
114 }
115
117 bool Complain) override {
118 std::vector<std::string> VFSOverlayFiles = HSOpts.VFSOverlayFiles;
119 PrebuiltModuleVFSMap.insert(
120 {CurrentFile, llvm::StringSet<>(VFSOverlayFiles)});
121 return checkHeaderSearchPaths(
122 HSOpts, ExistingHSOpts, Complain ? &Diags : nullptr, ExistingLangOpts);
123 }
124
125private:
126 PrebuiltModuleFilesT &PrebuiltModuleFiles;
127 llvm::SmallVector<std::string> &NewModuleFiles;
128 PrebuiltModuleVFSMapT &PrebuiltModuleVFSMap;
129 const HeaderSearchOptions &ExistingHSOpts;
130 const LangOptions &ExistingLangOpts;
131 DiagnosticsEngine &Diags;
132 std::string CurrentFile;
133};
134
135/// Visit the given prebuilt module and collect all of the modules it
136/// transitively imports and contributing input files.
137static bool visitPrebuiltModule(StringRef PrebuiltModuleFilename,
139 PrebuiltModuleFilesT &ModuleFiles,
140 PrebuiltModuleVFSMapT &PrebuiltModuleVFSMap,
141 DiagnosticsEngine &Diags) {
142 // List of module files to be processed.
144 PrebuiltModuleListener Listener(ModuleFiles, Worklist, PrebuiltModuleVFSMap,
146 Diags);
147
148 Listener.visitModuleFile(PrebuiltModuleFilename,
151 PrebuiltModuleFilename, CI.getFileManager(), CI.getModuleCache(),
153 /*FindModuleFileExtensions=*/false, Listener,
154 /*ValidateDiagnosticOptions=*/false, ASTReader::ARR_OutOfDate))
155 return true;
156
157 while (!Worklist.empty()) {
158 Listener.visitModuleFile(Worklist.back(), serialization::MK_ExplicitModule);
160 Worklist.pop_back_val(), CI.getFileManager(), CI.getModuleCache(),
162 /*FindModuleFileExtensions=*/false, Listener,
163 /*ValidateDiagnosticOptions=*/false))
164 return true;
165 }
166 return false;
167}
168
169/// Transform arbitrary file name into an object-like file name.
170static std::string makeObjFileName(StringRef FileName) {
171 SmallString<128> ObjFileName(FileName);
172 llvm::sys::path::replace_extension(ObjFileName, "o");
173 return std::string(ObjFileName);
174}
175
176/// Deduce the dependency target based on the output file and input files.
177static std::string
178deduceDepTarget(const std::string &OutputFile,
179 const SmallVectorImpl<FrontendInputFile> &InputFiles) {
180 if (OutputFile != "-")
181 return OutputFile;
182
183 if (InputFiles.empty() || !InputFiles.front().isFile())
184 return "clang-scan-deps\\ dependency";
185
186 return makeObjFileName(InputFiles.front().getFile());
187}
188
189/// Sanitize diagnostic options for dependency scan.
190static void sanitizeDiagOpts(DiagnosticOptions &DiagOpts) {
191 // Don't print 'X warnings and Y errors generated'.
192 DiagOpts.ShowCarets = false;
193 // Don't write out diagnostic file.
194 DiagOpts.DiagnosticSerializationFile.clear();
195 // Don't emit warnings except for scanning specific warnings.
196 // TODO: It would be useful to add a more principled way to ignore all
197 // warnings that come from source code. The issue is that we need to
198 // ignore warnings that could be surpressed by
199 // `#pragma clang diagnostic`, while still allowing some scanning
200 // warnings for things we're not ready to turn into errors yet.
201 // See `test/ClangScanDeps/diagnostic-pragmas.c` for an example.
202 llvm::erase_if(DiagOpts.Warnings, [](StringRef Warning) {
203 return llvm::StringSwitch<bool>(Warning)
204 .Cases("pch-vfs-diff", "error=pch-vfs-diff", false)
205 .StartsWith("no-error=", false)
206 .Default(true);
207 });
208}
209
210// Clang implements -D and -U by splatting text into a predefines buffer. This
211// allows constructs such as `-DFඞ=3 "-D F\u{0D9E} 4 3 2”` to be accepted and
212// define the same macro, or adding C++ style comments before the macro name.
213//
214// This function checks that the first non-space characters in the macro
215// obviously form an identifier that can be uniqued on without lexing. Failing
216// to do this could lead to changing the final definition of a macro.
217//
218// We could set up a preprocessor and actually lex the name, but that's very
219// heavyweight for a situation that will almost never happen in practice.
220static std::optional<StringRef> getSimpleMacroName(StringRef Macro) {
221 StringRef Name = Macro.split("=").first.ltrim(" \t");
222 std::size_t I = 0;
223
224 auto FinishName = [&]() -> std::optional<StringRef> {
225 StringRef SimpleName = Name.slice(0, I);
226 if (SimpleName.empty())
227 return std::nullopt;
228 return SimpleName;
229 };
230
231 for (; I != Name.size(); ++I) {
232 switch (Name[I]) {
233 case '(': // Start of macro parameter list
234 case ' ': // End of macro name
235 case '\t':
236 return FinishName();
237 case '_':
238 continue;
239 default:
240 if (llvm::isAlnum(Name[I]))
241 continue;
242 return std::nullopt;
243 }
244 }
245 return FinishName();
246}
247
248static void canonicalizeDefines(PreprocessorOptions &PPOpts) {
249 using MacroOpt = std::pair<StringRef, std::size_t>;
250 std::vector<MacroOpt> SimpleNames;
251 SimpleNames.reserve(PPOpts.Macros.size());
252 std::size_t Index = 0;
253 for (const auto &M : PPOpts.Macros) {
254 auto SName = getSimpleMacroName(M.first);
255 // Skip optimizing if we can't guarantee we can preserve relative order.
256 if (!SName)
257 return;
258 SimpleNames.emplace_back(*SName, Index);
259 ++Index;
260 }
261
262 llvm::stable_sort(SimpleNames, [](const MacroOpt &A, const MacroOpt &B) {
263 return A.first < B.first;
264 });
265 // Keep the last instance of each macro name by going in reverse
266 auto NewEnd = std::unique(
267 SimpleNames.rbegin(), SimpleNames.rend(),
268 [](const MacroOpt &A, const MacroOpt &B) { return A.first == B.first; });
269 SimpleNames.erase(SimpleNames.begin(), NewEnd.base());
270
271 // Apply permutation.
272 decltype(PPOpts.Macros) NewMacros;
273 NewMacros.reserve(SimpleNames.size());
274 for (std::size_t I = 0, E = SimpleNames.size(); I != E; ++I) {
275 std::size_t OriginalIndex = SimpleNames[I].second;
276 // We still emit undefines here as they may be undefining a predefined macro
277 NewMacros.push_back(std::move(PPOpts.Macros[OriginalIndex]));
278 }
279 std::swap(PPOpts.Macros, NewMacros);
280}
281
282/// A clang tool that runs the preprocessor in a mode that's optimized for
283/// dependency scanning for the given compiler invocation.
284class DependencyScanningAction : public tooling::ToolAction {
285public:
286 DependencyScanningAction(
287 StringRef WorkingDirectory, DependencyConsumer &Consumer,
288 DependencyActionController &Controller,
290 ScanningOutputFormat Format, ScanningOptimizations OptimizeArgs,
291 bool EagerLoadModules, bool DisableFree,
292 std::optional<StringRef> ModuleName = std::nullopt)
293 : WorkingDirectory(WorkingDirectory), Consumer(Consumer),
294 Controller(Controller), DepFS(std::move(DepFS)), Format(Format),
295 OptimizeArgs(OptimizeArgs), EagerLoadModules(EagerLoadModules),
296 DisableFree(DisableFree), ModuleName(ModuleName) {}
297
298 bool runInvocation(std::shared_ptr<CompilerInvocation> Invocation,
299 FileManager *DriverFileMgr,
300 std::shared_ptr<PCHContainerOperations> PCHContainerOps,
301 DiagnosticConsumer *DiagConsumer) override {
302 // Make a deep copy of the original Clang invocation.
303 CompilerInvocation OriginalInvocation(*Invocation);
304 // Restore the value of DisableFree, which may be modified by Tooling.
305 OriginalInvocation.getFrontendOpts().DisableFree = DisableFree;
306 if (any(OptimizeArgs & ScanningOptimizations::Macros))
307 canonicalizeDefines(OriginalInvocation.getPreprocessorOpts());
308
309 if (Scanned) {
310 // Scanning runs once for the first -cc1 invocation in a chain of driver
311 // jobs. For any dependent jobs, reuse the scanning result and just
312 // update the LastCC1Arguments to correspond to the new invocation.
313 // FIXME: to support multi-arch builds, each arch requires a separate scan
314 setLastCC1Arguments(std::move(OriginalInvocation));
315 return true;
316 }
317
318 Scanned = true;
319
320 // Create a compiler instance to handle the actual work.
321 ScanInstanceStorage.emplace(std::move(PCHContainerOps));
322 CompilerInstance &ScanInstance = *ScanInstanceStorage;
323 ScanInstance.setInvocation(std::move(Invocation));
324
325 // Create the compiler's actual diagnostics engine.
326 sanitizeDiagOpts(ScanInstance.getDiagnosticOpts());
327 ScanInstance.createDiagnostics(DiagConsumer, /*ShouldOwnClient=*/false);
328 if (!ScanInstance.hasDiagnostics())
329 return false;
330
331 // Some DiagnosticConsumers require that finish() is called.
332 auto DiagConsumerFinisher =
333 llvm::make_scope_exit([DiagConsumer]() { DiagConsumer->finish(); });
334
336 true;
337
338 ScanInstance.getFrontendOpts().GenerateGlobalModuleIndex = false;
339 ScanInstance.getFrontendOpts().UseGlobalModuleIndex = false;
340 ScanInstance.getFrontendOpts().ModulesShareFileManager = false;
341 ScanInstance.getHeaderSearchOpts().ModuleFormat = "raw";
343 any(OptimizeArgs & ScanningOptimizations::VFS);
344
345 // Support for virtual file system overlays.
347 ScanInstance.getInvocation(), ScanInstance.getDiagnostics(),
348 DriverFileMgr->getVirtualFileSystemPtr());
349
350 // Create a new FileManager to match the invocation's FileSystemOptions.
351 auto *FileMgr = ScanInstance.createFileManager(FS);
352 ScanInstance.createSourceManager(*FileMgr);
353
354 // Store the list of prebuilt module files into header search options. This
355 // will prevent the implicit build to create duplicate modules and will
356 // force reuse of the existing prebuilt module files instead.
357 PrebuiltModuleVFSMapT PrebuiltModuleVFSMap;
358 if (!ScanInstance.getPreprocessorOpts().ImplicitPCHInclude.empty())
359 if (visitPrebuiltModule(
361 ScanInstance,
363 PrebuiltModuleVFSMap, ScanInstance.getDiagnostics()))
364 return false;
365
366 // Use the dependency scanning optimized file system if requested to do so.
367 if (DepFS) {
369 DepFS;
371 [LocalDepFS = std::move(LocalDepFS)](FileEntryRef File)
373 if (llvm::ErrorOr<EntryRef> Entry =
374 LocalDepFS->getOrCreateFileSystemEntry(File.getName()))
375 if (LocalDepFS->ensureDirectiveTokensArePopulated(*Entry))
376 return Entry->getDirectiveTokens();
377 return std::nullopt;
378 };
379 }
380
381 // Create the dependency collector that will collect the produced
382 // dependencies.
383 //
384 // This also moves the existing dependency output options from the
385 // invocation to the collector. The options in the invocation are reset,
386 // which ensures that the compiler won't create new dependency collectors,
387 // and thus won't write out the extra '.d' files to disk.
388 auto Opts = std::make_unique<DependencyOutputOptions>();
389 std::swap(*Opts, ScanInstance.getInvocation().getDependencyOutputOpts());
390 // We need at least one -MT equivalent for the generator of make dependency
391 // files to work.
392 if (Opts->Targets.empty())
393 Opts->Targets = {
394 deduceDepTarget(ScanInstance.getFrontendOpts().OutputFile,
395 ScanInstance.getFrontendOpts().Inputs)};
396 Opts->IncludeSystemHeaders = true;
397
398 switch (Format) {
399 case ScanningOutputFormat::Make:
400 ScanInstance.addDependencyCollector(
401 std::make_shared<DependencyConsumerForwarder>(
402 std::move(Opts), WorkingDirectory, Consumer));
403 break;
404 case ScanningOutputFormat::P1689:
405 case ScanningOutputFormat::Full:
406 MDC = std::make_shared<ModuleDepCollector>(
407 std::move(Opts), ScanInstance, Consumer, Controller,
408 OriginalInvocation, std::move(PrebuiltModuleVFSMap), OptimizeArgs,
409 EagerLoadModules, Format == ScanningOutputFormat::P1689);
410 ScanInstance.addDependencyCollector(MDC);
411 break;
412 }
413
414 // Consider different header search and diagnostic options to create
415 // different modules. This avoids the unsound aliasing of module PCMs.
416 //
417 // TODO: Implement diagnostic bucketing to reduce the impact of strict
418 // context hashing.
419 ScanInstance.getHeaderSearchOpts().ModulesStrictContextHash = true;
423 true;
424
425 // Avoid some checks and module map parsing when loading PCM files.
426 ScanInstance.getPreprocessorOpts().ModulesCheckRelocated = false;
427
428 std::unique_ptr<FrontendAction> Action;
429
430 if (ModuleName)
431 Action = std::make_unique<GetDependenciesByModuleNameAction>(*ModuleName);
432 else
433 Action = std::make_unique<ReadPCHAndPreprocessAction>();
434
435 if (ScanInstance.getDiagnostics().hasErrorOccurred())
436 return false;
437
438 // Each action is responsible for calling finish.
439 DiagConsumerFinisher.release();
440 const bool Result = ScanInstance.ExecuteAction(*Action);
441
442 if (Result)
443 setLastCC1Arguments(std::move(OriginalInvocation));
444
445 return Result;
446 }
447
448 bool hasScanned() const { return Scanned; }
449
450 /// Take the cc1 arguments corresponding to the most recent invocation used
451 /// with this action. Any modifications implied by the discovered dependencies
452 /// will have already been applied.
453 std::vector<std::string> takeLastCC1Arguments() {
454 std::vector<std::string> Result;
455 std::swap(Result, LastCC1Arguments); // Reset LastCC1Arguments to empty.
456 return Result;
457 }
458
459private:
460 void setLastCC1Arguments(CompilerInvocation &&CI) {
461 if (MDC)
462 MDC->applyDiscoveredDependencies(CI);
463 LastCC1Arguments = CI.getCC1CommandLine();
464 }
465
466private:
467 StringRef WorkingDirectory;
468 DependencyConsumer &Consumer;
469 DependencyActionController &Controller;
472 ScanningOptimizations OptimizeArgs;
473 bool EagerLoadModules;
474 bool DisableFree;
475 std::optional<StringRef> ModuleName;
476 std::optional<CompilerInstance> ScanInstanceStorage;
477 std::shared_ptr<ModuleDepCollector> MDC;
478 std::vector<std::string> LastCC1Arguments;
479 bool Scanned = false;
480};
481
482} // end anonymous namespace
483
487 : Format(Service.getFormat()), OptimizeArgs(Service.getOptimizeArgs()),
488 EagerLoadModules(Service.shouldEagerLoadModules()) {
489 PCHContainerOps = std::make_shared<PCHContainerOperations>();
490 // We need to read object files from PCH built outside the scanner.
491 PCHContainerOps->registerReader(
492 std::make_unique<ObjectFilePCHContainerReader>());
493 // The scanner itself writes only raw ast files.
494 PCHContainerOps->registerWriter(std::make_unique<RawPCHContainerWriter>());
495
496 switch (Service.getMode()) {
498 DepFS =
500 BaseFS = DepFS;
501 break;
503 DepFS = nullptr;
504 BaseFS = FS;
505 break;
506 }
507}
508
510 StringRef WorkingDirectory, const std::vector<std::string> &CommandLine,
511 DependencyConsumer &Consumer, DependencyActionController &Controller,
512 std::optional<StringRef> ModuleName) {
513 std::vector<const char *> CLI;
514 for (const std::string &Arg : CommandLine)
515 CLI.push_back(Arg.c_str());
516 auto DiagOpts = CreateAndPopulateDiagOpts(CLI);
517 sanitizeDiagOpts(*DiagOpts);
518
519 // Capture the emitted diagnostics and report them to the client
520 // in the case of a failure.
521 std::string DiagnosticOutput;
522 llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput);
523 TextDiagnosticPrinter DiagPrinter(DiagnosticsOS, DiagOpts.release());
524
525 if (computeDependencies(WorkingDirectory, CommandLine, Consumer, Controller,
526 DiagPrinter, ModuleName))
527 return llvm::Error::success();
528 return llvm::make_error<llvm::StringError>(DiagnosticsOS.str(),
529 llvm::inconvertibleErrorCode());
530}
531
534 llvm::function_ref<bool(const driver::Command &Cmd)> Callback) {
536 Argv.reserve(ArgStrs.size());
537 for (const std::string &Arg : ArgStrs)
538 Argv.push_back(Arg.c_str());
539
540 llvm::vfs::FileSystem *FS = &FM.getVirtualFileSystem();
541
542 std::unique_ptr<driver::Driver> Driver = std::make_unique<driver::Driver>(
543 Argv[0], llvm::sys::getDefaultTargetTriple(), Diags,
544 "clang LLVM compiler", FS);
545 Driver->setTitle("clang_based_tool");
546
547 llvm::BumpPtrAllocator Alloc;
548 bool CLMode = driver::IsClangCL(
549 driver::getDriverMode(Argv[0], ArrayRef(Argv).slice(1)));
550
551 if (llvm::Error E = driver::expandResponseFiles(Argv, CLMode, Alloc, FS)) {
552 Diags.Report(diag::err_drv_expand_response_file)
553 << llvm::toString(std::move(E));
554 return false;
555 }
556
557 const std::unique_ptr<driver::Compilation> Compilation(
558 Driver->BuildCompilation(llvm::ArrayRef(Argv)));
559 if (!Compilation)
560 return false;
561
562 if (Compilation->containsError())
563 return false;
564
565 for (const driver::Command &Job : Compilation->getJobs()) {
566 if (!Callback(Job))
567 return false;
568 }
569 return true;
570}
571
573 std::vector<std::string> CommandLine, DependencyScanningAction &Action,
574 FileManager &FM,
575 std::shared_ptr<clang::PCHContainerOperations> &PCHContainerOps,
576 DiagnosticsEngine &Diags, DependencyConsumer &Consumer) {
577
578 // Save executable path before providing CommandLine to ToolInvocation
579 std::string Executable = CommandLine[0];
580 ToolInvocation Invocation(std::move(CommandLine), &Action, &FM,
581 PCHContainerOps);
582 Invocation.setDiagnosticConsumer(Diags.getClient());
583 Invocation.setDiagnosticOptions(&Diags.getDiagnosticOptions());
584 if (!Invocation.run())
585 return false;
586
587 std::vector<std::string> Args = Action.takeLastCC1Arguments();
588 Consumer.handleBuildCommand({std::move(Executable), std::move(Args)});
589 return true;
590}
591
593 StringRef WorkingDirectory, const std::vector<std::string> &CommandLine,
594 DependencyConsumer &Consumer, DependencyActionController &Controller,
595 DiagnosticConsumer &DC, std::optional<StringRef> ModuleName) {
596 // Reset what might have been modified in the previous worker invocation.
597 BaseFS->setCurrentWorkingDirectory(WorkingDirectory);
598
599 std::optional<std::vector<std::string>> ModifiedCommandLine;
601
602 // If we're scanning based on a module name alone, we don't expect the client
603 // to provide us with an input file. However, the driver really wants to have
604 // one. Let's just make it up to make the driver happy.
605 if (ModuleName) {
606 auto OverlayFS =
607 llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(BaseFS);
608 auto InMemoryFS =
609 llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
610 InMemoryFS->setCurrentWorkingDirectory(WorkingDirectory);
611 OverlayFS->pushOverlay(InMemoryFS);
612 ModifiedFS = OverlayFS;
613
614 SmallString<128> FakeInputPath;
615 // TODO: We should retry the creation if the path already exists.
616 llvm::sys::fs::createUniquePath(*ModuleName + "-%%%%%%%%.input",
617 FakeInputPath,
618 /*MakeAbsolute=*/false);
619 InMemoryFS->addFile(FakeInputPath, 0, llvm::MemoryBuffer::getMemBuffer(""));
620
621 ModifiedCommandLine = CommandLine;
622 ModifiedCommandLine->emplace_back(FakeInputPath);
623 }
624
625 const std::vector<std::string> &FinalCommandLine =
626 ModifiedCommandLine ? *ModifiedCommandLine : CommandLine;
627 auto &FinalFS = ModifiedFS ? ModifiedFS : BaseFS;
628
629 auto FileMgr =
630 llvm::makeIntrusiveRefCnt<FileManager>(FileSystemOptions{}, FinalFS);
631
632 std::vector<const char *> FinalCCommandLine(FinalCommandLine.size(), nullptr);
633 llvm::transform(FinalCommandLine, FinalCCommandLine.begin(),
634 [](const std::string &Str) { return Str.c_str(); });
635
636 auto DiagOpts = CreateAndPopulateDiagOpts(FinalCCommandLine);
637 sanitizeDiagOpts(*DiagOpts);
639 CompilerInstance::createDiagnostics(DiagOpts.release(), &DC,
640 /*ShouldOwnClient=*/false);
641
642 // Although `Diagnostics` are used only for command-line parsing, the
643 // custom `DiagConsumer` might expect a `SourceManager` to be present.
644 SourceManager SrcMgr(*Diags, *FileMgr);
645 Diags->setSourceManager(&SrcMgr);
646 // DisableFree is modified by Tooling for running
647 // in-process; preserve the original value, which is
648 // always true for a driver invocation.
649 bool DisableFree = true;
650 DependencyScanningAction Action(WorkingDirectory, Consumer, Controller, DepFS,
651 Format, OptimizeArgs, EagerLoadModules,
652 DisableFree, ModuleName);
653
654 bool Success = false;
655 if (FinalCommandLine[1] == "-cc1") {
656 Success = createAndRunToolInvocation(FinalCommandLine, Action, *FileMgr,
657 PCHContainerOps, *Diags, Consumer);
658 } else {
660 FinalCommandLine, *Diags, *FileMgr, [&](const driver::Command &Cmd) {
661 if (StringRef(Cmd.getCreator().getName()) != "clang") {
662 // Non-clang command. Just pass through to the dependency
663 // consumer.
664 Consumer.handleBuildCommand(
665 {Cmd.getExecutable(),
666 {Cmd.getArguments().begin(), Cmd.getArguments().end()}});
667 return true;
668 }
669
670 // Insert -cc1 comand line options into Argv
671 std::vector<std::string> Argv;
672 Argv.push_back(Cmd.getExecutable());
673 Argv.insert(Argv.end(), Cmd.getArguments().begin(),
674 Cmd.getArguments().end());
675
676 // Create an invocation that uses the underlying file
677 // system to ensure that any file system requests that
678 // are made by the driver do not go through the
679 // dependency scanning filesystem.
680 return createAndRunToolInvocation(std::move(Argv), Action, *FileMgr,
681 PCHContainerOps, *Diags, Consumer);
682 });
683 }
684
685 if (Success && !Action.hasScanned())
686 Diags->Report(diag::err_fe_expected_compiler_job)
687 << llvm::join(FinalCommandLine, " ");
688 return Success && Action.hasScanned();
689}
690
static bool forEachDriverJob(ArrayRef< std::string > ArgStrs, DiagnosticsEngine &Diags, FileManager &FM, llvm::function_ref< bool(const driver::Command &Cmd)> Callback)
static bool createAndRunToolInvocation(std::vector< std::string > CommandLine, DependencyScanningAction &Action, FileManager &FM, std::shared_ptr< clang::PCHContainerOperations > &PCHContainerOps, DiagnosticsEngine &Diags, DependencyConsumer &Consumer)
StringRef Filename
Definition: Format.cpp:2969
CompileCommand Cmd
Abstract interface for callback invocations by the ASTReader.
Definition: ASTReader.h:114
virtual bool ReadHeaderSearchPaths(const HeaderSearchOptions &HSOpts, bool Complain)
Receives the header search paths.
Definition: ASTReader.h:189
virtual void visitImport(StringRef ModuleName, StringRef Filename)
If needsImportVisitation returns true, this is called for each AST file imported by this AST file.
Definition: ASTReader.h:241
virtual void visitModuleFile(StringRef Filename, serialization::ModuleKind Kind)
This is called for each AST file loaded.
Definition: ASTReader.h:213
virtual bool needsImportVisitation() const
Returns true if this ASTReaderListener wants to receive the imports of the AST file via visitImport,...
Definition: ASTReader.h:237
@ ARR_OutOfDate
The client can handle an AST file that cannot load because it is out-of-date relative to its input fi...
Definition: ASTReader.h:1609
static bool readASTFileControlBlock(StringRef Filename, FileManager &FileMgr, const InMemoryModuleCache &ModuleCache, const PCHContainerReader &PCHContainerRdr, bool FindModuleFileExtensions, ASTReaderListener &Listener, bool ValidateDiagnosticOptions, unsigned ClientLoadCapabilities=ARR_ConfigurationMismatch|ARR_OutOfDate)
Read the control block for the named AST file.
Definition: ASTReader.cpp:5397
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
void createSourceManager(FileManager &FileMgr)
Create the source manager and replace any existing one with it.
void createDiagnostics(DiagnosticConsumer *Client=nullptr, bool ShouldOwnClient=true)
Create the diagnostics engine using the invocation's diagnostic options and replace any existing one ...
FileManager * createFileManager(IntrusiveRefCntPtr< llvm::vfs::FileSystem > VFS=nullptr)
Create the file manager and replace any existing one with it.
const PCHContainerReader & getPCHContainerReader() const
Return the appropriate PCHContainerReader depending on the current CodeGenOptions.
DiagnosticsEngine & getDiagnostics() const
Get the current diagnostics engine.
void setInvocation(std::shared_ptr< CompilerInvocation > Value)
setInvocation - Replace the current invocation.
FileManager & getFileManager() const
Return the current file manager to the caller.
InMemoryModuleCache & getModuleCache() const
void addDependencyCollector(std::shared_ptr< DependencyCollector > Listener)
FrontendOptions & getFrontendOpts()
HeaderSearchOptions & getHeaderSearchOpts()
CompilerInvocation & getInvocation()
PreprocessorOptions & getPreprocessorOpts()
bool ExecuteAction(FrontendAction &Act)
ExecuteAction - Execute the provided action against the compiler's CompilerInvocation object.
DiagnosticOptions & getDiagnosticOpts()
LangOptions & getLangOpts()
Helper class for holding the data necessary to invoke the compiler.
DependencyOutputOptions & getDependencyOutputOpts()
ArrayRef< std::string > getDependencies() const
Definition: Utils.h:69
Builds a dependency file when attached to a Preprocessor (for includes) and ASTReader (for module imp...
Definition: Utils.h:104
void finishedMainFile(DiagnosticsEngine &Diags) override
Called when the end of the main file is reached.
Abstract interface, implemented by clients of the front-end, which formats and prints fully processed...
Definition: Diagnostic.h:1745
virtual void finish()
Callback to inform the diagnostic client that processing of all source files has ended.
Definition: Diagnostic.h:1781
Options for controlling the compiler diagnostics engine.
std::vector< std::string > Warnings
The list of -W... options used to alter the diagnostic mappings, with the prefixes removed.
std::string DiagnosticSerializationFile
The file to serialize diagnostics to (non-appending).
Concrete class used by the front-end to report problems and issues.
Definition: Diagnostic.h:192
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
Definition: Diagnostic.h:1547
bool hasErrorOccurred() const
Definition: Diagnostic.h:843
DiagnosticOptions & getDiagnosticOptions() const
Retrieve the diagnostic options.
Definition: Diagnostic.h:562
DiagnosticConsumer * getClient()
Definition: Diagnostic.h:572
A reference to a FileEntry that includes the name of the file as it was accessed by the FileManager's...
Definition: FileEntry.h:57
Implements support for file system lookup, file system caching, and directory search management.
Definition: FileManager.h:53
llvm::vfs::FileSystem & getVirtualFileSystem() const
Definition: FileManager.h:245
llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > getVirtualFileSystemPtr() const
Definition: FileManager.h:247
Keeps track of options that affect how file operations are performed.
unsigned ModulesShareFileManager
Whether to share the FileManager when building modules.
std::string OutputFile
The output file, if any.
unsigned GenerateGlobalModuleIndex
Whether we can generate the global module index if needed.
SmallVector< FrontendInputFile, 0 > Inputs
The input files and their types.
unsigned UseGlobalModuleIndex
Whether we can use the global module index if available.
HeaderSearchOptions - Helper class for storing options related to the initialization of the HeaderSea...
unsigned ModulesStrictContextHash
Whether we should include all things that could impact the module in the hash.
std::map< std::string, std::string, std::less<> > PrebuiltModuleFiles
The mapping of module names to prebuilt module files.
unsigned ModulesSkipHeaderSearchPaths
Whether to entirely skip writing header search paths.
std::string ModuleFormat
The module/pch container format.
unsigned ModulesSkipDiagnosticOptions
Whether to entirely skip writing diagnostic options.
std::vector< std::string > VFSOverlayFiles
The set of user-provided virtual filesystem overlay files.
unsigned ModulesSkipPragmaDiagnosticMappings
Whether to entirely skip writing pragma diagnostic mappings.
unsigned ModulesIncludeVFSUsage
Whether to include ivfsoverlay usage information in written AST files.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:449
PreprocessorOptions - This class is used for passing the various options used in preprocessor initial...
bool ModulesCheckRelocated
Perform extra checks when loading PCM files for mutable file systems.
std::string ImplicitPCHInclude
The implicit PCH included at the start of the translation unit, or empty.
bool AllowPCHWithDifferentModulesCachePath
When true, a PCH with modules cache path different to the current compilation will not be rejected.
std::vector< std::pair< std::string, bool > > Macros
std::function< std::optional< ArrayRef< dependency_directives_scan::Directive > >(FileEntryRef)> DependencyDirectivesForFile
Function for getting the dependency preprocessor directives of a file.
This class handles loading and caching of source files into memory.
The base class of the type hierarchy.
Definition: Type.h:1607
Command - An executable path/name and argument vector to execute.
Definition: Job.h:106
Interface to process a clang::CompilerInvocation.
Definition: Tooling.h:80
virtual bool runInvocation(std::shared_ptr< CompilerInvocation > Invocation, FileManager *Files, std::shared_ptr< PCHContainerOperations > PCHContainerOps, DiagnosticConsumer *DiagConsumer)=0
Perform an action for an invocation.
Utility to run a FrontendAction in a single clang invocation.
Definition: Tooling.h:239
void setDiagnosticConsumer(DiagnosticConsumer *DiagConsumer)
Set a DiagnosticConsumer to use during driver command-line parsing and the action invocation itself.
Definition: Tooling.h:275
void setDiagnosticOptions(DiagnosticOptions *DiagOpts)
Set a DiagnosticOptions to use during driver command-line parsing.
Definition: Tooling.h:280
bool run()
Run the clang invocation.
Definition: Tooling.cpp:372
Dependency scanner callbacks that are used during scanning to influence the behaviour of the scan - f...
The dependency scanning service contains shared configuration and state that is used by the individua...
DependencyScanningFilesystemSharedCache & getSharedCache()
A virtual file system optimized for the dependency discovery.
bool computeDependencies(StringRef WorkingDirectory, const std::vector< std::string > &CommandLine, DependencyConsumer &DepConsumer, DependencyActionController &Controller, DiagnosticConsumer &DiagConsumer, std::optional< StringRef > ModuleName=std::nullopt)
Run the dependency scanning tool for a given clang driver command-line, and report the discovered dep...
DependencyScanningWorker(DependencyScanningService &Service, llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > FS)
llvm::StringRef getDriverMode(StringRef ProgName, ArrayRef< const char * > Args)
Returns the driver mode option's value, i.e.
Definition: Driver.cpp:6666
llvm::Error expandResponseFiles(SmallVectorImpl< const char * > &Args, bool ClangCLMode, llvm::BumpPtrAllocator &Alloc, llvm::vfs::FileSystem *FS=nullptr)
Expand response files from a clang driver or cc1 invocation.
Definition: Driver.cpp:6683
bool IsClangCL(StringRef DriverMode)
Checks whether the value produced by getDriverMode is for CL mode.
Definition: Driver.cpp:6681
ModuleKind
Specifies the kind of module that has been loaded.
Definition: ModuleFile.h:42
@ MK_ExplicitModule
File is an explicitly-loaded module.
Definition: ModuleFile.h:47
ScanningOutputFormat
The format that is output by the dependency scanner.
@ 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.
llvm::StringMap< llvm::StringSet<> > PrebuiltModuleVFSMapT
The JSON file list parser is used to communicate input to InstallAPI.
std::unique_ptr< DiagnosticOptions > CreateAndPopulateDiagOpts(ArrayRef< const char * > Argv)
@ Result
The result type of a method or function.
IntrusiveRefCntPtr< llvm::vfs::FileSystem > createVFSFromCompilerInvocation(const CompilerInvocation &CI, DiagnosticsEngine &Diags)
@ Success
Template argument deduction was successful.
Definition: Format.h:5378
int __ovld __cnfn any(char)
Returns 1 if the most significant bit in any component of x is set; otherwise returns 0.