jansvoboda11 created this revision. jansvoboda11 added reviewers: Bigcheese, dexonsmith. jansvoboda11 requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits.
When a translation unit uses a PCH and imports the same modules, we'd prefer to resolve to those modules instead of inventing new modules and reporting them as modular dependencies. Since the PCH modules have already been built, report them as file dependencies instead and nudge the compiler to reuse them when deciding whether to build a new module. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D103526 Files: clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp clang/test/ClangScanDeps/Inputs/modules-pch/cdb_pch.json clang/test/ClangScanDeps/Inputs/modules-pch/cdb_tu_with_common.json clang/test/ClangScanDeps/Inputs/modules-pch/mod_common_1.h clang/test/ClangScanDeps/Inputs/modules-pch/mod_common_2.h clang/test/ClangScanDeps/Inputs/modules-pch/mod_pch.h clang/test/ClangScanDeps/Inputs/modules-pch/mod_tu_with_common.h clang/test/ClangScanDeps/Inputs/modules-pch/module.modulemap clang/test/ClangScanDeps/Inputs/modules-pch/pch.h clang/test/ClangScanDeps/Inputs/modules-pch/tu_with_common.c clang/test/ClangScanDeps/modules-pch.c
Index: clang/test/ClangScanDeps/modules-pch.c =================================================================== --- clang/test/ClangScanDeps/modules-pch.c +++ clang/test/ClangScanDeps/modules-pch.c @@ -1,10 +1,124 @@ // RUN: rm -rf %t && mkdir %t // RUN: cp %S/Inputs/modules-pch/* %t +// Scan dependencies of the PCH: +// +// RUN: sed "s|DIR|%/t|g" %S/Inputs/modules-pch/cdb_pch.json > %t/cdb_pch.json +// RUN: echo -%t > %t/result_pch.json +// RUN: clang-scan-deps -compilation-database %t/cdb_pch.json -format experimental-full \ +// RUN: -generate-modules-path-args -build-dir %t/build -mode preprocess >> %t/result_pch.json +// RUN: cat %t/result_pch.json | FileCheck %s -check-prefix=CHECK-PCH +// +// CHECK-PCH: -[[PREFIX:.*]] +// CHECK-PCH-NEXT: { +// CHECK-PCH-NEXT: "modules": [ +// CHECK-PCH-NEXT: { +// CHECK-PCH-NEXT: "clang-module-deps": [], +// CHECK-PCH-NEXT: "clang-modulemap-file": "[[PREFIX]]/module.modulemap", +// CHECK-PCH-NEXT: "command-line": [ +// CHECK-PCH-NEXT: "-cc1" +// CHECK-PCH: "-emit-module" +// CHECK-PCH: "-fmodules" +// CHECK-PCH: "-fmodule-name=ModCommon1" +// CHECK-PCH: "-fno-implicit-modules" +// CHECK-PCH: ], +// CHECK-PCH-NEXT: "context-hash": "[[HASH_MOD_COMMON_1:.*]]", +// CHECK-PCH-NEXT: "file-deps": [ +// CHECK-PCH-NEXT: "[[PREFIX]]/mod_common_1.h", +// CHECK-PCH-NEXT: "[[PREFIX]]/module.modulemap" +// CHECK-PCH-NEXT: ], +// CHECK-PCH-NEXT: "name": "ModCommon1" +// CHECK-PCH-NEXT: }, +// CHECK-PCH-NEXT: { +// CHECK-PCH-NEXT: "clang-module-deps": [], +// CHECK-PCH-NEXT: "clang-modulemap-file": "[[PREFIX]]/module.modulemap", +// CHECK-PCH-NEXT: "command-line": [ +// CHECK-PCH-NEXT: "-cc1" +// CHECK-PCH: "-emit-module" +// CHECK-PCH: "-fmodules" +// CHECK-PCH: "-fmodule-name=ModCommon2" +// CHECK-PCH: "-fno-implicit-modules" +// CHECK-PCH: ], +// CHECK-PCH-NEXT: "context-hash": "[[HASH_MOD_COMMON_2:.*]]", +// CHECK-PCH-NEXT: "file-deps": [ +// CHECK-PCH-NEXT: "[[PREFIX]]/mod_common_2.h", +// CHECK-PCH-NEXT: "[[PREFIX]]/module.modulemap" +// CHECK-PCH-NEXT: ], +// CHECK-PCH-NEXT: "name": "ModCommon2" +// CHECK-PCH-NEXT: }, +// CHECK-PCH-NEXT: { +// CHECK-PCH-NEXT: "clang-module-deps": [ +// CHECK-PCH-NEXT: { +// CHECK-PCH-NEXT: "context-hash": "[[HASH_MOD_COMMON_2]]", +// CHECK-PCH-NEXT: "module-name": "ModCommon2" +// CHECK-PCH-NEXT: } +// CHECK-PCH-NEXT: ], +// CHECK-PCH-NEXT: "clang-modulemap-file": "[[PREFIX]]/module.modulemap", +// CHECK-PCH-NEXT: "command-line": [ +// CHECK-PCH-NEXT: "-cc1" +// CHECK-PCH: "-fmodule-map-file=[[PREFIX]]/module.modulemap" +// CHECK-PCH: "-emit-module" +// CHECK-PCH: "-fmodule-file=[[PREFIX]]/build/[[HASH_MOD_COMMON_2]]/ModCommon2-{{.*}}.pcm" +// CHECK-PCH: "-fmodules" +// CHECK-PCH: "-fmodule-name=ModPCH" +// CHECK-PCH: "-fno-implicit-modules" +// CHECK-PCH: ], +// CHECK-PCH-NEXT: "context-hash": "[[HASH_MOD_PCH:.*]]", +// CHECK-PCH-NEXT: "file-deps": [ +// CHECK-PCH-NEXT: "[[PREFIX]]/mod_pch.h", +// CHECK-PCH-NEXT: "[[PREFIX]]/module.modulemap" +// CHECK-PCH-NEXT: ], +// CHECK-PCH-NEXT: "name": "ModPCH" +// CHECK-PCH-NEXT: } +// CHECK-PCH-NEXT: ], +// CHECK-PCH-NEXT: "translation-units": [ +// CHECK-PCH-NEXT: { +// CHECK-PCH-NEXT: "clang-context-hash": "[[HASH_PCH:.*]]", +// CHECK-PCH-NEXT: "clang-module-deps": [ +// CHECK-PCH-NEXT: { +// CHECK-PCH-NEXT: "context-hash": "[[HASH_MOD_COMMON_1]]", +// CHECK-PCH-NEXT: "module-name": "ModCommon1" +// CHECK-PCH-NEXT: }, +// CHECK-PCH-NEXT: { +// CHECK-PCH-NEXT: "context-hash": "[[HASH_MOD_PCH]]", +// CHECK-PCH-NEXT: "module-name": "ModPCH" +// CHECK-PCH-NEXT: } +// CHECK-PCH-NEXT: ], +// CHECK-PCH-NEXT: "command-line": [ +// CHECK-PCH-NEXT: "-fno-implicit-modules", +// CHECK-PCH-NEXT: "-fno-implicit-module-maps", +// CHECK-PCH-DAG: "-fmodule-file=[[PREFIX]]/build/[[HASH_MOD_COMMON_1]]/ModCommon1-{{.*}}.pcm", +// CHECK-PCH-DAG: "-fmodule-file=[[PREFIX]]/build/[[HASH_MOD_COMMON_2]]/ModCommon2-{{.*}}.pcm", +// CHECK-PCH-DAG: "-fmodule-file=[[PREFIX]]/build/[[HASH_MOD_PCH]]/ModPCH-{{.*}}.pcm", +// CHECK-PCH-NEXT: "-fmodule-map-file=[[PREFIX]]/module.modulemap", +// CHECK-PCH-NEXT: "-fmodule-map-file=[[PREFIX]]/module.modulemap", +// CHECK-PCH-NEXT: "-fmodule-map-file=[[PREFIX]]/module.modulemap" +// CHECK-PCH-NEXT: ], +// CHECK-PCH-NEXT: "file-deps": [ +// CHECK-PCH-NEXT: "[[PREFIX]]/pch.h" +// CHECK-PCH-NEXT: ], +// CHECK-PCH-NEXT: "input-file": "[[PREFIX]]/pch.h" +// CHECK-PCH-NEXT: } +// CHECK-PCH-NEXT: ] +// CHECK-PCH-NEXT: } + // Explicitly build the PCH: // +// RUN: tail -n +2 %t/result_pch.json > %t/result_pch_stripped.json +// RUN: %python %S/../../utils/module-deps-to-rsp.py %t/result_pch_stripped.json \ +// RUN: --module-name=ModCommon1 > %t/mod_common_1.cc1.rsp +// RUN: %python %S/../../utils/module-deps-to-rsp.py %t/result_pch_stripped.json \ +// RUN: --module-name=ModCommon2 > %t/mod_common_2.cc1.rsp +// RUN: %python %S/../../utils/module-deps-to-rsp.py %t/result_pch_stripped.json \ +// RUN: --module-name=ModPCH > %t/mod_pch.cc1.rsp +// RUN: %python %S/../../utils/module-deps-to-rsp.py %t/result_pch_stripped.json \ +// RUN: --tu-index=0 > %t/pch.rsp +// +// RUN: %clang @%t/mod_common_1.cc1.rsp +// RUN: %clang @%t/mod_common_2.cc1.rsp +// RUN: %clang @%t/mod_pch.cc1.rsp // RUN: %clang -x c-header %t/pch.h -fmodules -gmodules -fimplicit-module-maps \ -// RUN: -fmodules-cache-path=%t/cache -o %t/pch.h.gch -fno-implicit-modules -fno-implicit-module-maps +// RUN: -fmodules-cache-path=%t/cache -o %t/pch.h.gch @%t/pch.rsp // Scan dependencies of the TU: // @@ -57,3 +171,81 @@ // CHECK-TU-NEXT: } // CHECK-TU-NEXT: ] // CHECK-TU-NEXT: } + +// Explicitly build the TU: +// +// RUN: tail -n +2 %t/result_tu.json > %t/result_tu_stripped.json +// RUN: %python %S/../../utils/module-deps-to-rsp.py %t/result_tu_stripped.json \ +// RUN: --module-name=ModTU > %t/mod_tu.cc1.rsp +// RUN: %python %S/../../utils/module-deps-to-rsp.py %t/result_tu_stripped.json \ +// RUN: --tu-index=0 > %t/tu.rsp +// +// RUN: %clang @%t/mod_tu.cc1.rsp +// RUN: %clang -fsyntax-only %s -fmodules -gmodules -fimplicit-module-maps \ +// RUN: -fmodules-cache-path=%t/cache -include %t/pch.h -o %t/tu.o @%t/tu.rsp + +// Scan dependencies of the TU that has common modules with the PCH: +// +// RUN: sed "s|DIR|%/t|g" %S/Inputs/modules-pch/cdb_tu_with_common.json > %t/cdb_tu_with_common.json +// RUN: echo -%t > %t/result_tu_with_common.json +// RUN: clang-scan-deps -compilation-database %t/cdb_tu_with_common.json -format experimental-full \ +// RUN: -generate-modules-path-args -build-dir %t/build -mode preprocess >> %t/result_tu_with_common.json +// RUN: cat %t/result_tu_with_common.json | FileCheck %s -check-prefix=CHECK-TU-WITH-COMMON +// +// CHECK-TU-WITH-COMMON: -[[PREFIX:.*]] +// CHECK-TU-WITH-COMMON-NEXT: { +// CHECK-TU-WITH-COMMON-NEXT: "modules": [ +// CHECK-TU-WITH-COMMON-NEXT: { +// CHECK-TU-WITH-COMMON-NEXT: "clang-module-deps": [], +// CHECK-TU-WITH-COMMON-NEXT: "clang-modulemap-file": "[[PREFIX]]/module.modulemap", +// CHECK-TU-WITH-COMMON-NEXT: "command-line": [ +// CHECK-TU-WITH-COMMON-NEXT: "-cc1", +// CHECK-TU-WITH-COMMON: "-emit-module", +// CHECK-TU-WITH-COMMON: "-fmodule-file=[[PREFIX]]/build/{{.*}}/ModCommon1-{{.*}}.pcm", +// CHECK-TU-WITH-COMMON: "-fmodule-name=ModTUWithCommon", +// CHECK-TU-WITH-COMMON: "-fno-implicit-modules", +// CHECK-TU-WITH-COMMON: ], +// CHECK-TU-WITH-COMMON-NEXT: "context-hash": "[[HASH_MOD_TU_WITH_COMMON:.*]]", +// CHECK-TU-WITH-COMMON-NEXT: "file-deps": [ +// CHECK-TU-WITH-COMMON-NEXT: "[[PREFIX]]/build/{{.*}}/ModCommon1-{{.*}}.pcm", +// CHECK-TU-WITH-COMMON-NEXT: "[[PREFIX]]/mod_tu_with_common.h", +// CHECK-TU-WITH-COMMON-NEXT: "[[PREFIX]]/module.modulemap" +// CHECK-TU-WITH-COMMON-NEXT: ], +// CHECK-TU-WITH-COMMON-NEXT: "name": "ModTUWithCommon" +// CHECK-TU-WITH-COMMON-NEXT: } +// CHECK-TU-WITH-COMMON-NEXT: ], +// CHECK-TU-WITH-COMMON-NEXT: "translation-units": [ +// CHECK-TU-WITH-COMMON-NEXT: { +// CHECK-TU-WITH-COMMON-NEXT: "clang-context-hash": "[[HASH_TU_WITH_COMMON:.*]]", +// CHECK-TU-WITH-COMMON-NEXT: "clang-module-deps": [ +// CHECK-TU-WITH-COMMON-NEXT: { +// CHECK-TU-WITH-COMMON-NEXT: "context-hash": "[[HASH_MOD_TU_WITH_COMMON]]", +// CHECK-TU-WITH-COMMON-NEXT: "module-name": "ModTUWithCommon" +// CHECK-TU-WITH-COMMON-NEXT: } +// CHECK-TU-WITH-COMMON-NEXT: ], +// CHECK-TU-WITH-COMMON-NEXT: "command-line": [ +// CHECK-TU-WITH-COMMON-NEXT: "-fno-implicit-modules", +// CHECK-TU-WITH-COMMON-NEXT: "-fno-implicit-module-maps", +// CHECK-TU-WITH-COMMON-NEXT: "-fmodule-file=[[PREFIX]]/build/[[HASH_MOD_TU_WITH_COMMON]]/ModTUWithCommon-{{.*}}.pcm", +// CHECK-TU-WITH-COMMON-NEXT: "-fmodule-map-file=[[PREFIX]]/module.modulemap" +// CHECK-TU-WITH-COMMON-NEXT: ], +// CHECK-TU-WITH-COMMON-NEXT: "file-deps": [ +// CHECK-TU-WITH-COMMON-NEXT: "[[PREFIX]]/tu_with_common.c", +// CHECK-TU-WITH-COMMON-NEXT: "[[PREFIX]]/pch.h.gch" +// CHECK-TU-WITH-COMMON-NEXT: ], +// CHECK-TU-WITH-COMMON-NEXT: "input-file": "[[PREFIX]]/tu_with_common.c" +// CHECK-TU-WITH-COMMON-NEXT: } +// CHECK-TU-WITH-COMMON-NEXT: ] +// CHECK-TU-WITH-COMMON-NEXT: } + +// Explicitly build the TU that has common modules with the PCH: +// +// RUN: tail -n +2 %t/result_tu_with_common.json > %t/result_tu_with_common_stripped.json +// RUN: %python %S/../../utils/module-deps-to-rsp.py %t/result_tu_with_common_stripped.json \ +// RUN: --module-name=ModTUWithCommon > %t/mod_tu_with_common.cc1.rsp +// RUN: %python %S/../../utils/module-deps-to-rsp.py %t/result_tu_with_common_stripped.json \ +// RUN: --tu-index=0 > %t/tu_with_common.rsp +// +// RUN: %clang @%t/mod_tu_with_common.cc1.rsp +// RUN: %clang -fsyntax-only %s -fmodules -gmodules -fimplicit-module-maps \ +// RUN: -fmodules-cache-path=%t/cache -include %t/pch.h -o %t/tu.o @%t/tu_with_common.rsp Index: clang/test/ClangScanDeps/Inputs/modules-pch/tu_with_common.c =================================================================== --- /dev/null +++ clang/test/ClangScanDeps/Inputs/modules-pch/tu_with_common.c @@ -0,0 +1,4 @@ +// tu_with_common.c + +#include "mod_common_2.h" +#include "mod_tu_with_common.h" Index: clang/test/ClangScanDeps/Inputs/modules-pch/pch.h =================================================================== --- clang/test/ClangScanDeps/Inputs/modules-pch/pch.h +++ clang/test/ClangScanDeps/Inputs/modules-pch/pch.h @@ -1 +1,4 @@ // pch.h + +#include "mod_common_1.h" +#include "mod_pch.h" Index: clang/test/ClangScanDeps/Inputs/modules-pch/module.modulemap =================================================================== --- clang/test/ClangScanDeps/Inputs/modules-pch/module.modulemap +++ clang/test/ClangScanDeps/Inputs/modules-pch/module.modulemap @@ -1,3 +1,19 @@ +module ModCommon1 { + header "mod_common_1.h" +} + +module ModCommon2 { + header "mod_common_2.h" +} + +module ModPCH { + header "mod_pch.h" +} + module ModTU { header "mod_tu.h" } + +module ModTUWithCommon { + header "mod_tu_with_common.h" +} Index: clang/test/ClangScanDeps/Inputs/modules-pch/mod_tu_with_common.h =================================================================== --- /dev/null +++ clang/test/ClangScanDeps/Inputs/modules-pch/mod_tu_with_common.h @@ -0,0 +1,3 @@ +// mod_tu_with_common.h + +#include "mod_common_1.h" Index: clang/test/ClangScanDeps/Inputs/modules-pch/mod_pch.h =================================================================== --- /dev/null +++ clang/test/ClangScanDeps/Inputs/modules-pch/mod_pch.h @@ -0,0 +1,3 @@ +// mod_pch.h + +#include "mod_common_2.h" Index: clang/test/ClangScanDeps/Inputs/modules-pch/mod_common_2.h =================================================================== --- /dev/null +++ clang/test/ClangScanDeps/Inputs/modules-pch/mod_common_2.h @@ -0,0 +1 @@ +// mod_common_2.h Index: clang/test/ClangScanDeps/Inputs/modules-pch/mod_common_1.h =================================================================== --- /dev/null +++ clang/test/ClangScanDeps/Inputs/modules-pch/mod_common_1.h @@ -0,0 +1 @@ +// mod_common_1.h Index: clang/test/ClangScanDeps/Inputs/modules-pch/cdb_tu_with_common.json =================================================================== --- /dev/null +++ clang/test/ClangScanDeps/Inputs/modules-pch/cdb_tu_with_common.json @@ -0,0 +1,7 @@ +[ + { + "directory": "DIR", + "command": "clang -fsyntax-only DIR/tu_with_common.c -fmodules -gmodules -fimplicit-module-maps -fmodules-cache-path=DIR/cache -include DIR/pch.h -o DIR/tu_with_common.o", + "file": "DIR/tu_with_common.c" + } +] Index: clang/test/ClangScanDeps/Inputs/modules-pch/cdb_pch.json =================================================================== --- /dev/null +++ clang/test/ClangScanDeps/Inputs/modules-pch/cdb_pch.json @@ -0,0 +1,7 @@ +[ + { + "directory": "DIR", + "command": "clang -x c-header DIR/pch.h -fmodules -gmodules -fimplicit-module-maps -fmodules-cache-path=DIR/cache -o DIR/pch.h.gch", + "file": "DIR/pch.h" + } +] Index: clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp =================================================================== --- clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp +++ clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp @@ -18,9 +18,9 @@ using namespace tooling; using namespace dependencies; -static CompilerInvocation -makeInvocationForModuleBuildWithoutPaths(const ModuleDeps &Deps, - const CompilerInvocation &Invocation) { +CompilerInvocation ModuleDepCollector::makeInvocationForModuleBuildWithoutPaths( + const ModuleDeps &Deps) const { + const CompilerInvocation &Invocation = Instance.getInvocation(); // Make a deep copy of the invocation. CompilerInvocation CI(Invocation); @@ -34,6 +34,19 @@ CI.getLangOpts()->ImplicitModules = false; + // The HeaderSearchOptions::PrebuiltModuleFiles that were injected into the + // original CompilerInvocation were an over-approximation. Check which ones + // were actually used in the module and pass them as FrontendOpts::ModuleFiles + // instead. + for (const auto &PrebuiltModuleFile : PrebuiltModuleFiles) { + CI.getHeaderSearchOpts().PrebuiltModuleFiles.erase( + PrebuiltModuleFile.first); + if (Deps.FileDeps.contains(PrebuiltModuleFile.second)) + CI.getFrontendOpts().ModuleFiles.push_back(PrebuiltModuleFile.second); + } + + CI.getPreprocessorOpts().ImplicitPCHInclude.clear(); + return CI; } @@ -148,7 +161,15 @@ return; const Module *TopLevelModule = Imported->getTopLevelModule(); - DirectModularDeps.insert(TopLevelModule); + + auto PrebuiltModuleIt = MDC.PrebuiltModuleFiles.find( + TopLevelModule->getTopLevelModuleName().str()); + // Don't add prebuilt modules to modular dependencies. The original + // command-line already contains these and we report them (or their parent) as + // file dependencies. We don't want to report them as modular dependencies, + // since they don't need to be built. + if (PrebuiltModuleIt == MDC.PrebuiltModuleFiles.end()) + DirectModularDeps.insert(TopLevelModule); } void ModuleDepCollectorPP::EndOfMainFile() { @@ -206,8 +227,12 @@ MD.FileDeps.insert(IF.getFile()->getName()); }); - MD.Invocation = - makeInvocationForModuleBuildWithoutPaths(MD, Instance.getInvocation()); + // Add direct prebuilt module dependencies now, so that we can use them when + // creating a CompilerInvocation and computing context hash for this + // ModuleDeps instance. + addDirectPrebuiltModuleDeps(M, MD); + + MD.Invocation = MDC.makeInvocationForModuleBuildWithoutPaths(MD); MD.ID.ContextHash = MD.Invocation.getModuleHash(); llvm::DenseSet<const Module *> AddedModules; @@ -216,6 +241,18 @@ return MD.ID; } +void ModuleDepCollectorPP::addDirectPrebuiltModuleDeps(const Module *M, + ModuleDeps &MD) { + for (const Module *Import : M->Imports) { + if (Import->getTopLevelModule() != M->getTopLevelModule()) { + auto PrebuiltModuleIt = + MDC.PrebuiltModuleFiles.find(Import->getTopLevelModuleName().str()); + if (PrebuiltModuleIt != MDC.PrebuiltModuleFiles.end()) + MD.FileDeps.insert(PrebuiltModuleIt->second); + } + } +} + void ModuleDepCollectorPP::addAllSubmoduleDeps( const Module *M, ModuleDeps &MD, llvm::DenseSet<const Module *> &AddedModules) { @@ -229,7 +266,9 @@ const Module *M, ModuleDeps &MD, llvm::DenseSet<const Module *> &AddedModules) { for (const Module *Import : M->Imports) { - if (Import->getTopLevelModule() != M->getTopLevelModule()) { + if (Import->getTopLevelModule() != M->getTopLevelModule() && + MDC.PrebuiltModuleFiles.find(Import->getTopLevelModuleName().str()) == + MDC.PrebuiltModuleFiles.end()) { ModuleID ImportID = handleTopLevelModule(Import->getTopLevelModule()); if (AddedModules.insert(Import->getTopLevelModule()).second) MD.ClangModuleDeps.push_back(ImportID); @@ -239,8 +278,10 @@ ModuleDepCollector::ModuleDepCollector( std::unique_ptr<DependencyOutputOptions> Opts, CompilerInstance &I, - DependencyConsumer &C) - : Instance(I), Consumer(C), Opts(std::move(Opts)) {} + DependencyConsumer &C, + std::map<std::string, std::string> PrebuiltModuleFiles) + : Instance(I), Consumer(C), Opts(std::move(Opts)), + PrebuiltModuleFiles(std::move(PrebuiltModuleFiles)) {} void ModuleDepCollector::attachToPreprocessor(Preprocessor &PP) { PP.addPPCallbacks(std::make_unique<ModuleDepCollectorPP>(Instance, *this)); Index: clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp =================================================================== --- clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp +++ clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp @@ -45,6 +45,23 @@ DependencyConsumer &C; }; +/// A listener that collects the names and paths to imported modules. +class ImportCollectingListener : public ASTReaderListener { +public: + ImportCollectingListener( + std::map<std::string, std::string> &PrebuiltModuleFiles) + : PrebuiltModuleFiles(PrebuiltModuleFiles) {} + + bool needsImportVisitation() const override { return true; } + + void visitImport(StringRef ModuleName, StringRef Filename) override { + PrebuiltModuleFiles[std::string(ModuleName)] = std::string(Filename); + } + +private: + std::map<std::string, std::string> &PrebuiltModuleFiles; +}; + /// A clang tool that runs the preprocessor in a mode that's optimized for /// dependency scanning for the given compiler invocation. class DependencyScanningAction : public tooling::ToolAction { @@ -101,6 +118,22 @@ Compiler.setFileManager(FileMgr); Compiler.createSourceManager(*FileMgr); + std::map<std::string, std::string> PrebuiltModuleFiles; + if (!Compiler.getPreprocessorOpts().ImplicitPCHInclude.empty()) { + /// Collect the modules that were prebuilt as part of the PCH. + ImportCollectingListener Listener(PrebuiltModuleFiles); + ASTReader::readASTFileControlBlock( + Compiler.getPreprocessorOpts().ImplicitPCHInclude, + Compiler.getFileManager(), Compiler.getPCHContainerReader(), + /*FindModuleFileExtensions=*/false, Listener, + /*ValidateDiagnosticOptions=*/false); + } + /// Configure the compiler with prebuilt modules. This will prevent it from + /// inventing new modules and instead force it to reuse whatever the PCH + /// already contains. + Compiler.getHeaderSearchOpts().PrebuiltModuleFiles.insert( + PrebuiltModuleFiles.begin(), PrebuiltModuleFiles.end()); + // Create the dependency collector that will collect the produced // dependencies. // @@ -122,7 +155,7 @@ break; case ScanningOutputFormat::Full: Compiler.addDependencyCollector(std::make_shared<ModuleDepCollector>( - std::move(Opts), Compiler, Consumer)); + std::move(Opts), Compiler, Consumer, std::move(PrebuiltModuleFiles))); break; } Index: clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h =================================================================== --- clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h +++ clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h @@ -143,6 +143,10 @@ void handleImport(const Module *Imported); + /// Adds direct modular dependencies that were prebuilt to the ModuleDeps + /// instance as file dependencies. + void addDirectPrebuiltModuleDeps(const Module *M, ModuleDeps &MD); + /// Traverses the previously collected direct modular dependencies to discover /// transitive modular dependencies and fills the parent \c ModuleDepCollector /// with both. @@ -158,7 +162,8 @@ class ModuleDepCollector final : public DependencyCollector { public: ModuleDepCollector(std::unique_ptr<DependencyOutputOptions> Opts, - CompilerInstance &I, DependencyConsumer &C); + CompilerInstance &I, DependencyConsumer &C, + std::map<std::string, std::string> PrebuiltModuleFiles); void attachToPreprocessor(Preprocessor &PP) override; void attachToASTReader(ASTReader &R) override; @@ -181,6 +186,12 @@ std::unordered_map<const Module *, ModuleDeps> ModularDeps; /// Options that control the dependency output generation. std::unique_ptr<DependencyOutputOptions> Opts; + /// Mapping between module names to module files that have been built prior to + /// the dependency scan. + std::map<std::string, std::string> PrebuiltModuleFiles; + + CompilerInvocation + makeInvocationForModuleBuildWithoutPaths(const ModuleDeps &Deps) const; }; } // end namespace dependencies
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits