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
158 const LangOptions &LangOpts,
159 CodeGenOptions &CGOpts) {
160 // TODO: Figure out better way to set options to their default value.
161 if (ProgramAction == frontend::GenerateModule) {
162 CGOpts.MainFileName.clear();
163 CGOpts.DwarfDebugFlags.clear();
164 }
165 if (ProgramAction == frontend::GeneratePCH ||
166 (ProgramAction == frontend::GenerateModule && !LangOpts.ModulesCodegen)) {
167 CGOpts.DebugCompilationDir.clear();
168 CGOpts.CoverageCompilationDir.clear();
169 CGOpts.CoverageDataFile.clear();
170 CGOpts.CoverageNotesFile.clear();
171 CGOpts.ProfileInstrumentUsePath.clear();
172 CGOpts.SampleProfileFile.clear();
173 CGOpts.ProfileRemappingFile.clear();
174 }
175}
176
181
182 // The scanner takes care to avoid passing non-affecting module maps to the
183 // explicit compiles. No need to do extra work just to find out there are no
184 // module map files to prune.
186
187 // Remove options incompatible with explicit module build or are likely to
188 // differ between identical modules discovered from different translation
189 // units.
190 CI.getFrontendOpts().Inputs.clear();
191 CI.getFrontendOpts().OutputFile.clear();
192 // LLVM options are not going to affect the AST
193 CI.getFrontendOpts().LLVMArgs.clear();
194
196 CI.getCodeGenOpts());
197
198 // Map output paths that affect behaviour to "-" so their existence is in the
199 // context hash. The final path will be computed in addOutputPaths.
202 if (!CI.getDependencyOutputOpts().OutputFile.empty())
204 CI.getDependencyOutputOpts().Targets.clear();
205
209 CI.getFrontendOpts().MTMigrateDir.clear();
210 CI.getLangOpts().ModuleName.clear();
211
212 // Remove any macro definitions that are explicitly ignored.
213 if (!CI.getHeaderSearchOpts().ModulesIgnoreMacros.empty()) {
214 llvm::erase_if(
216 [&CI](const std::pair<std::string, bool> &Def) {
217 StringRef MacroDef = Def.first;
218 return CI.getHeaderSearchOpts().ModulesIgnoreMacros.contains(
219 llvm::CachedHashString(MacroDef.split('=').first));
220 });
221 // Remove the now unused option.
223 }
224
225 return CI;
226}
227
229ModuleDepCollector::getInvocationAdjustedForModuleBuildWithoutOutputs(
230 const ModuleDeps &Deps,
231 llvm::function_ref<void(CowCompilerInvocation &)> Optimize) const {
232 CowCompilerInvocation CI = CommonInvocation;
233
236
237 // Inputs
238 InputKind ModuleMapInputKind(CI.getFrontendOpts().DashX.getLanguage(),
240 CI.getMutFrontendOpts().Inputs.emplace_back(Deps.ClangModuleMapFile,
241 ModuleMapInputKind);
242
243 auto CurrentModuleMapEntry =
244 ScanInstance.getFileManager().getFile(Deps.ClangModuleMapFile);
245 assert(CurrentModuleMapEntry && "module map file entry not found");
246
247 // Remove directly passed modulemap files. They will get added back if they
248 // were actually used.
250
251 auto DepModuleMapFiles = collectModuleMapFiles(Deps.ClangModuleDeps);
252 for (StringRef ModuleMapFile : Deps.ModuleMapFileDeps) {
253 // TODO: Track these as `FileEntryRef` to simplify the equality check below.
254 auto ModuleMapEntry = ScanInstance.getFileManager().getFile(ModuleMapFile);
255 assert(ModuleMapEntry && "module map file entry not found");
256
257 // Don't report module maps describing eagerly-loaded dependency. This
258 // information will be deserialized from the PCM.
259 // TODO: Verify this works fine when modulemap for module A is eagerly
260 // loaded from A.pcm, and module map passed on the command line contains
261 // definition of a submodule: "explicit module A.Private { ... }".
262 if (EagerLoadModules && DepModuleMapFiles.contains(*ModuleMapEntry))
263 continue;
264
265 // Don't report module map file of the current module unless it also
266 // describes a dependency (for symmetry).
267 if (*ModuleMapEntry == *CurrentModuleMapEntry &&
268 !DepModuleMapFiles.contains(*ModuleMapEntry))
269 continue;
270
271 CI.getMutFrontendOpts().ModuleMapFiles.emplace_back(ModuleMapFile);
272 }
273
274 // Report the prebuilt modules this module uses.
275 for (const auto &PrebuiltModule : Deps.PrebuiltModuleDeps)
276 CI.getMutFrontendOpts().ModuleFiles.push_back(PrebuiltModule.PCMFile);
277
278 // Add module file inputs from dependencies.
279 addModuleFiles(CI, Deps.ClangModuleDeps);
280
282 // Apply -Wsystem-headers-in-module for the current module.
283 if (llvm::is_contained(CI.getDiagnosticOpts().SystemHeaderWarningsModules,
284 Deps.ID.ModuleName))
285 CI.getMutDiagnosticOpts().Warnings.push_back("system-headers");
286 // Remove the now unused option(s).
288 }
289
290 Optimize(CI);
291
292 return CI;
293}
294
295llvm::DenseSet<const FileEntry *> ModuleDepCollector::collectModuleMapFiles(
296 ArrayRef<ModuleID> ClangModuleDeps) const {
298 for (const ModuleID &MID : ClangModuleDeps) {
299 ModuleDeps *MD = ModuleDepsByID.lookup(MID);
300 assert(MD && "Inconsistent dependency info");
301 // TODO: Track ClangModuleMapFile as `FileEntryRef`.
302 auto FE = ScanInstance.getFileManager().getFile(MD->ClangModuleMapFile);
303 assert(FE && "Missing module map file that was previously found");
304 ModuleMapFiles.insert(*FE);
305 }
306 return ModuleMapFiles;
307}
308
309void ModuleDepCollector::addModuleMapFiles(
310 CompilerInvocation &CI, ArrayRef<ModuleID> ClangModuleDeps) const {
311 if (EagerLoadModules)
312 return; // Only pcm is needed for eager load.
313
314 for (const ModuleID &MID : ClangModuleDeps) {
315 ModuleDeps *MD = ModuleDepsByID.lookup(MID);
316 assert(MD && "Inconsistent dependency info");
318 }
319}
320
321void ModuleDepCollector::addModuleFiles(
322 CompilerInvocation &CI, ArrayRef<ModuleID> ClangModuleDeps) const {
323 for (const ModuleID &MID : ClangModuleDeps) {
324 std::string PCMPath =
326 if (EagerLoadModules)
327 CI.getFrontendOpts().ModuleFiles.push_back(std::move(PCMPath));
328 else
330 {MID.ModuleName, std::move(PCMPath)});
331 }
332}
333
334void ModuleDepCollector::addModuleFiles(
335 CowCompilerInvocation &CI, ArrayRef<ModuleID> ClangModuleDeps) const {
336 for (const ModuleID &MID : ClangModuleDeps) {
337 std::string PCMPath =
339 if (EagerLoadModules)
340 CI.getMutFrontendOpts().ModuleFiles.push_back(std::move(PCMPath));
341 else
343 {MID.ModuleName, std::move(PCMPath)});
344 }
345}
346
348 switch (FIF.getKind().getLanguage()) {
350 case Language::Asm:
352 return false;
353 default:
354 return true;
355 }
356}
357
361 CI.getLangOpts(), CI.getCodeGenOpts());
362
363 if (llvm::any_of(CI.getFrontendOpts().Inputs, needsModules)) {
364 Preprocessor &PP = ScanInstance.getPreprocessor();
365 if (Module *CurrentModule = PP.getCurrentModuleImplementation())
366 if (OptionalFileEntryRef CurrentModuleMap =
368 .getModuleMap()
369 .getModuleMapFileForUniquing(CurrentModule))
370 CI.getFrontendOpts().ModuleMapFiles.emplace_back(
371 CurrentModuleMap->getNameAsRequested());
372
373 SmallVector<ModuleID> DirectDeps;
374 for (const auto &KV : ModularDeps)
375 if (DirectModularDeps.contains(KV.first))
376 DirectDeps.push_back(KV.second->ID);
377
378 // TODO: Report module maps the same way it's done for modular dependencies.
379 addModuleMapFiles(CI, DirectDeps);
380
381 addModuleFiles(CI, DirectDeps);
382
383 for (const auto &KV : DirectPrebuiltModularDeps)
384 CI.getFrontendOpts().ModuleFiles.push_back(KV.second.PCMFile);
385 }
386}
387
388static std::string getModuleContextHash(const ModuleDeps &MD,
389 const CowCompilerInvocation &CI,
390 bool EagerLoadModules,
391 llvm::vfs::FileSystem &VFS) {
392 llvm::HashBuilder<llvm::TruncatedBLAKE3<16>, llvm::endianness::native>
393 HashBuilder;
394 SmallString<32> Scratch;
395
396 // Hash the compiler version and serialization version to ensure the module
397 // will be readable.
398 HashBuilder.add(getClangFullRepositoryVersion());
400 llvm::ErrorOr<std::string> CWD = VFS.getCurrentWorkingDirectory();
401 if (CWD)
402 HashBuilder.add(*CWD);
403
404 // Hash the BuildInvocation without any input files.
405 SmallString<0> ArgVec;
406 ArgVec.reserve(4096);
407 CI.generateCC1CommandLine([&](const Twine &Arg) {
408 Arg.toVector(ArgVec);
409 ArgVec.push_back('\0');
410 });
411 HashBuilder.add(ArgVec);
412
413 // Hash the module dependencies. These paths may differ even if the invocation
414 // is identical if they depend on the contents of the files in the TU -- for
415 // example, case-insensitive paths to modulemap files. Usually such a case
416 // would indicate a missed optimization to canonicalize, but it may be
417 // difficult to canonicalize all cases when there is a VFS.
418 for (const auto &ID : MD.ClangModuleDeps) {
419 HashBuilder.add(ID.ModuleName);
420 HashBuilder.add(ID.ContextHash);
421 }
422
423 HashBuilder.add(EagerLoadModules);
424
425 llvm::BLAKE3Result<16> Hash = HashBuilder.final();
426 std::array<uint64_t, 2> Words;
427 static_assert(sizeof(Hash) == sizeof(Words), "Hash must match Words");
428 std::memcpy(Words.data(), Hash.data(), sizeof(Hash));
429 return toString(llvm::APInt(sizeof(Words) * 8, Words), 36, /*Signed=*/false);
430}
431
432void ModuleDepCollector::associateWithContextHash(
433 const CowCompilerInvocation &CI, ModuleDeps &Deps) {
435 Deps, CI, EagerLoadModules, ScanInstance.getVirtualFileSystem());
436 bool Inserted = ModuleDepsByID.insert({Deps.ID, &Deps}).second;
437 (void)Inserted;
438 assert(Inserted && "duplicate module mapping");
439}
440
444 FileID PrevFID,
447 return;
448
449 // This has to be delayed as the context hash can change at the start of
450 // `CompilerInstance::ExecuteAction`.
451 if (MDC.ContextHash.empty()) {
452 MDC.ContextHash = MDC.ScanInstance.getInvocation().getModuleHash();
453 MDC.Consumer.handleContextHash(MDC.ContextHash);
454 }
455
456 SourceManager &SM = MDC.ScanInstance.getSourceManager();
457
458 // Dependency generation really does want to go all the way to the
459 // file entry for a source location to find out what is depended on.
460 // We do not want #line markers to affect dependency generation!
461 if (std::optional<StringRef> Filename = SM.getNonBuiltinFilenameForID(FID))
462 MDC.addFileDep(llvm::sys::path::remove_leading_dotslash(*Filename));
463}
464
466 SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,
467 bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef File,
468 StringRef SearchPath, StringRef RelativePath, const Module *SuggestedModule,
469 bool ModuleImported, SrcMgr::CharacteristicKind FileType) {
470 if (!File && !ModuleImported) {
471 // This is a non-modular include that HeaderSearch failed to find. Add it
472 // here as `FileChanged` will never see it.
473 MDC.addFileDep(FileName);
474 }
475 handleImport(SuggestedModule);
476}
477
479 ModuleIdPath Path,
480 const Module *Imported) {
481 if (MDC.ScanInstance.getPreprocessor().isInImportingCXXNamedModules()) {
482 P1689ModuleInfo RequiredModule;
483 RequiredModule.ModuleName = Path[0].first->getName().str();
485 MDC.RequiredStdCXXModules.push_back(RequiredModule);
486 return;
487 }
488
489 handleImport(Imported);
490}
491
492void ModuleDepCollectorPP::handleImport(const Module *Imported) {
493 if (!Imported)
494 return;
495
496 const Module *TopLevelModule = Imported->getTopLevelModule();
497
498 if (MDC.isPrebuiltModule(TopLevelModule))
499 MDC.DirectPrebuiltModularDeps.insert(
500 {TopLevelModule, PrebuiltModuleDep{TopLevelModule}});
501 else
502 MDC.DirectModularDeps.insert(TopLevelModule);
503}
504
506 FileID MainFileID = MDC.ScanInstance.getSourceManager().getMainFileID();
507 MDC.MainFile = std::string(MDC.ScanInstance.getSourceManager()
508 .getFileEntryRefForID(MainFileID)
509 ->getName());
510
511 auto &PP = MDC.ScanInstance.getPreprocessor();
512 if (PP.isInNamedModule()) {
513 P1689ModuleInfo ProvidedModule;
514 ProvidedModule.ModuleName = PP.getNamedModuleName();
516 ProvidedModule.IsStdCXXModuleInterface = PP.isInNamedInterfaceUnit();
517 // Don't put implementation (non partition) unit as Provide.
518 // Put the module as required instead. Since the implementation
519 // unit will import the primary module implicitly.
520 if (PP.isInImplementationUnit())
521 MDC.RequiredStdCXXModules.push_back(ProvidedModule);
522 else
523 MDC.ProvidedStdCXXModule = ProvidedModule;
524 }
525
526 if (!MDC.ScanInstance.getPreprocessorOpts().ImplicitPCHInclude.empty())
527 MDC.addFileDep(MDC.ScanInstance.getPreprocessorOpts().ImplicitPCHInclude);
528
529 for (const Module *M :
530 MDC.ScanInstance.getPreprocessor().getAffectingClangModules())
531 if (!MDC.isPrebuiltModule(M))
532 MDC.DirectModularDeps.insert(M);
533
534 for (const Module *M : MDC.DirectModularDeps)
535 handleTopLevelModule(M);
536
537 MDC.Consumer.handleDependencyOutputOpts(*MDC.Opts);
538
539 if (MDC.IsStdModuleP1689Format)
541 MDC.ProvidedStdCXXModule, MDC.RequiredStdCXXModules);
542
543 for (auto &&I : MDC.ModularDeps)
544 MDC.Consumer.handleModuleDependency(*I.second);
545
546 for (const Module *M : MDC.DirectModularDeps) {
547 auto It = MDC.ModularDeps.find(M);
548 // Only report direct dependencies that were successfully handled.
549 if (It != MDC.ModularDeps.end())
550 MDC.Consumer.handleDirectModuleDependency(MDC.ModularDeps[M]->ID);
551 }
552
553 for (auto &&I : MDC.FileDeps)
554 MDC.Consumer.handleFileDependency(I);
555
556 for (auto &&I : MDC.DirectPrebuiltModularDeps)
557 MDC.Consumer.handlePrebuiltModuleDependency(I.second);
558}
559
560std::optional<ModuleID>
561ModuleDepCollectorPP::handleTopLevelModule(const Module *M) {
562 assert(M == M->getTopLevelModule() && "Expected top level module!");
563
564 // A top-level module might not be actually imported as a module when
565 // -fmodule-name is used to compile a translation unit that imports this
566 // module. In that case it can be skipped. The appropriate header
567 // dependencies will still be reported as expected.
568 if (!M->getASTFile())
569 return {};
570
571 // If this module has been handled already, just return its ID.
572 auto ModI = MDC.ModularDeps.insert({M, nullptr});
573 if (!ModI.second)
574 return ModI.first->second->ID;
575
576 ModI.first->second = std::make_unique<ModuleDeps>();
577 ModuleDeps &MD = *ModI.first->second;
578
580 MD.IsSystem = M->IsSystem;
581 // For modules which use export_as link name, the linked product that of the
582 // corresponding export_as-named module.
585
586 ModuleMap &ModMapInfo =
587 MDC.ScanInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap();
588
590
591 if (ModuleMap) {
592 SmallString<128> Path = ModuleMap->getNameAsRequested();
593 ModMapInfo.canonicalizeModuleMapPath(Path);
594 MD.ClangModuleMapFile = std::string(Path);
595 }
596
598 MDC.ScanInstance.getASTReader()->getModuleManager().lookup(
599 *M->getASTFile());
600 MDC.ScanInstance.getASTReader()->visitInputFileInfos(
601 *MF, /*IncludeSystem=*/true,
602 [&](const serialization::InputFileInfo &IFI, bool IsSystem) {
603 // __inferred_module.map is the result of the way in which an implicit
604 // module build handles inferred modules. It adds an overlay VFS with
605 // this file in the proper directory and relies on the rest of Clang to
606 // handle it like normal. With explicitly built modules we don't need
607 // to play VFS tricks, so replace it with the correct module map.
608 if (StringRef(IFI.Filename).ends_with("__inferred_module.map")) {
609 MDC.addFileDep(MD, ModuleMap->getName());
610 return;
611 }
612 MDC.addFileDep(MD, IFI.Filename);
613 });
614
616 addAllSubmodulePrebuiltDeps(M, MD, SeenDeps);
617 addAllSubmoduleDeps(M, MD, SeenDeps);
618 addAllAffectingClangModules(M, MD, SeenDeps);
619
620 MDC.ScanInstance.getASTReader()->visitInputFileInfos(
621 *MF, /*IncludeSystem=*/true,
622 [&](const serialization::InputFileInfo &IFI, bool IsSystem) {
623 if (!(IFI.TopLevel && IFI.ModuleMap))
624 return;
625 if (StringRef(IFI.FilenameAsRequested)
626 .ends_with("__inferred_module.map"))
627 return;
628 MD.ModuleMapFileDeps.emplace_back(IFI.FilenameAsRequested);
629 });
630
632 MDC.getInvocationAdjustedForModuleBuildWithoutOutputs(
633 MD, [&](CowCompilerInvocation &BuildInvocation) {
634 if (any(MDC.OptimizeArgs & (ScanningOptimizations::HeaderSearch |
637 *MDC.ScanInstance.getASTReader(), *MF,
638 MDC.PrebuiltModuleVFSMap,
639 MDC.OptimizeArgs);
640 if (any(MDC.OptimizeArgs & ScanningOptimizations::SystemWarnings))
642 BuildInvocation.getMutDiagnosticOpts(),
643 BuildInvocation.getFrontendOpts().IsSystemModule);
644 });
645
646 MDC.associateWithContextHash(CI, MD);
647
648 // Finish the compiler invocation. Requires dependencies and the context hash.
649 MDC.addOutputPaths(CI, MD);
650
651 MD.BuildInfo = std::move(CI);
652
653 return MD.ID;
654}
655
656static void forEachSubmoduleSorted(const Module *M,
657 llvm::function_ref<void(const Module *)> F) {
658 // Submodule order depends on order of header includes for inferred submodules
659 // we don't care about the exact order, so sort so that it's consistent across
660 // TUs to improve sharing.
662 llvm::stable_sort(Submodules, [](const Module *A, const Module *B) {
663 return A->Name < B->Name;
664 });
665 for (const Module *SubM : Submodules)
666 F(SubM);
667}
668
669void ModuleDepCollectorPP::addAllSubmodulePrebuiltDeps(
670 const Module *M, ModuleDeps &MD,
671 llvm::DenseSet<const Module *> &SeenSubmodules) {
672 addModulePrebuiltDeps(M, MD, SeenSubmodules);
673
674 forEachSubmoduleSorted(M, [&](const Module *SubM) {
675 addAllSubmodulePrebuiltDeps(SubM, MD, SeenSubmodules);
676 });
677}
678
679void ModuleDepCollectorPP::addModulePrebuiltDeps(
680 const Module *M, ModuleDeps &MD,
681 llvm::DenseSet<const Module *> &SeenSubmodules) {
682 for (const Module *Import : M->Imports)
683 if (Import->getTopLevelModule() != M->getTopLevelModule())
684 if (MDC.isPrebuiltModule(Import->getTopLevelModule()))
685 if (SeenSubmodules.insert(Import->getTopLevelModule()).second)
686 MD.PrebuiltModuleDeps.emplace_back(Import->getTopLevelModule());
687}
688
689void ModuleDepCollectorPP::addAllSubmoduleDeps(
690 const Module *M, ModuleDeps &MD,
691 llvm::DenseSet<const Module *> &AddedModules) {
692 addModuleDep(M, MD, AddedModules);
693
694 forEachSubmoduleSorted(M, [&](const Module *SubM) {
695 addAllSubmoduleDeps(SubM, MD, AddedModules);
696 });
697}
698
699void ModuleDepCollectorPP::addModuleDep(
700 const Module *M, ModuleDeps &MD,
701 llvm::DenseSet<const Module *> &AddedModules) {
702 for (const Module *Import : M->Imports) {
703 if (Import->getTopLevelModule() != M->getTopLevelModule() &&
704 !MDC.isPrebuiltModule(Import)) {
705 if (auto ImportID = handleTopLevelModule(Import->getTopLevelModule()))
706 if (AddedModules.insert(Import->getTopLevelModule()).second)
707 MD.ClangModuleDeps.push_back(*ImportID);
708 }
709 }
710}
711
712void ModuleDepCollectorPP::addAllAffectingClangModules(
713 const Module *M, ModuleDeps &MD,
714 llvm::DenseSet<const Module *> &AddedModules) {
715 addAffectingClangModule(M, MD, AddedModules);
716
717 for (const Module *SubM : M->submodules())
718 addAllAffectingClangModules(SubM, MD, AddedModules);
719}
720
721void ModuleDepCollectorPP::addAffectingClangModule(
722 const Module *M, ModuleDeps &MD,
723 llvm::DenseSet<const Module *> &AddedModules) {
724 for (const Module *Affecting : M->AffectingClangModules) {
725 assert(Affecting == Affecting->getTopLevelModule() &&
726 "Not quite import not top-level module");
727 if (Affecting != M->getTopLevelModule() &&
728 !MDC.isPrebuiltModule(Affecting)) {
729 if (auto ImportID = handleTopLevelModule(Affecting))
730 if (AddedModules.insert(Affecting).second)
731 MD.ClangModuleDeps.push_back(*ImportID);
732 }
733 }
734}
735
737 std::unique_ptr<DependencyOutputOptions> Opts,
738 CompilerInstance &ScanInstance, DependencyConsumer &C,
739 DependencyActionController &Controller, CompilerInvocation OriginalCI,
740 PrebuiltModuleVFSMapT PrebuiltModuleVFSMap,
741 ScanningOptimizations OptimizeArgs, bool EagerLoadModules,
742 bool IsStdModuleP1689Format)
743 : ScanInstance(ScanInstance), Consumer(C), Controller(Controller),
744 PrebuiltModuleVFSMap(std::move(PrebuiltModuleVFSMap)),
745 Opts(std::move(Opts)),
746 CommonInvocation(
747 makeCommonInvocationForModuleBuild(std::move(OriginalCI))),
748 OptimizeArgs(OptimizeArgs), EagerLoadModules(EagerLoadModules),
749 IsStdModuleP1689Format(IsStdModuleP1689Format) {}
750
752 PP.addPPCallbacks(std::make_unique<ModuleDepCollectorPP>(*this));
753}
754
756
757bool ModuleDepCollector::isPrebuiltModule(const Module *M) {
758 std::string Name(M->getTopLevelModuleName());
759 const auto &PrebuiltModuleFiles =
761 auto PrebuiltModuleFileIt = PrebuiltModuleFiles.find(Name);
762 if (PrebuiltModuleFileIt == PrebuiltModuleFiles.end())
763 return false;
764 assert("Prebuilt module came from the expected AST file" &&
765 PrebuiltModuleFileIt->second == M->getASTFile()->getName());
766 return true;
767}
768
769static StringRef makeAbsoluteAndPreferred(CompilerInstance &CI, StringRef Path,
770 SmallVectorImpl<char> &Storage) {
771 if (llvm::sys::path::is_absolute(Path) &&
772 !llvm::sys::path::is_style_windows(llvm::sys::path::Style::native))
773 return Path;
774 Storage.assign(Path.begin(), Path.end());
775 CI.getFileManager().makeAbsolutePath(Storage);
776 llvm::sys::path::make_preferred(Storage);
777 return StringRef(Storage.data(), Storage.size());
778}
779
780void ModuleDepCollector::addFileDep(StringRef Path) {
781 if (IsStdModuleP1689Format) {
782 // Within P1689 format, we don't want all the paths to be absolute path
783 // since it may violate the tranditional make style dependencies info.
784 FileDeps.push_back(std::string(Path));
785 return;
786 }
787
789 Path = makeAbsoluteAndPreferred(ScanInstance, Path, Storage);
790 FileDeps.push_back(std::string(Path));
791}
792
793void ModuleDepCollector::addFileDep(ModuleDeps &MD, StringRef Path) {
794 if (IsStdModuleP1689Format) {
795 MD.FileDeps.insert(Path);
796 return;
797 }
798
800 Path = makeAbsoluteAndPreferred(ScanInstance, Path, Storage);
801 MD.FileDeps.insert(Path);
802}
#define SM(sm)
Definition: Cuda.cpp:84
StringRef Filename
Definition: Format.cpp:2976
llvm::DenseSet< const void * > Visited
Definition: HTMLLogger.cpp:146
llvm::MachO::FileType FileType
Definition: MachO.h:45
llvm::MachO::Target Target
Definition: MachO.h:50
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.
SourceLocation Loc
Definition: SemaObjC.cpp:758
Reads an AST files chain containing the contents of a translation unit.
Definition: ASTReader.h:366
Represents a character-granular source range.
CodeGenOptions - Track various options which control how the code is optimized and passed to the back...
std::string CoverageNotesFile
The filename with path we use for coverage notes files.
std::string ProfileInstrumentUsePath
Name of the profile file to use as input for -fprofile-instr-use.
std::string SampleProfileFile
Name of the profile file to use with -fprofile-sample-use.
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 ProfileRemappingFile
Name of the profile remapping file to apply to the profile data supplied by -fprofile-sample-use or -...
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-headers-in-module=... options used to override whether -Wsystem-headers is enabl...
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.
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.
enum clang::FrontendOptions::@198 ARCMTAction
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...
unsigned ModulesPruneNonAffectingModuleMaps
Whether to prune non-affecting module map files from PCM files.
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:837
The kind of a file that we've been handed as an input.
Language getLanguage() const
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:461
std::string ModuleName
The module currently being compiled as specified by -fmodule-name.
Definition: LangOptions.h:509
OptionalFileEntryRef getModuleMapFileForUniquing(const Module *M) const
Definition: ModuleMap.cpp:1330
std::error_code canonicalizeModuleMapPath(SmallVectorImpl< char > &Path)
Canonicalize Path in a manner suitable for a module map file.
Definition: ModuleMap.cpp:1340
Describes a module or submodule.
Definition: Module.h:105
StringRef getTopLevelModuleName() const
Retrieve the name of the top-level module.
Definition: Module.h:676
llvm::SmallSetVector< Module *, 2 > Imports
The set of modules imported by this module, and on which this module depends.
Definition: Module.h:402
unsigned IsSystem
Whether this is a "system" module (which assumes that all headers in it are system headers).
Definition: Module.h:333
std::string Name
The name of this module.
Definition: Module.h:108
llvm::iterator_range< submodule_iterator > submodules()
Definition: Module.h:783
llvm::SmallVector< LinkLibrary, 2 > LinkLibraries
The set of libraries or frameworks to link against when an entity from this module is used.
Definition: Module.h:464
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:406
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:666
OptionalFileEntryRef getASTFile() const
The serialized AST file for this module, if one was created.
Definition: Module.h:681
bool UseExportAsModuleLinkName
Autolinking uses the framework name for linking purposes when this is false and the export_as name ot...
Definition: Module.h:468
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 directly imported.
Definition: ModuleFile.h:500
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
@ GeneratePCH
Generate pre-compiled header.
@ 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:56
const unsigned VERSION_MAJOR
AST file major version number supported by this version of Clang.
Definition: ASTBitCodes.h:46
@ 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.
void resetBenignCodeGenOptions(frontend::ActionKind ProgramAction, const LangOptions &LangOpts, CodeGenOptions &CGOpts)
Resets codegen options that don't affect modules/PCH.
@ 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.
if(T->getSizeExpr()) TRY_TO(TraverseStmt(const_cast< Expr * >(T -> getSizeExpr())))
void quoteMakeTarget(StringRef Target, SmallVectorImpl< char > &Res)
Quote target names for inclusion in GNU Make dependency files.
Definition: MakeSupport.cpp:11
@ 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
Definition: Format.h:5433
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.
llvm::SmallVector< Module::LinkLibrary, 2 > LinkLibraries
The set of libraries or frameworks to link against when an entity from this module is used.
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.