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 [LocalDepFS = DepFS](FileEntryRef File)
371 if (llvm::ErrorOr<EntryRef> Entry =
372 LocalDepFS->getOrCreateFileSystemEntry(File.getName()))
373 if (LocalDepFS->ensureDirectiveTokensArePopulated(*Entry))
374 return Entry->getDirectiveTokens();
375 return std::nullopt;
376 };
377
378 // Create the dependency collector that will collect the produced
379 // dependencies.
380 //
381 // This also moves the existing dependency output options from the
382 // invocation to the collector. The options in the invocation are reset,
383 // which ensures that the compiler won't create new dependency collectors,
384 // and thus won't write out the extra '.d' files to disk.
385 auto Opts = std::make_unique<DependencyOutputOptions>();
386 std::swap(*Opts, ScanInstance.getInvocation().getDependencyOutputOpts());
387 // We need at least one -MT equivalent for the generator of make dependency
388 // files to work.
389 if (Opts->Targets.empty())
390 Opts->Targets = {
391 deduceDepTarget(ScanInstance.getFrontendOpts().OutputFile,
392 ScanInstance.getFrontendOpts().Inputs)};
393 Opts->IncludeSystemHeaders = true;
394
395 switch (Format) {
396 case ScanningOutputFormat::Make:
397 ScanInstance.addDependencyCollector(
398 std::make_shared<DependencyConsumerForwarder>(
399 std::move(Opts), WorkingDirectory, Consumer));
400 break;
401 case ScanningOutputFormat::P1689:
402 case ScanningOutputFormat::Full:
403 MDC = std::make_shared<ModuleDepCollector>(
404 std::move(Opts), ScanInstance, Consumer, Controller,
405 OriginalInvocation, std::move(PrebuiltModuleVFSMap), OptimizeArgs,
406 EagerLoadModules, Format == ScanningOutputFormat::P1689);
407 ScanInstance.addDependencyCollector(MDC);
408 break;
409 }
410
411 // Consider different header search and diagnostic options to create
412 // different modules. This avoids the unsound aliasing of module PCMs.
413 //
414 // TODO: Implement diagnostic bucketing to reduce the impact of strict
415 // context hashing.
416 ScanInstance.getHeaderSearchOpts().ModulesStrictContextHash = true;
420 true;
421
422 // Avoid some checks and module map parsing when loading PCM files.
423 ScanInstance.getPreprocessorOpts().ModulesCheckRelocated = false;
424
425 std::unique_ptr<FrontendAction> Action;
426
427 if (ModuleName)
428 Action = std::make_unique<GetDependenciesByModuleNameAction>(*ModuleName);
429 else
430 Action = std::make_unique<ReadPCHAndPreprocessAction>();
431
432 if (ScanInstance.getDiagnostics().hasErrorOccurred())
433 return false;
434
435 // Each action is responsible for calling finish.
436 DiagConsumerFinisher.release();
437 const bool Result = ScanInstance.ExecuteAction(*Action);
438
439 if (Result)
440 setLastCC1Arguments(std::move(OriginalInvocation));
441
442 return Result;
443 }
444
445 bool hasScanned() const { return Scanned; }
446
447 /// Take the cc1 arguments corresponding to the most recent invocation used
448 /// with this action. Any modifications implied by the discovered dependencies
449 /// will have already been applied.
450 std::vector<std::string> takeLastCC1Arguments() {
451 std::vector<std::string> Result;
452 std::swap(Result, LastCC1Arguments); // Reset LastCC1Arguments to empty.
453 return Result;
454 }
455
456private:
457 void setLastCC1Arguments(CompilerInvocation &&CI) {
458 if (MDC)
459 MDC->applyDiscoveredDependencies(CI);
460 LastCC1Arguments = CI.getCC1CommandLine();
461 }
462
463private:
464 StringRef WorkingDirectory;
465 DependencyConsumer &Consumer;
466 DependencyActionController &Controller;
469 ScanningOptimizations OptimizeArgs;
470 bool EagerLoadModules;
471 bool DisableFree;
472 std::optional<StringRef> ModuleName;
473 std::optional<CompilerInstance> ScanInstanceStorage;
474 std::shared_ptr<ModuleDepCollector> MDC;
475 std::vector<std::string> LastCC1Arguments;
476 bool Scanned = false;
477};
478
479} // end anonymous namespace
480
484 : Format(Service.getFormat()), OptimizeArgs(Service.getOptimizeArgs()),
485 EagerLoadModules(Service.shouldEagerLoadModules()) {
486 PCHContainerOps = std::make_shared<PCHContainerOperations>();
487 // We need to read object files from PCH built outside the scanner.
488 PCHContainerOps->registerReader(
489 std::make_unique<ObjectFilePCHContainerReader>());
490 // The scanner itself writes only raw ast files.
491 PCHContainerOps->registerWriter(std::make_unique<RawPCHContainerWriter>());
492
493 switch (Service.getMode()) {
495 DepFS =
497 BaseFS = DepFS;
498 break;
500 DepFS = nullptr;
501 BaseFS = FS;
502 break;
503 }
504}
505
507 StringRef WorkingDirectory, const std::vector<std::string> &CommandLine,
508 DependencyConsumer &Consumer, DependencyActionController &Controller,
509 std::optional<StringRef> ModuleName) {
510 std::vector<const char *> CLI;
511 for (const std::string &Arg : CommandLine)
512 CLI.push_back(Arg.c_str());
513 auto DiagOpts = CreateAndPopulateDiagOpts(CLI);
514 sanitizeDiagOpts(*DiagOpts);
515
516 // Capture the emitted diagnostics and report them to the client
517 // in the case of a failure.
518 std::string DiagnosticOutput;
519 llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput);
520 TextDiagnosticPrinter DiagPrinter(DiagnosticsOS, DiagOpts.release());
521
522 if (computeDependencies(WorkingDirectory, CommandLine, Consumer, Controller,
523 DiagPrinter, ModuleName))
524 return llvm::Error::success();
525 return llvm::make_error<llvm::StringError>(DiagnosticsOS.str(),
526 llvm::inconvertibleErrorCode());
527}
528
531 llvm::function_ref<bool(const driver::Command &Cmd)> Callback) {
533 Argv.reserve(ArgStrs.size());
534 for (const std::string &Arg : ArgStrs)
535 Argv.push_back(Arg.c_str());
536
537 llvm::vfs::FileSystem *FS = &FM.getVirtualFileSystem();
538
539 std::unique_ptr<driver::Driver> Driver = std::make_unique<driver::Driver>(
540 Argv[0], llvm::sys::getDefaultTargetTriple(), Diags,
541 "clang LLVM compiler", FS);
542 Driver->setTitle("clang_based_tool");
543
544 llvm::BumpPtrAllocator Alloc;
545 bool CLMode = driver::IsClangCL(
546 driver::getDriverMode(Argv[0], ArrayRef(Argv).slice(1)));
547
548 if (llvm::Error E = driver::expandResponseFiles(Argv, CLMode, Alloc, FS)) {
549 Diags.Report(diag::err_drv_expand_response_file)
550 << llvm::toString(std::move(E));
551 return false;
552 }
553
554 const std::unique_ptr<driver::Compilation> Compilation(
555 Driver->BuildCompilation(llvm::ArrayRef(Argv)));
556 if (!Compilation)
557 return false;
558
559 if (Compilation->containsError())
560 return false;
561
562 for (const driver::Command &Job : Compilation->getJobs()) {
563 if (!Callback(Job))
564 return false;
565 }
566 return true;
567}
568
570 std::vector<std::string> CommandLine, DependencyScanningAction &Action,
571 FileManager &FM,
572 std::shared_ptr<clang::PCHContainerOperations> &PCHContainerOps,
573 DiagnosticsEngine &Diags, DependencyConsumer &Consumer) {
574
575 // Save executable path before providing CommandLine to ToolInvocation
576 std::string Executable = CommandLine[0];
577 ToolInvocation Invocation(std::move(CommandLine), &Action, &FM,
578 PCHContainerOps);
579 Invocation.setDiagnosticConsumer(Diags.getClient());
580 Invocation.setDiagnosticOptions(&Diags.getDiagnosticOptions());
581 if (!Invocation.run())
582 return false;
583
584 std::vector<std::string> Args = Action.takeLastCC1Arguments();
585 Consumer.handleBuildCommand({std::move(Executable), std::move(Args)});
586 return true;
587}
588
590 StringRef WorkingDirectory, const std::vector<std::string> &CommandLine,
591 DependencyConsumer &Consumer, DependencyActionController &Controller,
592 DiagnosticConsumer &DC, std::optional<StringRef> ModuleName) {
593 // Reset what might have been modified in the previous worker invocation.
594 BaseFS->setCurrentWorkingDirectory(WorkingDirectory);
595
596 std::optional<std::vector<std::string>> ModifiedCommandLine;
598
599 // If we're scanning based on a module name alone, we don't expect the client
600 // to provide us with an input file. However, the driver really wants to have
601 // one. Let's just make it up to make the driver happy.
602 if (ModuleName) {
603 auto OverlayFS =
604 llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(BaseFS);
605 auto InMemoryFS =
606 llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
607 InMemoryFS->setCurrentWorkingDirectory(WorkingDirectory);
608 OverlayFS->pushOverlay(InMemoryFS);
609 ModifiedFS = OverlayFS;
610
611 SmallString<128> FakeInputPath;
612 // TODO: We should retry the creation if the path already exists.
613 llvm::sys::fs::createUniquePath(*ModuleName + "-%%%%%%%%.input",
614 FakeInputPath,
615 /*MakeAbsolute=*/false);
616 InMemoryFS->addFile(FakeInputPath, 0, llvm::MemoryBuffer::getMemBuffer(""));
617
618 ModifiedCommandLine = CommandLine;
619 ModifiedCommandLine->emplace_back(FakeInputPath);
620 }
621
622 const std::vector<std::string> &FinalCommandLine =
623 ModifiedCommandLine ? *ModifiedCommandLine : CommandLine;
624 auto &FinalFS = ModifiedFS ? ModifiedFS : BaseFS;
625
626 auto FileMgr =
627 llvm::makeIntrusiveRefCnt<FileManager>(FileSystemOptions{}, FinalFS);
628
629 std::vector<const char *> FinalCCommandLine(FinalCommandLine.size(), nullptr);
630 llvm::transform(FinalCommandLine, FinalCCommandLine.begin(),
631 [](const std::string &Str) { return Str.c_str(); });
632
633 auto DiagOpts = CreateAndPopulateDiagOpts(FinalCCommandLine);
634 sanitizeDiagOpts(*DiagOpts);
636 CompilerInstance::createDiagnostics(DiagOpts.release(), &DC,
637 /*ShouldOwnClient=*/false);
638
639 // Although `Diagnostics` are used only for command-line parsing, the
640 // custom `DiagConsumer` might expect a `SourceManager` to be present.
641 SourceManager SrcMgr(*Diags, *FileMgr);
642 Diags->setSourceManager(&SrcMgr);
643 // DisableFree is modified by Tooling for running
644 // in-process; preserve the original value, which is
645 // always true for a driver invocation.
646 bool DisableFree = true;
647 DependencyScanningAction Action(WorkingDirectory, Consumer, Controller, DepFS,
648 Format, OptimizeArgs, EagerLoadModules,
649 DisableFree, ModuleName);
650
651 bool Success = false;
652 if (FinalCommandLine[1] == "-cc1") {
653 Success = createAndRunToolInvocation(FinalCommandLine, Action, *FileMgr,
654 PCHContainerOps, *Diags, Consumer);
655 } else {
657 FinalCommandLine, *Diags, *FileMgr, [&](const driver::Command &Cmd) {
658 if (StringRef(Cmd.getCreator().getName()) != "clang") {
659 // Non-clang command. Just pass through to the dependency
660 // consumer.
661 Consumer.handleBuildCommand(
662 {Cmd.getExecutable(),
663 {Cmd.getArguments().begin(), Cmd.getArguments().end()}});
664 return true;
665 }
666
667 // Insert -cc1 comand line options into Argv
668 std::vector<std::string> Argv;
669 Argv.push_back(Cmd.getExecutable());
670 Argv.insert(Argv.end(), Cmd.getArguments().begin(),
671 Cmd.getArguments().end());
672
673 // Create an invocation that uses the underlying file
674 // system to ensure that any file system requests that
675 // are made by the driver do not go through the
676 // dependency scanning filesystem.
677 return createAndRunToolInvocation(std::move(Argv), Action, *FileMgr,
678 PCHContainerOps, *Diags, Consumer);
679 });
680 }
681
682 if (Success && !Action.hasScanned())
683 Diags->Report(diag::err_fe_expected_compiler_job)
684 << llvm::join(FinalCommandLine, " ");
685 return Success && Action.hasScanned();
686}
687
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:2972
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:1631
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:5409
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:454
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:6679
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:6696
bool IsClangCL(StringRef DriverMode)
Checks whether the value produced by getDriverMode is for CL mode.
Definition: Driver.cpp:6694
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:5394
int __ovld __cnfn any(char)
Returns 1 if the most significant bit in any component of x is set; otherwise returns 0.