clang 20.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/Driver/Driver.h"
15#include "clang/Driver/Job.h"
16#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, llvm::less_first());
263 // Keep the last instance of each macro name by going in reverse
264 auto NewEnd = std::unique(
265 SimpleNames.rbegin(), SimpleNames.rend(),
266 [](const MacroOpt &A, const MacroOpt &B) { return A.first == B.first; });
267 SimpleNames.erase(SimpleNames.begin(), NewEnd.base());
268
269 // Apply permutation.
270 decltype(PPOpts.Macros) NewMacros;
271 NewMacros.reserve(SimpleNames.size());
272 for (std::size_t I = 0, E = SimpleNames.size(); I != E; ++I) {
273 std::size_t OriginalIndex = SimpleNames[I].second;
274 // We still emit undefines here as they may be undefining a predefined macro
275 NewMacros.push_back(std::move(PPOpts.Macros[OriginalIndex]));
276 }
277 std::swap(PPOpts.Macros, NewMacros);
278}
279
280/// A clang tool that runs the preprocessor in a mode that's optimized for
281/// dependency scanning for the given compiler invocation.
282class DependencyScanningAction : public tooling::ToolAction {
283public:
284 DependencyScanningAction(
285 StringRef WorkingDirectory, DependencyConsumer &Consumer,
286 DependencyActionController &Controller,
288 ScanningOutputFormat Format, ScanningOptimizations OptimizeArgs,
289 bool EagerLoadModules, bool DisableFree,
290 std::optional<StringRef> ModuleName = std::nullopt)
291 : WorkingDirectory(WorkingDirectory), Consumer(Consumer),
292 Controller(Controller), DepFS(std::move(DepFS)), Format(Format),
293 OptimizeArgs(OptimizeArgs), EagerLoadModules(EagerLoadModules),
294 DisableFree(DisableFree), ModuleName(ModuleName) {}
295
296 bool runInvocation(std::shared_ptr<CompilerInvocation> Invocation,
297 FileManager *DriverFileMgr,
298 std::shared_ptr<PCHContainerOperations> PCHContainerOps,
299 DiagnosticConsumer *DiagConsumer) override {
300 // Make a deep copy of the original Clang invocation.
301 CompilerInvocation OriginalInvocation(*Invocation);
302 // Restore the value of DisableFree, which may be modified by Tooling.
303 OriginalInvocation.getFrontendOpts().DisableFree = DisableFree;
304 if (any(OptimizeArgs & ScanningOptimizations::Macros))
305 canonicalizeDefines(OriginalInvocation.getPreprocessorOpts());
306
307 if (Scanned) {
308 // Scanning runs once for the first -cc1 invocation in a chain of driver
309 // jobs. For any dependent jobs, reuse the scanning result and just
310 // update the LastCC1Arguments to correspond to the new invocation.
311 // FIXME: to support multi-arch builds, each arch requires a separate scan
312 setLastCC1Arguments(std::move(OriginalInvocation));
313 return true;
314 }
315
316 Scanned = true;
317
318 // Create a compiler instance to handle the actual work.
319 ScanInstanceStorage.emplace(std::move(PCHContainerOps));
320 CompilerInstance &ScanInstance = *ScanInstanceStorage;
321 ScanInstance.setInvocation(std::move(Invocation));
322
323 // Create the compiler's actual diagnostics engine.
324 sanitizeDiagOpts(ScanInstance.getDiagnosticOpts());
325 ScanInstance.createDiagnostics(DiagConsumer, /*ShouldOwnClient=*/false);
326 if (!ScanInstance.hasDiagnostics())
327 return false;
328
329 // Some DiagnosticConsumers require that finish() is called.
330 auto DiagConsumerFinisher =
331 llvm::make_scope_exit([DiagConsumer]() { DiagConsumer->finish(); });
332
334 true;
335
336 ScanInstance.getFrontendOpts().GenerateGlobalModuleIndex = false;
337 ScanInstance.getFrontendOpts().UseGlobalModuleIndex = false;
338 ScanInstance.getFrontendOpts().ModulesShareFileManager = false;
339 ScanInstance.getHeaderSearchOpts().ModuleFormat = "raw";
341 any(OptimizeArgs & ScanningOptimizations::VFS);
342
343 // Support for virtual file system overlays.
345 ScanInstance.getInvocation(), ScanInstance.getDiagnostics(),
346 DriverFileMgr->getVirtualFileSystemPtr());
347
348 // Create a new FileManager to match the invocation's FileSystemOptions.
349 auto *FileMgr = ScanInstance.createFileManager(FS);
350 ScanInstance.createSourceManager(*FileMgr);
351
352 // Store the list of prebuilt module files into header search options. This
353 // will prevent the implicit build to create duplicate modules and will
354 // force reuse of the existing prebuilt module files instead.
355 PrebuiltModuleVFSMapT PrebuiltModuleVFSMap;
356 if (!ScanInstance.getPreprocessorOpts().ImplicitPCHInclude.empty())
357 if (visitPrebuiltModule(
359 ScanInstance,
361 PrebuiltModuleVFSMap, ScanInstance.getDiagnostics()))
362 return false;
363
364 // Use the dependency scanning optimized file system if requested to do so.
365 if (DepFS)
367 [LocalDepFS = DepFS](FileEntryRef File)
369 if (llvm::ErrorOr<EntryRef> Entry =
370 LocalDepFS->getOrCreateFileSystemEntry(File.getName()))
371 if (LocalDepFS->ensureDirectiveTokensArePopulated(*Entry))
372 return Entry->getDirectiveTokens();
373 return std::nullopt;
374 };
375
376 // Create the dependency collector that will collect the produced
377 // dependencies.
378 //
379 // This also moves the existing dependency output options from the
380 // invocation to the collector. The options in the invocation are reset,
381 // which ensures that the compiler won't create new dependency collectors,
382 // and thus won't write out the extra '.d' files to disk.
383 auto Opts = std::make_unique<DependencyOutputOptions>();
384 std::swap(*Opts, ScanInstance.getInvocation().getDependencyOutputOpts());
385 // We need at least one -MT equivalent for the generator of make dependency
386 // files to work.
387 if (Opts->Targets.empty())
388 Opts->Targets = {
389 deduceDepTarget(ScanInstance.getFrontendOpts().OutputFile,
390 ScanInstance.getFrontendOpts().Inputs)};
391 Opts->IncludeSystemHeaders = true;
392
393 switch (Format) {
394 case ScanningOutputFormat::Make:
395 ScanInstance.addDependencyCollector(
396 std::make_shared<DependencyConsumerForwarder>(
397 std::move(Opts), WorkingDirectory, Consumer));
398 break;
399 case ScanningOutputFormat::P1689:
400 case ScanningOutputFormat::Full:
401 MDC = std::make_shared<ModuleDepCollector>(
402 std::move(Opts), ScanInstance, Consumer, Controller,
403 OriginalInvocation, std::move(PrebuiltModuleVFSMap), OptimizeArgs,
404 EagerLoadModules, Format == ScanningOutputFormat::P1689);
405 ScanInstance.addDependencyCollector(MDC);
406 break;
407 }
408
409 // Consider different header search and diagnostic options to create
410 // different modules. This avoids the unsound aliasing of module PCMs.
411 //
412 // TODO: Implement diagnostic bucketing to reduce the impact of strict
413 // context hashing.
414 ScanInstance.getHeaderSearchOpts().ModulesStrictContextHash = true;
418 true;
419
420 // Avoid some checks and module map parsing when loading PCM files.
421 ScanInstance.getPreprocessorOpts().ModulesCheckRelocated = false;
422
423 std::unique_ptr<FrontendAction> Action;
424
425 if (ModuleName)
426 Action = std::make_unique<GetDependenciesByModuleNameAction>(*ModuleName);
427 else
428 Action = std::make_unique<ReadPCHAndPreprocessAction>();
429
430 if (ScanInstance.getDiagnostics().hasErrorOccurred())
431 return false;
432
433 // Each action is responsible for calling finish.
434 DiagConsumerFinisher.release();
435 const bool Result = ScanInstance.ExecuteAction(*Action);
436
437 if (Result)
438 setLastCC1Arguments(std::move(OriginalInvocation));
439
440 // Propagate the statistics to the parent FileManager.
441 DriverFileMgr->AddStats(ScanInstance.getFileManager());
442
443 return Result;
444 }
445
446 bool hasScanned() const { return Scanned; }
447
448 /// Take the cc1 arguments corresponding to the most recent invocation used
449 /// with this action. Any modifications implied by the discovered dependencies
450 /// will have already been applied.
451 std::vector<std::string> takeLastCC1Arguments() {
452 std::vector<std::string> Result;
453 std::swap(Result, LastCC1Arguments); // Reset LastCC1Arguments to empty.
454 return Result;
455 }
456
457private:
458 void setLastCC1Arguments(CompilerInvocation &&CI) {
459 if (MDC)
460 MDC->applyDiscoveredDependencies(CI);
461 LastCC1Arguments = CI.getCC1CommandLine();
462 }
463
464private:
465 StringRef WorkingDirectory;
466 DependencyConsumer &Consumer;
467 DependencyActionController &Controller;
470 ScanningOptimizations OptimizeArgs;
471 bool EagerLoadModules;
472 bool DisableFree;
473 std::optional<StringRef> ModuleName;
474 std::optional<CompilerInstance> ScanInstanceStorage;
475 std::shared_ptr<ModuleDepCollector> MDC;
476 std::vector<std::string> LastCC1Arguments;
477 bool Scanned = false;
478};
479
480} // end anonymous namespace
481
485 : Format(Service.getFormat()), OptimizeArgs(Service.getOptimizeArgs()),
486 EagerLoadModules(Service.shouldEagerLoadModules()) {
487 PCHContainerOps = std::make_shared<PCHContainerOperations>();
488 // We need to read object files from PCH built outside the scanner.
489 PCHContainerOps->registerReader(
490 std::make_unique<ObjectFilePCHContainerReader>());
491 // The scanner itself writes only raw ast files.
492 PCHContainerOps->registerWriter(std::make_unique<RawPCHContainerWriter>());
493
494 switch (Service.getMode()) {
496 DepFS =
498 BaseFS = DepFS;
499 break;
501 DepFS = nullptr;
502 BaseFS = FS;
503 break;
504 }
505}
506
508 StringRef WorkingDirectory, const std::vector<std::string> &CommandLine,
509 DependencyConsumer &Consumer, DependencyActionController &Controller,
510 std::optional<StringRef> ModuleName) {
511 std::vector<const char *> CLI;
512 for (const std::string &Arg : CommandLine)
513 CLI.push_back(Arg.c_str());
514 auto DiagOpts = CreateAndPopulateDiagOpts(CLI);
515 sanitizeDiagOpts(*DiagOpts);
516
517 // Capture the emitted diagnostics and report them to the client
518 // in the case of a failure.
519 std::string DiagnosticOutput;
520 llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput);
521 TextDiagnosticPrinter DiagPrinter(DiagnosticsOS, DiagOpts.release());
522
523 if (computeDependencies(WorkingDirectory, CommandLine, Consumer, Controller,
524 DiagPrinter, ModuleName))
525 return llvm::Error::success();
526 return llvm::make_error<llvm::StringError>(DiagnosticsOS.str(),
527 llvm::inconvertibleErrorCode());
528}
529
532 llvm::function_ref<bool(const driver::Command &Cmd)> Callback) {
534 Argv.reserve(ArgStrs.size());
535 for (const std::string &Arg : ArgStrs)
536 Argv.push_back(Arg.c_str());
537
538 llvm::vfs::FileSystem *FS = &FM.getVirtualFileSystem();
539
540 std::unique_ptr<driver::Driver> Driver = std::make_unique<driver::Driver>(
541 Argv[0], llvm::sys::getDefaultTargetTriple(), Diags,
542 "clang LLVM compiler", FS);
543 Driver->setTitle("clang_based_tool");
544
545 llvm::BumpPtrAllocator Alloc;
546 bool CLMode = driver::IsClangCL(
547 driver::getDriverMode(Argv[0], ArrayRef(Argv).slice(1)));
548
549 if (llvm::Error E = driver::expandResponseFiles(Argv, CLMode, Alloc, FS)) {
550 Diags.Report(diag::err_drv_expand_response_file)
551 << llvm::toString(std::move(E));
552 return false;
553 }
554
555 const std::unique_ptr<driver::Compilation> Compilation(
556 Driver->BuildCompilation(llvm::ArrayRef(Argv)));
557 if (!Compilation)
558 return false;
559
560 if (Compilation->containsError())
561 return false;
562
563 for (const driver::Command &Job : Compilation->getJobs()) {
564 if (!Callback(Job))
565 return false;
566 }
567 return true;
568}
569
571 std::vector<std::string> CommandLine, DependencyScanningAction &Action,
572 FileManager &FM,
573 std::shared_ptr<clang::PCHContainerOperations> &PCHContainerOps,
574 DiagnosticsEngine &Diags, DependencyConsumer &Consumer) {
575
576 // Save executable path before providing CommandLine to ToolInvocation
577 std::string Executable = CommandLine[0];
578 ToolInvocation Invocation(std::move(CommandLine), &Action, &FM,
579 PCHContainerOps);
580 Invocation.setDiagnosticConsumer(Diags.getClient());
581 Invocation.setDiagnosticOptions(&Diags.getDiagnosticOptions());
582 if (!Invocation.run())
583 return false;
584
585 std::vector<std::string> Args = Action.takeLastCC1Arguments();
586 Consumer.handleBuildCommand({std::move(Executable), std::move(Args)});
587 return true;
588}
589
591 StringRef WorkingDirectory, const std::vector<std::string> &CommandLine,
592 DependencyConsumer &Consumer, DependencyActionController &Controller,
593 DiagnosticConsumer &DC, std::optional<StringRef> ModuleName) {
594 // Reset what might have been modified in the previous worker invocation.
595 BaseFS->setCurrentWorkingDirectory(WorkingDirectory);
596
597 std::optional<std::vector<std::string>> ModifiedCommandLine;
599
600 // If we're scanning based on a module name alone, we don't expect the client
601 // to provide us with an input file. However, the driver really wants to have
602 // one. Let's just make it up to make the driver happy.
603 if (ModuleName) {
604 auto OverlayFS =
605 llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(BaseFS);
606 auto InMemoryFS =
607 llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
608 InMemoryFS->setCurrentWorkingDirectory(WorkingDirectory);
609 OverlayFS->pushOverlay(InMemoryFS);
610 ModifiedFS = OverlayFS;
611
612 SmallString<128> FakeInputPath;
613 // TODO: We should retry the creation if the path already exists.
614 llvm::sys::fs::createUniquePath(*ModuleName + "-%%%%%%%%.input",
615 FakeInputPath,
616 /*MakeAbsolute=*/false);
617 InMemoryFS->addFile(FakeInputPath, 0, llvm::MemoryBuffer::getMemBuffer(""));
618
619 ModifiedCommandLine = CommandLine;
620 ModifiedCommandLine->emplace_back(FakeInputPath);
621 }
622
623 const std::vector<std::string> &FinalCommandLine =
624 ModifiedCommandLine ? *ModifiedCommandLine : CommandLine;
625 auto &FinalFS = ModifiedFS ? ModifiedFS : BaseFS;
626
627 auto FileMgr =
628 llvm::makeIntrusiveRefCnt<FileManager>(FileSystemOptions{}, FinalFS);
629
630 std::vector<const char *> FinalCCommandLine(FinalCommandLine.size(), nullptr);
631 llvm::transform(FinalCommandLine, FinalCCommandLine.begin(),
632 [](const std::string &Str) { return Str.c_str(); });
633
634 auto DiagOpts = CreateAndPopulateDiagOpts(FinalCCommandLine);
635 sanitizeDiagOpts(*DiagOpts);
637 CompilerInstance::createDiagnostics(DiagOpts.release(), &DC,
638 /*ShouldOwnClient=*/false);
639
640 // Although `Diagnostics` are used only for command-line parsing, the
641 // custom `DiagConsumer` might expect a `SourceManager` to be present.
642 SourceManager SrcMgr(*Diags, *FileMgr);
643 Diags->setSourceManager(&SrcMgr);
644 // DisableFree is modified by Tooling for running
645 // in-process; preserve the original value, which is
646 // always true for a driver invocation.
647 bool DisableFree = true;
648 DependencyScanningAction Action(WorkingDirectory, Consumer, Controller, DepFS,
649 Format, OptimizeArgs, EagerLoadModules,
650 DisableFree, ModuleName);
651
652 bool Success = false;
653 if (FinalCommandLine[1] == "-cc1") {
654 Success = createAndRunToolInvocation(FinalCommandLine, Action, *FileMgr,
655 PCHContainerOps, *Diags, Consumer);
656 } else {
658 FinalCommandLine, *Diags, *FileMgr, [&](const driver::Command &Cmd) {
659 if (StringRef(Cmd.getCreator().getName()) != "clang") {
660 // Non-clang command. Just pass through to the dependency
661 // consumer.
662 Consumer.handleBuildCommand(
663 {Cmd.getExecutable(),
664 {Cmd.getArguments().begin(), Cmd.getArguments().end()}});
665 return true;
666 }
667
668 // Insert -cc1 comand line options into Argv
669 std::vector<std::string> Argv;
670 Argv.push_back(Cmd.getExecutable());
671 Argv.insert(Argv.end(), Cmd.getArguments().begin(),
672 Cmd.getArguments().end());
673
674 // Create an invocation that uses the underlying file
675 // system to ensure that any file system requests that
676 // are made by the driver do not go through the
677 // dependency scanning filesystem.
678 return createAndRunToolInvocation(std::move(Argv), Action, *FileMgr,
679 PCHContainerOps, *Diags, Consumer);
680 });
681 }
682
683 if (Success && !Action.hasScanned())
684 Diags->Report(diag::err_fe_expected_compiler_job)
685 << llvm::join(FinalCommandLine, " ");
686 return Success && Action.hasScanned();
687}
688
Expr * E
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:2989
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:1613
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:5395
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
void AddStats(const FileManager &Other)
Import statistics from a child FileManager and add them to this current FileManager.
llvm::vfs::FileSystem & getVirtualFileSystem() const
Definition: FileManager.h:251
llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > getVirtualFileSystemPtr() const
Definition: FileManager.h:253
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:461
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:1829
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:6718
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:6735
bool IsClangCL(StringRef DriverMode)
Checks whether the value produced by getDriverMode is for CL mode.
Definition: Driver.cpp:6733
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.
int __ovld __cnfn any(char)
Returns 1 if the most significant bit in any component of x is set; otherwise returns 0.