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" 15bdd1243dSDimitry Andric #include "llvm/Support/BLAKE3.h" 16fe6060f1SDimitry Andric #include "llvm/Support/StringSaver.h" 17bdd1243dSDimitry Andric #include <optional> 18480093f4SDimitry Andric 19480093f4SDimitry Andric using namespace clang; 20480093f4SDimitry Andric using namespace tooling; 21480093f4SDimitry Andric using namespace dependencies; 22480093f4SDimitry Andric 23349cc55cSDimitry Andric static void optimizeHeaderSearchOpts(HeaderSearchOptions &Opts, 24349cc55cSDimitry Andric ASTReader &Reader, 25349cc55cSDimitry Andric const serialization::ModuleFile &MF) { 26349cc55cSDimitry Andric // Only preserve search paths that were used during the dependency scan. 27349cc55cSDimitry Andric std::vector<HeaderSearchOptions::Entry> Entries = Opts.UserEntries; 28349cc55cSDimitry Andric Opts.UserEntries.clear(); 2981ad6265SDimitry Andric 3081ad6265SDimitry Andric llvm::BitVector SearchPathUsage(Entries.size()); 3181ad6265SDimitry Andric llvm::DenseSet<const serialization::ModuleFile *> Visited; 3281ad6265SDimitry Andric std::function<void(const serialization::ModuleFile *)> VisitMF = 3381ad6265SDimitry Andric [&](const serialization::ModuleFile *MF) { 3481ad6265SDimitry Andric SearchPathUsage |= MF->SearchPathUsage; 3581ad6265SDimitry Andric Visited.insert(MF); 3681ad6265SDimitry Andric for (const serialization::ModuleFile *Import : MF->Imports) 3781ad6265SDimitry Andric if (!Visited.contains(Import)) 3881ad6265SDimitry Andric VisitMF(Import); 3981ad6265SDimitry Andric }; 4081ad6265SDimitry Andric VisitMF(&MF); 4181ad6265SDimitry Andric 4281ad6265SDimitry Andric for (auto Idx : SearchPathUsage.set_bits()) 4381ad6265SDimitry Andric Opts.UserEntries.push_back(Entries[Idx]); 44349cc55cSDimitry Andric } 45349cc55cSDimitry Andric 46753f127fSDimitry Andric static std::vector<std::string> splitString(std::string S, char Separator) { 47753f127fSDimitry Andric SmallVector<StringRef> Segments; 48753f127fSDimitry Andric StringRef(S).split(Segments, Separator, /*MaxSplit=*/-1, /*KeepEmpty=*/false); 49753f127fSDimitry Andric std::vector<std::string> Result; 50753f127fSDimitry Andric Result.reserve(Segments.size()); 51753f127fSDimitry Andric for (StringRef Segment : Segments) 52753f127fSDimitry Andric Result.push_back(Segment.str()); 53753f127fSDimitry Andric return Result; 54753f127fSDimitry Andric } 55753f127fSDimitry Andric 56bdd1243dSDimitry Andric void ModuleDepCollector::addOutputPaths(CompilerInvocation &CI, 57bdd1243dSDimitry Andric ModuleDeps &Deps) { 58bdd1243dSDimitry Andric CI.getFrontendOpts().OutputFile = 59bdd1243dSDimitry Andric Consumer.lookupModuleOutput(Deps.ID, ModuleOutputKind::ModuleFile); 60bdd1243dSDimitry Andric if (!CI.getDiagnosticOpts().DiagnosticSerializationFile.empty()) 61753f127fSDimitry Andric CI.getDiagnosticOpts().DiagnosticSerializationFile = 62bdd1243dSDimitry Andric Consumer.lookupModuleOutput( 63bdd1243dSDimitry Andric Deps.ID, ModuleOutputKind::DiagnosticSerializationFile); 64bdd1243dSDimitry Andric if (!CI.getDependencyOutputOpts().OutputFile.empty()) { 65bdd1243dSDimitry Andric CI.getDependencyOutputOpts().OutputFile = 66bdd1243dSDimitry Andric Consumer.lookupModuleOutput(Deps.ID, ModuleOutputKind::DependencyFile); 67bdd1243dSDimitry Andric CI.getDependencyOutputOpts().Targets = 68bdd1243dSDimitry Andric splitString(Consumer.lookupModuleOutput( 69bdd1243dSDimitry Andric Deps.ID, ModuleOutputKind::DependencyTargets), 70bdd1243dSDimitry Andric '\0'); 71bdd1243dSDimitry Andric if (!CI.getDependencyOutputOpts().OutputFile.empty() && 72bdd1243dSDimitry Andric CI.getDependencyOutputOpts().Targets.empty()) { 73753f127fSDimitry Andric // Fallback to -o as dependency target, as in the driver. 74753f127fSDimitry Andric SmallString<128> Target; 75bdd1243dSDimitry Andric quoteMakeTarget(CI.getFrontendOpts().OutputFile, Target); 76bdd1243dSDimitry Andric CI.getDependencyOutputOpts().Targets.push_back(std::string(Target)); 77bdd1243dSDimitry Andric } 78753f127fSDimitry Andric } 79753f127fSDimitry Andric } 80fe6060f1SDimitry Andric 81bdd1243dSDimitry Andric CompilerInvocation 82bdd1243dSDimitry Andric ModuleDepCollector::makeInvocationForModuleBuildWithoutOutputs( 83bdd1243dSDimitry Andric const ModuleDeps &Deps, 84bdd1243dSDimitry Andric llvm::function_ref<void(CompilerInvocation &)> Optimize) const { 85bdd1243dSDimitry Andric // Make a deep copy of the original Clang invocation. 86bdd1243dSDimitry Andric CompilerInvocation CI(OriginalInvocation); 87fe6060f1SDimitry Andric 88bdd1243dSDimitry Andric CI.resetNonModularOptions(); 89bdd1243dSDimitry Andric CI.clearImplicitModuleBuildOptions(); 90bdd1243dSDimitry Andric 91bdd1243dSDimitry Andric // Remove options incompatible with explicit module build or are likely to 92bdd1243dSDimitry Andric // differ between identical modules discovered from different translation 93bdd1243dSDimitry Andric // units. 94bdd1243dSDimitry Andric CI.getFrontendOpts().Inputs.clear(); 95bdd1243dSDimitry Andric CI.getFrontendOpts().OutputFile.clear(); 96bdd1243dSDimitry Andric 97bdd1243dSDimitry Andric // TODO: Figure out better way to set options to their default value. 98bdd1243dSDimitry Andric CI.getCodeGenOpts().MainFileName.clear(); 99bdd1243dSDimitry Andric CI.getCodeGenOpts().DwarfDebugFlags.clear(); 100bdd1243dSDimitry Andric if (!CI.getLangOpts()->ModulesCodegen) { 101bdd1243dSDimitry Andric CI.getCodeGenOpts().DebugCompilationDir.clear(); 102bdd1243dSDimitry Andric CI.getCodeGenOpts().CoverageCompilationDir.clear(); 103fe6060f1SDimitry Andric } 104fe6060f1SDimitry Andric 105bdd1243dSDimitry Andric // Map output paths that affect behaviour to "-" so their existence is in the 106bdd1243dSDimitry Andric // context hash. The final path will be computed in addOutputPaths. 107bdd1243dSDimitry Andric if (!CI.getDiagnosticOpts().DiagnosticSerializationFile.empty()) 108bdd1243dSDimitry Andric CI.getDiagnosticOpts().DiagnosticSerializationFile = "-"; 109bdd1243dSDimitry Andric if (!CI.getDependencyOutputOpts().OutputFile.empty()) 110bdd1243dSDimitry Andric CI.getDependencyOutputOpts().OutputFile = "-"; 111bdd1243dSDimitry Andric CI.getDependencyOutputOpts().Targets.clear(); 112bdd1243dSDimitry Andric 113bdd1243dSDimitry Andric CI.getFrontendOpts().ProgramAction = frontend::GenerateModule; 114bdd1243dSDimitry Andric CI.getLangOpts()->ModuleName = Deps.ID.ModuleName; 115bdd1243dSDimitry Andric CI.getFrontendOpts().IsSystemModule = Deps.IsSystem; 116bdd1243dSDimitry Andric 117bdd1243dSDimitry Andric // Inputs 118bdd1243dSDimitry Andric InputKind ModuleMapInputKind(CI.getFrontendOpts().DashX.getLanguage(), 119bdd1243dSDimitry Andric InputKind::Format::ModuleMap); 120bdd1243dSDimitry Andric CI.getFrontendOpts().Inputs.emplace_back(Deps.ClangModuleMapFile, 121bdd1243dSDimitry Andric ModuleMapInputKind); 122bdd1243dSDimitry Andric 123bdd1243dSDimitry Andric auto CurrentModuleMapEntry = 124bdd1243dSDimitry Andric ScanInstance.getFileManager().getFile(Deps.ClangModuleMapFile); 125bdd1243dSDimitry Andric assert(CurrentModuleMapEntry && "module map file entry not found"); 126bdd1243dSDimitry Andric 127bdd1243dSDimitry Andric auto DepModuleMapFiles = collectModuleMapFiles(Deps.ClangModuleDeps); 128bdd1243dSDimitry Andric for (StringRef ModuleMapFile : Deps.ModuleMapFileDeps) { 129bdd1243dSDimitry Andric // TODO: Track these as `FileEntryRef` to simplify the equality check below. 130bdd1243dSDimitry Andric auto ModuleMapEntry = ScanInstance.getFileManager().getFile(ModuleMapFile); 131bdd1243dSDimitry Andric assert(ModuleMapEntry && "module map file entry not found"); 132bdd1243dSDimitry Andric 133bdd1243dSDimitry Andric // Don't report module maps describing eagerly-loaded dependency. This 134bdd1243dSDimitry Andric // information will be deserialized from the PCM. 135bdd1243dSDimitry Andric // TODO: Verify this works fine when modulemap for module A is eagerly 136bdd1243dSDimitry Andric // loaded from A.pcm, and module map passed on the command line contains 137bdd1243dSDimitry Andric // definition of a submodule: "explicit module A.Private { ... }". 138bdd1243dSDimitry Andric if (EagerLoadModules && DepModuleMapFiles.contains(*ModuleMapEntry)) 139bdd1243dSDimitry Andric continue; 140bdd1243dSDimitry Andric 141bdd1243dSDimitry Andric // Don't report module map file of the current module unless it also 142bdd1243dSDimitry Andric // describes a dependency (for symmetry). 143bdd1243dSDimitry Andric if (*ModuleMapEntry == *CurrentModuleMapEntry && 144bdd1243dSDimitry Andric !DepModuleMapFiles.contains(*ModuleMapEntry)) 145bdd1243dSDimitry Andric continue; 146bdd1243dSDimitry Andric 147bdd1243dSDimitry Andric CI.getFrontendOpts().ModuleMapFiles.emplace_back(ModuleMapFile); 148bdd1243dSDimitry Andric } 149bdd1243dSDimitry Andric 150bdd1243dSDimitry Andric // Report the prebuilt modules this module uses. 151bdd1243dSDimitry Andric for (const auto &PrebuiltModule : Deps.PrebuiltModuleDeps) 152bdd1243dSDimitry Andric CI.getFrontendOpts().ModuleFiles.push_back(PrebuiltModule.PCMFile); 153bdd1243dSDimitry Andric 154bdd1243dSDimitry Andric // Add module file inputs from dependencies. 155bdd1243dSDimitry Andric addModuleFiles(CI, Deps.ClangModuleDeps); 156bdd1243dSDimitry Andric 157bdd1243dSDimitry Andric // Remove any macro definitions that are explicitly ignored. 158bdd1243dSDimitry Andric if (!CI.getHeaderSearchOpts().ModulesIgnoreMacros.empty()) { 159bdd1243dSDimitry Andric llvm::erase_if( 160bdd1243dSDimitry Andric CI.getPreprocessorOpts().Macros, 161bdd1243dSDimitry Andric [&CI](const std::pair<std::string, bool> &Def) { 162bdd1243dSDimitry Andric StringRef MacroDef = Def.first; 163bdd1243dSDimitry Andric return CI.getHeaderSearchOpts().ModulesIgnoreMacros.contains( 164bdd1243dSDimitry Andric llvm::CachedHashString(MacroDef.split('=').first)); 165bdd1243dSDimitry Andric }); 166bdd1243dSDimitry Andric // Remove the now unused option. 167bdd1243dSDimitry Andric CI.getHeaderSearchOpts().ModulesIgnoreMacros.clear(); 168bdd1243dSDimitry Andric } 169bdd1243dSDimitry Andric 170bdd1243dSDimitry Andric Optimize(CI); 171bdd1243dSDimitry Andric 172bdd1243dSDimitry Andric return CI; 173bdd1243dSDimitry Andric } 174bdd1243dSDimitry Andric 175bdd1243dSDimitry Andric llvm::DenseSet<const FileEntry *> ModuleDepCollector::collectModuleMapFiles( 176bdd1243dSDimitry Andric ArrayRef<ModuleID> ClangModuleDeps) const { 177bdd1243dSDimitry Andric llvm::DenseSet<const FileEntry *> ModuleMapFiles; 178bdd1243dSDimitry Andric for (const ModuleID &MID : ClangModuleDeps) { 179bdd1243dSDimitry Andric ModuleDeps *MD = ModuleDepsByID.lookup(MID); 180bdd1243dSDimitry Andric assert(MD && "Inconsistent dependency info"); 181bdd1243dSDimitry Andric // TODO: Track ClangModuleMapFile as `FileEntryRef`. 182bdd1243dSDimitry Andric auto FE = ScanInstance.getFileManager().getFile(MD->ClangModuleMapFile); 183bdd1243dSDimitry Andric assert(FE && "Missing module map file that was previously found"); 184bdd1243dSDimitry Andric ModuleMapFiles.insert(*FE); 185bdd1243dSDimitry Andric } 186bdd1243dSDimitry Andric return ModuleMapFiles; 187bdd1243dSDimitry Andric } 188bdd1243dSDimitry Andric 189bdd1243dSDimitry Andric void ModuleDepCollector::addModuleMapFiles( 190bdd1243dSDimitry Andric CompilerInvocation &CI, ArrayRef<ModuleID> ClangModuleDeps) const { 191bdd1243dSDimitry Andric if (EagerLoadModules) 192bdd1243dSDimitry Andric return; // Only pcm is needed for eager load. 193bdd1243dSDimitry Andric 194bdd1243dSDimitry Andric for (const ModuleID &MID : ClangModuleDeps) { 195bdd1243dSDimitry Andric ModuleDeps *MD = ModuleDepsByID.lookup(MID); 196bdd1243dSDimitry Andric assert(MD && "Inconsistent dependency info"); 197bdd1243dSDimitry Andric CI.getFrontendOpts().ModuleMapFiles.push_back(MD->ClangModuleMapFile); 198bdd1243dSDimitry Andric } 199bdd1243dSDimitry Andric } 200bdd1243dSDimitry Andric 201bdd1243dSDimitry Andric void ModuleDepCollector::addModuleFiles( 202bdd1243dSDimitry Andric CompilerInvocation &CI, ArrayRef<ModuleID> ClangModuleDeps) const { 203bdd1243dSDimitry Andric for (const ModuleID &MID : ClangModuleDeps) { 204bdd1243dSDimitry Andric std::string PCMPath = 205bdd1243dSDimitry Andric Consumer.lookupModuleOutput(MID, ModuleOutputKind::ModuleFile); 206bdd1243dSDimitry Andric if (EagerLoadModules) 207bdd1243dSDimitry Andric CI.getFrontendOpts().ModuleFiles.push_back(std::move(PCMPath)); 208bdd1243dSDimitry Andric else 209bdd1243dSDimitry Andric CI.getHeaderSearchOpts().PrebuiltModuleFiles.insert( 210bdd1243dSDimitry Andric {MID.ModuleName, std::move(PCMPath)}); 211bdd1243dSDimitry Andric } 212bdd1243dSDimitry Andric } 213bdd1243dSDimitry Andric 214bdd1243dSDimitry Andric static bool needsModules(FrontendInputFile FIF) { 215bdd1243dSDimitry Andric switch (FIF.getKind().getLanguage()) { 216bdd1243dSDimitry Andric case Language::Unknown: 217bdd1243dSDimitry Andric case Language::Asm: 218bdd1243dSDimitry Andric case Language::LLVM_IR: 219bdd1243dSDimitry Andric return false; 220bdd1243dSDimitry Andric default: 221bdd1243dSDimitry Andric return true; 222bdd1243dSDimitry Andric } 223bdd1243dSDimitry Andric } 224bdd1243dSDimitry Andric 225bdd1243dSDimitry Andric void ModuleDepCollector::applyDiscoveredDependencies(CompilerInvocation &CI) { 226bdd1243dSDimitry Andric CI.clearImplicitModuleBuildOptions(); 227bdd1243dSDimitry Andric 228bdd1243dSDimitry Andric if (llvm::any_of(CI.getFrontendOpts().Inputs, needsModules)) { 229bdd1243dSDimitry Andric Preprocessor &PP = ScanInstance.getPreprocessor(); 230bdd1243dSDimitry Andric if (Module *CurrentModule = PP.getCurrentModuleImplementation()) 231bdd1243dSDimitry Andric if (OptionalFileEntryRef CurrentModuleMap = 232bdd1243dSDimitry Andric PP.getHeaderSearchInfo() 233bdd1243dSDimitry Andric .getModuleMap() 234bdd1243dSDimitry Andric .getModuleMapFileForUniquing(CurrentModule)) 235bdd1243dSDimitry Andric CI.getFrontendOpts().ModuleMapFiles.emplace_back( 236bdd1243dSDimitry Andric CurrentModuleMap->getName()); 237bdd1243dSDimitry Andric 238bdd1243dSDimitry Andric SmallVector<ModuleID> DirectDeps; 239bdd1243dSDimitry Andric for (const auto &KV : ModularDeps) 240bdd1243dSDimitry Andric if (KV.second->ImportedByMainFile) 241bdd1243dSDimitry Andric DirectDeps.push_back(KV.second->ID); 242bdd1243dSDimitry Andric 243bdd1243dSDimitry Andric // TODO: Report module maps the same way it's done for modular dependencies. 244bdd1243dSDimitry Andric addModuleMapFiles(CI, DirectDeps); 245bdd1243dSDimitry Andric 246bdd1243dSDimitry Andric addModuleFiles(CI, DirectDeps); 247bdd1243dSDimitry Andric 248bdd1243dSDimitry Andric for (const auto &KV : DirectPrebuiltModularDeps) 249bdd1243dSDimitry Andric CI.getFrontendOpts().ModuleFiles.push_back(KV.second.PCMFile); 250bdd1243dSDimitry Andric } 251bdd1243dSDimitry Andric } 252bdd1243dSDimitry Andric 253bdd1243dSDimitry Andric static std::string getModuleContextHash(const ModuleDeps &MD, 254bdd1243dSDimitry Andric const CompilerInvocation &CI, 255bdd1243dSDimitry Andric bool EagerLoadModules) { 256bdd1243dSDimitry Andric llvm::HashBuilder<llvm::TruncatedBLAKE3<16>, 257bdd1243dSDimitry Andric llvm::support::endianness::native> 258bdd1243dSDimitry Andric HashBuilder; 259bdd1243dSDimitry Andric SmallString<32> Scratch; 260bdd1243dSDimitry Andric 261bdd1243dSDimitry Andric // Hash the compiler version and serialization version to ensure the module 262bdd1243dSDimitry Andric // will be readable. 263bdd1243dSDimitry Andric HashBuilder.add(getClangFullRepositoryVersion()); 264bdd1243dSDimitry Andric HashBuilder.add(serialization::VERSION_MAJOR, serialization::VERSION_MINOR); 265bdd1243dSDimitry Andric 266bdd1243dSDimitry Andric // Hash the BuildInvocation without any input files. 267bdd1243dSDimitry Andric SmallVector<const char *, 32> DummyArgs; 268bdd1243dSDimitry Andric CI.generateCC1CommandLine(DummyArgs, [&](const Twine &Arg) { 269bdd1243dSDimitry Andric Scratch.clear(); 270bdd1243dSDimitry Andric StringRef Str = Arg.toStringRef(Scratch); 271bdd1243dSDimitry Andric HashBuilder.add(Str); 272bdd1243dSDimitry Andric return "<unused>"; 273bdd1243dSDimitry Andric }); 274bdd1243dSDimitry Andric 275bdd1243dSDimitry Andric // Hash the module dependencies. These paths may differ even if the invocation 276bdd1243dSDimitry Andric // is identical if they depend on the contents of the files in the TU -- for 277bdd1243dSDimitry Andric // example, case-insensitive paths to modulemap files. Usually such a case 278bdd1243dSDimitry Andric // would indicate a missed optimization to canonicalize, but it may be 279bdd1243dSDimitry Andric // difficult to canonicalize all cases when there is a VFS. 280bdd1243dSDimitry Andric for (const auto &ID : MD.ClangModuleDeps) { 281bdd1243dSDimitry Andric HashBuilder.add(ID.ModuleName); 282bdd1243dSDimitry Andric HashBuilder.add(ID.ContextHash); 283bdd1243dSDimitry Andric } 284bdd1243dSDimitry Andric 285bdd1243dSDimitry Andric HashBuilder.add(EagerLoadModules); 286bdd1243dSDimitry Andric 287bdd1243dSDimitry Andric llvm::BLAKE3Result<16> Hash = HashBuilder.final(); 288bdd1243dSDimitry Andric std::array<uint64_t, 2> Words; 289bdd1243dSDimitry Andric static_assert(sizeof(Hash) == sizeof(Words), "Hash must match Words"); 290bdd1243dSDimitry Andric std::memcpy(Words.data(), Hash.data(), sizeof(Hash)); 291bdd1243dSDimitry Andric return toString(llvm::APInt(sizeof(Words) * 8, Words), 36, /*Signed=*/false); 292bdd1243dSDimitry Andric } 293bdd1243dSDimitry Andric 294bdd1243dSDimitry Andric void ModuleDepCollector::associateWithContextHash(const CompilerInvocation &CI, 295bdd1243dSDimitry Andric ModuleDeps &Deps) { 296bdd1243dSDimitry Andric Deps.ID.ContextHash = getModuleContextHash(Deps, CI, EagerLoadModules); 297bdd1243dSDimitry Andric bool Inserted = ModuleDepsByID.insert({Deps.ID, &Deps}).second; 298bdd1243dSDimitry Andric (void)Inserted; 299bdd1243dSDimitry Andric assert(Inserted && "duplicate module mapping"); 300fe6060f1SDimitry Andric } 301fe6060f1SDimitry Andric 302480093f4SDimitry Andric void ModuleDepCollectorPP::FileChanged(SourceLocation Loc, 303480093f4SDimitry Andric FileChangeReason Reason, 304480093f4SDimitry Andric SrcMgr::CharacteristicKind FileType, 305480093f4SDimitry Andric FileID PrevFID) { 306480093f4SDimitry Andric if (Reason != PPCallbacks::EnterFile) 307480093f4SDimitry Andric return; 308480093f4SDimitry Andric 3095ffd83dbSDimitry Andric // This has to be delayed as the context hash can change at the start of 3105ffd83dbSDimitry Andric // `CompilerInstance::ExecuteAction`. 3115ffd83dbSDimitry Andric if (MDC.ContextHash.empty()) { 312349cc55cSDimitry Andric MDC.ContextHash = MDC.ScanInstance.getInvocation().getModuleHash(); 3135ffd83dbSDimitry Andric MDC.Consumer.handleContextHash(MDC.ContextHash); 3145ffd83dbSDimitry Andric } 3155ffd83dbSDimitry Andric 316349cc55cSDimitry Andric SourceManager &SM = MDC.ScanInstance.getSourceManager(); 317480093f4SDimitry Andric 318480093f4SDimitry Andric // Dependency generation really does want to go all the way to the 319480093f4SDimitry Andric // file entry for a source location to find out what is depended on. 320480093f4SDimitry Andric // We do not want #line markers to affect dependency generation! 321bdd1243dSDimitry Andric if (std::optional<StringRef> Filename = 322e8d8bef9SDimitry Andric SM.getNonBuiltinFilenameForID(SM.getFileID(SM.getExpansionLoc(Loc)))) 323bdd1243dSDimitry Andric MDC.addFileDep(llvm::sys::path::remove_leading_dotslash(*Filename)); 324480093f4SDimitry Andric } 325480093f4SDimitry Andric 326480093f4SDimitry Andric void ModuleDepCollectorPP::InclusionDirective( 327480093f4SDimitry Andric SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName, 328bdd1243dSDimitry Andric bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef File, 329480093f4SDimitry Andric StringRef SearchPath, StringRef RelativePath, const Module *Imported, 330480093f4SDimitry Andric SrcMgr::CharacteristicKind FileType) { 331480093f4SDimitry Andric if (!File && !Imported) { 332480093f4SDimitry Andric // This is a non-modular include that HeaderSearch failed to find. Add it 333480093f4SDimitry Andric // here as `FileChanged` will never see it. 334bdd1243dSDimitry Andric MDC.addFileDep(FileName); 3355ffd83dbSDimitry Andric } 3365ffd83dbSDimitry Andric handleImport(Imported); 337480093f4SDimitry Andric } 338480093f4SDimitry Andric 3395ffd83dbSDimitry Andric void ModuleDepCollectorPP::moduleImport(SourceLocation ImportLoc, 3405ffd83dbSDimitry Andric ModuleIdPath Path, 3415ffd83dbSDimitry Andric const Module *Imported) { 342*1ac55f4cSDimitry Andric if (MDC.ScanInstance.getPreprocessor().isInImportingCXXNamedModules()) { 343*1ac55f4cSDimitry Andric P1689ModuleInfo RequiredModule; 344*1ac55f4cSDimitry Andric RequiredModule.ModuleName = Path[0].first->getName().str(); 345*1ac55f4cSDimitry Andric RequiredModule.Type = P1689ModuleInfo::ModuleType::NamedCXXModule; 346*1ac55f4cSDimitry Andric MDC.RequiredStdCXXModules.push_back(RequiredModule); 347*1ac55f4cSDimitry Andric return; 348*1ac55f4cSDimitry Andric } 349*1ac55f4cSDimitry Andric 3505ffd83dbSDimitry Andric handleImport(Imported); 3515ffd83dbSDimitry Andric } 3525ffd83dbSDimitry Andric 3535ffd83dbSDimitry Andric void ModuleDepCollectorPP::handleImport(const Module *Imported) { 354480093f4SDimitry Andric if (!Imported) 355480093f4SDimitry Andric return; 356480093f4SDimitry Andric 357fe6060f1SDimitry Andric const Module *TopLevelModule = Imported->getTopLevelModule(); 358fe6060f1SDimitry Andric 359fe6060f1SDimitry Andric if (MDC.isPrebuiltModule(TopLevelModule)) 360bdd1243dSDimitry Andric MDC.DirectPrebuiltModularDeps.insert( 361bdd1243dSDimitry Andric {TopLevelModule, PrebuiltModuleDep{TopLevelModule}}); 362fe6060f1SDimitry Andric else 363fe6060f1SDimitry Andric DirectModularDeps.insert(TopLevelModule); 364480093f4SDimitry Andric } 365480093f4SDimitry Andric 366480093f4SDimitry Andric void ModuleDepCollectorPP::EndOfMainFile() { 367349cc55cSDimitry Andric FileID MainFileID = MDC.ScanInstance.getSourceManager().getMainFileID(); 368349cc55cSDimitry Andric MDC.MainFile = std::string(MDC.ScanInstance.getSourceManager() 369349cc55cSDimitry Andric .getFileEntryForID(MainFileID) 370349cc55cSDimitry Andric ->getName()); 371480093f4SDimitry Andric 372*1ac55f4cSDimitry Andric auto &PP = MDC.ScanInstance.getPreprocessor(); 373*1ac55f4cSDimitry Andric if (PP.isInNamedModule()) { 374*1ac55f4cSDimitry Andric P1689ModuleInfo ProvidedModule; 375*1ac55f4cSDimitry Andric ProvidedModule.ModuleName = PP.getNamedModuleName(); 376*1ac55f4cSDimitry Andric ProvidedModule.Type = P1689ModuleInfo::ModuleType::NamedCXXModule; 377*1ac55f4cSDimitry Andric ProvidedModule.IsStdCXXModuleInterface = PP.isInNamedInterfaceUnit(); 378*1ac55f4cSDimitry Andric // Don't put implementation (non partition) unit as Provide. 379*1ac55f4cSDimitry Andric // Put the module as required instead. Since the implementation 380*1ac55f4cSDimitry Andric // unit will import the primary module implicitly. 381*1ac55f4cSDimitry Andric if (PP.isInImplementationUnit()) 382*1ac55f4cSDimitry Andric MDC.RequiredStdCXXModules.push_back(ProvidedModule); 383*1ac55f4cSDimitry Andric else 384*1ac55f4cSDimitry Andric MDC.ProvidedStdCXXModule = ProvidedModule; 385*1ac55f4cSDimitry Andric } 386*1ac55f4cSDimitry Andric 387349cc55cSDimitry Andric if (!MDC.ScanInstance.getPreprocessorOpts().ImplicitPCHInclude.empty()) 388bdd1243dSDimitry Andric MDC.addFileDep(MDC.ScanInstance.getPreprocessorOpts().ImplicitPCHInclude); 389fe6060f1SDimitry Andric 390bdd1243dSDimitry Andric for (const Module *M : 391bdd1243dSDimitry Andric MDC.ScanInstance.getPreprocessor().getAffectingClangModules()) 392bdd1243dSDimitry Andric if (!MDC.isPrebuiltModule(M)) 393bdd1243dSDimitry Andric DirectModularDeps.insert(M); 394bdd1243dSDimitry Andric 395bdd1243dSDimitry Andric for (const Module *M : DirectModularDeps) 396480093f4SDimitry Andric handleTopLevelModule(M); 397480093f4SDimitry Andric 398fe6060f1SDimitry Andric MDC.Consumer.handleDependencyOutputOpts(*MDC.Opts); 399fe6060f1SDimitry Andric 400*1ac55f4cSDimitry Andric if (MDC.IsStdModuleP1689Format) 401*1ac55f4cSDimitry Andric MDC.Consumer.handleProvidedAndRequiredStdCXXModules( 402*1ac55f4cSDimitry Andric MDC.ProvidedStdCXXModule, MDC.RequiredStdCXXModules); 403*1ac55f4cSDimitry Andric 404fe6060f1SDimitry Andric for (auto &&I : MDC.ModularDeps) 40581ad6265SDimitry Andric MDC.Consumer.handleModuleDependency(*I.second); 406480093f4SDimitry Andric 407fe6060f1SDimitry Andric for (auto &&I : MDC.FileDeps) 408fe6060f1SDimitry Andric MDC.Consumer.handleFileDependency(I); 409fe6060f1SDimitry Andric 410bdd1243dSDimitry Andric for (auto &&I : MDC.DirectPrebuiltModularDeps) 411bdd1243dSDimitry Andric MDC.Consumer.handlePrebuiltModuleDependency(I.second); 412480093f4SDimitry Andric } 413480093f4SDimitry Andric 414bdd1243dSDimitry Andric std::optional<ModuleID> 415bdd1243dSDimitry Andric ModuleDepCollectorPP::handleTopLevelModule(const Module *M) { 416480093f4SDimitry Andric assert(M == M->getTopLevelModule() && "Expected top level module!"); 417480093f4SDimitry Andric 418bdd1243dSDimitry Andric // A top-level module might not be actually imported as a module when 419bdd1243dSDimitry Andric // -fmodule-name is used to compile a translation unit that imports this 420bdd1243dSDimitry Andric // module. In that case it can be skipped. The appropriate header 421bdd1243dSDimitry Andric // dependencies will still be reported as expected. 422bdd1243dSDimitry Andric if (!M->getASTFile()) 423bdd1243dSDimitry Andric return {}; 424bdd1243dSDimitry Andric 425fe6060f1SDimitry Andric // If this module has been handled already, just return its ID. 42681ad6265SDimitry Andric auto ModI = MDC.ModularDeps.insert({M, nullptr}); 427fe6060f1SDimitry Andric if (!ModI.second) 42881ad6265SDimitry Andric return ModI.first->second->ID; 429480093f4SDimitry Andric 43081ad6265SDimitry Andric ModI.first->second = std::make_unique<ModuleDeps>(); 43181ad6265SDimitry Andric ModuleDeps &MD = *ModI.first->second; 432480093f4SDimitry Andric 433fe6060f1SDimitry Andric MD.ID.ModuleName = M->getFullModuleName(); 434fe6060f1SDimitry Andric MD.ImportedByMainFile = DirectModularDeps.contains(M); 435fe6060f1SDimitry Andric MD.IsSystem = M->IsSystem; 436fe6060f1SDimitry Andric 437bdd1243dSDimitry Andric ModuleMap &ModMapInfo = 438bdd1243dSDimitry Andric MDC.ScanInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap(); 439bdd1243dSDimitry Andric 440bdd1243dSDimitry Andric OptionalFileEntryRef ModuleMap = ModMapInfo.getModuleMapFileForUniquing(M); 4410eae32dcSDimitry Andric 4420eae32dcSDimitry Andric if (ModuleMap) { 443bdd1243dSDimitry Andric SmallString<128> Path = ModuleMap->getNameAsRequested(); 444bdd1243dSDimitry Andric ModMapInfo.canonicalizeModuleMapPath(Path); 4450eae32dcSDimitry Andric MD.ClangModuleMapFile = std::string(Path); 4460eae32dcSDimitry Andric } 447fe6060f1SDimitry Andric 448480093f4SDimitry Andric serialization::ModuleFile *MF = 449349cc55cSDimitry Andric MDC.ScanInstance.getASTReader()->getModuleManager().lookup( 450349cc55cSDimitry Andric M->getASTFile()); 451349cc55cSDimitry Andric MDC.ScanInstance.getASTReader()->visitInputFiles( 452480093f4SDimitry Andric *MF, true, true, [&](const serialization::InputFile &IF, bool isSystem) { 453fe6060f1SDimitry Andric // __inferred_module.map is the result of the way in which an implicit 454fe6060f1SDimitry Andric // module build handles inferred modules. It adds an overlay VFS with 455fe6060f1SDimitry Andric // this file in the proper directory and relies on the rest of Clang to 456fe6060f1SDimitry Andric // handle it like normal. With explicitly built modules we don't need 457fe6060f1SDimitry Andric // to play VFS tricks, so replace it with the correct module map. 458fe6060f1SDimitry Andric if (IF.getFile()->getName().endswith("__inferred_module.map")) { 459bdd1243dSDimitry Andric MDC.addFileDep(MD, ModuleMap->getName()); 460fe6060f1SDimitry Andric return; 461fe6060f1SDimitry Andric } 462bdd1243dSDimitry Andric MDC.addFileDep(MD, IF.getFile()->getName()); 463480093f4SDimitry Andric }); 464480093f4SDimitry Andric 465bdd1243dSDimitry Andric llvm::DenseSet<const Module *> SeenDeps; 466bdd1243dSDimitry Andric addAllSubmodulePrebuiltDeps(M, MD, SeenDeps); 467bdd1243dSDimitry Andric addAllSubmoduleDeps(M, MD, SeenDeps); 468bdd1243dSDimitry Andric addAllAffectingClangModules(M, MD, SeenDeps); 469bdd1243dSDimitry Andric 47081ad6265SDimitry Andric MDC.ScanInstance.getASTReader()->visitTopLevelModuleMaps( 471bdd1243dSDimitry Andric *MF, [&](FileEntryRef FE) { 472bdd1243dSDimitry Andric if (FE.getNameAsRequested().endswith("__inferred_module.map")) 47381ad6265SDimitry Andric return; 474bdd1243dSDimitry Andric MD.ModuleMapFileDeps.emplace_back(FE.getNameAsRequested()); 47581ad6265SDimitry Andric }); 47681ad6265SDimitry Andric 477bdd1243dSDimitry Andric CompilerInvocation CI = MDC.makeInvocationForModuleBuildWithoutOutputs( 478349cc55cSDimitry Andric MD, [&](CompilerInvocation &BuildInvocation) { 479349cc55cSDimitry Andric if (MDC.OptimizeArgs) 480349cc55cSDimitry Andric optimizeHeaderSearchOpts(BuildInvocation.getHeaderSearchOpts(), 481349cc55cSDimitry Andric *MDC.ScanInstance.getASTReader(), *MF); 482349cc55cSDimitry Andric }); 483fe6060f1SDimitry Andric 484bdd1243dSDimitry Andric MDC.associateWithContextHash(CI, MD); 485bdd1243dSDimitry Andric 486bdd1243dSDimitry Andric // Finish the compiler invocation. Requires dependencies and the context hash. 487bdd1243dSDimitry Andric MDC.addOutputPaths(CI, MD); 488bdd1243dSDimitry Andric 489bdd1243dSDimitry Andric MD.BuildArguments = CI.getCC1CommandLine(); 490fe6060f1SDimitry Andric 491fe6060f1SDimitry Andric return MD.ID; 492fe6060f1SDimitry Andric } 493fe6060f1SDimitry Andric 49481ad6265SDimitry Andric static void forEachSubmoduleSorted(const Module *M, 49581ad6265SDimitry Andric llvm::function_ref<void(const Module *)> F) { 49681ad6265SDimitry Andric // Submodule order depends on order of header includes for inferred submodules 49781ad6265SDimitry Andric // we don't care about the exact order, so sort so that it's consistent across 49881ad6265SDimitry Andric // TUs to improve sharing. 49981ad6265SDimitry Andric SmallVector<const Module *> Submodules(M->submodule_begin(), 50081ad6265SDimitry Andric M->submodule_end()); 50181ad6265SDimitry Andric llvm::stable_sort(Submodules, [](const Module *A, const Module *B) { 50281ad6265SDimitry Andric return A->Name < B->Name; 50381ad6265SDimitry Andric }); 50481ad6265SDimitry Andric for (const Module *SubM : Submodules) 50581ad6265SDimitry Andric F(SubM); 50681ad6265SDimitry Andric } 50781ad6265SDimitry Andric 508349cc55cSDimitry Andric void ModuleDepCollectorPP::addAllSubmodulePrebuiltDeps( 509349cc55cSDimitry Andric const Module *M, ModuleDeps &MD, 510349cc55cSDimitry Andric llvm::DenseSet<const Module *> &SeenSubmodules) { 511349cc55cSDimitry Andric addModulePrebuiltDeps(M, MD, SeenSubmodules); 512349cc55cSDimitry Andric 51381ad6265SDimitry Andric forEachSubmoduleSorted(M, [&](const Module *SubM) { 514349cc55cSDimitry Andric addAllSubmodulePrebuiltDeps(SubM, MD, SeenSubmodules); 51581ad6265SDimitry Andric }); 516349cc55cSDimitry Andric } 517349cc55cSDimitry Andric 518349cc55cSDimitry Andric void ModuleDepCollectorPP::addModulePrebuiltDeps( 519349cc55cSDimitry Andric const Module *M, ModuleDeps &MD, 520349cc55cSDimitry Andric llvm::DenseSet<const Module *> &SeenSubmodules) { 521fe6060f1SDimitry Andric for (const Module *Import : M->Imports) 522fe6060f1SDimitry Andric if (Import->getTopLevelModule() != M->getTopLevelModule()) 523349cc55cSDimitry Andric if (MDC.isPrebuiltModule(Import->getTopLevelModule())) 524349cc55cSDimitry Andric if (SeenSubmodules.insert(Import->getTopLevelModule()).second) 525349cc55cSDimitry Andric MD.PrebuiltModuleDeps.emplace_back(Import->getTopLevelModule()); 526480093f4SDimitry Andric } 527480093f4SDimitry Andric 5285ffd83dbSDimitry Andric void ModuleDepCollectorPP::addAllSubmoduleDeps( 5295ffd83dbSDimitry Andric const Module *M, ModuleDeps &MD, 5305ffd83dbSDimitry Andric llvm::DenseSet<const Module *> &AddedModules) { 5315ffd83dbSDimitry Andric addModuleDep(M, MD, AddedModules); 532480093f4SDimitry Andric 53381ad6265SDimitry Andric forEachSubmoduleSorted(M, [&](const Module *SubM) { 5345ffd83dbSDimitry Andric addAllSubmoduleDeps(SubM, MD, AddedModules); 53581ad6265SDimitry Andric }); 536480093f4SDimitry Andric } 537480093f4SDimitry Andric 5385ffd83dbSDimitry Andric void ModuleDepCollectorPP::addModuleDep( 5395ffd83dbSDimitry Andric const Module *M, ModuleDeps &MD, 5405ffd83dbSDimitry Andric llvm::DenseSet<const Module *> &AddedModules) { 541480093f4SDimitry Andric for (const Module *Import : M->Imports) { 542fe6060f1SDimitry Andric if (Import->getTopLevelModule() != M->getTopLevelModule() && 543fe6060f1SDimitry Andric !MDC.isPrebuiltModule(Import)) { 544bdd1243dSDimitry Andric if (auto ImportID = handleTopLevelModule(Import->getTopLevelModule())) 5455ffd83dbSDimitry Andric if (AddedModules.insert(Import->getTopLevelModule()).second) 546bdd1243dSDimitry Andric MD.ClangModuleDeps.push_back(*ImportID); 547bdd1243dSDimitry Andric } 548bdd1243dSDimitry Andric } 549bdd1243dSDimitry Andric } 550bdd1243dSDimitry Andric 551bdd1243dSDimitry Andric void ModuleDepCollectorPP::addAllAffectingClangModules( 552bdd1243dSDimitry Andric const Module *M, ModuleDeps &MD, 553bdd1243dSDimitry Andric llvm::DenseSet<const Module *> &AddedModules) { 554bdd1243dSDimitry Andric addAffectingClangModule(M, MD, AddedModules); 555bdd1243dSDimitry Andric 556bdd1243dSDimitry Andric for (const Module *SubM : M->submodules()) 557bdd1243dSDimitry Andric addAllAffectingClangModules(SubM, MD, AddedModules); 558bdd1243dSDimitry Andric } 559bdd1243dSDimitry Andric 560bdd1243dSDimitry Andric void ModuleDepCollectorPP::addAffectingClangModule( 561bdd1243dSDimitry Andric const Module *M, ModuleDeps &MD, 562bdd1243dSDimitry Andric llvm::DenseSet<const Module *> &AddedModules) { 563bdd1243dSDimitry Andric for (const Module *Affecting : M->AffectingClangModules) { 564bdd1243dSDimitry Andric assert(Affecting == Affecting->getTopLevelModule() && 565bdd1243dSDimitry Andric "Not quite import not top-level module"); 566bdd1243dSDimitry Andric if (Affecting != M->getTopLevelModule() && 567bdd1243dSDimitry Andric !MDC.isPrebuiltModule(Affecting)) { 568bdd1243dSDimitry Andric if (auto ImportID = handleTopLevelModule(Affecting)) 569bdd1243dSDimitry Andric if (AddedModules.insert(Affecting).second) 570bdd1243dSDimitry Andric MD.ClangModuleDeps.push_back(*ImportID); 571480093f4SDimitry Andric } 572480093f4SDimitry Andric } 573480093f4SDimitry Andric } 574480093f4SDimitry Andric 5755ffd83dbSDimitry Andric ModuleDepCollector::ModuleDepCollector( 576349cc55cSDimitry Andric std::unique_ptr<DependencyOutputOptions> Opts, 577349cc55cSDimitry Andric CompilerInstance &ScanInstance, DependencyConsumer &C, 578*1ac55f4cSDimitry Andric CompilerInvocation OriginalCI, bool OptimizeArgs, bool EagerLoadModules, 579*1ac55f4cSDimitry Andric bool IsStdModuleP1689Format) 580349cc55cSDimitry Andric : ScanInstance(ScanInstance), Consumer(C), Opts(std::move(Opts)), 581bdd1243dSDimitry Andric OriginalInvocation(std::move(OriginalCI)), OptimizeArgs(OptimizeArgs), 582*1ac55f4cSDimitry Andric EagerLoadModules(EagerLoadModules), 583*1ac55f4cSDimitry Andric IsStdModuleP1689Format(IsStdModuleP1689Format) {} 584480093f4SDimitry Andric 585480093f4SDimitry Andric void ModuleDepCollector::attachToPreprocessor(Preprocessor &PP) { 586349cc55cSDimitry Andric PP.addPPCallbacks(std::make_unique<ModuleDepCollectorPP>(*this)); 587480093f4SDimitry Andric } 588480093f4SDimitry Andric 589480093f4SDimitry Andric void ModuleDepCollector::attachToASTReader(ASTReader &R) {} 590fe6060f1SDimitry Andric 591fe6060f1SDimitry Andric bool ModuleDepCollector::isPrebuiltModule(const Module *M) { 592fe6060f1SDimitry Andric std::string Name(M->getTopLevelModuleName()); 593fe6060f1SDimitry Andric const auto &PrebuiltModuleFiles = 594349cc55cSDimitry Andric ScanInstance.getHeaderSearchOpts().PrebuiltModuleFiles; 595fe6060f1SDimitry Andric auto PrebuiltModuleFileIt = PrebuiltModuleFiles.find(Name); 596fe6060f1SDimitry Andric if (PrebuiltModuleFileIt == PrebuiltModuleFiles.end()) 597fe6060f1SDimitry Andric return false; 598fe6060f1SDimitry Andric assert("Prebuilt module came from the expected AST file" && 599fe6060f1SDimitry Andric PrebuiltModuleFileIt->second == M->getASTFile()->getName()); 600fe6060f1SDimitry Andric return true; 601fe6060f1SDimitry Andric } 602bdd1243dSDimitry Andric 603bdd1243dSDimitry Andric static StringRef makeAbsoluteAndPreferred(CompilerInstance &CI, StringRef Path, 604bdd1243dSDimitry Andric SmallVectorImpl<char> &Storage) { 605bdd1243dSDimitry Andric if (llvm::sys::path::is_absolute(Path) && 606bdd1243dSDimitry Andric !llvm::sys::path::is_style_windows(llvm::sys::path::Style::native)) 607bdd1243dSDimitry Andric return Path; 608bdd1243dSDimitry Andric Storage.assign(Path.begin(), Path.end()); 609bdd1243dSDimitry Andric CI.getFileManager().makeAbsolutePath(Storage); 610bdd1243dSDimitry Andric llvm::sys::path::make_preferred(Storage); 611bdd1243dSDimitry Andric return StringRef(Storage.data(), Storage.size()); 612bdd1243dSDimitry Andric } 613bdd1243dSDimitry Andric 614bdd1243dSDimitry Andric void ModuleDepCollector::addFileDep(StringRef Path) { 615bdd1243dSDimitry Andric llvm::SmallString<256> Storage; 616bdd1243dSDimitry Andric Path = makeAbsoluteAndPreferred(ScanInstance, Path, Storage); 617bdd1243dSDimitry Andric FileDeps.push_back(std::string(Path)); 618bdd1243dSDimitry Andric } 619bdd1243dSDimitry Andric 620bdd1243dSDimitry Andric void ModuleDepCollector::addFileDep(ModuleDeps &MD, StringRef Path) { 621bdd1243dSDimitry Andric llvm::SmallString<256> Storage; 622bdd1243dSDimitry Andric Path = makeAbsoluteAndPreferred(ScanInstance, Path, Storage); 623bdd1243dSDimitry Andric MD.FileDeps.insert(Path); 624bdd1243dSDimitry Andric } 625