1480093f4SDimitry Andric //===- ModuleDepCollector.cpp - Callbacks to collect deps -------*- C++ -*-===// 2480093f4SDimitry Andric // 3349cc55cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4349cc55cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5349cc55cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6480093f4SDimitry Andric // 7480093f4SDimitry Andric //===----------------------------------------------------------------------===// 8480093f4SDimitry Andric 9480093f4SDimitry Andric #include "clang/Tooling/DependencyScanning/ModuleDepCollector.h" 10480093f4SDimitry Andric 11753f127fSDimitry Andric #include "clang/Basic/MakeSupport.h" 12480093f4SDimitry Andric #include "clang/Frontend/CompilerInstance.h" 13480093f4SDimitry Andric #include "clang/Lex/Preprocessor.h" 14480093f4SDimitry Andric #include "clang/Tooling/DependencyScanning/DependencyScanningWorker.h" 155f757f3fSDimitry Andric #include "llvm/ADT/STLExtras.h" 16bdd1243dSDimitry Andric #include "llvm/Support/BLAKE3.h" 17fe6060f1SDimitry Andric #include "llvm/Support/StringSaver.h" 18bdd1243dSDimitry Andric #include <optional> 19480093f4SDimitry Andric 20480093f4SDimitry Andric using namespace clang; 21480093f4SDimitry Andric using namespace tooling; 22480093f4SDimitry Andric using namespace dependencies; 23480093f4SDimitry Andric 245f757f3fSDimitry Andric const std::vector<std::string> &ModuleDeps::getBuildArguments() { 255f757f3fSDimitry Andric assert(!std::holds_alternative<std::monostate>(BuildInfo) && 265f757f3fSDimitry Andric "Using uninitialized ModuleDeps"); 275f757f3fSDimitry Andric if (const auto *CI = std::get_if<CowCompilerInvocation>(&BuildInfo)) 285f757f3fSDimitry Andric BuildInfo = CI->getCC1CommandLine(); 295f757f3fSDimitry Andric return std::get<std::vector<std::string>>(BuildInfo); 305f757f3fSDimitry Andric } 315f757f3fSDimitry Andric 32*0fca6ea1SDimitry Andric static void 33*0fca6ea1SDimitry Andric optimizeHeaderSearchOpts(HeaderSearchOptions &Opts, ASTReader &Reader, 34*0fca6ea1SDimitry Andric const serialization::ModuleFile &MF, 35*0fca6ea1SDimitry Andric const PrebuiltModuleVFSMapT &PrebuiltModuleVFSMap, 36*0fca6ea1SDimitry Andric ScanningOptimizations OptimizeArgs) { 37*0fca6ea1SDimitry Andric if (any(OptimizeArgs & ScanningOptimizations::HeaderSearch)) { 38349cc55cSDimitry Andric // Only preserve search paths that were used during the dependency scan. 39*0fca6ea1SDimitry Andric std::vector<HeaderSearchOptions::Entry> Entries; 40*0fca6ea1SDimitry Andric std::swap(Opts.UserEntries, Entries); 4181ad6265SDimitry Andric 4281ad6265SDimitry Andric llvm::BitVector SearchPathUsage(Entries.size()); 4381ad6265SDimitry Andric llvm::DenseSet<const serialization::ModuleFile *> Visited; 4481ad6265SDimitry Andric std::function<void(const serialization::ModuleFile *)> VisitMF = 4581ad6265SDimitry Andric [&](const serialization::ModuleFile *MF) { 4681ad6265SDimitry Andric SearchPathUsage |= MF->SearchPathUsage; 4781ad6265SDimitry Andric Visited.insert(MF); 4881ad6265SDimitry Andric for (const serialization::ModuleFile *Import : MF->Imports) 4981ad6265SDimitry Andric if (!Visited.contains(Import)) 5081ad6265SDimitry Andric VisitMF(Import); 5181ad6265SDimitry Andric }; 5281ad6265SDimitry Andric VisitMF(&MF); 5381ad6265SDimitry Andric 54*0fca6ea1SDimitry Andric if (SearchPathUsage.size() != Entries.size()) 55*0fca6ea1SDimitry Andric llvm::report_fatal_error( 56*0fca6ea1SDimitry Andric "Inconsistent search path options between modules detected"); 57*0fca6ea1SDimitry Andric 5881ad6265SDimitry Andric for (auto Idx : SearchPathUsage.set_bits()) 59*0fca6ea1SDimitry Andric Opts.UserEntries.push_back(std::move(Entries[Idx])); 60*0fca6ea1SDimitry Andric } 61*0fca6ea1SDimitry Andric if (any(OptimizeArgs & ScanningOptimizations::VFS)) { 62*0fca6ea1SDimitry Andric std::vector<std::string> VFSOverlayFiles; 63*0fca6ea1SDimitry Andric std::swap(Opts.VFSOverlayFiles, VFSOverlayFiles); 64*0fca6ea1SDimitry Andric 65*0fca6ea1SDimitry Andric llvm::BitVector VFSUsage(VFSOverlayFiles.size()); 66*0fca6ea1SDimitry Andric llvm::DenseSet<const serialization::ModuleFile *> Visited; 67*0fca6ea1SDimitry Andric std::function<void(const serialization::ModuleFile *)> VisitMF = 68*0fca6ea1SDimitry Andric [&](const serialization::ModuleFile *MF) { 69*0fca6ea1SDimitry Andric Visited.insert(MF); 70*0fca6ea1SDimitry Andric if (MF->Kind == serialization::MK_ImplicitModule) { 71*0fca6ea1SDimitry Andric VFSUsage |= MF->VFSUsage; 72*0fca6ea1SDimitry Andric // We only need to recurse into implicit modules. Other module types 73*0fca6ea1SDimitry Andric // will have the correct set of VFSs for anything they depend on. 74*0fca6ea1SDimitry Andric for (const serialization::ModuleFile *Import : MF->Imports) 75*0fca6ea1SDimitry Andric if (!Visited.contains(Import)) 76*0fca6ea1SDimitry Andric VisitMF(Import); 77*0fca6ea1SDimitry Andric } else { 78*0fca6ea1SDimitry Andric // This is not an implicitly built module, so it may have different 79*0fca6ea1SDimitry Andric // VFS options. Fall back to a string comparison instead. 80*0fca6ea1SDimitry Andric auto VFSMap = PrebuiltModuleVFSMap.find(MF->FileName); 81*0fca6ea1SDimitry Andric if (VFSMap == PrebuiltModuleVFSMap.end()) 82*0fca6ea1SDimitry Andric return; 83*0fca6ea1SDimitry Andric for (std::size_t I = 0, E = VFSOverlayFiles.size(); I != E; ++I) { 84*0fca6ea1SDimitry Andric if (VFSMap->second.contains(VFSOverlayFiles[I])) 85*0fca6ea1SDimitry Andric VFSUsage[I] = true; 86*0fca6ea1SDimitry Andric } 87*0fca6ea1SDimitry Andric } 88*0fca6ea1SDimitry Andric }; 89*0fca6ea1SDimitry Andric VisitMF(&MF); 90*0fca6ea1SDimitry Andric 91*0fca6ea1SDimitry Andric if (VFSUsage.size() != VFSOverlayFiles.size()) 92*0fca6ea1SDimitry Andric llvm::report_fatal_error( 93*0fca6ea1SDimitry Andric "Inconsistent -ivfsoverlay options between modules detected"); 94*0fca6ea1SDimitry Andric 95*0fca6ea1SDimitry Andric for (auto Idx : VFSUsage.set_bits()) 96*0fca6ea1SDimitry Andric Opts.VFSOverlayFiles.push_back(std::move(VFSOverlayFiles[Idx])); 97*0fca6ea1SDimitry Andric } 98349cc55cSDimitry Andric } 99349cc55cSDimitry Andric 1005f757f3fSDimitry Andric static void optimizeDiagnosticOpts(DiagnosticOptions &Opts, 1015f757f3fSDimitry Andric bool IsSystemModule) { 1025f757f3fSDimitry Andric // If this is not a system module or -Wsystem-headers was passed, don't 1035f757f3fSDimitry Andric // optimize. 1045f757f3fSDimitry Andric if (!IsSystemModule) 1055f757f3fSDimitry Andric return; 1065f757f3fSDimitry Andric bool Wsystem_headers = false; 1075f757f3fSDimitry Andric for (StringRef Opt : Opts.Warnings) { 1085f757f3fSDimitry Andric bool isPositive = !Opt.consume_front("no-"); 1095f757f3fSDimitry Andric if (Opt == "system-headers") 1105f757f3fSDimitry Andric Wsystem_headers = isPositive; 1115f757f3fSDimitry Andric } 1125f757f3fSDimitry Andric if (Wsystem_headers) 1135f757f3fSDimitry Andric return; 1145f757f3fSDimitry Andric 1155f757f3fSDimitry Andric // Remove all warning flags. System modules suppress most, but not all, 1165f757f3fSDimitry Andric // warnings. 1175f757f3fSDimitry Andric Opts.Warnings.clear(); 1185f757f3fSDimitry Andric Opts.UndefPrefixes.clear(); 1195f757f3fSDimitry Andric Opts.Remarks.clear(); 1205f757f3fSDimitry Andric } 1215f757f3fSDimitry Andric 122753f127fSDimitry Andric static std::vector<std::string> splitString(std::string S, char Separator) { 123753f127fSDimitry Andric SmallVector<StringRef> Segments; 124753f127fSDimitry Andric StringRef(S).split(Segments, Separator, /*MaxSplit=*/-1, /*KeepEmpty=*/false); 125753f127fSDimitry Andric std::vector<std::string> Result; 126753f127fSDimitry Andric Result.reserve(Segments.size()); 127753f127fSDimitry Andric for (StringRef Segment : Segments) 128753f127fSDimitry Andric Result.push_back(Segment.str()); 129753f127fSDimitry Andric return Result; 130753f127fSDimitry Andric } 131753f127fSDimitry Andric 1325f757f3fSDimitry Andric void ModuleDepCollector::addOutputPaths(CowCompilerInvocation &CI, 133bdd1243dSDimitry Andric ModuleDeps &Deps) { 1345f757f3fSDimitry Andric CI.getMutFrontendOpts().OutputFile = 13506c3fb27SDimitry Andric Controller.lookupModuleOutput(Deps.ID, ModuleOutputKind::ModuleFile); 136bdd1243dSDimitry Andric if (!CI.getDiagnosticOpts().DiagnosticSerializationFile.empty()) 1375f757f3fSDimitry Andric CI.getMutDiagnosticOpts().DiagnosticSerializationFile = 13806c3fb27SDimitry Andric Controller.lookupModuleOutput( 139bdd1243dSDimitry Andric Deps.ID, ModuleOutputKind::DiagnosticSerializationFile); 140bdd1243dSDimitry Andric if (!CI.getDependencyOutputOpts().OutputFile.empty()) { 1415f757f3fSDimitry Andric CI.getMutDependencyOutputOpts().OutputFile = Controller.lookupModuleOutput( 14206c3fb27SDimitry Andric Deps.ID, ModuleOutputKind::DependencyFile); 1435f757f3fSDimitry Andric CI.getMutDependencyOutputOpts().Targets = 14406c3fb27SDimitry Andric splitString(Controller.lookupModuleOutput( 145bdd1243dSDimitry Andric Deps.ID, ModuleOutputKind::DependencyTargets), 146bdd1243dSDimitry Andric '\0'); 147bdd1243dSDimitry Andric if (!CI.getDependencyOutputOpts().OutputFile.empty() && 148bdd1243dSDimitry Andric CI.getDependencyOutputOpts().Targets.empty()) { 149753f127fSDimitry Andric // Fallback to -o as dependency target, as in the driver. 150753f127fSDimitry Andric SmallString<128> Target; 151bdd1243dSDimitry Andric quoteMakeTarget(CI.getFrontendOpts().OutputFile, Target); 1525f757f3fSDimitry Andric CI.getMutDependencyOutputOpts().Targets.push_back(std::string(Target)); 153bdd1243dSDimitry Andric } 154753f127fSDimitry Andric } 155753f127fSDimitry Andric } 156fe6060f1SDimitry Andric 157*0fca6ea1SDimitry Andric void dependencies::resetBenignCodeGenOptions(frontend::ActionKind ProgramAction, 158*0fca6ea1SDimitry Andric const LangOptions &LangOpts, 159*0fca6ea1SDimitry Andric CodeGenOptions &CGOpts) { 160*0fca6ea1SDimitry Andric // TODO: Figure out better way to set options to their default value. 161*0fca6ea1SDimitry Andric if (ProgramAction == frontend::GenerateModule) { 162*0fca6ea1SDimitry Andric CGOpts.MainFileName.clear(); 163*0fca6ea1SDimitry Andric CGOpts.DwarfDebugFlags.clear(); 164*0fca6ea1SDimitry Andric } 165*0fca6ea1SDimitry Andric if (ProgramAction == frontend::GeneratePCH || 166*0fca6ea1SDimitry Andric (ProgramAction == frontend::GenerateModule && !LangOpts.ModulesCodegen)) { 167*0fca6ea1SDimitry Andric CGOpts.DebugCompilationDir.clear(); 168*0fca6ea1SDimitry Andric CGOpts.CoverageCompilationDir.clear(); 169*0fca6ea1SDimitry Andric CGOpts.CoverageDataFile.clear(); 170*0fca6ea1SDimitry Andric CGOpts.CoverageNotesFile.clear(); 171*0fca6ea1SDimitry Andric CGOpts.ProfileInstrumentUsePath.clear(); 172*0fca6ea1SDimitry Andric CGOpts.SampleProfileFile.clear(); 173*0fca6ea1SDimitry Andric CGOpts.ProfileRemappingFile.clear(); 174*0fca6ea1SDimitry Andric } 175*0fca6ea1SDimitry Andric } 176*0fca6ea1SDimitry Andric 1775f757f3fSDimitry Andric static CowCompilerInvocation 1785f757f3fSDimitry Andric makeCommonInvocationForModuleBuild(CompilerInvocation CI) { 179bdd1243dSDimitry Andric CI.resetNonModularOptions(); 180bdd1243dSDimitry Andric CI.clearImplicitModuleBuildOptions(); 181bdd1243dSDimitry Andric 182*0fca6ea1SDimitry Andric // The scanner takes care to avoid passing non-affecting module maps to the 183*0fca6ea1SDimitry Andric // explicit compiles. No need to do extra work just to find out there are no 184*0fca6ea1SDimitry Andric // module map files to prune. 185*0fca6ea1SDimitry Andric CI.getHeaderSearchOpts().ModulesPruneNonAffectingModuleMaps = false; 186*0fca6ea1SDimitry Andric 187bdd1243dSDimitry Andric // Remove options incompatible with explicit module build or are likely to 188bdd1243dSDimitry Andric // differ between identical modules discovered from different translation 189bdd1243dSDimitry Andric // units. 190bdd1243dSDimitry Andric CI.getFrontendOpts().Inputs.clear(); 191bdd1243dSDimitry Andric CI.getFrontendOpts().OutputFile.clear(); 1925f757f3fSDimitry Andric // LLVM options are not going to affect the AST 1935f757f3fSDimitry Andric CI.getFrontendOpts().LLVMArgs.clear(); 194bdd1243dSDimitry Andric 195*0fca6ea1SDimitry Andric resetBenignCodeGenOptions(frontend::GenerateModule, CI.getLangOpts(), 196*0fca6ea1SDimitry Andric CI.getCodeGenOpts()); 197fe6060f1SDimitry Andric 198bdd1243dSDimitry Andric // Map output paths that affect behaviour to "-" so their existence is in the 199bdd1243dSDimitry Andric // context hash. The final path will be computed in addOutputPaths. 200bdd1243dSDimitry Andric if (!CI.getDiagnosticOpts().DiagnosticSerializationFile.empty()) 201bdd1243dSDimitry Andric CI.getDiagnosticOpts().DiagnosticSerializationFile = "-"; 202bdd1243dSDimitry Andric if (!CI.getDependencyOutputOpts().OutputFile.empty()) 203bdd1243dSDimitry Andric CI.getDependencyOutputOpts().OutputFile = "-"; 204bdd1243dSDimitry Andric CI.getDependencyOutputOpts().Targets.clear(); 205bdd1243dSDimitry Andric 206bdd1243dSDimitry Andric CI.getFrontendOpts().ProgramAction = frontend::GenerateModule; 20706c3fb27SDimitry Andric CI.getFrontendOpts().ARCMTAction = FrontendOptions::ARCMT_None; 20806c3fb27SDimitry Andric CI.getFrontendOpts().ObjCMTAction = FrontendOptions::ObjCMT_None; 20906c3fb27SDimitry Andric CI.getFrontendOpts().MTMigrateDir.clear(); 2105f757f3fSDimitry Andric CI.getLangOpts().ModuleName.clear(); 2115f757f3fSDimitry Andric 2125f757f3fSDimitry Andric // Remove any macro definitions that are explicitly ignored. 2135f757f3fSDimitry Andric if (!CI.getHeaderSearchOpts().ModulesIgnoreMacros.empty()) { 2145f757f3fSDimitry Andric llvm::erase_if( 2155f757f3fSDimitry Andric CI.getPreprocessorOpts().Macros, 2165f757f3fSDimitry Andric [&CI](const std::pair<std::string, bool> &Def) { 2175f757f3fSDimitry Andric StringRef MacroDef = Def.first; 2185f757f3fSDimitry Andric return CI.getHeaderSearchOpts().ModulesIgnoreMacros.contains( 2195f757f3fSDimitry Andric llvm::CachedHashString(MacroDef.split('=').first)); 2205f757f3fSDimitry Andric }); 2215f757f3fSDimitry Andric // Remove the now unused option. 2225f757f3fSDimitry Andric CI.getHeaderSearchOpts().ModulesIgnoreMacros.clear(); 2235f757f3fSDimitry Andric } 2245f757f3fSDimitry Andric 2255f757f3fSDimitry Andric return CI; 2265f757f3fSDimitry Andric } 2275f757f3fSDimitry Andric 2285f757f3fSDimitry Andric CowCompilerInvocation 2295f757f3fSDimitry Andric ModuleDepCollector::getInvocationAdjustedForModuleBuildWithoutOutputs( 2305f757f3fSDimitry Andric const ModuleDeps &Deps, 2315f757f3fSDimitry Andric llvm::function_ref<void(CowCompilerInvocation &)> Optimize) const { 2325f757f3fSDimitry Andric CowCompilerInvocation CI = CommonInvocation; 2335f757f3fSDimitry Andric 2345f757f3fSDimitry Andric CI.getMutLangOpts().ModuleName = Deps.ID.ModuleName; 2355f757f3fSDimitry Andric CI.getMutFrontendOpts().IsSystemModule = Deps.IsSystem; 236bdd1243dSDimitry Andric 237bdd1243dSDimitry Andric // Inputs 238bdd1243dSDimitry Andric InputKind ModuleMapInputKind(CI.getFrontendOpts().DashX.getLanguage(), 239bdd1243dSDimitry Andric InputKind::Format::ModuleMap); 2405f757f3fSDimitry Andric CI.getMutFrontendOpts().Inputs.emplace_back(Deps.ClangModuleMapFile, 241bdd1243dSDimitry Andric ModuleMapInputKind); 242bdd1243dSDimitry Andric 243bdd1243dSDimitry Andric auto CurrentModuleMapEntry = 244bdd1243dSDimitry Andric ScanInstance.getFileManager().getFile(Deps.ClangModuleMapFile); 245bdd1243dSDimitry Andric assert(CurrentModuleMapEntry && "module map file entry not found"); 246bdd1243dSDimitry Andric 247*0fca6ea1SDimitry Andric // Remove directly passed modulemap files. They will get added back if they 248*0fca6ea1SDimitry Andric // were actually used. 249*0fca6ea1SDimitry Andric CI.getMutFrontendOpts().ModuleMapFiles.clear(); 250*0fca6ea1SDimitry Andric 251bdd1243dSDimitry Andric auto DepModuleMapFiles = collectModuleMapFiles(Deps.ClangModuleDeps); 252bdd1243dSDimitry Andric for (StringRef ModuleMapFile : Deps.ModuleMapFileDeps) { 253bdd1243dSDimitry Andric // TODO: Track these as `FileEntryRef` to simplify the equality check below. 254bdd1243dSDimitry Andric auto ModuleMapEntry = ScanInstance.getFileManager().getFile(ModuleMapFile); 255bdd1243dSDimitry Andric assert(ModuleMapEntry && "module map file entry not found"); 256bdd1243dSDimitry Andric 257bdd1243dSDimitry Andric // Don't report module maps describing eagerly-loaded dependency. This 258bdd1243dSDimitry Andric // information will be deserialized from the PCM. 259bdd1243dSDimitry Andric // TODO: Verify this works fine when modulemap for module A is eagerly 260bdd1243dSDimitry Andric // loaded from A.pcm, and module map passed on the command line contains 261bdd1243dSDimitry Andric // definition of a submodule: "explicit module A.Private { ... }". 262bdd1243dSDimitry Andric if (EagerLoadModules && DepModuleMapFiles.contains(*ModuleMapEntry)) 263bdd1243dSDimitry Andric continue; 264bdd1243dSDimitry Andric 265bdd1243dSDimitry Andric // Don't report module map file of the current module unless it also 266bdd1243dSDimitry Andric // describes a dependency (for symmetry). 267bdd1243dSDimitry Andric if (*ModuleMapEntry == *CurrentModuleMapEntry && 268bdd1243dSDimitry Andric !DepModuleMapFiles.contains(*ModuleMapEntry)) 269bdd1243dSDimitry Andric continue; 270bdd1243dSDimitry Andric 2715f757f3fSDimitry Andric CI.getMutFrontendOpts().ModuleMapFiles.emplace_back(ModuleMapFile); 272bdd1243dSDimitry Andric } 273bdd1243dSDimitry Andric 274bdd1243dSDimitry Andric // Report the prebuilt modules this module uses. 275bdd1243dSDimitry Andric for (const auto &PrebuiltModule : Deps.PrebuiltModuleDeps) 2765f757f3fSDimitry Andric CI.getMutFrontendOpts().ModuleFiles.push_back(PrebuiltModule.PCMFile); 277bdd1243dSDimitry Andric 278bdd1243dSDimitry Andric // Add module file inputs from dependencies. 279bdd1243dSDimitry Andric addModuleFiles(CI, Deps.ClangModuleDeps); 280bdd1243dSDimitry Andric 2815f757f3fSDimitry Andric if (!CI.getDiagnosticOpts().SystemHeaderWarningsModules.empty()) { 2825f757f3fSDimitry Andric // Apply -Wsystem-headers-in-module for the current module. 2835f757f3fSDimitry Andric if (llvm::is_contained(CI.getDiagnosticOpts().SystemHeaderWarningsModules, 2845f757f3fSDimitry Andric Deps.ID.ModuleName)) 2855f757f3fSDimitry Andric CI.getMutDiagnosticOpts().Warnings.push_back("system-headers"); 2865f757f3fSDimitry Andric // Remove the now unused option(s). 2875f757f3fSDimitry Andric CI.getMutDiagnosticOpts().SystemHeaderWarningsModules.clear(); 288bdd1243dSDimitry Andric } 289bdd1243dSDimitry Andric 290bdd1243dSDimitry Andric Optimize(CI); 291bdd1243dSDimitry Andric 292bdd1243dSDimitry Andric return CI; 293bdd1243dSDimitry Andric } 294bdd1243dSDimitry Andric 295bdd1243dSDimitry Andric llvm::DenseSet<const FileEntry *> ModuleDepCollector::collectModuleMapFiles( 296bdd1243dSDimitry Andric ArrayRef<ModuleID> ClangModuleDeps) const { 297bdd1243dSDimitry Andric llvm::DenseSet<const FileEntry *> ModuleMapFiles; 298bdd1243dSDimitry Andric for (const ModuleID &MID : ClangModuleDeps) { 299bdd1243dSDimitry Andric ModuleDeps *MD = ModuleDepsByID.lookup(MID); 300bdd1243dSDimitry Andric assert(MD && "Inconsistent dependency info"); 301bdd1243dSDimitry Andric // TODO: Track ClangModuleMapFile as `FileEntryRef`. 302bdd1243dSDimitry Andric auto FE = ScanInstance.getFileManager().getFile(MD->ClangModuleMapFile); 303bdd1243dSDimitry Andric assert(FE && "Missing module map file that was previously found"); 304bdd1243dSDimitry Andric ModuleMapFiles.insert(*FE); 305bdd1243dSDimitry Andric } 306bdd1243dSDimitry Andric return ModuleMapFiles; 307bdd1243dSDimitry Andric } 308bdd1243dSDimitry Andric 309bdd1243dSDimitry Andric void ModuleDepCollector::addModuleMapFiles( 310bdd1243dSDimitry Andric CompilerInvocation &CI, ArrayRef<ModuleID> ClangModuleDeps) const { 311bdd1243dSDimitry Andric if (EagerLoadModules) 312bdd1243dSDimitry Andric return; // Only pcm is needed for eager load. 313bdd1243dSDimitry Andric 314bdd1243dSDimitry Andric for (const ModuleID &MID : ClangModuleDeps) { 315bdd1243dSDimitry Andric ModuleDeps *MD = ModuleDepsByID.lookup(MID); 316bdd1243dSDimitry Andric assert(MD && "Inconsistent dependency info"); 317bdd1243dSDimitry Andric CI.getFrontendOpts().ModuleMapFiles.push_back(MD->ClangModuleMapFile); 318bdd1243dSDimitry Andric } 319bdd1243dSDimitry Andric } 320bdd1243dSDimitry Andric 321bdd1243dSDimitry Andric void ModuleDepCollector::addModuleFiles( 322bdd1243dSDimitry Andric CompilerInvocation &CI, ArrayRef<ModuleID> ClangModuleDeps) const { 323bdd1243dSDimitry Andric for (const ModuleID &MID : ClangModuleDeps) { 324bdd1243dSDimitry Andric std::string PCMPath = 32506c3fb27SDimitry Andric Controller.lookupModuleOutput(MID, ModuleOutputKind::ModuleFile); 326bdd1243dSDimitry Andric if (EagerLoadModules) 327bdd1243dSDimitry Andric CI.getFrontendOpts().ModuleFiles.push_back(std::move(PCMPath)); 328bdd1243dSDimitry Andric else 329bdd1243dSDimitry Andric CI.getHeaderSearchOpts().PrebuiltModuleFiles.insert( 330bdd1243dSDimitry Andric {MID.ModuleName, std::move(PCMPath)}); 331bdd1243dSDimitry Andric } 332bdd1243dSDimitry Andric } 333bdd1243dSDimitry Andric 3345f757f3fSDimitry Andric void ModuleDepCollector::addModuleFiles( 3355f757f3fSDimitry Andric CowCompilerInvocation &CI, ArrayRef<ModuleID> ClangModuleDeps) const { 3365f757f3fSDimitry Andric for (const ModuleID &MID : ClangModuleDeps) { 3375f757f3fSDimitry Andric std::string PCMPath = 3385f757f3fSDimitry Andric Controller.lookupModuleOutput(MID, ModuleOutputKind::ModuleFile); 3395f757f3fSDimitry Andric if (EagerLoadModules) 3405f757f3fSDimitry Andric CI.getMutFrontendOpts().ModuleFiles.push_back(std::move(PCMPath)); 3415f757f3fSDimitry Andric else 3425f757f3fSDimitry Andric CI.getMutHeaderSearchOpts().PrebuiltModuleFiles.insert( 3435f757f3fSDimitry Andric {MID.ModuleName, std::move(PCMPath)}); 3445f757f3fSDimitry Andric } 3455f757f3fSDimitry Andric } 3465f757f3fSDimitry Andric 347bdd1243dSDimitry Andric static bool needsModules(FrontendInputFile FIF) { 348bdd1243dSDimitry Andric switch (FIF.getKind().getLanguage()) { 349bdd1243dSDimitry Andric case Language::Unknown: 350bdd1243dSDimitry Andric case Language::Asm: 351bdd1243dSDimitry Andric case Language::LLVM_IR: 352bdd1243dSDimitry Andric return false; 353bdd1243dSDimitry Andric default: 354bdd1243dSDimitry Andric return true; 355bdd1243dSDimitry Andric } 356bdd1243dSDimitry Andric } 357bdd1243dSDimitry Andric 358bdd1243dSDimitry Andric void ModuleDepCollector::applyDiscoveredDependencies(CompilerInvocation &CI) { 359bdd1243dSDimitry Andric CI.clearImplicitModuleBuildOptions(); 360*0fca6ea1SDimitry Andric resetBenignCodeGenOptions(CI.getFrontendOpts().ProgramAction, 361*0fca6ea1SDimitry Andric CI.getLangOpts(), CI.getCodeGenOpts()); 362bdd1243dSDimitry Andric 363bdd1243dSDimitry Andric if (llvm::any_of(CI.getFrontendOpts().Inputs, needsModules)) { 364bdd1243dSDimitry Andric Preprocessor &PP = ScanInstance.getPreprocessor(); 365bdd1243dSDimitry Andric if (Module *CurrentModule = PP.getCurrentModuleImplementation()) 366bdd1243dSDimitry Andric if (OptionalFileEntryRef CurrentModuleMap = 367bdd1243dSDimitry Andric PP.getHeaderSearchInfo() 368bdd1243dSDimitry Andric .getModuleMap() 369bdd1243dSDimitry Andric .getModuleMapFileForUniquing(CurrentModule)) 370bdd1243dSDimitry Andric CI.getFrontendOpts().ModuleMapFiles.emplace_back( 37106c3fb27SDimitry Andric CurrentModuleMap->getNameAsRequested()); 372bdd1243dSDimitry Andric 373bdd1243dSDimitry Andric SmallVector<ModuleID> DirectDeps; 374bdd1243dSDimitry Andric for (const auto &KV : ModularDeps) 3755f757f3fSDimitry Andric if (DirectModularDeps.contains(KV.first)) 376bdd1243dSDimitry Andric DirectDeps.push_back(KV.second->ID); 377bdd1243dSDimitry Andric 378bdd1243dSDimitry Andric // TODO: Report module maps the same way it's done for modular dependencies. 379bdd1243dSDimitry Andric addModuleMapFiles(CI, DirectDeps); 380bdd1243dSDimitry Andric 381bdd1243dSDimitry Andric addModuleFiles(CI, DirectDeps); 382bdd1243dSDimitry Andric 383bdd1243dSDimitry Andric for (const auto &KV : DirectPrebuiltModularDeps) 384bdd1243dSDimitry Andric CI.getFrontendOpts().ModuleFiles.push_back(KV.second.PCMFile); 385bdd1243dSDimitry Andric } 386bdd1243dSDimitry Andric } 387bdd1243dSDimitry Andric 388bdd1243dSDimitry Andric static std::string getModuleContextHash(const ModuleDeps &MD, 3895f757f3fSDimitry Andric const CowCompilerInvocation &CI, 3905f757f3fSDimitry Andric bool EagerLoadModules, 3915f757f3fSDimitry Andric llvm::vfs::FileSystem &VFS) { 3925f757f3fSDimitry Andric llvm::HashBuilder<llvm::TruncatedBLAKE3<16>, llvm::endianness::native> 393bdd1243dSDimitry Andric HashBuilder; 394bdd1243dSDimitry Andric SmallString<32> Scratch; 395bdd1243dSDimitry Andric 396bdd1243dSDimitry Andric // Hash the compiler version and serialization version to ensure the module 397bdd1243dSDimitry Andric // will be readable. 398bdd1243dSDimitry Andric HashBuilder.add(getClangFullRepositoryVersion()); 399bdd1243dSDimitry Andric HashBuilder.add(serialization::VERSION_MAJOR, serialization::VERSION_MINOR); 4005f757f3fSDimitry Andric llvm::ErrorOr<std::string> CWD = VFS.getCurrentWorkingDirectory(); 4015f757f3fSDimitry Andric if (CWD) 4025f757f3fSDimitry Andric HashBuilder.add(*CWD); 403bdd1243dSDimitry Andric 404bdd1243dSDimitry Andric // Hash the BuildInvocation without any input files. 4055f757f3fSDimitry Andric SmallString<0> ArgVec; 4065f757f3fSDimitry Andric ArgVec.reserve(4096); 4075f757f3fSDimitry Andric CI.generateCC1CommandLine([&](const Twine &Arg) { 4085f757f3fSDimitry Andric Arg.toVector(ArgVec); 4095f757f3fSDimitry Andric ArgVec.push_back('\0'); 4105f757f3fSDimitry Andric }); 4115f757f3fSDimitry Andric HashBuilder.add(ArgVec); 412bdd1243dSDimitry Andric 413bdd1243dSDimitry Andric // Hash the module dependencies. These paths may differ even if the invocation 414bdd1243dSDimitry Andric // is identical if they depend on the contents of the files in the TU -- for 415bdd1243dSDimitry Andric // example, case-insensitive paths to modulemap files. Usually such a case 416bdd1243dSDimitry Andric // would indicate a missed optimization to canonicalize, but it may be 417bdd1243dSDimitry Andric // difficult to canonicalize all cases when there is a VFS. 418bdd1243dSDimitry Andric for (const auto &ID : MD.ClangModuleDeps) { 419bdd1243dSDimitry Andric HashBuilder.add(ID.ModuleName); 420bdd1243dSDimitry Andric HashBuilder.add(ID.ContextHash); 421bdd1243dSDimitry Andric } 422bdd1243dSDimitry Andric 423bdd1243dSDimitry Andric HashBuilder.add(EagerLoadModules); 424bdd1243dSDimitry Andric 425bdd1243dSDimitry Andric llvm::BLAKE3Result<16> Hash = HashBuilder.final(); 426bdd1243dSDimitry Andric std::array<uint64_t, 2> Words; 427bdd1243dSDimitry Andric static_assert(sizeof(Hash) == sizeof(Words), "Hash must match Words"); 428bdd1243dSDimitry Andric std::memcpy(Words.data(), Hash.data(), sizeof(Hash)); 429bdd1243dSDimitry Andric return toString(llvm::APInt(sizeof(Words) * 8, Words), 36, /*Signed=*/false); 430bdd1243dSDimitry Andric } 431bdd1243dSDimitry Andric 4325f757f3fSDimitry Andric void ModuleDepCollector::associateWithContextHash( 4335f757f3fSDimitry Andric const CowCompilerInvocation &CI, ModuleDeps &Deps) { 4345f757f3fSDimitry Andric Deps.ID.ContextHash = getModuleContextHash( 4355f757f3fSDimitry Andric Deps, CI, EagerLoadModules, ScanInstance.getVirtualFileSystem()); 436bdd1243dSDimitry Andric bool Inserted = ModuleDepsByID.insert({Deps.ID, &Deps}).second; 437bdd1243dSDimitry Andric (void)Inserted; 438bdd1243dSDimitry Andric assert(Inserted && "duplicate module mapping"); 439fe6060f1SDimitry Andric } 440fe6060f1SDimitry Andric 44106c3fb27SDimitry Andric void ModuleDepCollectorPP::LexedFileChanged(FileID FID, 44206c3fb27SDimitry Andric LexedFileChangeReason Reason, 443480093f4SDimitry Andric SrcMgr::CharacteristicKind FileType, 44406c3fb27SDimitry Andric FileID PrevFID, 44506c3fb27SDimitry Andric SourceLocation Loc) { 44606c3fb27SDimitry Andric if (Reason != LexedFileChangeReason::EnterFile) 447480093f4SDimitry Andric return; 448480093f4SDimitry Andric 4495ffd83dbSDimitry Andric // This has to be delayed as the context hash can change at the start of 4505ffd83dbSDimitry Andric // `CompilerInstance::ExecuteAction`. 4515ffd83dbSDimitry Andric if (MDC.ContextHash.empty()) { 452349cc55cSDimitry Andric MDC.ContextHash = MDC.ScanInstance.getInvocation().getModuleHash(); 4535ffd83dbSDimitry Andric MDC.Consumer.handleContextHash(MDC.ContextHash); 4545ffd83dbSDimitry Andric } 4555ffd83dbSDimitry Andric 456349cc55cSDimitry Andric SourceManager &SM = MDC.ScanInstance.getSourceManager(); 457480093f4SDimitry Andric 458480093f4SDimitry Andric // Dependency generation really does want to go all the way to the 459480093f4SDimitry Andric // file entry for a source location to find out what is depended on. 460480093f4SDimitry Andric // We do not want #line markers to affect dependency generation! 46106c3fb27SDimitry Andric if (std::optional<StringRef> Filename = SM.getNonBuiltinFilenameForID(FID)) 462bdd1243dSDimitry Andric MDC.addFileDep(llvm::sys::path::remove_leading_dotslash(*Filename)); 463480093f4SDimitry Andric } 464480093f4SDimitry Andric 465480093f4SDimitry Andric void ModuleDepCollectorPP::InclusionDirective( 466480093f4SDimitry Andric SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName, 467bdd1243dSDimitry Andric bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef File, 468*0fca6ea1SDimitry Andric StringRef SearchPath, StringRef RelativePath, const Module *SuggestedModule, 469*0fca6ea1SDimitry Andric bool ModuleImported, SrcMgr::CharacteristicKind FileType) { 470*0fca6ea1SDimitry Andric if (!File && !ModuleImported) { 471480093f4SDimitry Andric // This is a non-modular include that HeaderSearch failed to find. Add it 472480093f4SDimitry Andric // here as `FileChanged` will never see it. 473bdd1243dSDimitry Andric MDC.addFileDep(FileName); 4745ffd83dbSDimitry Andric } 475*0fca6ea1SDimitry Andric handleImport(SuggestedModule); 476480093f4SDimitry Andric } 477480093f4SDimitry Andric 4785ffd83dbSDimitry Andric void ModuleDepCollectorPP::moduleImport(SourceLocation ImportLoc, 4795ffd83dbSDimitry Andric ModuleIdPath Path, 4805ffd83dbSDimitry Andric const Module *Imported) { 4811ac55f4cSDimitry Andric if (MDC.ScanInstance.getPreprocessor().isInImportingCXXNamedModules()) { 4821ac55f4cSDimitry Andric P1689ModuleInfo RequiredModule; 4831ac55f4cSDimitry Andric RequiredModule.ModuleName = Path[0].first->getName().str(); 4841ac55f4cSDimitry Andric RequiredModule.Type = P1689ModuleInfo::ModuleType::NamedCXXModule; 4851ac55f4cSDimitry Andric MDC.RequiredStdCXXModules.push_back(RequiredModule); 4861ac55f4cSDimitry Andric return; 4871ac55f4cSDimitry Andric } 4881ac55f4cSDimitry Andric 4895ffd83dbSDimitry Andric handleImport(Imported); 4905ffd83dbSDimitry Andric } 4915ffd83dbSDimitry Andric 4925ffd83dbSDimitry Andric void ModuleDepCollectorPP::handleImport(const Module *Imported) { 493480093f4SDimitry Andric if (!Imported) 494480093f4SDimitry Andric return; 495480093f4SDimitry Andric 496fe6060f1SDimitry Andric const Module *TopLevelModule = Imported->getTopLevelModule(); 497fe6060f1SDimitry Andric 498fe6060f1SDimitry Andric if (MDC.isPrebuiltModule(TopLevelModule)) 499bdd1243dSDimitry Andric MDC.DirectPrebuiltModularDeps.insert( 500bdd1243dSDimitry Andric {TopLevelModule, PrebuiltModuleDep{TopLevelModule}}); 501fe6060f1SDimitry Andric else 5025f757f3fSDimitry Andric MDC.DirectModularDeps.insert(TopLevelModule); 503480093f4SDimitry Andric } 504480093f4SDimitry Andric 505480093f4SDimitry Andric void ModuleDepCollectorPP::EndOfMainFile() { 506349cc55cSDimitry Andric FileID MainFileID = MDC.ScanInstance.getSourceManager().getMainFileID(); 507349cc55cSDimitry Andric MDC.MainFile = std::string(MDC.ScanInstance.getSourceManager() 5085f757f3fSDimitry Andric .getFileEntryRefForID(MainFileID) 509349cc55cSDimitry Andric ->getName()); 510480093f4SDimitry Andric 5111ac55f4cSDimitry Andric auto &PP = MDC.ScanInstance.getPreprocessor(); 5121ac55f4cSDimitry Andric if (PP.isInNamedModule()) { 5131ac55f4cSDimitry Andric P1689ModuleInfo ProvidedModule; 5141ac55f4cSDimitry Andric ProvidedModule.ModuleName = PP.getNamedModuleName(); 5151ac55f4cSDimitry Andric ProvidedModule.Type = P1689ModuleInfo::ModuleType::NamedCXXModule; 5161ac55f4cSDimitry Andric ProvidedModule.IsStdCXXModuleInterface = PP.isInNamedInterfaceUnit(); 5171ac55f4cSDimitry Andric // Don't put implementation (non partition) unit as Provide. 5181ac55f4cSDimitry Andric // Put the module as required instead. Since the implementation 5191ac55f4cSDimitry Andric // unit will import the primary module implicitly. 5201ac55f4cSDimitry Andric if (PP.isInImplementationUnit()) 5211ac55f4cSDimitry Andric MDC.RequiredStdCXXModules.push_back(ProvidedModule); 5221ac55f4cSDimitry Andric else 5231ac55f4cSDimitry Andric MDC.ProvidedStdCXXModule = ProvidedModule; 5241ac55f4cSDimitry Andric } 5251ac55f4cSDimitry Andric 526349cc55cSDimitry Andric if (!MDC.ScanInstance.getPreprocessorOpts().ImplicitPCHInclude.empty()) 527bdd1243dSDimitry Andric MDC.addFileDep(MDC.ScanInstance.getPreprocessorOpts().ImplicitPCHInclude); 528fe6060f1SDimitry Andric 529bdd1243dSDimitry Andric for (const Module *M : 530bdd1243dSDimitry Andric MDC.ScanInstance.getPreprocessor().getAffectingClangModules()) 531bdd1243dSDimitry Andric if (!MDC.isPrebuiltModule(M)) 5325f757f3fSDimitry Andric MDC.DirectModularDeps.insert(M); 533bdd1243dSDimitry Andric 5345f757f3fSDimitry Andric for (const Module *M : MDC.DirectModularDeps) 535480093f4SDimitry Andric handleTopLevelModule(M); 536480093f4SDimitry Andric 537fe6060f1SDimitry Andric MDC.Consumer.handleDependencyOutputOpts(*MDC.Opts); 538fe6060f1SDimitry Andric 5391ac55f4cSDimitry Andric if (MDC.IsStdModuleP1689Format) 5401ac55f4cSDimitry Andric MDC.Consumer.handleProvidedAndRequiredStdCXXModules( 5411ac55f4cSDimitry Andric MDC.ProvidedStdCXXModule, MDC.RequiredStdCXXModules); 5421ac55f4cSDimitry Andric 543fe6060f1SDimitry Andric for (auto &&I : MDC.ModularDeps) 54481ad6265SDimitry Andric MDC.Consumer.handleModuleDependency(*I.second); 545480093f4SDimitry Andric 5465f757f3fSDimitry Andric for (const Module *M : MDC.DirectModularDeps) { 5475f757f3fSDimitry Andric auto It = MDC.ModularDeps.find(M); 5485f757f3fSDimitry Andric // Only report direct dependencies that were successfully handled. 5495f757f3fSDimitry Andric if (It != MDC.ModularDeps.end()) 5505f757f3fSDimitry Andric MDC.Consumer.handleDirectModuleDependency(MDC.ModularDeps[M]->ID); 5515f757f3fSDimitry Andric } 5525f757f3fSDimitry Andric 553fe6060f1SDimitry Andric for (auto &&I : MDC.FileDeps) 554fe6060f1SDimitry Andric MDC.Consumer.handleFileDependency(I); 555fe6060f1SDimitry Andric 556bdd1243dSDimitry Andric for (auto &&I : MDC.DirectPrebuiltModularDeps) 557bdd1243dSDimitry Andric MDC.Consumer.handlePrebuiltModuleDependency(I.second); 558480093f4SDimitry Andric } 559480093f4SDimitry Andric 560bdd1243dSDimitry Andric std::optional<ModuleID> 561bdd1243dSDimitry Andric ModuleDepCollectorPP::handleTopLevelModule(const Module *M) { 562480093f4SDimitry Andric assert(M == M->getTopLevelModule() && "Expected top level module!"); 563480093f4SDimitry Andric 564bdd1243dSDimitry Andric // A top-level module might not be actually imported as a module when 565bdd1243dSDimitry Andric // -fmodule-name is used to compile a translation unit that imports this 566bdd1243dSDimitry Andric // module. In that case it can be skipped. The appropriate header 567bdd1243dSDimitry Andric // dependencies will still be reported as expected. 568bdd1243dSDimitry Andric if (!M->getASTFile()) 569bdd1243dSDimitry Andric return {}; 570bdd1243dSDimitry Andric 571fe6060f1SDimitry Andric // If this module has been handled already, just return its ID. 57281ad6265SDimitry Andric auto ModI = MDC.ModularDeps.insert({M, nullptr}); 573fe6060f1SDimitry Andric if (!ModI.second) 57481ad6265SDimitry Andric return ModI.first->second->ID; 575480093f4SDimitry Andric 57681ad6265SDimitry Andric ModI.first->second = std::make_unique<ModuleDeps>(); 57781ad6265SDimitry Andric ModuleDeps &MD = *ModI.first->second; 578480093f4SDimitry Andric 579fe6060f1SDimitry Andric MD.ID.ModuleName = M->getFullModuleName(); 580fe6060f1SDimitry Andric MD.IsSystem = M->IsSystem; 581*0fca6ea1SDimitry Andric // For modules which use export_as link name, the linked product that of the 582*0fca6ea1SDimitry Andric // corresponding export_as-named module. 583*0fca6ea1SDimitry Andric if (!M->UseExportAsModuleLinkName) 584*0fca6ea1SDimitry Andric MD.LinkLibraries = M->LinkLibraries; 585fe6060f1SDimitry Andric 586bdd1243dSDimitry Andric ModuleMap &ModMapInfo = 587bdd1243dSDimitry Andric MDC.ScanInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap(); 588bdd1243dSDimitry Andric 589bdd1243dSDimitry Andric OptionalFileEntryRef ModuleMap = ModMapInfo.getModuleMapFileForUniquing(M); 5900eae32dcSDimitry Andric 5910eae32dcSDimitry Andric if (ModuleMap) { 592bdd1243dSDimitry Andric SmallString<128> Path = ModuleMap->getNameAsRequested(); 593bdd1243dSDimitry Andric ModMapInfo.canonicalizeModuleMapPath(Path); 5940eae32dcSDimitry Andric MD.ClangModuleMapFile = std::string(Path); 5950eae32dcSDimitry Andric } 596fe6060f1SDimitry Andric 597480093f4SDimitry Andric serialization::ModuleFile *MF = 598349cc55cSDimitry Andric MDC.ScanInstance.getASTReader()->getModuleManager().lookup( 5995f757f3fSDimitry Andric *M->getASTFile()); 6005f757f3fSDimitry Andric MDC.ScanInstance.getASTReader()->visitInputFileInfos( 6015f757f3fSDimitry Andric *MF, /*IncludeSystem=*/true, 6025f757f3fSDimitry Andric [&](const serialization::InputFileInfo &IFI, bool IsSystem) { 603fe6060f1SDimitry Andric // __inferred_module.map is the result of the way in which an implicit 604fe6060f1SDimitry Andric // module build handles inferred modules. It adds an overlay VFS with 605fe6060f1SDimitry Andric // this file in the proper directory and relies on the rest of Clang to 606fe6060f1SDimitry Andric // handle it like normal. With explicitly built modules we don't need 607fe6060f1SDimitry Andric // to play VFS tricks, so replace it with the correct module map. 6085f757f3fSDimitry Andric if (StringRef(IFI.Filename).ends_with("__inferred_module.map")) { 609bdd1243dSDimitry Andric MDC.addFileDep(MD, ModuleMap->getName()); 610fe6060f1SDimitry Andric return; 611fe6060f1SDimitry Andric } 6125f757f3fSDimitry Andric MDC.addFileDep(MD, IFI.Filename); 613480093f4SDimitry Andric }); 614480093f4SDimitry Andric 615bdd1243dSDimitry Andric llvm::DenseSet<const Module *> SeenDeps; 616bdd1243dSDimitry Andric addAllSubmodulePrebuiltDeps(M, MD, SeenDeps); 617bdd1243dSDimitry Andric addAllSubmoduleDeps(M, MD, SeenDeps); 618bdd1243dSDimitry Andric addAllAffectingClangModules(M, MD, SeenDeps); 619bdd1243dSDimitry Andric 6205f757f3fSDimitry Andric MDC.ScanInstance.getASTReader()->visitInputFileInfos( 6215f757f3fSDimitry Andric *MF, /*IncludeSystem=*/true, 6225f757f3fSDimitry Andric [&](const serialization::InputFileInfo &IFI, bool IsSystem) { 6235f757f3fSDimitry Andric if (!(IFI.TopLevel && IFI.ModuleMap)) 62481ad6265SDimitry Andric return; 6255f757f3fSDimitry Andric if (StringRef(IFI.FilenameAsRequested) 6265f757f3fSDimitry Andric .ends_with("__inferred_module.map")) 6275f757f3fSDimitry Andric return; 6285f757f3fSDimitry Andric MD.ModuleMapFileDeps.emplace_back(IFI.FilenameAsRequested); 62981ad6265SDimitry Andric }); 63081ad6265SDimitry Andric 6315f757f3fSDimitry Andric CowCompilerInvocation CI = 6325f757f3fSDimitry Andric MDC.getInvocationAdjustedForModuleBuildWithoutOutputs( 6335f757f3fSDimitry Andric MD, [&](CowCompilerInvocation &BuildInvocation) { 634*0fca6ea1SDimitry Andric if (any(MDC.OptimizeArgs & (ScanningOptimizations::HeaderSearch | 635*0fca6ea1SDimitry Andric ScanningOptimizations::VFS))) 6365f757f3fSDimitry Andric optimizeHeaderSearchOpts(BuildInvocation.getMutHeaderSearchOpts(), 637*0fca6ea1SDimitry Andric *MDC.ScanInstance.getASTReader(), *MF, 638*0fca6ea1SDimitry Andric MDC.PrebuiltModuleVFSMap, 639*0fca6ea1SDimitry Andric MDC.OptimizeArgs); 6405f757f3fSDimitry Andric if (any(MDC.OptimizeArgs & ScanningOptimizations::SystemWarnings)) 6415f757f3fSDimitry Andric optimizeDiagnosticOpts( 6425f757f3fSDimitry Andric BuildInvocation.getMutDiagnosticOpts(), 6435f757f3fSDimitry Andric BuildInvocation.getFrontendOpts().IsSystemModule); 644349cc55cSDimitry Andric }); 645fe6060f1SDimitry Andric 646bdd1243dSDimitry Andric MDC.associateWithContextHash(CI, MD); 647bdd1243dSDimitry Andric 648bdd1243dSDimitry Andric // Finish the compiler invocation. Requires dependencies and the context hash. 649bdd1243dSDimitry Andric MDC.addOutputPaths(CI, MD); 650bdd1243dSDimitry Andric 6515f757f3fSDimitry Andric MD.BuildInfo = std::move(CI); 652fe6060f1SDimitry Andric 653fe6060f1SDimitry Andric return MD.ID; 654fe6060f1SDimitry Andric } 655fe6060f1SDimitry Andric 65681ad6265SDimitry Andric static void forEachSubmoduleSorted(const Module *M, 65781ad6265SDimitry Andric llvm::function_ref<void(const Module *)> F) { 65881ad6265SDimitry Andric // Submodule order depends on order of header includes for inferred submodules 65981ad6265SDimitry Andric // we don't care about the exact order, so sort so that it's consistent across 66081ad6265SDimitry Andric // TUs to improve sharing. 66106c3fb27SDimitry Andric SmallVector<const Module *> Submodules(M->submodules()); 66281ad6265SDimitry Andric llvm::stable_sort(Submodules, [](const Module *A, const Module *B) { 66381ad6265SDimitry Andric return A->Name < B->Name; 66481ad6265SDimitry Andric }); 66581ad6265SDimitry Andric for (const Module *SubM : Submodules) 66681ad6265SDimitry Andric F(SubM); 66781ad6265SDimitry Andric } 66881ad6265SDimitry Andric 669349cc55cSDimitry Andric void ModuleDepCollectorPP::addAllSubmodulePrebuiltDeps( 670349cc55cSDimitry Andric const Module *M, ModuleDeps &MD, 671349cc55cSDimitry Andric llvm::DenseSet<const Module *> &SeenSubmodules) { 672349cc55cSDimitry Andric addModulePrebuiltDeps(M, MD, SeenSubmodules); 673349cc55cSDimitry Andric 67481ad6265SDimitry Andric forEachSubmoduleSorted(M, [&](const Module *SubM) { 675349cc55cSDimitry Andric addAllSubmodulePrebuiltDeps(SubM, MD, SeenSubmodules); 67681ad6265SDimitry Andric }); 677349cc55cSDimitry Andric } 678349cc55cSDimitry Andric 679349cc55cSDimitry Andric void ModuleDepCollectorPP::addModulePrebuiltDeps( 680349cc55cSDimitry Andric const Module *M, ModuleDeps &MD, 681349cc55cSDimitry Andric llvm::DenseSet<const Module *> &SeenSubmodules) { 682fe6060f1SDimitry Andric for (const Module *Import : M->Imports) 683fe6060f1SDimitry Andric if (Import->getTopLevelModule() != M->getTopLevelModule()) 684349cc55cSDimitry Andric if (MDC.isPrebuiltModule(Import->getTopLevelModule())) 685349cc55cSDimitry Andric if (SeenSubmodules.insert(Import->getTopLevelModule()).second) 686349cc55cSDimitry Andric MD.PrebuiltModuleDeps.emplace_back(Import->getTopLevelModule()); 687480093f4SDimitry Andric } 688480093f4SDimitry Andric 6895ffd83dbSDimitry Andric void ModuleDepCollectorPP::addAllSubmoduleDeps( 6905ffd83dbSDimitry Andric const Module *M, ModuleDeps &MD, 6915ffd83dbSDimitry Andric llvm::DenseSet<const Module *> &AddedModules) { 6925ffd83dbSDimitry Andric addModuleDep(M, MD, AddedModules); 693480093f4SDimitry Andric 69481ad6265SDimitry Andric forEachSubmoduleSorted(M, [&](const Module *SubM) { 6955ffd83dbSDimitry Andric addAllSubmoduleDeps(SubM, MD, AddedModules); 69681ad6265SDimitry Andric }); 697480093f4SDimitry Andric } 698480093f4SDimitry Andric 6995ffd83dbSDimitry Andric void ModuleDepCollectorPP::addModuleDep( 7005ffd83dbSDimitry Andric const Module *M, ModuleDeps &MD, 7015ffd83dbSDimitry Andric llvm::DenseSet<const Module *> &AddedModules) { 702480093f4SDimitry Andric for (const Module *Import : M->Imports) { 703fe6060f1SDimitry Andric if (Import->getTopLevelModule() != M->getTopLevelModule() && 704fe6060f1SDimitry Andric !MDC.isPrebuiltModule(Import)) { 705bdd1243dSDimitry Andric if (auto ImportID = handleTopLevelModule(Import->getTopLevelModule())) 7065ffd83dbSDimitry Andric if (AddedModules.insert(Import->getTopLevelModule()).second) 707bdd1243dSDimitry Andric MD.ClangModuleDeps.push_back(*ImportID); 708bdd1243dSDimitry Andric } 709bdd1243dSDimitry Andric } 710bdd1243dSDimitry Andric } 711bdd1243dSDimitry Andric 712bdd1243dSDimitry Andric void ModuleDepCollectorPP::addAllAffectingClangModules( 713bdd1243dSDimitry Andric const Module *M, ModuleDeps &MD, 714bdd1243dSDimitry Andric llvm::DenseSet<const Module *> &AddedModules) { 715bdd1243dSDimitry Andric addAffectingClangModule(M, MD, AddedModules); 716bdd1243dSDimitry Andric 717bdd1243dSDimitry Andric for (const Module *SubM : M->submodules()) 718bdd1243dSDimitry Andric addAllAffectingClangModules(SubM, MD, AddedModules); 719bdd1243dSDimitry Andric } 720bdd1243dSDimitry Andric 721bdd1243dSDimitry Andric void ModuleDepCollectorPP::addAffectingClangModule( 722bdd1243dSDimitry Andric const Module *M, ModuleDeps &MD, 723bdd1243dSDimitry Andric llvm::DenseSet<const Module *> &AddedModules) { 724bdd1243dSDimitry Andric for (const Module *Affecting : M->AffectingClangModules) { 725bdd1243dSDimitry Andric assert(Affecting == Affecting->getTopLevelModule() && 726bdd1243dSDimitry Andric "Not quite import not top-level module"); 727bdd1243dSDimitry Andric if (Affecting != M->getTopLevelModule() && 728bdd1243dSDimitry Andric !MDC.isPrebuiltModule(Affecting)) { 729bdd1243dSDimitry Andric if (auto ImportID = handleTopLevelModule(Affecting)) 730bdd1243dSDimitry Andric if (AddedModules.insert(Affecting).second) 731bdd1243dSDimitry Andric MD.ClangModuleDeps.push_back(*ImportID); 732480093f4SDimitry Andric } 733480093f4SDimitry Andric } 734480093f4SDimitry Andric } 735480093f4SDimitry Andric 7365ffd83dbSDimitry Andric ModuleDepCollector::ModuleDepCollector( 737349cc55cSDimitry Andric std::unique_ptr<DependencyOutputOptions> Opts, 738349cc55cSDimitry Andric CompilerInstance &ScanInstance, DependencyConsumer &C, 73906c3fb27SDimitry Andric DependencyActionController &Controller, CompilerInvocation OriginalCI, 740*0fca6ea1SDimitry Andric PrebuiltModuleVFSMapT PrebuiltModuleVFSMap, 7415f757f3fSDimitry Andric ScanningOptimizations OptimizeArgs, bool EagerLoadModules, 7425f757f3fSDimitry Andric bool IsStdModuleP1689Format) 74306c3fb27SDimitry Andric : ScanInstance(ScanInstance), Consumer(C), Controller(Controller), 744*0fca6ea1SDimitry Andric PrebuiltModuleVFSMap(std::move(PrebuiltModuleVFSMap)), 7455f757f3fSDimitry Andric Opts(std::move(Opts)), 7465f757f3fSDimitry Andric CommonInvocation( 7475f757f3fSDimitry Andric makeCommonInvocationForModuleBuild(std::move(OriginalCI))), 74806c3fb27SDimitry Andric OptimizeArgs(OptimizeArgs), EagerLoadModules(EagerLoadModules), 7491ac55f4cSDimitry Andric IsStdModuleP1689Format(IsStdModuleP1689Format) {} 750480093f4SDimitry Andric 751480093f4SDimitry Andric void ModuleDepCollector::attachToPreprocessor(Preprocessor &PP) { 752349cc55cSDimitry Andric PP.addPPCallbacks(std::make_unique<ModuleDepCollectorPP>(*this)); 753480093f4SDimitry Andric } 754480093f4SDimitry Andric 755480093f4SDimitry Andric void ModuleDepCollector::attachToASTReader(ASTReader &R) {} 756fe6060f1SDimitry Andric 757fe6060f1SDimitry Andric bool ModuleDepCollector::isPrebuiltModule(const Module *M) { 758fe6060f1SDimitry Andric std::string Name(M->getTopLevelModuleName()); 759fe6060f1SDimitry Andric const auto &PrebuiltModuleFiles = 760349cc55cSDimitry Andric ScanInstance.getHeaderSearchOpts().PrebuiltModuleFiles; 761fe6060f1SDimitry Andric auto PrebuiltModuleFileIt = PrebuiltModuleFiles.find(Name); 762fe6060f1SDimitry Andric if (PrebuiltModuleFileIt == PrebuiltModuleFiles.end()) 763fe6060f1SDimitry Andric return false; 764fe6060f1SDimitry Andric assert("Prebuilt module came from the expected AST file" && 765fe6060f1SDimitry Andric PrebuiltModuleFileIt->second == M->getASTFile()->getName()); 766fe6060f1SDimitry Andric return true; 767fe6060f1SDimitry Andric } 768bdd1243dSDimitry Andric 769bdd1243dSDimitry Andric static StringRef makeAbsoluteAndPreferred(CompilerInstance &CI, StringRef Path, 770bdd1243dSDimitry Andric SmallVectorImpl<char> &Storage) { 771bdd1243dSDimitry Andric if (llvm::sys::path::is_absolute(Path) && 772bdd1243dSDimitry Andric !llvm::sys::path::is_style_windows(llvm::sys::path::Style::native)) 773bdd1243dSDimitry Andric return Path; 774bdd1243dSDimitry Andric Storage.assign(Path.begin(), Path.end()); 775bdd1243dSDimitry Andric CI.getFileManager().makeAbsolutePath(Storage); 776bdd1243dSDimitry Andric llvm::sys::path::make_preferred(Storage); 777bdd1243dSDimitry Andric return StringRef(Storage.data(), Storage.size()); 778bdd1243dSDimitry Andric } 779bdd1243dSDimitry Andric 780bdd1243dSDimitry Andric void ModuleDepCollector::addFileDep(StringRef Path) { 7815f757f3fSDimitry Andric if (IsStdModuleP1689Format) { 7825f757f3fSDimitry Andric // Within P1689 format, we don't want all the paths to be absolute path 7835f757f3fSDimitry Andric // since it may violate the tranditional make style dependencies info. 7845f757f3fSDimitry Andric FileDeps.push_back(std::string(Path)); 7855f757f3fSDimitry Andric return; 7865f757f3fSDimitry Andric } 7875f757f3fSDimitry Andric 788bdd1243dSDimitry Andric llvm::SmallString<256> Storage; 789bdd1243dSDimitry Andric Path = makeAbsoluteAndPreferred(ScanInstance, Path, Storage); 790bdd1243dSDimitry Andric FileDeps.push_back(std::string(Path)); 791bdd1243dSDimitry Andric } 792bdd1243dSDimitry Andric 793bdd1243dSDimitry Andric void ModuleDepCollector::addFileDep(ModuleDeps &MD, StringRef Path) { 7945f757f3fSDimitry Andric if (IsStdModuleP1689Format) { 7955f757f3fSDimitry Andric MD.FileDeps.insert(Path); 7965f757f3fSDimitry Andric return; 7975f757f3fSDimitry Andric } 7985f757f3fSDimitry Andric 799bdd1243dSDimitry Andric llvm::SmallString<256> Storage; 800bdd1243dSDimitry Andric Path = makeAbsoluteAndPreferred(ScanInstance, Path, Storage); 801bdd1243dSDimitry Andric MD.FileDeps.insert(Path); 802bdd1243dSDimitry Andric } 803