clang 20.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
24void ModuleDeps::forEachFileDep(llvm::function_ref<void(StringRef)> Cb) const {
25 SmallString<0> PathBuf;
26 PathBuf.reserve(256);
27 for (StringRef FileDep : FileDeps) {
28 auto ResolvedFileDep =
29 ASTReader::ResolveImportedPath(PathBuf, FileDep, FileDepsBaseDir);
30 Cb(*ResolvedFileDep);
31 }
32}
33
34const std::vector<std::string> &ModuleDeps::getBuildArguments() {
35 assert(!std::holds_alternative<std::monostate>(BuildInfo) &&
36 "Using uninitialized ModuleDeps");
37 if (const auto *CI = std::get_if<CowCompilerInvocation>(&BuildInfo))
38 BuildInfo = CI->getCC1CommandLine();
39 return std::get<std::vector<std::string>>(BuildInfo);
40}
41
42static void
45 const PrebuiltModuleVFSMapT &PrebuiltModuleVFSMap,
46 ScanningOptimizations OptimizeArgs) {
47 if (any(OptimizeArgs & ScanningOptimizations::HeaderSearch)) {
48 // Only preserve search paths that were used during the dependency scan.
49 std::vector<HeaderSearchOptions::Entry> Entries;
50 std::swap(Opts.UserEntries, Entries);
51
52 llvm::BitVector SearchPathUsage(Entries.size());
53 llvm::DenseSet<const serialization::ModuleFile *> Visited;
54 std::function<void(const serialization::ModuleFile *)> VisitMF =
55 [&](const serialization::ModuleFile *MF) {
56 SearchPathUsage |= MF->SearchPathUsage;
57 Visited.insert(MF);
59 if (!Visited.contains(Import))
60 VisitMF(Import);
61 };
62 VisitMF(&MF);
63
64 if (SearchPathUsage.size() != Entries.size())
65 llvm::report_fatal_error(
66 "Inconsistent search path options between modules detected");
67
68 for (auto Idx : SearchPathUsage.set_bits())
69 Opts.UserEntries.push_back(std::move(Entries[Idx]));
70 }
71 if (any(OptimizeArgs & ScanningOptimizations::VFS)) {
72 std::vector<std::string> VFSOverlayFiles;
73 std::swap(Opts.VFSOverlayFiles, VFSOverlayFiles);
74
75 llvm::BitVector VFSUsage(VFSOverlayFiles.size());
76 llvm::DenseSet<const serialization::ModuleFile *> Visited;
77 std::function<void(const serialization::ModuleFile *)> VisitMF =
78 [&](const serialization::ModuleFile *MF) {
79 Visited.insert(MF);
81 VFSUsage |= MF->VFSUsage;
82 // We only need to recurse into implicit modules. Other module types
83 // will have the correct set of VFSs for anything they depend on.
85 if (!Visited.contains(Import))
86 VisitMF(Import);
87 } else {
88 // This is not an implicitly built module, so it may have different
89 // VFS options. Fall back to a string comparison instead.
90 auto VFSMap = PrebuiltModuleVFSMap.find(MF->FileName);
91 if (VFSMap == PrebuiltModuleVFSMap.end())
92 return;
93 for (std::size_t I = 0, E = VFSOverlayFiles.size(); I != E; ++I) {
94 if (VFSMap->second.contains(VFSOverlayFiles[I]))
95 VFSUsage[I] = true;
96 }
97 }
98 };
99 VisitMF(&MF);
100
101 if (VFSUsage.size() != VFSOverlayFiles.size())
102 llvm::report_fatal_error(
103 "Inconsistent -ivfsoverlay options between modules detected");
104
105 for (auto Idx : VFSUsage.set_bits())
106 Opts.VFSOverlayFiles.push_back(std::move(VFSOverlayFiles[Idx]));
107 }
108}
109
111 bool IsSystemModule) {
112 // If this is not a system module or -Wsystem-headers was passed, don't
113 // optimize.
114 if (!IsSystemModule)
115 return;
116 bool Wsystem_headers = false;
117 for (StringRef Opt : Opts.Warnings) {
118 bool isPositive = !Opt.consume_front("no-");
119 if (Opt == "system-headers")
120 Wsystem_headers = isPositive;
121 }
122 if (Wsystem_headers)
123 return;
124
125 // Remove all warning flags. System modules suppress most, but not all,
126 // warnings.
127 Opts.Warnings.clear();
128 Opts.UndefPrefixes.clear();
129 Opts.Remarks.clear();
130}
131
132static std::vector<std::string> splitString(std::string S, char Separator) {
133 SmallVector<StringRef> Segments;
134 StringRef(S).split(Segments, Separator, /*MaxSplit=*/-1, /*KeepEmpty=*/false);
135 std::vector<std::string> Result;
136 Result.reserve(Segments.size());
137 for (StringRef Segment : Segments)
138 Result.push_back(Segment.str());
139 return Result;
140}
141
142void ModuleDepCollector::addOutputPaths(CowCompilerInvocation &CI,
143 ModuleDeps &Deps) {
148 Controller.lookupModuleOutput(
150 if (!CI.getDependencyOutputOpts().OutputFile.empty()) {
156 '\0');
157 if (!CI.getDependencyOutputOpts().OutputFile.empty() &&
158 CI.getDependencyOutputOpts().Targets.empty()) {
159 // Fallback to -o as dependency target, as in the driver.
162 CI.getMutDependencyOutputOpts().Targets.push_back(std::string(Target));
163 }
164 }
165}
166
168 const LangOptions &LangOpts,
169 CodeGenOptions &CGOpts) {
170 // TODO: Figure out better way to set options to their default value.
171 if (ProgramAction == frontend::GenerateModule) {
172 CGOpts.MainFileName.clear();
173 CGOpts.DwarfDebugFlags.clear();
174 }
175 if (ProgramAction == frontend::GeneratePCH ||
176 (ProgramAction == frontend::GenerateModule && !LangOpts.ModulesCodegen)) {
177 CGOpts.DebugCompilationDir.clear();
178 CGOpts.CoverageCompilationDir.clear();
179 CGOpts.CoverageDataFile.clear();
180 CGOpts.CoverageNotesFile.clear();
181 CGOpts.ProfileInstrumentUsePath.clear();
182 CGOpts.SampleProfileFile.clear();
183 CGOpts.ProfileRemappingFile.clear();
184 }
185}
186
191
192 // The scanner takes care to avoid passing non-affecting module maps to the
193 // explicit compiles. No need to do extra work just to find out there are no
194 // module map files to prune.
196
197 // Remove options incompatible with explicit module build or are likely to
198 // differ between identical modules discovered from different translation
199 // units.
200 CI.getFrontendOpts().Inputs.clear();
201 CI.getFrontendOpts().OutputFile.clear();
202 // LLVM options are not going to affect the AST
203 CI.getFrontendOpts().LLVMArgs.clear();
204
206 CI.getCodeGenOpts());
207
208 // Map output paths that affect behaviour to "-" so their existence is in the
209 // context hash. The final path will be computed in addOutputPaths.
212 if (!CI.getDependencyOutputOpts().OutputFile.empty())
214 CI.getDependencyOutputOpts().Targets.clear();
215
219 CI.getFrontendOpts().MTMigrateDir.clear();
220 CI.getLangOpts().ModuleName.clear();
221
222 // Remove any macro definitions that are explicitly ignored.
223 if (!CI.getHeaderSearchOpts().ModulesIgnoreMacros.empty()) {
224 llvm::erase_if(
226 [&CI](const std::pair<std::string, bool> &Def) {
227 StringRef MacroDef = Def.first;
228 return CI.getHeaderSearchOpts().ModulesIgnoreMacros.contains(
229 llvm::CachedHashString(MacroDef.split('=').first));
230 });
231 // Remove the now unused option.
233 }
234
235 return CI;
236}
237
239ModuleDepCollector::getInvocationAdjustedForModuleBuildWithoutOutputs(
240 const ModuleDeps &Deps,
241 llvm::function_ref<void(CowCompilerInvocation &)> Optimize) const {
242 CowCompilerInvocation CI = CommonInvocation;
243
246
247 // Inputs
248 InputKind ModuleMapInputKind(CI.getFrontendOpts().DashX.getLanguage(),
250 CI.getMutFrontendOpts().Inputs.emplace_back(Deps.ClangModuleMapFile,
251 ModuleMapInputKind);
252
253 auto CurrentModuleMapEntry =
255 assert(CurrentModuleMapEntry && "module map file entry not found");
256
257 // Remove directly passed modulemap files. They will get added back if they
258 // were actually used.
260
261 auto DepModuleMapFiles = collectModuleMapFiles(Deps.ClangModuleDeps);
262 for (StringRef ModuleMapFile : Deps.ModuleMapFileDeps) {
263 // TODO: Track these as `FileEntryRef` to simplify the equality check below.
264 auto ModuleMapEntry =
265 ScanInstance.getFileManager().getOptionalFileRef(ModuleMapFile);
266 assert(ModuleMapEntry && "module map file entry not found");
267
268 // Don't report module maps describing eagerly-loaded dependency. This
269 // information will be deserialized from the PCM.
270 // TODO: Verify this works fine when modulemap for module A is eagerly
271 // loaded from A.pcm, and module map passed on the command line contains
272 // definition of a submodule: "explicit module A.Private { ... }".
273 if (EagerLoadModules && DepModuleMapFiles.contains(*ModuleMapEntry))
274 continue;
275
276 // Don't report module map file of the current module unless it also
277 // describes a dependency (for symmetry).
278 if (*ModuleMapEntry == *CurrentModuleMapEntry &&
279 !DepModuleMapFiles.contains(*ModuleMapEntry))
280 continue;
281
282 CI.getMutFrontendOpts().ModuleMapFiles.emplace_back(ModuleMapFile);
283 }
284
285 // Report the prebuilt modules this module uses.
286 for (const auto &PrebuiltModule : Deps.PrebuiltModuleDeps)
287 CI.getMutFrontendOpts().ModuleFiles.push_back(PrebuiltModule.PCMFile);
288
289 // Add module file inputs from dependencies.
290 addModuleFiles(CI, Deps.ClangModuleDeps);
291
293 // Apply -Wsystem-headers-in-module for the current module.
294 if (llvm::is_contained(CI.getDiagnosticOpts().SystemHeaderWarningsModules,
295 Deps.ID.ModuleName))
296 CI.getMutDiagnosticOpts().Warnings.push_back("system-headers");
297 // Remove the now unused option(s).
299 }
300
301 Optimize(CI);
302
303 return CI;
304}
305
306llvm::DenseSet<const FileEntry *> ModuleDepCollector::collectModuleMapFiles(
307 ArrayRef<ModuleID> ClangModuleDeps) const {
308 llvm::DenseSet<const FileEntry *> ModuleMapFiles;
309 for (const ModuleID &MID : ClangModuleDeps) {
310 ModuleDeps *MD = ModuleDepsByID.lookup(MID);
311 assert(MD && "Inconsistent dependency info");
312 // TODO: Track ClangModuleMapFile as `FileEntryRef`.
313 auto FE = ScanInstance.getFileManager().getOptionalFileRef(
315 assert(FE && "Missing module map file that was previously found");
316 ModuleMapFiles.insert(*FE);
317 }
318 return ModuleMapFiles;
319}
320
321void ModuleDepCollector::addModuleMapFiles(
322 CompilerInvocation &CI, ArrayRef<ModuleID> ClangModuleDeps) const {
323 if (EagerLoadModules)
324 return; // Only pcm is needed for eager load.
325
326 for (const ModuleID &MID : ClangModuleDeps) {
327 ModuleDeps *MD = ModuleDepsByID.lookup(MID);
328 assert(MD && "Inconsistent dependency info");
330 }
331}
332
333void ModuleDepCollector::addModuleFiles(
334 CompilerInvocation &CI, ArrayRef<ModuleID> ClangModuleDeps) const {
335 for (const ModuleID &MID : ClangModuleDeps) {
336 std::string PCMPath =
338 if (EagerLoadModules)
339 CI.getFrontendOpts().ModuleFiles.push_back(std::move(PCMPath));
340 else
342 {MID.ModuleName, std::move(PCMPath)});
343 }
344}
345
346void ModuleDepCollector::addModuleFiles(
347 CowCompilerInvocation &CI, ArrayRef<ModuleID> ClangModuleDeps) const {
348 for (const ModuleID &MID : ClangModuleDeps) {
349 std::string PCMPath =
351 if (EagerLoadModules)
352 CI.getMutFrontendOpts().ModuleFiles.push_back(std::move(PCMPath));
353 else
355 {MID.ModuleName, std::move(PCMPath)});
356 }
357}
358
360 switch (FIF.getKind().getLanguage()) {
362 case Language::Asm:
364 return false;
365 default:
366 return true;
367 }
368}
369
373 CI.getLangOpts(), CI.getCodeGenOpts());
374
375 if (llvm::any_of(CI.getFrontendOpts().Inputs, needsModules)) {
376 Preprocessor &PP = ScanInstance.getPreprocessor();
377 if (Module *CurrentModule = PP.getCurrentModuleImplementation())
378 if (OptionalFileEntryRef CurrentModuleMap =
380 .getModuleMap()
381 .getModuleMapFileForUniquing(CurrentModule))
382 CI.getFrontendOpts().ModuleMapFiles.emplace_back(
383 CurrentModuleMap->getNameAsRequested());
384
385 SmallVector<ModuleID> DirectDeps;
386 for (const auto &KV : ModularDeps)
387 if (DirectModularDeps.contains(KV.first))
388 DirectDeps.push_back(KV.second->ID);
389
390 // TODO: Report module maps the same way it's done for modular dependencies.
391 addModuleMapFiles(CI, DirectDeps);
392
393 addModuleFiles(CI, DirectDeps);
394
395 for (const auto &KV : DirectPrebuiltModularDeps)
396 CI.getFrontendOpts().ModuleFiles.push_back(KV.second.PCMFile);
397 }
398}
399
400static std::string getModuleContextHash(const ModuleDeps &MD,
401 const CowCompilerInvocation &CI,
402 bool EagerLoadModules,
403 llvm::vfs::FileSystem &VFS) {
404 llvm::HashBuilder<llvm::TruncatedBLAKE3<16>, llvm::endianness::native>
405 HashBuilder;
406 SmallString<32> Scratch;
407
408 // Hash the compiler version and serialization version to ensure the module
409 // will be readable.
410 HashBuilder.add(getClangFullRepositoryVersion());
412 llvm::ErrorOr<std::string> CWD = VFS.getCurrentWorkingDirectory();
413 if (CWD)
414 HashBuilder.add(*CWD);
415
416 // Hash the BuildInvocation without any input files.
417 SmallString<0> ArgVec;
418 ArgVec.reserve(4096);
419 CI.generateCC1CommandLine([&](const Twine &Arg) {
420 Arg.toVector(ArgVec);
421 ArgVec.push_back('\0');
422 });
423 HashBuilder.add(ArgVec);
424
425 // Hash the module dependencies. These paths may differ even if the invocation
426 // is identical if they depend on the contents of the files in the TU -- for
427 // example, case-insensitive paths to modulemap files. Usually such a case
428 // would indicate a missed optimization to canonicalize, but it may be
429 // difficult to canonicalize all cases when there is a VFS.
430 for (const auto &ID : MD.ClangModuleDeps) {
431 HashBuilder.add(ID.ModuleName);
432 HashBuilder.add(ID.ContextHash);
433 }
434
435 HashBuilder.add(EagerLoadModules);
436
437 llvm::BLAKE3Result<16> Hash = HashBuilder.final();
438 std::array<uint64_t, 2> Words;
439 static_assert(sizeof(Hash) == sizeof(Words), "Hash must match Words");
440 std::memcpy(Words.data(), Hash.data(), sizeof(Hash));
441 return toString(llvm::APInt(sizeof(Words) * 8, Words), 36, /*Signed=*/false);
442}
443
444void ModuleDepCollector::associateWithContextHash(
445 const CowCompilerInvocation &CI, ModuleDeps &Deps) {
447 Deps, CI, EagerLoadModules, ScanInstance.getVirtualFileSystem());
448 bool Inserted = ModuleDepsByID.insert({Deps.ID, &Deps}).second;
449 (void)Inserted;
450 assert(Inserted && "duplicate module mapping");
451}
452
456 FileID PrevFID,
459 return;
460
461 // This has to be delayed as the context hash can change at the start of
462 // `CompilerInstance::ExecuteAction`.
463 if (MDC.ContextHash.empty()) {
464 MDC.ContextHash = MDC.ScanInstance.getInvocation().getModuleHash();
465 MDC.Consumer.handleContextHash(MDC.ContextHash);
466 }
467
468 SourceManager &SM = MDC.ScanInstance.getSourceManager();
469
470 // Dependency generation really does want to go all the way to the
471 // file entry for a source location to find out what is depended on.
472 // We do not want #line markers to affect dependency generation!
473 if (std::optional<StringRef> Filename = SM.getNonBuiltinFilenameForID(FID))
474 MDC.addFileDep(llvm::sys::path::remove_leading_dotslash(*Filename));
475}
476
478 SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,
479 bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef File,
480 StringRef SearchPath, StringRef RelativePath, const Module *SuggestedModule,
481 bool ModuleImported, SrcMgr::CharacteristicKind FileType) {
482 if (!File && !ModuleImported) {
483 // This is a non-modular include that HeaderSearch failed to find. Add it
484 // here as `FileChanged` will never see it.
485 MDC.addFileDep(FileName);
486 }
487 handleImport(SuggestedModule);
488}
489
492 const Module *Imported) {
493 if (MDC.ScanInstance.getPreprocessor().isInImportingCXXNamedModules()) {
494 P1689ModuleInfo RequiredModule;
495 RequiredModule.ModuleName = Path[0].first->getName().str();
497 MDC.RequiredStdCXXModules.push_back(RequiredModule);
498 return;
499 }
500
501 handleImport(Imported);
502}
503
504void ModuleDepCollectorPP::handleImport(const Module *Imported) {
505 if (!Imported)
506 return;
507
508 const Module *TopLevelModule = Imported->getTopLevelModule();
509
510 if (MDC.isPrebuiltModule(TopLevelModule))
511 MDC.DirectPrebuiltModularDeps.insert(
512 {TopLevelModule, PrebuiltModuleDep{TopLevelModule}});
513 else
514 MDC.DirectModularDeps.insert(TopLevelModule);
515}
516
518 FileID MainFileID = MDC.ScanInstance.getSourceManager().getMainFileID();
519 MDC.MainFile = std::string(MDC.ScanInstance.getSourceManager()
520 .getFileEntryRefForID(MainFileID)
521 ->getName());
522
523 auto &PP = MDC.ScanInstance.getPreprocessor();
524 if (PP.isInNamedModule()) {
525 P1689ModuleInfo ProvidedModule;
526 ProvidedModule.ModuleName = PP.getNamedModuleName();
528 ProvidedModule.IsStdCXXModuleInterface = PP.isInNamedInterfaceUnit();
529 // Don't put implementation (non partition) unit as Provide.
530 // Put the module as required instead. Since the implementation
531 // unit will import the primary module implicitly.
532 if (PP.isInImplementationUnit())
533 MDC.RequiredStdCXXModules.push_back(ProvidedModule);
534 else
535 MDC.ProvidedStdCXXModule = ProvidedModule;
536 }
537
538 if (!MDC.ScanInstance.getPreprocessorOpts().ImplicitPCHInclude.empty())
539 MDC.addFileDep(MDC.ScanInstance.getPreprocessorOpts().ImplicitPCHInclude);
540
541 for (const Module *M :
542 MDC.ScanInstance.getPreprocessor().getAffectingClangModules())
543 if (!MDC.isPrebuiltModule(M))
544 MDC.DirectModularDeps.insert(M);
545
546 for (const Module *M : MDC.DirectModularDeps)
547 handleTopLevelModule(M);
548
549 MDC.Consumer.handleDependencyOutputOpts(*MDC.Opts);
550
551 if (MDC.IsStdModuleP1689Format)
553 MDC.ProvidedStdCXXModule, MDC.RequiredStdCXXModules);
554
555 for (auto &&I : MDC.ModularDeps)
556 MDC.Consumer.handleModuleDependency(*I.second);
557
558 for (const Module *M : MDC.DirectModularDeps) {
559 auto It = MDC.ModularDeps.find(M);
560 // Only report direct dependencies that were successfully handled.
561 if (It != MDC.ModularDeps.end())
562 MDC.Consumer.handleDirectModuleDependency(It->second->ID);
563 }
564
565 for (auto &&I : MDC.FileDeps)
566 MDC.Consumer.handleFileDependency(I);
567
568 for (auto &&I : MDC.DirectPrebuiltModularDeps)
569 MDC.Consumer.handlePrebuiltModuleDependency(I.second);
570}
571
572std::optional<ModuleID>
573ModuleDepCollectorPP::handleTopLevelModule(const Module *M) {
574 assert(M == M->getTopLevelModule() && "Expected top level module!");
575
576 // A top-level module might not be actually imported as a module when
577 // -fmodule-name is used to compile a translation unit that imports this
578 // module. In that case it can be skipped. The appropriate header
579 // dependencies will still be reported as expected.
580 if (!M->getASTFile())
581 return {};
582
583 // If this module has been handled already, just return its ID.
584 if (auto ModI = MDC.ModularDeps.find(M); ModI != MDC.ModularDeps.end())
585 return ModI->second->ID;
586
587 auto OwnedMD = std::make_unique<ModuleDeps>();
588 ModuleDeps &MD = *OwnedMD;
589
591 MD.IsSystem = M->IsSystem;
592 // For modules which use export_as link name, the linked product that of the
593 // corresponding export_as-named module.
596
597 ModuleMap &ModMapInfo =
598 MDC.ScanInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap();
599
600 if (auto ModuleMap = ModMapInfo.getModuleMapFileForUniquing(M)) {
601 SmallString<128> Path = ModuleMap->getNameAsRequested();
603 MD.ClangModuleMapFile = std::string(Path);
604 }
605
607 MDC.ScanInstance.getASTReader()->getModuleManager().lookup(
608 *M->getASTFile());
609 MD.FileDepsBaseDir = MF->BaseDirectory;
610 MDC.ScanInstance.getASTReader()->visitInputFileInfos(
611 *MF, /*IncludeSystem=*/true,
612 [&](const serialization::InputFileInfo &IFI, bool IsSystem) {
613 // The __inferred_module.map file is an insignificant implementation
614 // detail of implicitly-built modules. The PCM will also report the
615 // actual on-disk module map file that allowed inferring the module,
616 // which is what we need for building the module explicitly
617 // Let's ignore this file.
618 if (IFI.UnresolvedImportedFilename.ends_with("__inferred_module.map"))
619 return;
620 MDC.addFileDep(MD, IFI.UnresolvedImportedFilename);
621 });
622
623 llvm::DenseSet<const Module *> SeenDeps;
624 addAllSubmodulePrebuiltDeps(M, MD, SeenDeps);
625 addAllSubmoduleDeps(M, MD, SeenDeps);
626 addAllAffectingClangModules(M, MD, SeenDeps);
627
628 SmallString<0> PathBuf;
629 PathBuf.reserve(256);
630 MDC.ScanInstance.getASTReader()->visitInputFileInfos(
631 *MF, /*IncludeSystem=*/true,
632 [&](const serialization::InputFileInfo &IFI, bool IsSystem) {
633 if (!(IFI.TopLevel && IFI.ModuleMap))
634 return;
636 "__inferred_module.map"))
637 return;
638 auto ResolvedFilenameAsRequested = ASTReader::ResolveImportedPath(
640 MF->BaseDirectory);
641 MD.ModuleMapFileDeps.emplace_back(*ResolvedFilenameAsRequested);
642 });
643
645 MDC.getInvocationAdjustedForModuleBuildWithoutOutputs(
646 MD, [&](CowCompilerInvocation &BuildInvocation) {
647 if (any(MDC.OptimizeArgs & (ScanningOptimizations::HeaderSearch |
650 *MDC.ScanInstance.getASTReader(), *MF,
651 MDC.PrebuiltModuleVFSMap,
652 MDC.OptimizeArgs);
653 if (any(MDC.OptimizeArgs & ScanningOptimizations::SystemWarnings))
655 BuildInvocation.getMutDiagnosticOpts(),
656 BuildInvocation.getFrontendOpts().IsSystemModule);
657 });
658
659 MDC.associateWithContextHash(CI, MD);
660
661 // Finish the compiler invocation. Requires dependencies and the context hash.
662 MDC.addOutputPaths(CI, MD);
663
664 MD.BuildInfo = std::move(CI);
665
666 MDC.ModularDeps.insert({M, std::move(OwnedMD)});
667
668 return MD.ID;
669}
670
671static void forEachSubmoduleSorted(const Module *M,
672 llvm::function_ref<void(const Module *)> F) {
673 // Submodule order depends on order of header includes for inferred submodules
674 // we don't care about the exact order, so sort so that it's consistent across
675 // TUs to improve sharing.
677 llvm::stable_sort(Submodules, [](const Module *A, const Module *B) {
678 return A->Name < B->Name;
679 });
680 for (const Module *SubM : Submodules)
681 F(SubM);
682}
683
684void ModuleDepCollectorPP::addAllSubmodulePrebuiltDeps(
685 const Module *M, ModuleDeps &MD,
686 llvm::DenseSet<const Module *> &SeenSubmodules) {
687 addModulePrebuiltDeps(M, MD, SeenSubmodules);
688
689 forEachSubmoduleSorted(M, [&](const Module *SubM) {
690 addAllSubmodulePrebuiltDeps(SubM, MD, SeenSubmodules);
691 });
692}
693
694void ModuleDepCollectorPP::addModulePrebuiltDeps(
695 const Module *M, ModuleDeps &MD,
696 llvm::DenseSet<const Module *> &SeenSubmodules) {
697 for (const Module *Import : M->Imports)
698 if (Import->getTopLevelModule() != M->getTopLevelModule())
699 if (MDC.isPrebuiltModule(Import->getTopLevelModule()))
700 if (SeenSubmodules.insert(Import->getTopLevelModule()).second)
701 MD.PrebuiltModuleDeps.emplace_back(Import->getTopLevelModule());
702}
703
704void ModuleDepCollectorPP::addAllSubmoduleDeps(
705 const Module *M, ModuleDeps &MD,
706 llvm::DenseSet<const Module *> &AddedModules) {
707 addModuleDep(M, MD, AddedModules);
708
709 forEachSubmoduleSorted(M, [&](const Module *SubM) {
710 addAllSubmoduleDeps(SubM, MD, AddedModules);
711 });
712}
713
714void ModuleDepCollectorPP::addModuleDep(
715 const Module *M, ModuleDeps &MD,
716 llvm::DenseSet<const Module *> &AddedModules) {
717 for (const Module *Import : M->Imports) {
718 if (Import->getTopLevelModule() != M->getTopLevelModule() &&
719 !MDC.isPrebuiltModule(Import)) {
720 if (auto ImportID = handleTopLevelModule(Import->getTopLevelModule()))
721 if (AddedModules.insert(Import->getTopLevelModule()).second)
722 MD.ClangModuleDeps.push_back(*ImportID);
723 }
724 }
725}
726
727void ModuleDepCollectorPP::addAllAffectingClangModules(
728 const Module *M, ModuleDeps &MD,
729 llvm::DenseSet<const Module *> &AddedModules) {
730 addAffectingClangModule(M, MD, AddedModules);
731
732 for (const Module *SubM : M->submodules())
733 addAllAffectingClangModules(SubM, MD, AddedModules);
734}
735
736void ModuleDepCollectorPP::addAffectingClangModule(
737 const Module *M, ModuleDeps &MD,
738 llvm::DenseSet<const Module *> &AddedModules) {
739 for (const Module *Affecting : M->AffectingClangModules) {
740 assert(Affecting == Affecting->getTopLevelModule() &&
741 "Not quite import not top-level module");
742 if (Affecting != M->getTopLevelModule() &&
743 !MDC.isPrebuiltModule(Affecting)) {
744 if (auto ImportID = handleTopLevelModule(Affecting))
745 if (AddedModules.insert(Affecting).second)
746 MD.ClangModuleDeps.push_back(*ImportID);
747 }
748 }
749}
750
752 std::unique_ptr<DependencyOutputOptions> Opts,
753 CompilerInstance &ScanInstance, DependencyConsumer &C,
754 DependencyActionController &Controller, CompilerInvocation OriginalCI,
755 PrebuiltModuleVFSMapT PrebuiltModuleVFSMap,
756 ScanningOptimizations OptimizeArgs, bool EagerLoadModules,
757 bool IsStdModuleP1689Format)
758 : ScanInstance(ScanInstance), Consumer(C), Controller(Controller),
759 PrebuiltModuleVFSMap(std::move(PrebuiltModuleVFSMap)),
760 Opts(std::move(Opts)),
761 CommonInvocation(
762 makeCommonInvocationForModuleBuild(std::move(OriginalCI))),
763 OptimizeArgs(OptimizeArgs), EagerLoadModules(EagerLoadModules),
764 IsStdModuleP1689Format(IsStdModuleP1689Format) {}
765
767 PP.addPPCallbacks(std::make_unique<ModuleDepCollectorPP>(*this));
768}
769
771
772bool ModuleDepCollector::isPrebuiltModule(const Module *M) {
773 std::string Name(M->getTopLevelModuleName());
774 const auto &PrebuiltModuleFiles =
776 auto PrebuiltModuleFileIt = PrebuiltModuleFiles.find(Name);
777 if (PrebuiltModuleFileIt == PrebuiltModuleFiles.end())
778 return false;
779 assert("Prebuilt module came from the expected AST file" &&
780 PrebuiltModuleFileIt->second == M->getASTFile()->getName());
781 return true;
782}
783
784static StringRef makeAbsoluteAndPreferred(CompilerInstance &CI, StringRef Path,
785 SmallVectorImpl<char> &Storage) {
786 if (llvm::sys::path::is_absolute(Path) &&
787 !llvm::sys::path::is_style_windows(llvm::sys::path::Style::native))
788 return Path;
789 Storage.assign(Path.begin(), Path.end());
790 CI.getFileManager().makeAbsolutePath(Storage);
791 llvm::sys::path::make_preferred(Storage);
792 return StringRef(Storage.data(), Storage.size());
793}
794
795void ModuleDepCollector::addFileDep(StringRef Path) {
796 if (IsStdModuleP1689Format) {
797 // Within P1689 format, we don't want all the paths to be absolute path
798 // since it may violate the traditional make style dependencies info.
799 FileDeps.emplace_back(Path);
800 return;
801 }
802
804 Path = makeAbsoluteAndPreferred(ScanInstance, Path, Storage);
805 FileDeps.emplace_back(Path);
806}
807
808void ModuleDepCollector::addFileDep(ModuleDeps &MD, StringRef Path) {
809 MD.FileDeps.emplace_back(Path);
810}
#define SM(sm)
Definition: Cuda.cpp:84
IndirectLocalPath & Path
Expr * E
StringRef Filename
Definition: Format.cpp:3032
llvm::DenseSet< const void * > Visited
Definition: HTMLLogger.cpp:145
llvm::MachO::FileType FileType
Definition: MachO.h:46
llvm::MachO::Target Target
Definition: MachO.h:51
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:759
Reads an AST files chain containing the contents of a translation unit.
Definition: ASTReader.h:383
static TemporarilyOwnedStringRef ResolveImportedPath(SmallString< 0 > &Buf, StringRef Path, ModuleFile &ModF)
Resolve Path in the context of module file M.
Definition: ASTReader.cpp:2815
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...
OptionalFileEntryRef getOptionalFileRef(StringRef Filename, bool OpenFile=false, bool CacheFailure=true)
Get a FileEntryRef if it exists, without doing anything on error.
Definition: FileManager.h:245
bool makeAbsolutePath(SmallVectorImpl< char > &Path) const
Makes Path absolute taking into account FileSystemOptions and the working directory option.
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.
SmallVector< FrontendInputFile, 0 > Inputs
The input files and their types.
frontend::ActionKind ProgramAction
The frontend action to perform.
enum clang::FrontendOptions::@199 ARCMTAction
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:821
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:499
std::string ModuleName
The module currently being compiled as specified by -fmodule-name.
Definition: LangOptions.h:547
OptionalFileEntryRef getModuleMapFileForUniquing(const Module *M) const
Definition: ModuleMap.cpp:1348
std::error_code canonicalizeModuleMapPath(SmallVectorImpl< char > &Path)
Canonicalize Path in a manner suitable for a module map file.
Definition: ModuleMap.cpp:1358
Describes a module or submodule.
Definition: Module.h:115
StringRef getTopLevelModuleName() const
Retrieve the name of the top-level module.
Definition: Module.h:703
llvm::SmallSetVector< Module *, 2 > Imports
The set of modules imported by this module, and on which this module depends.
Definition: Module.h:429
unsigned IsSystem
Whether this is a "system" module (which assumes that all headers in it are system headers).
Definition: Module.h:360
std::string Name
The name of this module.
Definition: Module.h:118
llvm::iterator_range< submodule_iterator > submodules()
Definition: Module.h:809
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:491
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:433
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:240
Module * getTopLevelModule()
Retrieve the top-level module for this (sub)module, which may be this module.
Definition: Module.h:693
OptionalFileEntryRef getASTFile() const
The serialized AST file for this module, if one was created.
Definition: Module.h:708
bool UseExportAsModuleLinkName
Autolinking uses the framework name for linking purposes when this is false and the export_as name ot...
Definition: Module.h:495
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:138
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:130
std::string FileName
The file name of the module file.
Definition: ModuleFile.h:145
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:196
llvm::BitVector VFSUsage
The bit vector denoting usage of each VFS entry (true = used).
Definition: ModuleFile.h:199
ModuleKind Kind
The type of this module.
Definition: ModuleFile.h:142
std::string BaseDirectory
The base directory of the module.
Definition: ModuleFile.h:151
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:57
const unsigned VERSION_MAJOR
AST file major version number supported by this version of Clang.
Definition: ASTBitCodes.h:47
@ MK_ImplicitModule
File is an implicitly-loaded module.
Definition: ModuleFile.h:45
@ 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
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:64
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.
void forEachFileDep(llvm::function_ref< void(StringRef)> Cb) const
Invokes Cb for all file dependencies of this module.
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.
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.