clang 19.0.0git
ModuleDepCollector.cpp
Go to the documentation of this file.
1//===- ModuleDepCollector.cpp - Callbacks to collect deps -------*- C++ -*-===//
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
10
15#include "llvm/ADT/STLExtras.h"
16#include "llvm/Support/BLAKE3.h"
17#include "llvm/Support/StringSaver.h"
18#include <optional>
19
20using namespace clang;
21using namespace tooling;
22using namespace dependencies;
23
24const std::vector<std::string> &ModuleDeps::getBuildArguments() {
25 assert(!std::holds_alternative<std::monostate>(BuildInfo) &&
26 "Using uninitialized ModuleDeps");
27 if (const auto *CI = std::get_if<CowCompilerInvocation>(&BuildInfo))
28 BuildInfo = CI->getCC1CommandLine();
29 return std::get<std::vector<std::string>>(BuildInfo);
30}
31
32static void
35 const PrebuiltModuleVFSMapT &PrebuiltModuleVFSMap,
36 ScanningOptimizations OptimizeArgs) {
37 if (any(OptimizeArgs & ScanningOptimizations::HeaderSearch)) {
38 // Only preserve search paths that were used during the dependency scan.
39 std::vector<HeaderSearchOptions::Entry> Entries;
40 std::swap(Opts.UserEntries, Entries);
41
42 llvm::BitVector SearchPathUsage(Entries.size());
44 std::function<void(const serialization::ModuleFile *)> VisitMF =
45 [&](const serialization::ModuleFile *MF) {
46 SearchPathUsage |= MF->SearchPathUsage;
47 Visited.insert(MF);
49 if (!Visited.contains(Import))
50 VisitMF(Import);
51 };
52 VisitMF(&MF);
53
54 if (SearchPathUsage.size() != Entries.size())
55 llvm::report_fatal_error(
56 "Inconsistent search path options between modules detected");
57
58 for (auto Idx : SearchPathUsage.set_bits())
59 Opts.UserEntries.push_back(std::move(Entries[Idx]));
60 }
61 if (any(OptimizeArgs & ScanningOptimizations::VFS)) {
62 std::vector<std::string> VFSOverlayFiles;
63 std::swap(Opts.VFSOverlayFiles, VFSOverlayFiles);
64
65 llvm::BitVector VFSUsage(VFSOverlayFiles.size());
67 std::function<void(const serialization::ModuleFile *)> VisitMF =
68 [&](const serialization::ModuleFile *MF) {
69 Visited.insert(MF);
71 VFSUsage |= MF->VFSUsage;
72 // We only need to recurse into implicit modules. Other module types
73 // will have the correct set of VFSs for anything they depend on.
75 if (!Visited.contains(Import))
76 VisitMF(Import);
77 } else {
78 // This is not an implicitly built module, so it may have different
79 // VFS options. Fall back to a string comparison instead.
80 auto VFSMap = PrebuiltModuleVFSMap.find(MF->FileName);
81 if (VFSMap == PrebuiltModuleVFSMap.end())
82 return;
83 for (std::size_t I = 0, E = VFSOverlayFiles.size(); I != E; ++I) {
84 if (VFSMap->second.contains(VFSOverlayFiles[I]))
85 VFSUsage[I] = true;
86 }
87 }
88 };
89 VisitMF(&MF);
90
91 if (VFSUsage.size() != VFSOverlayFiles.size())
92 llvm::report_fatal_error(
93 "Inconsistent -ivfsoverlay options between modules detected");
94
95 for (auto Idx : VFSUsage.set_bits())
96 Opts.VFSOverlayFiles.push_back(std::move(VFSOverlayFiles[Idx]));
97 }
98}
99
101 bool IsSystemModule) {
102 // If this is not a system module or -Wsystem-headers was passed, don't
103 // optimize.
104 if (!IsSystemModule)
105 return;
106 bool Wsystem_headers = false;
107 for (StringRef Opt : Opts.Warnings) {
108 bool isPositive = !Opt.consume_front("no-");
109 if (Opt == "system-headers")
110 Wsystem_headers = isPositive;
111 }
112 if (Wsystem_headers)
113 return;
114
115 // Remove all warning flags. System modules suppress most, but not all,
116 // warnings.
117 Opts.Warnings.clear();
118 Opts.UndefPrefixes.clear();
119 Opts.Remarks.clear();
120}
121
122static std::vector<std::string> splitString(std::string S, char Separator) {
123 SmallVector<StringRef> Segments;
124 StringRef(S).split(Segments, Separator, /*MaxSplit=*/-1, /*KeepEmpty=*/false);
125 std::vector<std::string> Result;
126 Result.reserve(Segments.size());
127 for (StringRef Segment : Segments)
128 Result.push_back(Segment.str());
129 return Result;
130}
131
132void ModuleDepCollector::addOutputPaths(CowCompilerInvocation &CI,
133 ModuleDeps &Deps) {
138 Controller.lookupModuleOutput(
140 if (!CI.getDependencyOutputOpts().OutputFile.empty()) {
146 '\0');
147 if (!CI.getDependencyOutputOpts().OutputFile.empty() &&
148 CI.getDependencyOutputOpts().Targets.empty()) {
149 // Fallback to -o as dependency target, as in the driver.
152 CI.getMutDependencyOutputOpts().Targets.push_back(std::string(Target));
153 }
154 }
155}
156
161
162 // Remove options incompatible with explicit module build or are likely to
163 // differ between identical modules discovered from different translation
164 // units.
165 CI.getFrontendOpts().Inputs.clear();
166 CI.getFrontendOpts().OutputFile.clear();
167 // LLVM options are not going to affect the AST
168 CI.getFrontendOpts().LLVMArgs.clear();
169
170 // TODO: Figure out better way to set options to their default value.
171 CI.getCodeGenOpts().MainFileName.clear();
172 CI.getCodeGenOpts().DwarfDebugFlags.clear();
173 if (!CI.getLangOpts().ModulesCodegen) {
176 CI.getCodeGenOpts().CoverageDataFile.clear();
178 }
179
180 // Map output paths that affect behaviour to "-" so their existence is in the
181 // context hash. The final path will be computed in addOutputPaths.
184 if (!CI.getDependencyOutputOpts().OutputFile.empty())
186 CI.getDependencyOutputOpts().Targets.clear();
187
191 CI.getFrontendOpts().MTMigrateDir.clear();
192 CI.getLangOpts().ModuleName.clear();
193
194 // Remove any macro definitions that are explicitly ignored.
195 if (!CI.getHeaderSearchOpts().ModulesIgnoreMacros.empty()) {
196 llvm::erase_if(
198 [&CI](const std::pair<std::string, bool> &Def) {
199 StringRef MacroDef = Def.first;
200 return CI.getHeaderSearchOpts().ModulesIgnoreMacros.contains(
201 llvm::CachedHashString(MacroDef.split('=').first));
202 });
203 // Remove the now unused option.
205 }
206
207 return CI;
208}
209
211ModuleDepCollector::getInvocationAdjustedForModuleBuildWithoutOutputs(
212 const ModuleDeps &Deps,
213 llvm::function_ref<void(CowCompilerInvocation &)> Optimize) const {
214 CowCompilerInvocation CI = CommonInvocation;
215
218
219 // Inputs
220 InputKind ModuleMapInputKind(CI.getFrontendOpts().DashX.getLanguage(),
222 CI.getMutFrontendOpts().Inputs.emplace_back(Deps.ClangModuleMapFile,
223 ModuleMapInputKind);
224
225 auto CurrentModuleMapEntry =
226 ScanInstance.getFileManager().getFile(Deps.ClangModuleMapFile);
227 assert(CurrentModuleMapEntry && "module map file entry not found");
228
229 // Remove directly passed modulemap files. They will get added back if they
230 // were actually used.
232
233 auto DepModuleMapFiles = collectModuleMapFiles(Deps.ClangModuleDeps);
234 for (StringRef ModuleMapFile : Deps.ModuleMapFileDeps) {
235 // TODO: Track these as `FileEntryRef` to simplify the equality check below.
236 auto ModuleMapEntry = ScanInstance.getFileManager().getFile(ModuleMapFile);
237 assert(ModuleMapEntry && "module map file entry not found");
238
239 // Don't report module maps describing eagerly-loaded dependency. This
240 // information will be deserialized from the PCM.
241 // TODO: Verify this works fine when modulemap for module A is eagerly
242 // loaded from A.pcm, and module map passed on the command line contains
243 // definition of a submodule: "explicit module A.Private { ... }".
244 if (EagerLoadModules && DepModuleMapFiles.contains(*ModuleMapEntry))
245 continue;
246
247 // Don't report module map file of the current module unless it also
248 // describes a dependency (for symmetry).
249 if (*ModuleMapEntry == *CurrentModuleMapEntry &&
250 !DepModuleMapFiles.contains(*ModuleMapEntry))
251 continue;
252
253 CI.getMutFrontendOpts().ModuleMapFiles.emplace_back(ModuleMapFile);
254 }
255
256 // Report the prebuilt modules this module uses.
257 for (const auto &PrebuiltModule : Deps.PrebuiltModuleDeps)
258 CI.getMutFrontendOpts().ModuleFiles.push_back(PrebuiltModule.PCMFile);
259
260 // Add module file inputs from dependencies.
261 addModuleFiles(CI, Deps.ClangModuleDeps);
262
264 // Apply -Wsystem-headers-in-module for the current module.
265 if (llvm::is_contained(CI.getDiagnosticOpts().SystemHeaderWarningsModules,
266 Deps.ID.ModuleName))
267 CI.getMutDiagnosticOpts().Warnings.push_back("system-headers");
268 // Remove the now unused option(s).
270 }
271
272 Optimize(CI);
273
274 return CI;
275}
276
277llvm::DenseSet<const FileEntry *> ModuleDepCollector::collectModuleMapFiles(
278 ArrayRef<ModuleID> ClangModuleDeps) const {
280 for (const ModuleID &MID : ClangModuleDeps) {
281 ModuleDeps *MD = ModuleDepsByID.lookup(MID);
282 assert(MD && "Inconsistent dependency info");
283 // TODO: Track ClangModuleMapFile as `FileEntryRef`.
284 auto FE = ScanInstance.getFileManager().getFile(MD->ClangModuleMapFile);
285 assert(FE && "Missing module map file that was previously found");
286 ModuleMapFiles.insert(*FE);
287 }
288 return ModuleMapFiles;
289}
290
291void ModuleDepCollector::addModuleMapFiles(
292 CompilerInvocation &CI, ArrayRef<ModuleID> ClangModuleDeps) const {
293 if (EagerLoadModules)
294 return; // Only pcm is needed for eager load.
295
296 for (const ModuleID &MID : ClangModuleDeps) {
297 ModuleDeps *MD = ModuleDepsByID.lookup(MID);
298 assert(MD && "Inconsistent dependency info");
300 }
301}
302
303void ModuleDepCollector::addModuleFiles(
304 CompilerInvocation &CI, ArrayRef<ModuleID> ClangModuleDeps) const {
305 for (const ModuleID &MID : ClangModuleDeps) {
306 std::string PCMPath =
308 if (EagerLoadModules)
309 CI.getFrontendOpts().ModuleFiles.push_back(std::move(PCMPath));
310 else
312 {MID.ModuleName, std::move(PCMPath)});
313 }
314}
315
316void ModuleDepCollector::addModuleFiles(
317 CowCompilerInvocation &CI, ArrayRef<ModuleID> ClangModuleDeps) const {
318 for (const ModuleID &MID : ClangModuleDeps) {
319 std::string PCMPath =
321 if (EagerLoadModules)
322 CI.getMutFrontendOpts().ModuleFiles.push_back(std::move(PCMPath));
323 else
325 {MID.ModuleName, std::move(PCMPath)});
326 }
327}
328
330 switch (FIF.getKind().getLanguage()) {
332 case Language::Asm:
334 return false;
335 default:
336 return true;
337 }
338}
339
342
343 if (llvm::any_of(CI.getFrontendOpts().Inputs, needsModules)) {
344 Preprocessor &PP = ScanInstance.getPreprocessor();
345 if (Module *CurrentModule = PP.getCurrentModuleImplementation())
346 if (OptionalFileEntryRef CurrentModuleMap =
348 .getModuleMap()
349 .getModuleMapFileForUniquing(CurrentModule))
350 CI.getFrontendOpts().ModuleMapFiles.emplace_back(
351 CurrentModuleMap->getNameAsRequested());
352
353 SmallVector<ModuleID> DirectDeps;
354 for (const auto &KV : ModularDeps)
355 if (DirectModularDeps.contains(KV.first))
356 DirectDeps.push_back(KV.second->ID);
357
358 // TODO: Report module maps the same way it's done for modular dependencies.
359 addModuleMapFiles(CI, DirectDeps);
360
361 addModuleFiles(CI, DirectDeps);
362
363 for (const auto &KV : DirectPrebuiltModularDeps)
364 CI.getFrontendOpts().ModuleFiles.push_back(KV.second.PCMFile);
365 }
366}
367
368static std::string getModuleContextHash(const ModuleDeps &MD,
369 const CowCompilerInvocation &CI,
370 bool EagerLoadModules,
371 llvm::vfs::FileSystem &VFS) {
372 llvm::HashBuilder<llvm::TruncatedBLAKE3<16>, llvm::endianness::native>
373 HashBuilder;
374 SmallString<32> Scratch;
375
376 // Hash the compiler version and serialization version to ensure the module
377 // will be readable.
378 HashBuilder.add(getClangFullRepositoryVersion());
380 llvm::ErrorOr<std::string> CWD = VFS.getCurrentWorkingDirectory();
381 if (CWD)
382 HashBuilder.add(*CWD);
383
384 // Hash the BuildInvocation without any input files.
385 SmallString<0> ArgVec;
386 ArgVec.reserve(4096);
387 CI.generateCC1CommandLine([&](const Twine &Arg) {
388 Arg.toVector(ArgVec);
389 ArgVec.push_back('\0');
390 });
391 HashBuilder.add(ArgVec);
392
393 // Hash the module dependencies. These paths may differ even if the invocation
394 // is identical if they depend on the contents of the files in the TU -- for
395 // example, case-insensitive paths to modulemap files. Usually such a case
396 // would indicate a missed optimization to canonicalize, but it may be
397 // difficult to canonicalize all cases when there is a VFS.
398 for (const auto &ID : MD.ClangModuleDeps) {
399 HashBuilder.add(ID.ModuleName);
400 HashBuilder.add(ID.ContextHash);
401 }
402
403 HashBuilder.add(EagerLoadModules);
404
405 llvm::BLAKE3Result<16> Hash = HashBuilder.final();
406 std::array<uint64_t, 2> Words;
407 static_assert(sizeof(Hash) == sizeof(Words), "Hash must match Words");
408 std::memcpy(Words.data(), Hash.data(), sizeof(Hash));
409 return toString(llvm::APInt(sizeof(Words) * 8, Words), 36, /*Signed=*/false);
410}
411
412void ModuleDepCollector::associateWithContextHash(
413 const CowCompilerInvocation &CI, ModuleDeps &Deps) {
415 Deps, CI, EagerLoadModules, ScanInstance.getVirtualFileSystem());
416 bool Inserted = ModuleDepsByID.insert({Deps.ID, &Deps}).second;
417 (void)Inserted;
418 assert(Inserted && "duplicate module mapping");
419}
420
424 FileID PrevFID,
425 SourceLocation Loc) {
427 return;
428
429 // This has to be delayed as the context hash can change at the start of
430 // `CompilerInstance::ExecuteAction`.
431 if (MDC.ContextHash.empty()) {
432 MDC.ContextHash = MDC.ScanInstance.getInvocation().getModuleHash();
433 MDC.Consumer.handleContextHash(MDC.ContextHash);
434 }
435
436 SourceManager &SM = MDC.ScanInstance.getSourceManager();
437
438 // Dependency generation really does want to go all the way to the
439 // file entry for a source location to find out what is depended on.
440 // We do not want #line markers to affect dependency generation!
441 if (std::optional<StringRef> Filename = SM.getNonBuiltinFilenameForID(FID))
442 MDC.addFileDep(llvm::sys::path::remove_leading_dotslash(*Filename));
443}
444
446 SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,
447 bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef File,
448 StringRef SearchPath, StringRef RelativePath, const Module *SuggestedModule,
449 bool ModuleImported, SrcMgr::CharacteristicKind FileType) {
450 if (!File && !ModuleImported) {
451 // This is a non-modular include that HeaderSearch failed to find. Add it
452 // here as `FileChanged` will never see it.
453 MDC.addFileDep(FileName);
454 }
455 handleImport(SuggestedModule);
456}
457
459 ModuleIdPath Path,
460 const Module *Imported) {
461 if (MDC.ScanInstance.getPreprocessor().isInImportingCXXNamedModules()) {
462 P1689ModuleInfo RequiredModule;
463 RequiredModule.ModuleName = Path[0].first->getName().str();
465 MDC.RequiredStdCXXModules.push_back(RequiredModule);
466 return;
467 }
468
469 handleImport(Imported);
470}
471
472void ModuleDepCollectorPP::handleImport(const Module *Imported) {
473 if (!Imported)
474 return;
475
476 const Module *TopLevelModule = Imported->getTopLevelModule();
477
478 if (MDC.isPrebuiltModule(TopLevelModule))
479 MDC.DirectPrebuiltModularDeps.insert(
480 {TopLevelModule, PrebuiltModuleDep{TopLevelModule}});
481 else
482 MDC.DirectModularDeps.insert(TopLevelModule);
483}
484
486 FileID MainFileID = MDC.ScanInstance.getSourceManager().getMainFileID();
487 MDC.MainFile = std::string(MDC.ScanInstance.getSourceManager()
488 .getFileEntryRefForID(MainFileID)
489 ->getName());
490
491 auto &PP = MDC.ScanInstance.getPreprocessor();
492 if (PP.isInNamedModule()) {
493 P1689ModuleInfo ProvidedModule;
494 ProvidedModule.ModuleName = PP.getNamedModuleName();
496 ProvidedModule.IsStdCXXModuleInterface = PP.isInNamedInterfaceUnit();
497 // Don't put implementation (non partition) unit as Provide.
498 // Put the module as required instead. Since the implementation
499 // unit will import the primary module implicitly.
500 if (PP.isInImplementationUnit())
501 MDC.RequiredStdCXXModules.push_back(ProvidedModule);
502 else
503 MDC.ProvidedStdCXXModule = ProvidedModule;
504 }
505
506 if (!MDC.ScanInstance.getPreprocessorOpts().ImplicitPCHInclude.empty())
507 MDC.addFileDep(MDC.ScanInstance.getPreprocessorOpts().ImplicitPCHInclude);
508
509 for (const Module *M :
510 MDC.ScanInstance.getPreprocessor().getAffectingClangModules())
511 if (!MDC.isPrebuiltModule(M))
512 MDC.DirectModularDeps.insert(M);
513
514 for (const Module *M : MDC.DirectModularDeps)
515 handleTopLevelModule(M);
516
517 MDC.Consumer.handleDependencyOutputOpts(*MDC.Opts);
518
519 if (MDC.IsStdModuleP1689Format)
521 MDC.ProvidedStdCXXModule, MDC.RequiredStdCXXModules);
522
523 for (auto &&I : MDC.ModularDeps)
524 MDC.Consumer.handleModuleDependency(*I.second);
525
526 for (const Module *M : MDC.DirectModularDeps) {
527 auto It = MDC.ModularDeps.find(M);
528 // Only report direct dependencies that were successfully handled.
529 if (It != MDC.ModularDeps.end())
530 MDC.Consumer.handleDirectModuleDependency(MDC.ModularDeps[M]->ID);
531 }
532
533 for (auto &&I : MDC.FileDeps)
534 MDC.Consumer.handleFileDependency(I);
535
536 for (auto &&I : MDC.DirectPrebuiltModularDeps)
537 MDC.Consumer.handlePrebuiltModuleDependency(I.second);
538}
539
540std::optional<ModuleID>
541ModuleDepCollectorPP::handleTopLevelModule(const Module *M) {
542 assert(M == M->getTopLevelModule() && "Expected top level module!");
543
544 // A top-level module might not be actually imported as a module when
545 // -fmodule-name is used to compile a translation unit that imports this
546 // module. In that case it can be skipped. The appropriate header
547 // dependencies will still be reported as expected.
548 if (!M->getASTFile())
549 return {};
550
551 // If this module has been handled already, just return its ID.
552 auto ModI = MDC.ModularDeps.insert({M, nullptr});
553 if (!ModI.second)
554 return ModI.first->second->ID;
555
556 ModI.first->second = std::make_unique<ModuleDeps>();
557 ModuleDeps &MD = *ModI.first->second;
558
560 MD.IsSystem = M->IsSystem;
561
562 ModuleMap &ModMapInfo =
563 MDC.ScanInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap();
564
566
567 if (ModuleMap) {
568 SmallString<128> Path = ModuleMap->getNameAsRequested();
569 ModMapInfo.canonicalizeModuleMapPath(Path);
570 MD.ClangModuleMapFile = std::string(Path);
571 }
572
574 MDC.ScanInstance.getASTReader()->getModuleManager().lookup(
575 *M->getASTFile());
576 MDC.ScanInstance.getASTReader()->visitInputFileInfos(
577 *MF, /*IncludeSystem=*/true,
578 [&](const serialization::InputFileInfo &IFI, bool IsSystem) {
579 // __inferred_module.map is the result of the way in which an implicit
580 // module build handles inferred modules. It adds an overlay VFS with
581 // this file in the proper directory and relies on the rest of Clang to
582 // handle it like normal. With explicitly built modules we don't need
583 // to play VFS tricks, so replace it with the correct module map.
584 if (StringRef(IFI.Filename).ends_with("__inferred_module.map")) {
585 MDC.addFileDep(MD, ModuleMap->getName());
586 return;
587 }
588 MDC.addFileDep(MD, IFI.Filename);
589 });
590
592 addAllSubmodulePrebuiltDeps(M, MD, SeenDeps);
593 addAllSubmoduleDeps(M, MD, SeenDeps);
594 addAllAffectingClangModules(M, MD, SeenDeps);
595
596 MDC.ScanInstance.getASTReader()->visitInputFileInfos(
597 *MF, /*IncludeSystem=*/true,
598 [&](const serialization::InputFileInfo &IFI, bool IsSystem) {
599 if (!(IFI.TopLevel && IFI.ModuleMap))
600 return;
601 if (StringRef(IFI.FilenameAsRequested)
602 .ends_with("__inferred_module.map"))
603 return;
604 MD.ModuleMapFileDeps.emplace_back(IFI.FilenameAsRequested);
605 });
606
608 MDC.getInvocationAdjustedForModuleBuildWithoutOutputs(
609 MD, [&](CowCompilerInvocation &BuildInvocation) {
610 if (any(MDC.OptimizeArgs & (ScanningOptimizations::HeaderSearch |
613 *MDC.ScanInstance.getASTReader(), *MF,
614 MDC.PrebuiltModuleVFSMap,
615 MDC.OptimizeArgs);
616 if (any(MDC.OptimizeArgs & ScanningOptimizations::SystemWarnings))
618 BuildInvocation.getMutDiagnosticOpts(),
619 BuildInvocation.getFrontendOpts().IsSystemModule);
620 });
621
622 MDC.associateWithContextHash(CI, MD);
623
624 // Finish the compiler invocation. Requires dependencies and the context hash.
625 MDC.addOutputPaths(CI, MD);
626
627 MD.BuildInfo = std::move(CI);
628
629 return MD.ID;
630}
631
632static void forEachSubmoduleSorted(const Module *M,
633 llvm::function_ref<void(const Module *)> F) {
634 // Submodule order depends on order of header includes for inferred submodules
635 // we don't care about the exact order, so sort so that it's consistent across
636 // TUs to improve sharing.
638 llvm::stable_sort(Submodules, [](const Module *A, const Module *B) {
639 return A->Name < B->Name;
640 });
641 for (const Module *SubM : Submodules)
642 F(SubM);
643}
644
645void ModuleDepCollectorPP::addAllSubmodulePrebuiltDeps(
646 const Module *M, ModuleDeps &MD,
647 llvm::DenseSet<const Module *> &SeenSubmodules) {
648 addModulePrebuiltDeps(M, MD, SeenSubmodules);
649
650 forEachSubmoduleSorted(M, [&](const Module *SubM) {
651 addAllSubmodulePrebuiltDeps(SubM, MD, SeenSubmodules);
652 });
653}
654
655void ModuleDepCollectorPP::addModulePrebuiltDeps(
656 const Module *M, ModuleDeps &MD,
657 llvm::DenseSet<const Module *> &SeenSubmodules) {
658 for (const Module *Import : M->Imports)
659 if (Import->getTopLevelModule() != M->getTopLevelModule())
660 if (MDC.isPrebuiltModule(Import->getTopLevelModule()))
661 if (SeenSubmodules.insert(Import->getTopLevelModule()).second)
662 MD.PrebuiltModuleDeps.emplace_back(Import->getTopLevelModule());
663}
664
665void ModuleDepCollectorPP::addAllSubmoduleDeps(
666 const Module *M, ModuleDeps &MD,
667 llvm::DenseSet<const Module *> &AddedModules) {
668 addModuleDep(M, MD, AddedModules);
669
670 forEachSubmoduleSorted(M, [&](const Module *SubM) {
671 addAllSubmoduleDeps(SubM, MD, AddedModules);
672 });
673}
674
675void ModuleDepCollectorPP::addModuleDep(
676 const Module *M, ModuleDeps &MD,
677 llvm::DenseSet<const Module *> &AddedModules) {
678 for (const Module *Import : M->Imports) {
679 if (Import->getTopLevelModule() != M->getTopLevelModule() &&
680 !MDC.isPrebuiltModule(Import)) {
681 if (auto ImportID = handleTopLevelModule(Import->getTopLevelModule()))
682 if (AddedModules.insert(Import->getTopLevelModule()).second)
683 MD.ClangModuleDeps.push_back(*ImportID);
684 }
685 }
686}
687
688void ModuleDepCollectorPP::addAllAffectingClangModules(
689 const Module *M, ModuleDeps &MD,
690 llvm::DenseSet<const Module *> &AddedModules) {
691 addAffectingClangModule(M, MD, AddedModules);
692
693 for (const Module *SubM : M->submodules())
694 addAllAffectingClangModules(SubM, MD, AddedModules);
695}
696
697void ModuleDepCollectorPP::addAffectingClangModule(
698 const Module *M, ModuleDeps &MD,
699 llvm::DenseSet<const Module *> &AddedModules) {
700 for (const Module *Affecting : M->AffectingClangModules) {
701 assert(Affecting == Affecting->getTopLevelModule() &&
702 "Not quite import not top-level module");
703 if (Affecting != M->getTopLevelModule() &&
704 !MDC.isPrebuiltModule(Affecting)) {
705 if (auto ImportID = handleTopLevelModule(Affecting))
706 if (AddedModules.insert(Affecting).second)
707 MD.ClangModuleDeps.push_back(*ImportID);
708 }
709 }
710}
711
713 std::unique_ptr<DependencyOutputOptions> Opts,
714 CompilerInstance &ScanInstance, DependencyConsumer &C,
715 DependencyActionController &Controller, CompilerInvocation OriginalCI,
716 PrebuiltModuleVFSMapT PrebuiltModuleVFSMap,
717 ScanningOptimizations OptimizeArgs, bool EagerLoadModules,
718 bool IsStdModuleP1689Format)
719 : ScanInstance(ScanInstance), Consumer(C), Controller(Controller),
720 PrebuiltModuleVFSMap(std::move(PrebuiltModuleVFSMap)),
721 Opts(std::move(Opts)),
722 CommonInvocation(
723 makeCommonInvocationForModuleBuild(std::move(OriginalCI))),
724 OptimizeArgs(OptimizeArgs), EagerLoadModules(EagerLoadModules),
725 IsStdModuleP1689Format(IsStdModuleP1689Format) {}
726
728 PP.addPPCallbacks(std::make_unique<ModuleDepCollectorPP>(*this));
729}
730
732
733bool ModuleDepCollector::isPrebuiltModule(const Module *M) {
734 std::string Name(M->getTopLevelModuleName());
735 const auto &PrebuiltModuleFiles =
737 auto PrebuiltModuleFileIt = PrebuiltModuleFiles.find(Name);
738 if (PrebuiltModuleFileIt == PrebuiltModuleFiles.end())
739 return false;
740 assert("Prebuilt module came from the expected AST file" &&
741 PrebuiltModuleFileIt->second == M->getASTFile()->getName());
742 return true;
743}
744
745static StringRef makeAbsoluteAndPreferred(CompilerInstance &CI, StringRef Path,
746 SmallVectorImpl<char> &Storage) {
747 if (llvm::sys::path::is_absolute(Path) &&
748 !llvm::sys::path::is_style_windows(llvm::sys::path::Style::native))
749 return Path;
750 Storage.assign(Path.begin(), Path.end());
751 CI.getFileManager().makeAbsolutePath(Storage);
752 llvm::sys::path::make_preferred(Storage);
753 return StringRef(Storage.data(), Storage.size());
754}
755
756void ModuleDepCollector::addFileDep(StringRef Path) {
757 if (IsStdModuleP1689Format) {
758 // Within P1689 format, we don't want all the paths to be absolute path
759 // since it may violate the tranditional make style dependencies info.
760 FileDeps.push_back(std::string(Path));
761 return;
762 }
763
765 Path = makeAbsoluteAndPreferred(ScanInstance, Path, Storage);
766 FileDeps.push_back(std::string(Path));
767}
768
769void ModuleDepCollector::addFileDep(ModuleDeps &MD, StringRef Path) {
770 if (IsStdModuleP1689Format) {
771 MD.FileDeps.insert(Path);
772 return;
773 }
774
776 Path = makeAbsoluteAndPreferred(ScanInstance, Path, Storage);
777 MD.FileDeps.insert(Path);
778}
#define SM(sm)
Definition: Cuda.cpp:82
StringRef Filename
Definition: Format.cpp:2980
llvm::DenseSet< const void * > Visited
Definition: HTMLLogger.cpp:146
static void optimizeHeaderSearchOpts(HeaderSearchOptions &Opts, ASTReader &Reader, const serialization::ModuleFile &MF, const PrebuiltModuleVFSMapT &PrebuiltModuleVFSMap, ScanningOptimizations OptimizeArgs)
static std::vector< std::string > splitString(std::string S, char Separator)
static std::string getModuleContextHash(const ModuleDeps &MD, const CowCompilerInvocation &CI, bool EagerLoadModules, llvm::vfs::FileSystem &VFS)
static void optimizeDiagnosticOpts(DiagnosticOptions &Opts, bool IsSystemModule)
static StringRef makeAbsoluteAndPreferred(CompilerInstance &CI, StringRef Path, SmallVectorImpl< char > &Storage)
static CowCompilerInvocation makeCommonInvocationForModuleBuild(CompilerInvocation CI)
static void forEachSubmoduleSorted(const Module *M, llvm::function_ref< void(const Module *)> F)
static bool needsModules(FrontendInputFile FIF)
Defines the clang::Preprocessor interface.
static std::string toString(const clang::SanitizerSet &Sanitizers)
Produce a string containing comma-separated names of sanitizers in Sanitizers set.
Reads an AST files chain containing the contents of a translation unit.
Definition: ASTReader.h:366
Represents a character-granular source range.
std::string CoverageNotesFile
The filename with path we use for coverage notes files.
std::string CoverageDataFile
The filename with path we use for coverage data files.
std::string DebugCompilationDir
The string to embed in debug information as the current working directory.
std::string MainFileName
The user provided name for the "main file", if non-empty.
std::string CoverageCompilationDir
The string to embed in coverage mapping as the current working directory.
std::string DwarfDebugFlags
The string to embed in the debug information for the compile unit, if non-empty.
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
FileManager & getFileManager() const
Return the current file manager to the caller.
IntrusiveRefCntPtr< ASTReader > getASTReader() const
Preprocessor & getPreprocessor() const
Return the current preprocessor.
HeaderSearchOptions & getHeaderSearchOpts()
CompilerInvocation & getInvocation()
PreprocessorOptions & getPreprocessorOpts()
llvm::vfs::FileSystem & getVirtualFileSystem() const
SourceManager & getSourceManager() const
Return the current source manager.
const FrontendOptions & getFrontendOpts() const
void generateCC1CommandLine(llvm::SmallVectorImpl< const char * > &Args, StringAllocator SA) const
Generate cc1-compatible command line arguments from this instance.
const DependencyOutputOptions & getDependencyOutputOpts() const
const DiagnosticOptions & getDiagnosticOpts() const
Helper class for holding the data necessary to invoke the compiler.
PreprocessorOptions & getPreprocessorOpts()
void clearImplicitModuleBuildOptions()
Disable implicit modules and canonicalize options that are only used by implicit modules.
LangOptions & getLangOpts()
Mutable getters.
DependencyOutputOptions & getDependencyOutputOpts()
void resetNonModularOptions()
Reset all of the options that are not considered when building a module.
FrontendOptions & getFrontendOpts()
std::string getModuleHash() const
Retrieve a module hash string that is suitable for uniquely identifying the conditions under which th...
CodeGenOptions & getCodeGenOpts()
HeaderSearchOptions & getHeaderSearchOpts()
DiagnosticOptions & getDiagnosticOpts()
Same as CompilerInvocation, but with copy-on-write optimization.
FrontendOptions & getMutFrontendOpts()
LangOptions & getMutLangOpts()
Mutable getters.
HeaderSearchOptions & getMutHeaderSearchOpts()
DiagnosticOptions & getMutDiagnosticOpts()
DependencyOutputOptions & getMutDependencyOutputOpts()
std::string OutputFile
The file to write dependency output to.
std::vector< std::string > Targets
A list of names to use as the targets in the dependency file; this list must contain at least one ent...
Options for controlling the compiler diagnostics engine.
std::vector< std::string > Remarks
The list of -R... options used to alter the diagnostic mappings, with the prefixes removed.
std::vector< std::string > Warnings
The list of -W... options used to alter the diagnostic mappings, with the prefixes removed.
std::vector< std::string > UndefPrefixes
The list of prefixes from -Wundef-prefix=... used to generate warnings for undefined macros.
std::vector< std::string > SystemHeaderWarningsModules
The list of -Wsystem-header-in-module=... options used to override whether -Wsystem-headers is enable...
std::string DiagnosticSerializationFile
The file to serialize diagnostics to (non-appending).
StringRef getName() const
The name of this FileEntry.
Definition: FileEntry.h:61
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
bool makeAbsolutePath(SmallVectorImpl< char > &Path) const
Makes Path absolute taking into account FileSystemOptions and the working directory option.
llvm::ErrorOr< const FileEntry * > getFile(StringRef Filename, bool OpenFile=false, bool CacheFailure=true)
Lookup, cache, and verify the specified file (real or virtual).
An input file for the front end.
InputKind getKind() const
InputKind DashX
The input kind, either specified via -x argument or deduced from the input file name.
std::vector< std::string > ModuleFiles
The list of additional prebuilt module files to load before processing the input.
enum clang::FrontendOptions::@192 ARCMTAction
unsigned IsSystemModule
When using -emit-module, treat the modulemap as a system module.
std::vector< std::string > LLVMArgs
A list of arguments to forward to LLVM's option processing; this should only be used for debugging an...
std::string OutputFile
The output file, if any.
SmallVector< FrontendInputFile, 0 > Inputs
The input files and their types.
frontend::ActionKind ProgramAction
The frontend action to perform.
std::vector< std::string > ModuleMapFiles
The list of module map files to load before processing the input.
HeaderSearchOptions - Helper class for storing options related to the initialization of the HeaderSea...
std::map< std::string, std::string, std::less<> > PrebuiltModuleFiles
The mapping of module names to prebuilt module files.
llvm::SmallSetVector< llvm::CachedHashString, 16 > ModulesIgnoreMacros
The set of macro names that should be ignored for the purposes of computing the module hash.
std::vector< std::string > VFSOverlayFiles
The set of user-provided virtual filesystem overlay files.
std::vector< Entry > UserEntries
User specified include entries.
ModuleMap & getModuleMap()
Retrieve the module map.
Definition: HeaderSearch.h:812
The kind of a file that we've been handed as an input.
Language getLanguage() const
std::string ModuleName
The module currently being compiled as specified by -fmodule-name.
Definition: LangOptions.h:466
OptionalFileEntryRef getModuleMapFileForUniquing(const Module *M) const
Get the module map file that (along with the module name) uniquely identifies this module.
Definition: ModuleMap.cpp:1320
std::error_code canonicalizeModuleMapPath(SmallVectorImpl< char > &Path)
Canonicalize Path in a manner suitable for a module map file.
Definition: ModuleMap.cpp:1335
Describes a module or submodule.
Definition: Module.h:105
StringRef getTopLevelModuleName() const
Retrieve the name of the top-level module.
Definition: Module.h:670
llvm::SmallSetVector< Module *, 2 > Imports
The set of modules imported by this module, and on which this module depends.
Definition: Module.h:401
unsigned IsSystem
Whether this is a "system" module (which assumes that all headers in it are system headers).
Definition: Module.h:332
std::string Name
The name of this module.
Definition: Module.h:108
llvm::iterator_range< submodule_iterator > submodules()
Definition: Module.h:777
llvm::SmallSetVector< Module *, 2 > AffectingClangModules
The set of top-level modules that affected the compilation of this module, but were not imported.
Definition: Module.h:405
std::string getFullModuleName(bool AllowStringLiterals=false) const
Retrieve the full name of this module, including the path from its top-level module.
Definition: Module.cpp:244
Module * getTopLevelModule()
Retrieve the top-level module for this (sub)module, which may be this module.
Definition: Module.h:660
OptionalFileEntryRef getASTFile() const
The serialized AST file for this module, if one was created.
Definition: Module.h:675
std::string ImplicitPCHInclude
The implicit PCH included at the start of the translation unit, or empty.
std::vector< std::pair< std::string, bool > > Macros
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
Definition: Preprocessor.h:128
bool isInImportingCXXNamedModules() const
If we're importing a standard C++20 Named Modules.
void addPPCallbacks(std::unique_ptr< PPCallbacks > C)
Module * getCurrentModuleImplementation()
Retrieves the module whose implementation we're current compiling, if any.
HeaderSearch & getHeaderSearchInfo() const
const llvm::SmallSetVector< Module *, 2 > & getAffectingClangModules() const
Get the set of top-level clang modules that affected preprocessing, but were not imported.
Encodes a location in the source.
This class handles loading and caching of source files into memory.
OptionalFileEntryRef getFileEntryRefForID(FileID FID) const
Returns the FileEntryRef for the provided FileID.
FileID getMainFileID() const
Returns the FileID of the main source file.
Token - This structure provides full information about a lexed token.
Definition: Token.h:36
Information about a module that has been loaded by the ASTReader.
Definition: ModuleFile.h:124
std::string FileName
The file name of the module file.
Definition: ModuleFile.h:139
llvm::SetVector< ModuleFile * > Imports
List of modules which this module depends on.
Definition: ModuleFile.h:516
llvm::BitVector SearchPathUsage
The bit vector denoting usage of each header search entry (true = used).
Definition: ModuleFile.h:190
llvm::BitVector VFSUsage
The bit vector denoting usage of each VFS entry (true = used).
Definition: ModuleFile.h:193
ModuleKind Kind
The type of this module.
Definition: ModuleFile.h:136
Dependency scanner callbacks that are used during scanning to influence the behaviour of the scan - f...
virtual std::string lookupModuleOutput(const ModuleID &ID, ModuleOutputKind Kind)=0
virtual void handleModuleDependency(ModuleDeps MD)=0
virtual void handlePrebuiltModuleDependency(PrebuiltModuleDep PMD)=0
virtual void handleDependencyOutputOpts(const DependencyOutputOptions &Opts)=0
virtual void handleProvidedAndRequiredStdCXXModules(std::optional< P1689ModuleInfo > Provided, std::vector< P1689ModuleInfo > Requires)
virtual void handleDirectModuleDependency(ModuleID MD)=0
virtual void handleFileDependency(StringRef Filename)=0
virtual void handleContextHash(std::string Hash)=0
void EndOfMainFile() override
Callback invoked when the end of the main file is reached.
void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName, bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef File, StringRef SearchPath, StringRef RelativePath, const Module *SuggestedModule, bool ModuleImported, SrcMgr::CharacteristicKind FileType) override
Callback invoked whenever an inclusion directive of any kind (#include, #import, etc....
void LexedFileChanged(FileID FID, LexedFileChangeReason Reason, SrcMgr::CharacteristicKind FileType, FileID PrevFID, SourceLocation Loc) override
Callback invoked whenever the Lexer moves to a different file for lexing.
void moduleImport(SourceLocation ImportLoc, ModuleIdPath Path, const Module *Imported) override
Callback invoked whenever there was an explicit module-import syntax.
ModuleDepCollector(std::unique_ptr< DependencyOutputOptions > Opts, CompilerInstance &ScanInstance, DependencyConsumer &C, DependencyActionController &Controller, CompilerInvocation OriginalCI, PrebuiltModuleVFSMapT PrebuiltModuleVFSMap, ScanningOptimizations OptimizeArgs, bool EagerLoadModules, bool IsStdModuleP1689Format)
void applyDiscoveredDependencies(CompilerInvocation &CI)
Apply any changes implied by the discovered dependencies to the given invocation, (e....
void attachToPreprocessor(Preprocessor &PP) override
CharacteristicKind
Indicates whether a file or directory holds normal user code, system code, or system code which is im...
Definition: SourceManager.h:81
@ GenerateModule
Generate pre-compiled module from a module map.
const unsigned VERSION_MINOR
AST file minor version number supported by this version of Clang.
Definition: ASTBitCodes.h:54
const unsigned VERSION_MAJOR
AST file major version number supported by this version of Clang.
Definition: ASTBitCodes.h:44
@ MK_ImplicitModule
File is an implicitly-loaded module.
Definition: ModuleFile.h:44
@ DiagnosticSerializationFile
The path of the serialized diagnostic file (.dia), if any.
@ DependencyFile
The path of the dependency file (.d), if any.
@ DependencyTargets
The null-separated list of names to use as the targets in the dependency file, if any.
@ ModuleFile
The module file (.pcm). Required.
@ VFS
Remove unused -ivfsoverlay arguments.
@ SystemWarnings
Remove warnings from system modules.
@ HeaderSearch
Remove unused header search paths including header maps.
llvm::StringMap< llvm::StringSet<> > PrebuiltModuleVFSMapT
The JSON file list parser is used to communicate input to InstallAPI.
void quoteMakeTarget(StringRef Target, SmallVectorImpl< char > &Res)
Quote target names for inclusion in GNU Make dependency files.
Definition: MakeSupport.cpp:11
@ LLVM_IR
LLVM IR: we accept this so that we can run the optimizer on it, and compile it to assembly or object ...
@ Asm
Assembly: we accept this only so that we can preprocess it.
@ Result
The result type of a method or function.
std::string getClangFullRepositoryVersion()
Retrieves the full repository version that is an amalgamation of the information in getClangRepositor...
Definition: Version.cpp:68
if(T->getSizeExpr()) TRY_TO(TraverseStmt(T -> getSizeExpr()))
Definition: Format.h:5304
int __ovld __cnfn any(char)
Returns 1 if the most significant bit in any component of x is set; otherwise returns 0.
The input file info that has been loaded from an AST file.
Definition: ModuleFile.h:63
std::string ClangModuleMapFile
The path to the modulemap file which defines this module.
std::vector< std::string > ModuleMapFileDeps
A collection of absolute paths to module map files that this module needs to know about.
std::vector< PrebuiltModuleDep > PrebuiltModuleDeps
A collection of prebuilt modular dependencies this module directly depends on, not including transiti...
std::vector< ModuleID > ClangModuleDeps
A list of module identifiers this module directly depends on, not including transitive dependencies.
ModuleID ID
The identifier of the module.
const std::vector< std::string > & getBuildArguments()
Get (or compute) the compiler invocation that can be used to build this module.
llvm::StringSet FileDeps
A collection of absolute paths to files that this module directly depends on, not including transitiv...
bool IsSystem
Whether this is a "system" module.
This is used to identify a specific module.
std::string ContextHash
The context hash of a module represents the compiler options that affect the resulting command-line i...
std::string ModuleName
The name of the module.
P1689ModuleInfo - Represents the needed information of standard C++20 modules for P1689 format.
std::string ModuleName
The name of the module. This may include : for partitions.
bool IsStdCXXModuleInterface
If this module is a standard c++ interface unit.
Modular dependency that has already been built prior to the dependency scan.