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.
To reduce the number of explicit builds of a single module, we can try to squash multiple occurances of the module with different command-lines (and context hashes) by removing benign command-line options. The greatest contributors to benign differences between command-lines are the header search paths. In this patch, the lookup cache in `HeaderSearch` is used to determine which paths were actually used when implicitly building the module during scanning. This information is serialized into the unhashed control block of the implicitly-built PCM. The dependency scanner then loads this and may use it to prune the header search paths before computing the context hash of the module and generating the command-line. We could also prune the header search paths when serializing `HeaderSearchOptions` into the PCM. That way, we could do it only once instead of every load of the PCM file by dependency scanner. However, that would result in a PCM file whose contents don't produce the same context hash, which is probably highly surprising. There is an alternative approach to storing extra information into the PCM: wire up preprocessor callbacks to capture the used header search paths on-the-fly during preprocessing of modularized headers (similar to what we currently do for the main source file and textual headers). Right now, that's not compatible with the fact that we do an actual implicit build producing PCM files during dependency scanning. The second run of dependency scanner loads the PCM from the first run, skipping the preprocessing altogether, which would result in different results between runs. We can revisit this approach when we Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D102488 Files: clang/include/clang/Lex/HeaderSearch.h clang/include/clang/Serialization/ASTBitCodes.h clang/include/clang/Serialization/ModuleFile.h clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h clang/lib/Serialization/ASTReader.cpp clang/lib/Serialization/ASTWriter.cpp clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp clang/test/ClangScanDeps/Inputs/header-search-pruning/a/a.h clang/test/ClangScanDeps/Inputs/header-search-pruning/b/b.h clang/test/ClangScanDeps/Inputs/header-search-pruning/cdb.json clang/test/ClangScanDeps/Inputs/header-search-pruning/mod.h clang/test/ClangScanDeps/Inputs/header-search-pruning/module.modulemap clang/test/ClangScanDeps/header-search-pruning.cpp clang/test/ClangScanDeps/modules-full.cpp clang/tools/clang-scan-deps/ClangScanDeps.cpp
Index: clang/tools/clang-scan-deps/ClangScanDeps.cpp =================================================================== --- clang/tools/clang-scan-deps/ClangScanDeps.cpp +++ clang/tools/clang-scan-deps/ClangScanDeps.cpp @@ -163,6 +163,11 @@ "'-fmodule-file=', '-o', '-fmodule-map-file='."), llvm::cl::init(false), llvm::cl::cat(DependencyScannerCategory)); +static llvm::cl::opt<bool> OptimizeArgs( + "optimize-args", + llvm::cl::desc("Whether to optimize command-line arguments of modules."), + llvm::cl::init(false), llvm::cl::cat(DependencyScannerCategory)); + llvm::cl::opt<unsigned> NumThreads("j", llvm::cl::Optional, llvm::cl::desc("Number of worker threads to use (default: use " @@ -357,7 +362,26 @@ private: StringRef lookupPCMPath(ModuleID MID) { - return Modules[IndexedModuleID{MID, 0}].ImplicitModulePCMPath; + auto PCMPath = PCMPaths.insert({IndexedModuleID{MID, 0}, ""}); + if (PCMPath.second) + PCMPath.first->second = constructPCMPath(lookupModuleDeps(MID)); + return PCMPath.first->second; + } + + /// Construct a path where to put the explicitly built PCM - essentially the + /// path to implicitly built PCM with the context hash replaced by the final + /// (potentially modified) context hash. + std::string constructPCMPath(const ModuleDeps &MD) const { + const std::string &ImplicitPCMPath = MD.ImplicitModulePCMPath; + StringRef Filename = llvm::sys::path::filename(ImplicitPCMPath); + StringRef ImplicitContextHashPath = + llvm::sys::path::parent_path(ImplicitPCMPath); + StringRef ModuleCachePath = + llvm::sys::path::parent_path(ImplicitContextHashPath); + + SmallString<64> ExplicitPCMPath = ModuleCachePath; + llvm::sys::path::append(ExplicitPCMPath, MD.ID.ContextHash, Filename); + return std::string(ExplicitPCMPath); } const ModuleDeps &lookupModuleDeps(ModuleID MID) { @@ -395,6 +419,8 @@ std::mutex Lock; std::unordered_map<IndexedModuleID, ModuleDeps, IndexedModuleIDHasher> Modules; + std::unordered_map<IndexedModuleID, std::string, IndexedModuleIDHasher> + PCMPaths; std::vector<InputDeps> Inputs; }; @@ -554,7 +580,7 @@ SharedStream DependencyOS(llvm::outs()); DependencyScanningService Service(ScanMode, Format, ReuseFileManager, - SkipExcludedPPRanges); + SkipExcludedPPRanges, OptimizeArgs); llvm::ThreadPool Pool(llvm::hardware_concurrency(NumThreads)); std::vector<std::unique_ptr<DependencyScanningTool>> WorkerTools; for (unsigned I = 0; I < Pool.getThreadCount(); ++I) Index: clang/test/ClangScanDeps/modules-full.cpp =================================================================== --- clang/test/ClangScanDeps/modules-full.cpp +++ clang/test/ClangScanDeps/modules-full.cpp @@ -96,7 +96,7 @@ // CHECK-NEXT: ], // CHECK-NEXT: "translation-units": [ // CHECK-NEXT: { -// CHECK-NEXT: "clang-context-hash": "[[CONTEXT_HASH_H2]]", +// CHECK-NEXT: "clang-context-hash": "[[CONTEXT_HASH_H3:[A-Z0-9]+]]", // CHECK-NEXT: "clang-module-deps": [ // CHECK-NEXT: { // CHECK-NEXT: "context-hash": "[[CONTEXT_HASH_H2]]", @@ -117,7 +117,7 @@ // CHECK-NEXT: "input-file": "[[PREFIX]]/modules_cdb_input.cpp" // CHECK-NEXT: }, // CHECK-NEXT: { -// CHECK-NEXT: "clang-context-hash": "[[CONTEXT_HASH_H2]]", +// CHECK-NEXT: "clang-context-hash": "[[CONTEXT_HASH_H3]]", // CHECK-NEXT: "clang-module-deps": [ // CHECK-NEXT: { // CHECK-NEXT: "context-hash": "[[CONTEXT_HASH_H2]]", @@ -138,7 +138,7 @@ // CHECK-NEXT: "input-file": "[[PREFIX]]/modules_cdb_input.cpp" // CHECK-NEXT: }, // CHECK-NEXT: { -// CHECK-NEXT: "clang-context-hash": "[[CONTEXT_HASH_H2]]", +// CHECK-NEXT: "clang-context-hash": "[[CONTEXT_HASH_H3]]", // CHECK-NEXT: "clang-module-deps": [ // CHECK-NEXT: { // CHECK-NEXT: "context-hash": "[[CONTEXT_HASH_H2]]", @@ -159,7 +159,7 @@ // CHECK-NEXT: "input-file": "[[PREFIX]]/modules_cdb_input.cpp" // CHECK-NEXT: }, // CHECK-NEXT: { -// CHECK-NEXT: "clang-context-hash": "[[CONTEXT_HASH_H1]]", +// CHECK-NEXT: "clang-context-hash": "[[CONTEXT_HASH_H4:[A-Z0-9]+]]", // CHECK-NEXT: "clang-module-deps": [ // CHECK-NEXT: { // CHECK-NEXT: "context-hash": "[[CONTEXT_HASH_H1]]", Index: clang/test/ClangScanDeps/header-search-pruning.cpp =================================================================== --- /dev/null +++ clang/test/ClangScanDeps/header-search-pruning.cpp @@ -0,0 +1,87 @@ +// RUN: rm -rf %t && mkdir -p %t +// RUN: cp -r %S/Inputs/header-search-pruning/* %t +// RUN: cp %S/header-search-pruning.cpp %t/header-search-pruning.cpp +// RUN: sed -e "s|DIR|%t|g" -e "s|DEFINES|-DINCLUDE_A|g" %S/Inputs/header-search-pruning/cdb.json > %t/cdb_a.json +// RUN: sed -e "s|DIR|%t|g" -e "s|DEFINES|-DINCLUDE_B|g" %S/Inputs/header-search-pruning/cdb.json > %t/cdb_b.json +// RUN: sed -e "s|DIR|%t|g" -e "s|DEFINES|-DINCLUDE_A -DINCLUDE_B|g" %S/Inputs/header-search-pruning/cdb.json > %t/cdb_ab.json +// +// RUN: clang-scan-deps -compilation-database %t/cdb_a.json -format experimental-full -optimize-args >> %t/result_a.json +// RUN: cat %t/result_a.json | sed 's/\\/\//g' | FileCheck --check-prefixes=CHECK_A %s +// +// RUN: clang-scan-deps -compilation-database %t/cdb_b.json -format experimental-full -optimize-args >> %t/result_b.json +// RUN: cat %t/result_b.json | sed 's/\\/\//g' | FileCheck --check-prefixes=CHECK_B %s +// +// RUN: clang-scan-deps -compilation-database %t/cdb_ab.json -format experimental-full -optimize-args >> %t/result_ab.json +// RUN: cat %t/result_ab.json | sed 's/\\/\//g' | FileCheck --check-prefixes=CHECK_AB %s + +#include "mod.h" + +// CHECK_A: { +// CHECK_A-NEXT: "modules": [ +// CHECK_A-NEXT: { +// CHECK_A-NEXT: "clang-module-deps": [], +// CHECK_A-NEXT: "clang-modulemap-file": "{{.*}}", +// CHECK_A-NEXT: "command-line": [ +// CHECK_A-NEXT: "-cc1" +// CHECK_A: "-I" +// CHECK_A: "a" +// CHECK_A-NOT: "-I" +// CHECK_A-NOT: "b" +// CHECK_A: ], +// CHECK_A-NEXT: "context-hash": "[[HASH:.*]]", +// CHECK_A-NEXT: "file-deps": [ +// CHECK_A-NEXT: "[[PREFIX:.*]]/a/a.h", +// CHECK_A-NEXT: "[[PREFIX]]/mod.h", +// CHECK_A-NEXT: "[[PREFIX]]/module.modulemap" +// CHECK_A-NEXT: ], +// CHECK_A-NEXT: "name": "mod" +// CHECK_A-NEXT: } +// CHECK_A-NEXT: ] +// CHECK_A: } + +// CHECK_B: { +// CHECK_B-NEXT: "modules": [ +// CHECK_B-NEXT: { +// CHECK_B-NEXT: "clang-module-deps": [], +// CHECK_B-NEXT: "clang-modulemap-file": "{{.*}}", +// CHECK_B-NEXT: "command-line": [ +// CHECK_B-NEXT: "-cc1" +// CHECK_B-NOT: "-I" +// CHECK_B-NOT: "a" +// CHECK_B: "-I" +// CHECK_B: "b" +// CHECK_B: ], +// CHECK_B-NEXT: "context-hash": "[[HASH:.*]]", +// CHECK_B-NEXT: "file-deps": [ +// CHECK_B-NEXT: "[[PREFIX:.*]]/b/b.h", +// CHECK_B-NEXT: "[[PREFIX]]/mod.h", +// CHECK_B-NEXT: "[[PREFIX]]/module.modulemap" +// CHECK_B-NEXT: ], +// CHECK_B-NEXT: "name": "mod" +// CHECK_B-NEXT: } +// CHECK_B-NEXT: ] +// CHECK_B: } + +// CHECK_AB: { +// CHECK_AB-NEXT: "modules": [ +// CHECK_AB-NEXT: { +// CHECK_AB-NEXT: "clang-module-deps": [], +// CHECK_AB-NEXT: "clang-modulemap-file": "{{.*}}", +// CHECK_AB-NEXT: "command-line": [ +// CHECK_AB-NEXT: "-cc1" +// CHECK_AB: "-I" +// CHECK_AB: "a" +// CHECK_AB: "-I" +// CHECK_AB: "b" +// CHECK_AB: ], +// CHECK_AB-NEXT: "context-hash": "[[HASH:.*]]", +// CHECK_AB-NEXT: "file-deps": [ +// CHECK_AB-NEXT: "[[PREFIX:.*]]/a/a.h", +// CHECK_AB-NEXT: "[[PREFIX:.*]]/b/b.h", +// CHECK_AB-NEXT: "[[PREFIX]]/mod.h", +// CHECK_AB-NEXT: "[[PREFIX]]/module.modulemap" +// CHECK_AB-NEXT: ], +// CHECK_AB-NEXT: "name": "mod" +// CHECK_AB-NEXT: } +// CHECK_AB-NEXT: ] +// CHECK_AB: } Index: clang/test/ClangScanDeps/Inputs/header-search-pruning/module.modulemap =================================================================== --- /dev/null +++ clang/test/ClangScanDeps/Inputs/header-search-pruning/module.modulemap @@ -0,0 +1,4 @@ +module mod { + header "mod.h" + export * +} Index: clang/test/ClangScanDeps/Inputs/header-search-pruning/mod.h =================================================================== --- /dev/null +++ clang/test/ClangScanDeps/Inputs/header-search-pruning/mod.h @@ -0,0 +1,7 @@ +#ifdef INCLUDE_A +#include "a.h" +#endif + +#ifdef INCLUDE_B +#include "b.h" +#endif Index: clang/test/ClangScanDeps/Inputs/header-search-pruning/cdb.json =================================================================== --- /dev/null +++ clang/test/ClangScanDeps/Inputs/header-search-pruning/cdb.json @@ -0,0 +1,7 @@ +[ + { + "directory": "DIR", + "command": "clang -E DIR/header-search-pruning.cpp -Ia -Ib DEFINES -fmodules -fcxx-modules -fmodules-cache-path=DIR/module-cache -fimplicit-modules -fmodule-map-file=DIR/module.modulemap", + "file": "DIR/header-search-pruning.cpp" + } +] Index: clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp =================================================================== --- clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp +++ clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp @@ -18,9 +18,19 @@ using namespace tooling; using namespace dependencies; -static CompilerInvocation -makeInvocationForModuleBuildWithoutPaths(const ModuleDeps &Deps, - const CompilerInvocation &Invocation) { +static void optimizeHeaderSearchOpts(HeaderSearchOptions &Opts, + const std::set<unsigned> &UsedEntryIdxs) { + std::vector<HeaderSearchOptions::Entry> &Entries = Opts.UserEntries; + std::vector<HeaderSearchOptions::Entry> OrigEntries(Entries); + + Entries.clear(); + for (unsigned Idx : UsedEntryIdxs) + Entries.push_back(OrigEntries[Idx]); +} + +static CompilerInvocation makeInvocationForModuleBuildWithoutPaths( + const ModuleDeps &Deps, const CompilerInvocation &Invocation, + llvm::function_ref<void(CompilerInvocation &)> Optimize) { // Make a deep copy of the invocation. CompilerInvocation CI(Invocation); @@ -35,6 +45,8 @@ CI.getLangOpts()->ImplicitModules = false; CI.getHeaderSearchOpts().ImplicitModuleMaps = false; + Optimize(CI); + return CI; } @@ -189,8 +201,12 @@ MD.FileDeps.insert(IF.getFile()->getName()); }); - MD.Invocation = - makeInvocationForModuleBuildWithoutPaths(MD, Instance.getInvocation()); + MD.Invocation = makeInvocationForModuleBuildWithoutPaths( + MD, Instance.getInvocation(), [&](CompilerInvocation &CI) { + if (MDC.OptimizeArgs) + optimizeHeaderSearchOpts(CI.getHeaderSearchOpts(), + MF->UsedHeaderSearchPathIdxs); + }); MD.ID.ContextHash = MD.Invocation.getModuleHash(); llvm::DenseSet<const Module *> AddedModules; @@ -222,8 +238,9 @@ ModuleDepCollector::ModuleDepCollector( std::unique_ptr<DependencyOutputOptions> Opts, CompilerInstance &I, - DependencyConsumer &C) - : Instance(I), Consumer(C), Opts(std::move(Opts)) {} + DependencyConsumer &C, bool OptimizeArgs) + : Instance(I), Consumer(C), OptimizeArgs(OptimizeArgs), + Opts(std::move(Opts)) {} 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 @@ -52,10 +52,10 @@ StringRef WorkingDirectory, DependencyConsumer &Consumer, llvm::IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> DepFS, ExcludedPreprocessorDirectiveSkipMapping *PPSkipMappings, - ScanningOutputFormat Format) + ScanningOutputFormat Format, bool OptimizeArgs) : WorkingDirectory(WorkingDirectory), Consumer(Consumer), - DepFS(std::move(DepFS)), PPSkipMappings(PPSkipMappings), - Format(Format) {} + DepFS(std::move(DepFS)), PPSkipMappings(PPSkipMappings), Format(Format), + OptimizeArgs(OptimizeArgs) {} bool runInvocation(std::shared_ptr<CompilerInvocation> Invocation, FileManager *FileMgr, @@ -121,7 +121,7 @@ break; case ScanningOutputFormat::Full: Compiler.addDependencyCollector(std::make_shared<ModuleDepCollector>( - std::move(Opts), Compiler, Consumer)); + std::move(Opts), Compiler, Consumer, OptimizeArgs)); break; } @@ -145,13 +145,14 @@ llvm::IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> DepFS; ExcludedPreprocessorDirectiveSkipMapping *PPSkipMappings; ScanningOutputFormat Format; + bool OptimizeArgs; }; } // end anonymous namespace DependencyScanningWorker::DependencyScanningWorker( DependencyScanningService &Service) - : Format(Service.getFormat()) { + : Format(Service.getFormat()), OptimizeArgs(Service.canOptimizeArgs()) { DiagOpts = new DiagnosticOptions(); PCHContainerOps = std::make_shared<PCHContainerOperations>(); RealFS = llvm::vfs::createPhysicalFileSystem(); @@ -194,7 +195,7 @@ Tool.setPrintErrorMessage(false); Tool.setDiagnosticConsumer(&DC); DependencyScanningAction Action(WorkingDirectory, Consumer, DepFS, - PPSkipMappings.get(), Format); + PPSkipMappings.get(), Format, OptimizeArgs); return !Tool.run(&Action); }); } Index: clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp =================================================================== --- clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp +++ clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp @@ -14,6 +14,6 @@ DependencyScanningService::DependencyScanningService( ScanningMode Mode, ScanningOutputFormat Format, bool ReuseFileManager, - bool SkipExcludedPPRanges) + bool SkipExcludedPPRanges, bool OptimizeArgs) : Mode(Mode), Format(Format), ReuseFileManager(ReuseFileManager), - SkipExcludedPPRanges(SkipExcludedPPRanges) {} + SkipExcludedPPRanges(SkipExcludedPPRanges), OptimizeArgs(OptimizeArgs) {} Index: clang/lib/Serialization/ASTWriter.cpp =================================================================== --- clang/lib/Serialization/ASTWriter.cpp +++ clang/lib/Serialization/ASTWriter.cpp @@ -1097,6 +1097,16 @@ // Write out the diagnostic/pragma mappings. WritePragmaDiagnosticMappings(Diags, /* isModule = */ WritingModule); + Record.clear(); + + // Used search path indices. + auto UsedSearchPathIdxs = PP.getHeaderSearchInfo().GetUsedSearchPathIdxs(); + Record.push_back(UsedSearchPathIdxs.size()); + for (unsigned Idx : UsedSearchPathIdxs) + Record.push_back(Idx); + + Stream.EmitRecord(USED_HEADER_SEARCH_PATHS, Record); + // Leave the options block. Stream.ExitBlock(); return Signature; Index: clang/lib/Serialization/ASTReader.cpp =================================================================== --- clang/lib/Serialization/ASTReader.cpp +++ clang/lib/Serialization/ASTReader.cpp @@ -4795,6 +4795,14 @@ F->PragmaDiagMappings.insert(F->PragmaDiagMappings.end(), Record.begin(), Record.end()); break; + case USED_HEADER_SEARCH_PATHS: + if (F) { + unsigned Idx = 0; + unsigned Count = Record[Idx++]; + for (unsigned I = 0; I < Count; ++I) + F->UsedHeaderSearchPathIdxs.insert(Record[Idx++]); + } + break; } } } Index: clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h =================================================================== --- clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h +++ clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h @@ -20,6 +20,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringSet.h" #include "llvm/Support/raw_ostream.h" +#include <set> #include <string> #include <unordered_map> @@ -158,7 +159,8 @@ class ModuleDepCollector final : public DependencyCollector { public: ModuleDepCollector(std::unique_ptr<DependencyOutputOptions> Opts, - CompilerInstance &I, DependencyConsumer &C); + CompilerInstance &I, DependencyConsumer &C, + bool OptimizeArgs); void attachToPreprocessor(Preprocessor &PP) override; void attachToASTReader(ASTReader &R) override; @@ -170,6 +172,8 @@ CompilerInstance &Instance; /// The consumer of collected dependency information. DependencyConsumer &Consumer; + /// Whether to optimize the modules' command-line arguments. + bool OptimizeArgs; /// Path to the main source file. std::string MainFile; /// Hash identifying the compilation conditions of the current TU. Index: clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h =================================================================== --- clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h +++ clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h @@ -77,6 +77,7 @@ /// worker. If null, the file manager will not be reused. llvm::IntrusiveRefCntPtr<FileManager> Files; ScanningOutputFormat Format; + bool OptimizeArgs; }; } // end namespace dependencies Index: clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h =================================================================== --- clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h +++ clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h @@ -48,7 +48,8 @@ public: DependencyScanningService(ScanningMode Mode, ScanningOutputFormat Format, bool ReuseFileManager = true, - bool SkipExcludedPPRanges = true); + bool SkipExcludedPPRanges = true, + bool OptimizeArgs = false); ScanningMode getMode() const { return Mode; } @@ -58,6 +59,8 @@ bool canSkipExcludedPPRanges() const { return SkipExcludedPPRanges; } + bool canOptimizeArgs() const { return OptimizeArgs; } + DependencyScanningFilesystemSharedCache &getSharedCache() { return SharedCache; } @@ -70,6 +73,7 @@ /// ranges by bumping the buffer pointer in the lexer instead of lexing the /// tokens in the range until reaching the corresponding directive. const bool SkipExcludedPPRanges; + const bool OptimizeArgs; /// The global file system cache. DependencyScanningFilesystemSharedCache SharedCache; }; Index: clang/include/clang/Serialization/ModuleFile.h =================================================================== --- clang/include/clang/Serialization/ModuleFile.h +++ clang/include/clang/Serialization/ModuleFile.h @@ -30,6 +30,7 @@ #include <cassert> #include <cstdint> #include <memory> +#include <set> #include <string> #include <vector> @@ -173,6 +174,10 @@ /// unique module files based on AST contents. ASTFileSignature ASTBlockHash; + /// The indices of header search paths that were actually used when building + /// the module file. + std::set<unsigned> UsedHeaderSearchPathIdxs; + /// Whether this module has been directly imported by the /// user. bool DirectlyImported = false; Index: clang/include/clang/Serialization/ASTBitCodes.h =================================================================== --- clang/include/clang/Serialization/ASTBitCodes.h +++ clang/include/clang/Serialization/ASTBitCodes.h @@ -402,6 +402,10 @@ /// Record code for \#pragma diagnostic mappings. DIAG_PRAGMA_MAPPINGS, + + /// Record code for indices of header search paths that were actually used + /// when building the module. + USED_HEADER_SEARCH_PATHS, }; /// Record code for extension blocks. Index: clang/include/clang/Lex/HeaderSearch.h =================================================================== --- clang/include/clang/Lex/HeaderSearch.h +++ clang/include/clang/Lex/HeaderSearch.h @@ -21,12 +21,13 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringMap.h" -#include "llvm/ADT/StringSet.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSet.h" #include "llvm/Support/Allocator.h" #include <cassert> #include <cstddef> #include <memory> +#include <set> #include <string> #include <utility> #include <vector> @@ -290,6 +291,15 @@ SystemDirIdx++; } + /// Return indices of used search paths. + std::set<unsigned> GetUsedSearchPathIdxs() const { + std::set<unsigned> UsedSearchPathIdxs; + for (const auto &Entry : LookupFileCache) + if (Entry.second.HitIdx < SearchDirs.size()) + UsedSearchPathIdxs.insert(Entry.second.HitIdx); + return UsedSearchPathIdxs; + } + /// Set the list of system header prefixes. void SetSystemHeaderPrefixes(ArrayRef<std::pair<std::string, bool>> P) { SystemHeaderPrefixes.assign(P.begin(), P.end());
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits