133a745e6SMichael Spencer //===- ModuleDepCollector.cpp - Callbacks to collect deps -------*- C++ -*-===// 233a745e6SMichael Spencer // 3c874dd53SChristopher Di Bella // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4c874dd53SChristopher Di Bella // See https://llvm.org/LICENSE.txt for license information. 5c874dd53SChristopher Di Bella // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 633a745e6SMichael Spencer // 733a745e6SMichael Spencer //===----------------------------------------------------------------------===// 833a745e6SMichael Spencer 933a745e6SMichael Spencer #include "clang/Tooling/DependencyScanning/ModuleDepCollector.h" 1033a745e6SMichael Spencer 113ce78cbdSBen Langmuir #include "clang/Basic/MakeSupport.h" 1233a745e6SMichael Spencer #include "clang/Frontend/CompilerInstance.h" 1333a745e6SMichael Spencer #include "clang/Lex/Preprocessor.h" 1433a745e6SMichael Spencer #include "clang/Tooling/DependencyScanning/DependencyScanningWorker.h" 15dc5cbba3SBen Langmuir #include "llvm/ADT/STLExtras.h" 1602871701SBen Langmuir #include "llvm/Support/BLAKE3.h" 170a92e09cSJan Svoboda #include "llvm/Support/StringSaver.h" 18a1580d7bSKazu Hirata #include <optional> 1933a745e6SMichael Spencer 2033a745e6SMichael Spencer using namespace clang; 2133a745e6SMichael Spencer using namespace tooling; 2233a745e6SMichael Spencer using namespace dependencies; 2333a745e6SMichael Spencer 24*9d4837f4SJan Svoboda void ModuleDeps::forEachFileDep(llvm::function_ref<void(StringRef)> Cb) const { 25*9d4837f4SJan Svoboda SmallString<0> PathBuf; 26*9d4837f4SJan Svoboda PathBuf.reserve(256); 27*9d4837f4SJan Svoboda for (StringRef FileDep : FileDeps) { 28*9d4837f4SJan Svoboda auto ResolvedFileDep = 29*9d4837f4SJan Svoboda ASTReader::ResolveImportedPath(PathBuf, FileDep, FileDepsBaseDir); 30*9d4837f4SJan Svoboda Cb(*ResolvedFileDep); 31*9d4837f4SJan Svoboda } 32*9d4837f4SJan Svoboda } 33*9d4837f4SJan Svoboda 343b1a6865SJan Svoboda const std::vector<std::string> &ModuleDeps::getBuildArguments() { 353b1a6865SJan Svoboda assert(!std::holds_alternative<std::monostate>(BuildInfo) && 363b1a6865SJan Svoboda "Using uninitialized ModuleDeps"); 373b1a6865SJan Svoboda if (const auto *CI = std::get_if<CowCompilerInvocation>(&BuildInfo)) 383b1a6865SJan Svoboda BuildInfo = CI->getCC1CommandLine(); 393b1a6865SJan Svoboda return std::get<std::vector<std::string>>(BuildInfo); 403b1a6865SJan Svoboda } 413b1a6865SJan Svoboda 42de3b2c29SMichael Spencer static void 43de3b2c29SMichael Spencer optimizeHeaderSearchOpts(HeaderSearchOptions &Opts, ASTReader &Reader, 447847e445SMichael Spencer const serialization::ModuleFile &MF, 45de3b2c29SMichael Spencer const PrebuiltModuleVFSMapT &PrebuiltModuleVFSMap, 467847e445SMichael Spencer ScanningOptimizations OptimizeArgs) { 477847e445SMichael Spencer if (any(OptimizeArgs & ScanningOptimizations::HeaderSearch)) { 486a1f50b8SJan Svoboda // Only preserve search paths that were used during the dependency scan. 497847e445SMichael Spencer std::vector<HeaderSearchOptions::Entry> Entries; 507847e445SMichael Spencer std::swap(Opts.UserEntries, Entries); 51d73daa91SJan Svoboda 52d73daa91SJan Svoboda llvm::BitVector SearchPathUsage(Entries.size()); 53d73daa91SJan Svoboda llvm::DenseSet<const serialization::ModuleFile *> Visited; 54d73daa91SJan Svoboda std::function<void(const serialization::ModuleFile *)> VisitMF = 55d73daa91SJan Svoboda [&](const serialization::ModuleFile *MF) { 56d73daa91SJan Svoboda SearchPathUsage |= MF->SearchPathUsage; 57d73daa91SJan Svoboda Visited.insert(MF); 58d73daa91SJan Svoboda for (const serialization::ModuleFile *Import : MF->Imports) 59d73daa91SJan Svoboda if (!Visited.contains(Import)) 60d73daa91SJan Svoboda VisitMF(Import); 61d73daa91SJan Svoboda }; 62d73daa91SJan Svoboda VisitMF(&MF); 63d73daa91SJan Svoboda 647847e445SMichael Spencer if (SearchPathUsage.size() != Entries.size()) 657847e445SMichael Spencer llvm::report_fatal_error( 667847e445SMichael Spencer "Inconsistent search path options between modules detected"); 677847e445SMichael Spencer 68d73daa91SJan Svoboda for (auto Idx : SearchPathUsage.set_bits()) 697847e445SMichael Spencer Opts.UserEntries.push_back(std::move(Entries[Idx])); 707847e445SMichael Spencer } 717847e445SMichael Spencer if (any(OptimizeArgs & ScanningOptimizations::VFS)) { 727847e445SMichael Spencer std::vector<std::string> VFSOverlayFiles; 737847e445SMichael Spencer std::swap(Opts.VFSOverlayFiles, VFSOverlayFiles); 747847e445SMichael Spencer 757847e445SMichael Spencer llvm::BitVector VFSUsage(VFSOverlayFiles.size()); 767847e445SMichael Spencer llvm::DenseSet<const serialization::ModuleFile *> Visited; 777847e445SMichael Spencer std::function<void(const serialization::ModuleFile *)> VisitMF = 787847e445SMichael Spencer [&](const serialization::ModuleFile *MF) { 797847e445SMichael Spencer Visited.insert(MF); 80de3b2c29SMichael Spencer if (MF->Kind == serialization::MK_ImplicitModule) { 81de3b2c29SMichael Spencer VFSUsage |= MF->VFSUsage; 82de3b2c29SMichael Spencer // We only need to recurse into implicit modules. Other module types 83de3b2c29SMichael Spencer // will have the correct set of VFSs for anything they depend on. 847847e445SMichael Spencer for (const serialization::ModuleFile *Import : MF->Imports) 857847e445SMichael Spencer if (!Visited.contains(Import)) 867847e445SMichael Spencer VisitMF(Import); 87de3b2c29SMichael Spencer } else { 88de3b2c29SMichael Spencer // This is not an implicitly built module, so it may have different 89de3b2c29SMichael Spencer // VFS options. Fall back to a string comparison instead. 90de3b2c29SMichael Spencer auto VFSMap = PrebuiltModuleVFSMap.find(MF->FileName); 91de3b2c29SMichael Spencer if (VFSMap == PrebuiltModuleVFSMap.end()) 92de3b2c29SMichael Spencer return; 93de3b2c29SMichael Spencer for (std::size_t I = 0, E = VFSOverlayFiles.size(); I != E; ++I) { 94de3b2c29SMichael Spencer if (VFSMap->second.contains(VFSOverlayFiles[I])) 95de3b2c29SMichael Spencer VFSUsage[I] = true; 96de3b2c29SMichael Spencer } 97de3b2c29SMichael Spencer } 987847e445SMichael Spencer }; 997847e445SMichael Spencer VisitMF(&MF); 1007847e445SMichael Spencer 1017847e445SMichael Spencer if (VFSUsage.size() != VFSOverlayFiles.size()) 1027847e445SMichael Spencer llvm::report_fatal_error( 1037847e445SMichael Spencer "Inconsistent -ivfsoverlay options between modules detected"); 1047847e445SMichael Spencer 1057847e445SMichael Spencer for (auto Idx : VFSUsage.set_bits()) 1067847e445SMichael Spencer Opts.VFSOverlayFiles.push_back(std::move(VFSOverlayFiles[Idx])); 1077847e445SMichael Spencer } 1086a1f50b8SJan Svoboda } 1096a1f50b8SJan Svoboda 110731152e1SMichael Spencer static void optimizeDiagnosticOpts(DiagnosticOptions &Opts, 111731152e1SMichael Spencer bool IsSystemModule) { 112731152e1SMichael Spencer // If this is not a system module or -Wsystem-headers was passed, don't 113731152e1SMichael Spencer // optimize. 114731152e1SMichael Spencer if (!IsSystemModule) 115731152e1SMichael Spencer return; 116731152e1SMichael Spencer bool Wsystem_headers = false; 117731152e1SMichael Spencer for (StringRef Opt : Opts.Warnings) { 118731152e1SMichael Spencer bool isPositive = !Opt.consume_front("no-"); 119731152e1SMichael Spencer if (Opt == "system-headers") 120731152e1SMichael Spencer Wsystem_headers = isPositive; 121731152e1SMichael Spencer } 122731152e1SMichael Spencer if (Wsystem_headers) 123731152e1SMichael Spencer return; 124731152e1SMichael Spencer 125731152e1SMichael Spencer // Remove all warning flags. System modules suppress most, but not all, 126731152e1SMichael Spencer // warnings. 127731152e1SMichael Spencer Opts.Warnings.clear(); 128731152e1SMichael Spencer Opts.UndefPrefixes.clear(); 129731152e1SMichael Spencer Opts.Remarks.clear(); 130731152e1SMichael Spencer } 131731152e1SMichael Spencer 1325482432bSBen Langmuir static std::vector<std::string> splitString(std::string S, char Separator) { 1335482432bSBen Langmuir SmallVector<StringRef> Segments; 1345482432bSBen Langmuir StringRef(S).split(Segments, Separator, /*MaxSplit=*/-1, /*KeepEmpty=*/false); 1355482432bSBen Langmuir std::vector<std::string> Result; 1365482432bSBen Langmuir Result.reserve(Segments.size()); 1375482432bSBen Langmuir for (StringRef Segment : Segments) 1385482432bSBen Langmuir Result.push_back(Segment.str()); 1395482432bSBen Langmuir return Result; 1405482432bSBen Langmuir } 1415482432bSBen Langmuir 1429208065aSJan Svoboda void ModuleDepCollector::addOutputPaths(CowCompilerInvocation &CI, 143e8febb23SBen Langmuir ModuleDeps &Deps) { 1449208065aSJan Svoboda CI.getMutFrontendOpts().OutputFile = 145296ba5bbSBen Langmuir Controller.lookupModuleOutput(Deps.ID, ModuleOutputKind::ModuleFile); 1465482432bSBen Langmuir if (!CI.getDiagnosticOpts().DiagnosticSerializationFile.empty()) 1479208065aSJan Svoboda CI.getMutDiagnosticOpts().DiagnosticSerializationFile = 148296ba5bbSBen Langmuir Controller.lookupModuleOutput( 1495482432bSBen Langmuir Deps.ID, ModuleOutputKind::DiagnosticSerializationFile); 1505482432bSBen Langmuir if (!CI.getDependencyOutputOpts().OutputFile.empty()) { 1519208065aSJan Svoboda CI.getMutDependencyOutputOpts().OutputFile = Controller.lookupModuleOutput( 152296ba5bbSBen Langmuir Deps.ID, ModuleOutputKind::DependencyFile); 1539208065aSJan Svoboda CI.getMutDependencyOutputOpts().Targets = 154296ba5bbSBen Langmuir splitString(Controller.lookupModuleOutput( 1555482432bSBen Langmuir Deps.ID, ModuleOutputKind::DependencyTargets), 1565482432bSBen Langmuir '\0'); 1575482432bSBen Langmuir if (!CI.getDependencyOutputOpts().OutputFile.empty() && 1585482432bSBen Langmuir CI.getDependencyOutputOpts().Targets.empty()) { 1595482432bSBen Langmuir // Fallback to -o as dependency target, as in the driver. 1605482432bSBen Langmuir SmallString<128> Target; 1615482432bSBen Langmuir quoteMakeTarget(CI.getFrontendOpts().OutputFile, Target); 1629208065aSJan Svoboda CI.getMutDependencyOutputOpts().Targets.push_back(std::string(Target)); 1635482432bSBen Langmuir } 1645482432bSBen Langmuir } 1655482432bSBen Langmuir } 1665482432bSBen Langmuir 16763310243SArgyrios Kyrtzidis void dependencies::resetBenignCodeGenOptions(frontend::ActionKind ProgramAction, 16863310243SArgyrios Kyrtzidis const LangOptions &LangOpts, 16963310243SArgyrios Kyrtzidis CodeGenOptions &CGOpts) { 17063310243SArgyrios Kyrtzidis // TODO: Figure out better way to set options to their default value. 17163310243SArgyrios Kyrtzidis if (ProgramAction == frontend::GenerateModule) { 17263310243SArgyrios Kyrtzidis CGOpts.MainFileName.clear(); 17363310243SArgyrios Kyrtzidis CGOpts.DwarfDebugFlags.clear(); 17463310243SArgyrios Kyrtzidis } 17563310243SArgyrios Kyrtzidis if (ProgramAction == frontend::GeneratePCH || 17663310243SArgyrios Kyrtzidis (ProgramAction == frontend::GenerateModule && !LangOpts.ModulesCodegen)) { 17763310243SArgyrios Kyrtzidis CGOpts.DebugCompilationDir.clear(); 17863310243SArgyrios Kyrtzidis CGOpts.CoverageCompilationDir.clear(); 17963310243SArgyrios Kyrtzidis CGOpts.CoverageDataFile.clear(); 18063310243SArgyrios Kyrtzidis CGOpts.CoverageNotesFile.clear(); 18163310243SArgyrios Kyrtzidis CGOpts.ProfileInstrumentUsePath.clear(); 18263310243SArgyrios Kyrtzidis CGOpts.SampleProfileFile.clear(); 18363310243SArgyrios Kyrtzidis CGOpts.ProfileRemappingFile.clear(); 18463310243SArgyrios Kyrtzidis } 18563310243SArgyrios Kyrtzidis } 18663310243SArgyrios Kyrtzidis 1879208065aSJan Svoboda static CowCompilerInvocation 1889208065aSJan Svoboda makeCommonInvocationForModuleBuild(CompilerInvocation CI) { 1893708a148SBen Langmuir CI.resetNonModularOptions(); 1903708a148SBen Langmuir CI.clearImplicitModuleBuildOptions(); 1916da811fdSJan Svoboda 1923ea5dff0SJan Svoboda // The scanner takes care to avoid passing non-affecting module maps to the 1933ea5dff0SJan Svoboda // explicit compiles. No need to do extra work just to find out there are no 1943ea5dff0SJan Svoboda // module map files to prune. 1953ea5dff0SJan Svoboda CI.getHeaderSearchOpts().ModulesPruneNonAffectingModuleMaps = false; 1963ea5dff0SJan Svoboda 1975b6c0837SJan Svoboda // Remove options incompatible with explicit module build or are likely to 1985b6c0837SJan Svoboda // differ between identical modules discovered from different translation 1995b6c0837SJan Svoboda // units. 2000a92e09cSJan Svoboda CI.getFrontendOpts().Inputs.clear(); 2010a92e09cSJan Svoboda CI.getFrontendOpts().OutputFile.clear(); 202e007551bSJuergen Ributzka // LLVM options are not going to affect the AST 203e007551bSJuergen Ributzka CI.getFrontendOpts().LLVMArgs.clear(); 204060b2534SJan Svoboda 20563310243SArgyrios Kyrtzidis resetBenignCodeGenOptions(frontend::GenerateModule, CI.getLangOpts(), 20663310243SArgyrios Kyrtzidis CI.getCodeGenOpts()); 207060b2534SJan Svoboda 2085482432bSBen Langmuir // Map output paths that affect behaviour to "-" so their existence is in the 2095482432bSBen Langmuir // context hash. The final path will be computed in addOutputPaths. 2105482432bSBen Langmuir if (!CI.getDiagnosticOpts().DiagnosticSerializationFile.empty()) 2115482432bSBen Langmuir CI.getDiagnosticOpts().DiagnosticSerializationFile = "-"; 2125482432bSBen Langmuir if (!CI.getDependencyOutputOpts().OutputFile.empty()) 2135482432bSBen Langmuir CI.getDependencyOutputOpts().OutputFile = "-"; 2146626f6feSBen Langmuir CI.getDependencyOutputOpts().Targets.clear(); 2150a92e09cSJan Svoboda 2160a92e09cSJan Svoboda CI.getFrontendOpts().ProgramAction = frontend::GenerateModule; 217ffa2a647SMichael Spencer CI.getFrontendOpts().ARCMTAction = FrontendOptions::ARCMT_None; 218ffa2a647SMichael Spencer CI.getFrontendOpts().ObjCMTAction = FrontendOptions::ObjCMT_None; 219ffa2a647SMichael Spencer CI.getFrontendOpts().MTMigrateDir.clear(); 2209208065aSJan Svoboda CI.getLangOpts().ModuleName.clear(); 2219208065aSJan Svoboda 2229208065aSJan Svoboda // Remove any macro definitions that are explicitly ignored. 2239208065aSJan Svoboda if (!CI.getHeaderSearchOpts().ModulesIgnoreMacros.empty()) { 2249208065aSJan Svoboda llvm::erase_if( 2259208065aSJan Svoboda CI.getPreprocessorOpts().Macros, 2269208065aSJan Svoboda [&CI](const std::pair<std::string, bool> &Def) { 2279208065aSJan Svoboda StringRef MacroDef = Def.first; 2289208065aSJan Svoboda return CI.getHeaderSearchOpts().ModulesIgnoreMacros.contains( 2299208065aSJan Svoboda llvm::CachedHashString(MacroDef.split('=').first)); 2309208065aSJan Svoboda }); 2319208065aSJan Svoboda // Remove the now unused option. 2329208065aSJan Svoboda CI.getHeaderSearchOpts().ModulesIgnoreMacros.clear(); 2339208065aSJan Svoboda } 2349208065aSJan Svoboda 2359208065aSJan Svoboda return CI; 2369208065aSJan Svoboda } 2379208065aSJan Svoboda 2389208065aSJan Svoboda CowCompilerInvocation 2399208065aSJan Svoboda ModuleDepCollector::getInvocationAdjustedForModuleBuildWithoutOutputs( 2409208065aSJan Svoboda const ModuleDeps &Deps, 2419208065aSJan Svoboda llvm::function_ref<void(CowCompilerInvocation &)> Optimize) const { 2429208065aSJan Svoboda CowCompilerInvocation CI = CommonInvocation; 2439208065aSJan Svoboda 2449208065aSJan Svoboda CI.getMutLangOpts().ModuleName = Deps.ID.ModuleName; 2459208065aSJan Svoboda CI.getMutFrontendOpts().IsSystemModule = Deps.IsSystem; 2460a92e09cSJan Svoboda 2475482432bSBen Langmuir // Inputs 2485482432bSBen Langmuir InputKind ModuleMapInputKind(CI.getFrontendOpts().DashX.getLanguage(), 2495482432bSBen Langmuir InputKind::Format::ModuleMap); 2509208065aSJan Svoboda CI.getMutFrontendOpts().Inputs.emplace_back(Deps.ClangModuleMapFile, 2515482432bSBen Langmuir ModuleMapInputKind); 25220fa87c7SJan Svoboda 25320fa87c7SJan Svoboda auto CurrentModuleMapEntry = 254b1aea98cSJan Svoboda ScanInstance.getFileManager().getOptionalFileRef(Deps.ClangModuleMapFile); 25520fa87c7SJan Svoboda assert(CurrentModuleMapEntry && "module map file entry not found"); 25620fa87c7SJan Svoboda 257c003d851SMichael Spencer // Remove directly passed modulemap files. They will get added back if they 258c003d851SMichael Spencer // were actually used. 259c003d851SMichael Spencer CI.getMutFrontendOpts().ModuleMapFiles.clear(); 260c003d851SMichael Spencer 26120fa87c7SJan Svoboda auto DepModuleMapFiles = collectModuleMapFiles(Deps.ClangModuleDeps); 26220fa87c7SJan Svoboda for (StringRef ModuleMapFile : Deps.ModuleMapFileDeps) { 26305ec16d9SBen Langmuir // TODO: Track these as `FileEntryRef` to simplify the equality check below. 264b1aea98cSJan Svoboda auto ModuleMapEntry = 265b1aea98cSJan Svoboda ScanInstance.getFileManager().getOptionalFileRef(ModuleMapFile); 26605ec16d9SBen Langmuir assert(ModuleMapEntry && "module map file entry not found"); 26705ec16d9SBen Langmuir 26820fa87c7SJan Svoboda // Don't report module maps describing eagerly-loaded dependency. This 26920fa87c7SJan Svoboda // information will be deserialized from the PCM. 27020fa87c7SJan Svoboda // TODO: Verify this works fine when modulemap for module A is eagerly 27120fa87c7SJan Svoboda // loaded from A.pcm, and module map passed on the command line contains 27220fa87c7SJan Svoboda // definition of a submodule: "explicit module A.Private { ... }". 27305ec16d9SBen Langmuir if (EagerLoadModules && DepModuleMapFiles.contains(*ModuleMapEntry)) 27420fa87c7SJan Svoboda continue; 27520fa87c7SJan Svoboda 27620fa87c7SJan Svoboda // Don't report module map file of the current module unless it also 27720fa87c7SJan Svoboda // describes a dependency (for symmetry). 27820fa87c7SJan Svoboda if (*ModuleMapEntry == *CurrentModuleMapEntry && 27905ec16d9SBen Langmuir !DepModuleMapFiles.contains(*ModuleMapEntry)) 28020fa87c7SJan Svoboda continue; 28120fa87c7SJan Svoboda 2829208065aSJan Svoboda CI.getMutFrontendOpts().ModuleMapFiles.emplace_back(ModuleMapFile); 28320fa87c7SJan Svoboda } 2845482432bSBen Langmuir 2855482432bSBen Langmuir // Report the prebuilt modules this module uses. 2865482432bSBen Langmuir for (const auto &PrebuiltModule : Deps.PrebuiltModuleDeps) 2879208065aSJan Svoboda CI.getMutFrontendOpts().ModuleFiles.push_back(PrebuiltModule.PCMFile); 2885482432bSBen Langmuir 28943854fa2SBen Langmuir // Add module file inputs from dependencies. 29043854fa2SBen Langmuir addModuleFiles(CI, Deps.ClangModuleDeps); 29143854fa2SBen Langmuir 2929208065aSJan Svoboda if (!CI.getDiagnosticOpts().SystemHeaderWarningsModules.empty()) { 293dc5cbba3SBen Langmuir // Apply -Wsystem-headers-in-module for the current module. 294dc5cbba3SBen Langmuir if (llvm::is_contained(CI.getDiagnosticOpts().SystemHeaderWarningsModules, 295dc5cbba3SBen Langmuir Deps.ID.ModuleName)) 2969208065aSJan Svoboda CI.getMutDiagnosticOpts().Warnings.push_back("system-headers"); 297dc5cbba3SBen Langmuir // Remove the now unused option(s). 2989208065aSJan Svoboda CI.getMutDiagnosticOpts().SystemHeaderWarningsModules.clear(); 2999208065aSJan Svoboda } 300dc5cbba3SBen Langmuir 3016a1f50b8SJan Svoboda Optimize(CI); 3026a1f50b8SJan Svoboda 3030a92e09cSJan Svoboda return CI; 3040a92e09cSJan Svoboda } 3050a92e09cSJan Svoboda 30605ec16d9SBen Langmuir llvm::DenseSet<const FileEntry *> ModuleDepCollector::collectModuleMapFiles( 30720fa87c7SJan Svoboda ArrayRef<ModuleID> ClangModuleDeps) const { 30805ec16d9SBen Langmuir llvm::DenseSet<const FileEntry *> ModuleMapFiles; 30920fa87c7SJan Svoboda for (const ModuleID &MID : ClangModuleDeps) { 31020fa87c7SJan Svoboda ModuleDeps *MD = ModuleDepsByID.lookup(MID); 31120fa87c7SJan Svoboda assert(MD && "Inconsistent dependency info"); 31205ec16d9SBen Langmuir // TODO: Track ClangModuleMapFile as `FileEntryRef`. 313b1aea98cSJan Svoboda auto FE = ScanInstance.getFileManager().getOptionalFileRef( 314b1aea98cSJan Svoboda MD->ClangModuleMapFile); 31505ec16d9SBen Langmuir assert(FE && "Missing module map file that was previously found"); 31605ec16d9SBen Langmuir ModuleMapFiles.insert(*FE); 31720fa87c7SJan Svoboda } 31820fa87c7SJan Svoboda return ModuleMapFiles; 31920fa87c7SJan Svoboda } 32020fa87c7SJan Svoboda 321c0a55121SBen Langmuir void ModuleDepCollector::addModuleMapFiles( 322c0a55121SBen Langmuir CompilerInvocation &CI, ArrayRef<ModuleID> ClangModuleDeps) const { 323c0a55121SBen Langmuir if (EagerLoadModules) 324c0a55121SBen Langmuir return; // Only pcm is needed for eager load. 325c0a55121SBen Langmuir 326c0a55121SBen Langmuir for (const ModuleID &MID : ClangModuleDeps) { 327c0a55121SBen Langmuir ModuleDeps *MD = ModuleDepsByID.lookup(MID); 328c0a55121SBen Langmuir assert(MD && "Inconsistent dependency info"); 329c0a55121SBen Langmuir CI.getFrontendOpts().ModuleMapFiles.push_back(MD->ClangModuleMapFile); 330c0a55121SBen Langmuir } 331c0a55121SBen Langmuir } 332c0a55121SBen Langmuir 333c0a55121SBen Langmuir void ModuleDepCollector::addModuleFiles( 334c0a55121SBen Langmuir CompilerInvocation &CI, ArrayRef<ModuleID> ClangModuleDeps) const { 335c0a55121SBen Langmuir for (const ModuleID &MID : ClangModuleDeps) { 336c0a55121SBen Langmuir std::string PCMPath = 337296ba5bbSBen Langmuir Controller.lookupModuleOutput(MID, ModuleOutputKind::ModuleFile); 338c0a55121SBen Langmuir if (EagerLoadModules) 339c0a55121SBen Langmuir CI.getFrontendOpts().ModuleFiles.push_back(std::move(PCMPath)); 340c0a55121SBen Langmuir else 341c0a55121SBen Langmuir CI.getHeaderSearchOpts().PrebuiltModuleFiles.insert( 342c0a55121SBen Langmuir {MID.ModuleName, std::move(PCMPath)}); 343c0a55121SBen Langmuir } 344c0a55121SBen Langmuir } 345c0a55121SBen Langmuir 3469208065aSJan Svoboda void ModuleDepCollector::addModuleFiles( 3479208065aSJan Svoboda CowCompilerInvocation &CI, ArrayRef<ModuleID> ClangModuleDeps) const { 3489208065aSJan Svoboda for (const ModuleID &MID : ClangModuleDeps) { 3499208065aSJan Svoboda std::string PCMPath = 3509208065aSJan Svoboda Controller.lookupModuleOutput(MID, ModuleOutputKind::ModuleFile); 3519208065aSJan Svoboda if (EagerLoadModules) 3529208065aSJan Svoboda CI.getMutFrontendOpts().ModuleFiles.push_back(std::move(PCMPath)); 3539208065aSJan Svoboda else 3549208065aSJan Svoboda CI.getMutHeaderSearchOpts().PrebuiltModuleFiles.insert( 3559208065aSJan Svoboda {MID.ModuleName, std::move(PCMPath)}); 3569208065aSJan Svoboda } 3579208065aSJan Svoboda } 3589208065aSJan Svoboda 35983902c40SBen Langmuir static bool needsModules(FrontendInputFile FIF) { 36083902c40SBen Langmuir switch (FIF.getKind().getLanguage()) { 36183902c40SBen Langmuir case Language::Unknown: 36283902c40SBen Langmuir case Language::Asm: 36383902c40SBen Langmuir case Language::LLVM_IR: 36483902c40SBen Langmuir return false; 36583902c40SBen Langmuir default: 36683902c40SBen Langmuir return true; 36783902c40SBen Langmuir } 36883902c40SBen Langmuir } 36983902c40SBen Langmuir 37083902c40SBen Langmuir void ModuleDepCollector::applyDiscoveredDependencies(CompilerInvocation &CI) { 37183902c40SBen Langmuir CI.clearImplicitModuleBuildOptions(); 37263310243SArgyrios Kyrtzidis resetBenignCodeGenOptions(CI.getFrontendOpts().ProgramAction, 37363310243SArgyrios Kyrtzidis CI.getLangOpts(), CI.getCodeGenOpts()); 37483902c40SBen Langmuir 37583902c40SBen Langmuir if (llvm::any_of(CI.getFrontendOpts().Inputs, needsModules)) { 3769dc0b167SJan Svoboda Preprocessor &PP = ScanInstance.getPreprocessor(); 3779dc0b167SJan Svoboda if (Module *CurrentModule = PP.getCurrentModuleImplementation()) 378854c10f8SBenjamin Kramer if (OptionalFileEntryRef CurrentModuleMap = 3799dc0b167SJan Svoboda PP.getHeaderSearchInfo() 3809dc0b167SJan Svoboda .getModuleMap() 3819dc0b167SJan Svoboda .getModuleMapFileForUniquing(CurrentModule)) 3829dc0b167SJan Svoboda CI.getFrontendOpts().ModuleMapFiles.emplace_back( 38373dba2f6SBen Langmuir CurrentModuleMap->getNameAsRequested()); 3849dc0b167SJan Svoboda 38583902c40SBen Langmuir SmallVector<ModuleID> DirectDeps; 38683902c40SBen Langmuir for (const auto &KV : ModularDeps) 387c75b331fSJan Svoboda if (DirectModularDeps.contains(KV.first)) 38883902c40SBen Langmuir DirectDeps.push_back(KV.second->ID); 38983902c40SBen Langmuir 39020fa87c7SJan Svoboda // TODO: Report module maps the same way it's done for modular dependencies. 39183902c40SBen Langmuir addModuleMapFiles(CI, DirectDeps); 39220fa87c7SJan Svoboda 39383902c40SBen Langmuir addModuleFiles(CI, DirectDeps); 39483902c40SBen Langmuir 39583902c40SBen Langmuir for (const auto &KV : DirectPrebuiltModularDeps) 39683902c40SBen Langmuir CI.getFrontendOpts().ModuleFiles.push_back(KV.second.PCMFile); 39783902c40SBen Langmuir } 39883902c40SBen Langmuir } 39983902c40SBen Langmuir 400be795ee1SJan Svoboda static std::string getModuleContextHash(const ModuleDeps &MD, 4019208065aSJan Svoboda const CowCompilerInvocation &CI, 40213386c60SMichael Spencer bool EagerLoadModules, 40313386c60SMichael Spencer llvm::vfs::FileSystem &VFS) { 404d7b18d50SKazu Hirata llvm::HashBuilder<llvm::TruncatedBLAKE3<16>, llvm::endianness::native> 40502871701SBen Langmuir HashBuilder; 40602871701SBen Langmuir SmallString<32> Scratch; 40702871701SBen Langmuir 40802871701SBen Langmuir // Hash the compiler version and serialization version to ensure the module 40902871701SBen Langmuir // will be readable. 41002871701SBen Langmuir HashBuilder.add(getClangFullRepositoryVersion()); 41102871701SBen Langmuir HashBuilder.add(serialization::VERSION_MAJOR, serialization::VERSION_MINOR); 41213386c60SMichael Spencer llvm::ErrorOr<std::string> CWD = VFS.getCurrentWorkingDirectory(); 41313386c60SMichael Spencer if (CWD) 41413386c60SMichael Spencer HashBuilder.add(*CWD); 41502871701SBen Langmuir 41602871701SBen Langmuir // Hash the BuildInvocation without any input files. 4178fd56ea1SJan Svoboda SmallString<0> ArgVec; 4188fd56ea1SJan Svoboda ArgVec.reserve(4096); 4198fd56ea1SJan Svoboda CI.generateCC1CommandLine([&](const Twine &Arg) { 4208fd56ea1SJan Svoboda Arg.toVector(ArgVec); 4218fd56ea1SJan Svoboda ArgVec.push_back('\0'); 4228fd56ea1SJan Svoboda }); 4238fd56ea1SJan Svoboda HashBuilder.add(ArgVec); 42402871701SBen Langmuir 4255482432bSBen Langmuir // Hash the module dependencies. These paths may differ even if the invocation 4265482432bSBen Langmuir // is identical if they depend on the contents of the files in the TU -- for 4275482432bSBen Langmuir // example, case-insensitive paths to modulemap files. Usually such a case 4285482432bSBen Langmuir // would indicate a missed optimization to canonicalize, but it may be 4295482432bSBen Langmuir // difficult to canonicalize all cases when there is a VFS. 43002871701SBen Langmuir for (const auto &ID : MD.ClangModuleDeps) { 43102871701SBen Langmuir HashBuilder.add(ID.ModuleName); 43202871701SBen Langmuir HashBuilder.add(ID.ContextHash); 43302871701SBen Langmuir } 43402871701SBen Langmuir 435be795ee1SJan Svoboda HashBuilder.add(EagerLoadModules); 436be795ee1SJan Svoboda 43702871701SBen Langmuir llvm::BLAKE3Result<16> Hash = HashBuilder.final(); 43802871701SBen Langmuir std::array<uint64_t, 2> Words; 43902871701SBen Langmuir static_assert(sizeof(Hash) == sizeof(Words), "Hash must match Words"); 44002871701SBen Langmuir std::memcpy(Words.data(), Hash.data(), sizeof(Hash)); 44102871701SBen Langmuir return toString(llvm::APInt(sizeof(Words) * 8, Words), 36, /*Signed=*/false); 44202871701SBen Langmuir } 44302871701SBen Langmuir 4449208065aSJan Svoboda void ModuleDepCollector::associateWithContextHash( 4459208065aSJan Svoboda const CowCompilerInvocation &CI, ModuleDeps &Deps) { 44613386c60SMichael Spencer Deps.ID.ContextHash = getModuleContextHash( 44713386c60SMichael Spencer Deps, CI, EagerLoadModules, ScanInstance.getVirtualFileSystem()); 448c0a55121SBen Langmuir bool Inserted = ModuleDepsByID.insert({Deps.ID, &Deps}).second; 449c0a55121SBen Langmuir (void)Inserted; 450c0a55121SBen Langmuir assert(Inserted && "duplicate module mapping"); 451c0a55121SBen Langmuir } 452c0a55121SBen Langmuir 4538711120eSBen Langmuir void ModuleDepCollectorPP::LexedFileChanged(FileID FID, 4548711120eSBen Langmuir LexedFileChangeReason Reason, 45533a745e6SMichael Spencer SrcMgr::CharacteristicKind FileType, 4568711120eSBen Langmuir FileID PrevFID, 4578711120eSBen Langmuir SourceLocation Loc) { 4588711120eSBen Langmuir if (Reason != LexedFileChangeReason::EnterFile) 45933a745e6SMichael Spencer return; 46033a745e6SMichael Spencer 461356a4b43SMichael Spencer // This has to be delayed as the context hash can change at the start of 462356a4b43SMichael Spencer // `CompilerInstance::ExecuteAction`. 463356a4b43SMichael Spencer if (MDC.ContextHash.empty()) { 464207e9fdeSJan Svoboda MDC.ContextHash = MDC.ScanInstance.getInvocation().getModuleHash(); 465356a4b43SMichael Spencer MDC.Consumer.handleContextHash(MDC.ContextHash); 466356a4b43SMichael Spencer } 467356a4b43SMichael Spencer 468207e9fdeSJan Svoboda SourceManager &SM = MDC.ScanInstance.getSourceManager(); 46933a745e6SMichael Spencer 47033a745e6SMichael Spencer // Dependency generation really does want to go all the way to the 47133a745e6SMichael Spencer // file entry for a source location to find out what is depended on. 47233a745e6SMichael Spencer // We do not want #line markers to affect dependency generation! 4738711120eSBen Langmuir if (std::optional<StringRef> Filename = SM.getNonBuiltinFilenameForID(FID)) 474b4c6dc2eSBen Langmuir MDC.addFileDep(llvm::sys::path::remove_leading_dotslash(*Filename)); 47533a745e6SMichael Spencer } 47633a745e6SMichael Spencer 47733a745e6SMichael Spencer void ModuleDepCollectorPP::InclusionDirective( 47833a745e6SMichael Spencer SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName, 479854c10f8SBenjamin Kramer bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef File, 480da95d926SJan Svoboda StringRef SearchPath, StringRef RelativePath, const Module *SuggestedModule, 481da95d926SJan Svoboda bool ModuleImported, SrcMgr::CharacteristicKind FileType) { 482da95d926SJan Svoboda if (!File && !ModuleImported) { 48333a745e6SMichael Spencer // This is a non-modular include that HeaderSearch failed to find. Add it 48433a745e6SMichael Spencer // here as `FileChanged` will never see it. 485b4c6dc2eSBen Langmuir MDC.addFileDep(FileName); 48633a745e6SMichael Spencer } 487da95d926SJan Svoboda handleImport(SuggestedModule); 488356a4b43SMichael Spencer } 48933a745e6SMichael Spencer 490356a4b43SMichael Spencer void ModuleDepCollectorPP::moduleImport(SourceLocation ImportLoc, 491356a4b43SMichael Spencer ModuleIdPath Path, 492356a4b43SMichael Spencer const Module *Imported) { 493eb70b38fSChuanqi Xu if (MDC.ScanInstance.getPreprocessor().isInImportingCXXNamedModules()) { 494eb70b38fSChuanqi Xu P1689ModuleInfo RequiredModule; 495eb70b38fSChuanqi Xu RequiredModule.ModuleName = Path[0].first->getName().str(); 496eb70b38fSChuanqi Xu RequiredModule.Type = P1689ModuleInfo::ModuleType::NamedCXXModule; 497eb70b38fSChuanqi Xu MDC.RequiredStdCXXModules.push_back(RequiredModule); 498eb70b38fSChuanqi Xu return; 499eb70b38fSChuanqi Xu } 500eb70b38fSChuanqi Xu 501356a4b43SMichael Spencer handleImport(Imported); 502356a4b43SMichael Spencer } 503356a4b43SMichael Spencer 504356a4b43SMichael Spencer void ModuleDepCollectorPP::handleImport(const Module *Imported) { 50533a745e6SMichael Spencer if (!Imported) 50633a745e6SMichael Spencer return; 50733a745e6SMichael Spencer 508772e9f88SJan Svoboda const Module *TopLevelModule = Imported->getTopLevelModule(); 5094629554fSJan Svoboda 5104629554fSJan Svoboda if (MDC.isPrebuiltModule(TopLevelModule)) 511c0a55121SBen Langmuir MDC.DirectPrebuiltModularDeps.insert( 512c0a55121SBen Langmuir {TopLevelModule, PrebuiltModuleDep{TopLevelModule}}); 5134629554fSJan Svoboda else 514c75b331fSJan Svoboda MDC.DirectModularDeps.insert(TopLevelModule); 51533a745e6SMichael Spencer } 51633a745e6SMichael Spencer 51733a745e6SMichael Spencer void ModuleDepCollectorPP::EndOfMainFile() { 518207e9fdeSJan Svoboda FileID MainFileID = MDC.ScanInstance.getSourceManager().getMainFileID(); 519207e9fdeSJan Svoboda MDC.MainFile = std::string(MDC.ScanInstance.getSourceManager() 520b19fe81eSJan Svoboda .getFileEntryRefForID(MainFileID) 521207e9fdeSJan Svoboda ->getName()); 52233a745e6SMichael Spencer 523eb70b38fSChuanqi Xu auto &PP = MDC.ScanInstance.getPreprocessor(); 524eb70b38fSChuanqi Xu if (PP.isInNamedModule()) { 525eb70b38fSChuanqi Xu P1689ModuleInfo ProvidedModule; 526eb70b38fSChuanqi Xu ProvidedModule.ModuleName = PP.getNamedModuleName(); 527eb70b38fSChuanqi Xu ProvidedModule.Type = P1689ModuleInfo::ModuleType::NamedCXXModule; 528eb70b38fSChuanqi Xu ProvidedModule.IsStdCXXModuleInterface = PP.isInNamedInterfaceUnit(); 529eb70b38fSChuanqi Xu // Don't put implementation (non partition) unit as Provide. 530eb70b38fSChuanqi Xu // Put the module as required instead. Since the implementation 531eb70b38fSChuanqi Xu // unit will import the primary module implicitly. 532eb70b38fSChuanqi Xu if (PP.isInImplementationUnit()) 533eb70b38fSChuanqi Xu MDC.RequiredStdCXXModules.push_back(ProvidedModule); 534eb70b38fSChuanqi Xu else 535eb70b38fSChuanqi Xu MDC.ProvidedStdCXXModule = ProvidedModule; 536eb70b38fSChuanqi Xu } 537eb70b38fSChuanqi Xu 538207e9fdeSJan Svoboda if (!MDC.ScanInstance.getPreprocessorOpts().ImplicitPCHInclude.empty()) 539b4c6dc2eSBen Langmuir MDC.addFileDep(MDC.ScanInstance.getPreprocessorOpts().ImplicitPCHInclude); 5409223209bSJan Svoboda 541002bfdd6SJan Svoboda for (const Module *M : 542e8541e4bSChuanqi Xu MDC.ScanInstance.getPreprocessor().getAffectingClangModules()) 543002bfdd6SJan Svoboda if (!MDC.isPrebuiltModule(M)) 544c75b331fSJan Svoboda MDC.DirectModularDeps.insert(M); 545002bfdd6SJan Svoboda 546c75b331fSJan Svoboda for (const Module *M : MDC.DirectModularDeps) 54733a745e6SMichael Spencer handleTopLevelModule(M); 54833a745e6SMichael Spencer 549f95ff816SJan Svoboda MDC.Consumer.handleDependencyOutputOpts(*MDC.Opts); 550f95ff816SJan Svoboda 551eb70b38fSChuanqi Xu if (MDC.IsStdModuleP1689Format) 552eb70b38fSChuanqi Xu MDC.Consumer.handleProvidedAndRequiredStdCXXModules( 553eb70b38fSChuanqi Xu MDC.ProvidedStdCXXModule, MDC.RequiredStdCXXModules); 554eb70b38fSChuanqi Xu 555772e9f88SJan Svoboda for (auto &&I : MDC.ModularDeps) 556835fcf2aSBen Langmuir MDC.Consumer.handleModuleDependency(*I.second); 55733a745e6SMichael Spencer 558c75b331fSJan Svoboda for (const Module *M : MDC.DirectModularDeps) { 559c75b331fSJan Svoboda auto It = MDC.ModularDeps.find(M); 560c75b331fSJan Svoboda // Only report direct dependencies that were successfully handled. 561c75b331fSJan Svoboda if (It != MDC.ModularDeps.end()) 562c7895f0dSKazu Hirata MDC.Consumer.handleDirectModuleDependency(It->second->ID); 563c75b331fSJan Svoboda } 564c75b331fSJan Svoboda 565772e9f88SJan Svoboda for (auto &&I : MDC.FileDeps) 566f95ff816SJan Svoboda MDC.Consumer.handleFileDependency(I); 5674629554fSJan Svoboda 568c0a55121SBen Langmuir for (auto &&I : MDC.DirectPrebuiltModularDeps) 569c0a55121SBen Langmuir MDC.Consumer.handlePrebuiltModuleDependency(I.second); 57033a745e6SMichael Spencer } 57133a745e6SMichael Spencer 57296a54b22SJan Svoboda std::optional<ModuleID> 57396a54b22SJan Svoboda ModuleDepCollectorPP::handleTopLevelModule(const Module *M) { 57433a745e6SMichael Spencer assert(M == M->getTopLevelModule() && "Expected top level module!"); 57533a745e6SMichael Spencer 57696a54b22SJan Svoboda // A top-level module might not be actually imported as a module when 57796a54b22SJan Svoboda // -fmodule-name is used to compile a translation unit that imports this 57896a54b22SJan Svoboda // module. In that case it can be skipped. The appropriate header 57996a54b22SJan Svoboda // dependencies will still be reported as expected. 58096a54b22SJan Svoboda if (!M->getASTFile()) 58196a54b22SJan Svoboda return {}; 58296a54b22SJan Svoboda 583b9d5b0c2SJan Svoboda // If this module has been handled already, just return its ID. 5845acd9d11SJan Svoboda if (auto ModI = MDC.ModularDeps.find(M); ModI != MDC.ModularDeps.end()) 5855acd9d11SJan Svoboda return ModI->second->ID; 58633a745e6SMichael Spencer 5875acd9d11SJan Svoboda auto OwnedMD = std::make_unique<ModuleDeps>(); 5885acd9d11SJan Svoboda ModuleDeps &MD = *OwnedMD; 58933a745e6SMichael Spencer 590b9d5b0c2SJan Svoboda MD.ID.ModuleName = M->getFullModuleName(); 591b9d5b0c2SJan Svoboda MD.IsSystem = M->IsSystem; 59268eb3b20SArtem Chikin // For modules which use export_as link name, the linked product that of the 59368eb3b20SArtem Chikin // corresponding export_as-named module. 59468eb3b20SArtem Chikin if (!M->UseExportAsModuleLinkName) 59568eb3b20SArtem Chikin MD.LinkLibraries = M->LinkLibraries; 596b9d5b0c2SJan Svoboda 597074fcec1SBen Langmuir ModuleMap &ModMapInfo = 598074fcec1SBen Langmuir MDC.ScanInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap(); 599074fcec1SBen Langmuir 600da1a16aeSJan Svoboda if (auto ModuleMap = ModMapInfo.getModuleMapFileForUniquing(M)) { 601074fcec1SBen Langmuir SmallString<128> Path = ModuleMap->getNameAsRequested(); 602074fcec1SBen Langmuir ModMapInfo.canonicalizeModuleMapPath(Path); 60337e6e022SMichael Spencer MD.ClangModuleMapFile = std::string(Path); 60437e6e022SMichael Spencer } 605b9d5b0c2SJan Svoboda 60633a745e6SMichael Spencer serialization::ModuleFile *MF = 607207e9fdeSJan Svoboda MDC.ScanInstance.getASTReader()->getModuleManager().lookup( 6080cb0a48cSJan Svoboda *M->getASTFile()); 609*9d4837f4SJan Svoboda MD.FileDepsBaseDir = MF->BaseDirectory; 610dcd3a0c9SJan Svoboda MDC.ScanInstance.getASTReader()->visitInputFileInfos( 611dcd3a0c9SJan Svoboda *MF, /*IncludeSystem=*/true, 612dcd3a0c9SJan Svoboda [&](const serialization::InputFileInfo &IFI, bool IsSystem) { 613da1a16aeSJan Svoboda // The __inferred_module.map file is an insignificant implementation 614da1a16aeSJan Svoboda // detail of implicitly-built modules. The PCM will also report the 615da1a16aeSJan Svoboda // actual on-disk module map file that allowed inferring the module, 616da1a16aeSJan Svoboda // which is what we need for building the module explicitly 617da1a16aeSJan Svoboda // Let's ignore this file. 618*9d4837f4SJan Svoboda if (IFI.UnresolvedImportedFilename.ends_with("__inferred_module.map")) 6197defab08SMichael Spencer return; 620*9d4837f4SJan Svoboda MDC.addFileDep(MD, IFI.UnresolvedImportedFilename); 62133a745e6SMichael Spencer }); 62233a745e6SMichael Spencer 623f35230aeSJan Svoboda llvm::DenseSet<const Module *> SeenDeps; 624f35230aeSJan Svoboda addAllSubmodulePrebuiltDeps(M, MD, SeenDeps); 625f35230aeSJan Svoboda addAllSubmoduleDeps(M, MD, SeenDeps); 626e8541e4bSChuanqi Xu addAllAffectingClangModules(M, MD, SeenDeps); 627f35230aeSJan Svoboda 628*9d4837f4SJan Svoboda SmallString<0> PathBuf; 629*9d4837f4SJan Svoboda PathBuf.reserve(256); 630dcd3a0c9SJan Svoboda MDC.ScanInstance.getASTReader()->visitInputFileInfos( 631dcd3a0c9SJan Svoboda *MF, /*IncludeSystem=*/true, 632dcd3a0c9SJan Svoboda [&](const serialization::InputFileInfo &IFI, bool IsSystem) { 633dcd3a0c9SJan Svoboda if (!(IFI.TopLevel && IFI.ModuleMap)) 634a6ef3635SJan Svoboda return; 635*9d4837f4SJan Svoboda if (IFI.UnresolvedImportedFilenameAsRequested.ends_with( 636*9d4837f4SJan Svoboda "__inferred_module.map")) 637dcd3a0c9SJan Svoboda return; 638*9d4837f4SJan Svoboda auto ResolvedFilenameAsRequested = ASTReader::ResolveImportedPath( 639*9d4837f4SJan Svoboda PathBuf, IFI.UnresolvedImportedFilenameAsRequested, 640*9d4837f4SJan Svoboda MF->BaseDirectory); 641*9d4837f4SJan Svoboda MD.ModuleMapFileDeps.emplace_back(*ResolvedFilenameAsRequested); 642a6ef3635SJan Svoboda }); 6434629554fSJan Svoboda 6449208065aSJan Svoboda CowCompilerInvocation CI = 6459208065aSJan Svoboda MDC.getInvocationAdjustedForModuleBuildWithoutOutputs( 6469208065aSJan Svoboda MD, [&](CowCompilerInvocation &BuildInvocation) { 6477847e445SMichael Spencer if (any(MDC.OptimizeArgs & (ScanningOptimizations::HeaderSearch | 6487847e445SMichael Spencer ScanningOptimizations::VFS))) 6499208065aSJan Svoboda optimizeHeaderSearchOpts(BuildInvocation.getMutHeaderSearchOpts(), 6507847e445SMichael Spencer *MDC.ScanInstance.getASTReader(), *MF, 651de3b2c29SMichael Spencer MDC.PrebuiltModuleVFSMap, 6527847e445SMichael Spencer MDC.OptimizeArgs); 653731152e1SMichael Spencer if (any(MDC.OptimizeArgs & ScanningOptimizations::SystemWarnings)) 654731152e1SMichael Spencer optimizeDiagnosticOpts( 655731152e1SMichael Spencer BuildInvocation.getMutDiagnosticOpts(), 656731152e1SMichael Spencer BuildInvocation.getFrontendOpts().IsSystemModule); 6576a1f50b8SJan Svoboda }); 658b9d5b0c2SJan Svoboda 659c0a55121SBen Langmuir MDC.associateWithContextHash(CI, MD); 660c0a55121SBen Langmuir 6615482432bSBen Langmuir // Finish the compiler invocation. Requires dependencies and the context hash. 662e8febb23SBen Langmuir MDC.addOutputPaths(CI, MD); 663e8febb23SBen Langmuir 6643b1a6865SJan Svoboda MD.BuildInfo = std::move(CI); 665e8febb23SBen Langmuir 6665acd9d11SJan Svoboda MDC.ModularDeps.insert({M, std::move(OwnedMD)}); 6675acd9d11SJan Svoboda 668b9d5b0c2SJan Svoboda return MD.ID; 66933a745e6SMichael Spencer } 67033a745e6SMichael Spencer 6714a3a9a5fSBen Langmuir static void forEachSubmoduleSorted(const Module *M, 6724a3a9a5fSBen Langmuir llvm::function_ref<void(const Module *)> F) { 6734a3a9a5fSBen Langmuir // Submodule order depends on order of header includes for inferred submodules 6744a3a9a5fSBen Langmuir // we don't care about the exact order, so sort so that it's consistent across 6754a3a9a5fSBen Langmuir // TUs to improve sharing. 67640136eceSStoorx SmallVector<const Module *> Submodules(M->submodules()); 6774a3a9a5fSBen Langmuir llvm::stable_sort(Submodules, [](const Module *A, const Module *B) { 6784a3a9a5fSBen Langmuir return A->Name < B->Name; 6794a3a9a5fSBen Langmuir }); 6804a3a9a5fSBen Langmuir for (const Module *SubM : Submodules) 6814a3a9a5fSBen Langmuir F(SubM); 6824a3a9a5fSBen Langmuir } 6834a3a9a5fSBen Langmuir 68483c633eaSJan Svoboda void ModuleDepCollectorPP::addAllSubmodulePrebuiltDeps( 68583c633eaSJan Svoboda const Module *M, ModuleDeps &MD, 68683c633eaSJan Svoboda llvm::DenseSet<const Module *> &SeenSubmodules) { 68783c633eaSJan Svoboda addModulePrebuiltDeps(M, MD, SeenSubmodules); 68883c633eaSJan Svoboda 6894a3a9a5fSBen Langmuir forEachSubmoduleSorted(M, [&](const Module *SubM) { 69083c633eaSJan Svoboda addAllSubmodulePrebuiltDeps(SubM, MD, SeenSubmodules); 6914a3a9a5fSBen Langmuir }); 69283c633eaSJan Svoboda } 69383c633eaSJan Svoboda 69483c633eaSJan Svoboda void ModuleDepCollectorPP::addModulePrebuiltDeps( 69583c633eaSJan Svoboda const Module *M, ModuleDeps &MD, 69683c633eaSJan Svoboda llvm::DenseSet<const Module *> &SeenSubmodules) { 6974629554fSJan Svoboda for (const Module *Import : M->Imports) 6984629554fSJan Svoboda if (Import->getTopLevelModule() != M->getTopLevelModule()) 6993b8f536fSJan Svoboda if (MDC.isPrebuiltModule(Import->getTopLevelModule())) 7003b8f536fSJan Svoboda if (SeenSubmodules.insert(Import->getTopLevelModule()).second) 7013b8f536fSJan Svoboda MD.PrebuiltModuleDeps.emplace_back(Import->getTopLevelModule()); 7024629554fSJan Svoboda } 7034629554fSJan Svoboda 704356a4b43SMichael Spencer void ModuleDepCollectorPP::addAllSubmoduleDeps( 705356a4b43SMichael Spencer const Module *M, ModuleDeps &MD, 706356a4b43SMichael Spencer llvm::DenseSet<const Module *> &AddedModules) { 707356a4b43SMichael Spencer addModuleDep(M, MD, AddedModules); 70833a745e6SMichael Spencer 7094a3a9a5fSBen Langmuir forEachSubmoduleSorted(M, [&](const Module *SubM) { 710356a4b43SMichael Spencer addAllSubmoduleDeps(SubM, MD, AddedModules); 7114a3a9a5fSBen Langmuir }); 71233a745e6SMichael Spencer } 71333a745e6SMichael Spencer 714356a4b43SMichael Spencer void ModuleDepCollectorPP::addModuleDep( 715356a4b43SMichael Spencer const Module *M, ModuleDeps &MD, 716356a4b43SMichael Spencer llvm::DenseSet<const Module *> &AddedModules) { 71733a745e6SMichael Spencer for (const Module *Import : M->Imports) { 7184629554fSJan Svoboda if (Import->getTopLevelModule() != M->getTopLevelModule() && 7194629554fSJan Svoboda !MDC.isPrebuiltModule(Import)) { 72096a54b22SJan Svoboda if (auto ImportID = handleTopLevelModule(Import->getTopLevelModule())) 721356a4b43SMichael Spencer if (AddedModules.insert(Import->getTopLevelModule()).second) 72296a54b22SJan Svoboda MD.ClangModuleDeps.push_back(*ImportID); 72333a745e6SMichael Spencer } 72433a745e6SMichael Spencer } 72533a745e6SMichael Spencer } 72633a745e6SMichael Spencer 727e8541e4bSChuanqi Xu void ModuleDepCollectorPP::addAllAffectingClangModules( 728002bfdd6SJan Svoboda const Module *M, ModuleDeps &MD, 729002bfdd6SJan Svoboda llvm::DenseSet<const Module *> &AddedModules) { 730e8541e4bSChuanqi Xu addAffectingClangModule(M, MD, AddedModules); 731002bfdd6SJan Svoboda 732002bfdd6SJan Svoboda for (const Module *SubM : M->submodules()) 733e8541e4bSChuanqi Xu addAllAffectingClangModules(SubM, MD, AddedModules); 734002bfdd6SJan Svoboda } 735002bfdd6SJan Svoboda 736e8541e4bSChuanqi Xu void ModuleDepCollectorPP::addAffectingClangModule( 737002bfdd6SJan Svoboda const Module *M, ModuleDeps &MD, 738002bfdd6SJan Svoboda llvm::DenseSet<const Module *> &AddedModules) { 739e8541e4bSChuanqi Xu for (const Module *Affecting : M->AffectingClangModules) { 740002bfdd6SJan Svoboda assert(Affecting == Affecting->getTopLevelModule() && 741002bfdd6SJan Svoboda "Not quite import not top-level module"); 742002bfdd6SJan Svoboda if (Affecting != M->getTopLevelModule() && 743002bfdd6SJan Svoboda !MDC.isPrebuiltModule(Affecting)) { 74496a54b22SJan Svoboda if (auto ImportID = handleTopLevelModule(Affecting)) 745002bfdd6SJan Svoboda if (AddedModules.insert(Affecting).second) 74696a54b22SJan Svoboda MD.ClangModuleDeps.push_back(*ImportID); 747002bfdd6SJan Svoboda } 748002bfdd6SJan Svoboda } 749002bfdd6SJan Svoboda } 750002bfdd6SJan Svoboda 751356a4b43SMichael Spencer ModuleDepCollector::ModuleDepCollector( 752207e9fdeSJan Svoboda std::unique_ptr<DependencyOutputOptions> Opts, 753207e9fdeSJan Svoboda CompilerInstance &ScanInstance, DependencyConsumer &C, 754296ba5bbSBen Langmuir DependencyActionController &Controller, CompilerInvocation OriginalCI, 755de3b2c29SMichael Spencer PrebuiltModuleVFSMapT PrebuiltModuleVFSMap, 756fb07d9ccSMichael Spencer ScanningOptimizations OptimizeArgs, bool EagerLoadModules, 757fb07d9ccSMichael Spencer bool IsStdModuleP1689Format) 758296ba5bbSBen Langmuir : ScanInstance(ScanInstance), Consumer(C), Controller(Controller), 759de3b2c29SMichael Spencer PrebuiltModuleVFSMap(std::move(PrebuiltModuleVFSMap)), 7609208065aSJan Svoboda Opts(std::move(Opts)), 7619208065aSJan Svoboda CommonInvocation( 7629208065aSJan Svoboda makeCommonInvocationForModuleBuild(std::move(OriginalCI))), 763296ba5bbSBen Langmuir OptimizeArgs(OptimizeArgs), EagerLoadModules(EagerLoadModules), 764eb70b38fSChuanqi Xu IsStdModuleP1689Format(IsStdModuleP1689Format) {} 76533a745e6SMichael Spencer 76633a745e6SMichael Spencer void ModuleDepCollector::attachToPreprocessor(Preprocessor &PP) { 76724616664SJan Svoboda PP.addPPCallbacks(std::make_unique<ModuleDepCollectorPP>(*this)); 76833a745e6SMichael Spencer } 76933a745e6SMichael Spencer 77033a745e6SMichael Spencer void ModuleDepCollector::attachToASTReader(ASTReader &R) {} 7714629554fSJan Svoboda 7724629554fSJan Svoboda bool ModuleDepCollector::isPrebuiltModule(const Module *M) { 7734629554fSJan Svoboda std::string Name(M->getTopLevelModuleName()); 7744629554fSJan Svoboda const auto &PrebuiltModuleFiles = 775207e9fdeSJan Svoboda ScanInstance.getHeaderSearchOpts().PrebuiltModuleFiles; 7764629554fSJan Svoboda auto PrebuiltModuleFileIt = PrebuiltModuleFiles.find(Name); 7774629554fSJan Svoboda if (PrebuiltModuleFileIt == PrebuiltModuleFiles.end()) 7784629554fSJan Svoboda return false; 7794629554fSJan Svoboda assert("Prebuilt module came from the expected AST file" && 7804629554fSJan Svoboda PrebuiltModuleFileIt->second == M->getASTFile()->getName()); 7814629554fSJan Svoboda return true; 7824629554fSJan Svoboda } 783b4c6dc2eSBen Langmuir 7848ab388e1SJan Svoboda static StringRef makeAbsoluteAndPreferred(CompilerInstance &CI, StringRef Path, 785b4c6dc2eSBen Langmuir SmallVectorImpl<char> &Storage) { 7864d6483e9SJan Svoboda if (llvm::sys::path::is_absolute(Path) && 7874d6483e9SJan Svoboda !llvm::sys::path::is_style_windows(llvm::sys::path::Style::native)) 788b4c6dc2eSBen Langmuir return Path; 789b4c6dc2eSBen Langmuir Storage.assign(Path.begin(), Path.end()); 790b4c6dc2eSBen Langmuir CI.getFileManager().makeAbsolutePath(Storage); 7918ab388e1SJan Svoboda llvm::sys::path::make_preferred(Storage); 792b4c6dc2eSBen Langmuir return StringRef(Storage.data(), Storage.size()); 793b4c6dc2eSBen Langmuir } 794b4c6dc2eSBen Langmuir 795b4c6dc2eSBen Langmuir void ModuleDepCollector::addFileDep(StringRef Path) { 796e107c946SChuanqi Xu if (IsStdModuleP1689Format) { 797e107c946SChuanqi Xu // Within P1689 format, we don't want all the paths to be absolute path 798*9d4837f4SJan Svoboda // since it may violate the traditional make style dependencies info. 799*9d4837f4SJan Svoboda FileDeps.emplace_back(Path); 800e107c946SChuanqi Xu return; 801e107c946SChuanqi Xu } 802e107c946SChuanqi Xu 803b4c6dc2eSBen Langmuir llvm::SmallString<256> Storage; 8048ab388e1SJan Svoboda Path = makeAbsoluteAndPreferred(ScanInstance, Path, Storage); 805*9d4837f4SJan Svoboda FileDeps.emplace_back(Path); 806b4c6dc2eSBen Langmuir } 807b4c6dc2eSBen Langmuir 808b4c6dc2eSBen Langmuir void ModuleDepCollector::addFileDep(ModuleDeps &MD, StringRef Path) { 809*9d4837f4SJan Svoboda MD.FileDeps.emplace_back(Path); 810b4c6dc2eSBen Langmuir } 811