diff --git a/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h b/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h --- a/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h +++ b/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h @@ -42,6 +42,16 @@ /// Modules with the same name but a different \c ContextHash should be /// treated as separate modules for the purpose of a build. std::string ContextHash; + + bool operator==(const ModuleID &Other) const { + return ModuleName == Other.ModuleName && ContextHash == Other.ContextHash; + } +}; + +struct ModuleIDHasher { + std::size_t operator()(const ModuleID &MID) const { + return llvm::hash_combine(MID.ModuleName, MID.ContextHash); + } }; struct ModuleDeps { diff --git a/clang/test/ClangScanDeps/modules-full.cpp b/clang/test/ClangScanDeps/modules-full.cpp --- a/clang/test/ClangScanDeps/modules-full.cpp +++ b/clang/test/ClangScanDeps/modules-full.cpp @@ -20,6 +20,12 @@ // RUN: -generate-modules-path-args -mode preprocess-minimized-sources >> %t.result // RUN: cat %t.result | sed 's/\\/\//g' | FileCheck --check-prefixes=CHECK,CHECK-ABS %s // +// RUN: echo %t.dir > %t.result +// RUN: clang-scan-deps -compilation-database %t.cdb -j 4 -format experimental-full \ +// RUN: -generate-modules-path-args -module-files-dir %t.dir/custom \ +// RUN: -mode preprocess-minimized-sources >> %t.result +// RUN: cat %t.result | sed 's/\\/\//g' | FileCheck --check-prefixes=CHECK,CHECK-CUSTOM %s +// // RUN: echo %t.dir > %t_clangcl.result // RUN: clang-scan-deps -compilation-database %t_clangcl.cdb -j 4 -format experimental-full \ // RUN: -mode preprocess-minimized-sources >> %t_clangcl.result @@ -45,9 +51,11 @@ // CHECK-NEXT: "-cc1" // CHECK-NO-ABS-NOT: "-fmodule-map-file={{.*}}" // CHECK-ABS: "-fmodule-map-file=[[PREFIX]]/Inputs/module.modulemap" +// CHECK-CUSTOM: "-fmodule-map-file=[[PREFIX]]/Inputs/module.modulemap" // CHECK: "-emit-module" // CHECK-NO-ABS-NOT: "-fmodule-file={{.*}}" // CHECK-ABS: "-fmodule-file=[[PREFIX]]/module-cache{{(_clangcl)?}}/[[CONTEXT_HASH_H1]]/header2-{{[A-Z0-9]+}}.pcm" +// CHECK-CUSTOM: "-fmodule-file=[[PREFIX]]/custom/[[CONTEXT_HASH_H1]]/header2-{{[A-Z0-9]+}}.pcm" // CHECK: "-fmodule-name=header1" // CHECK: "-fno-implicit-modules" // CHECK: ], @@ -105,8 +113,10 @@ // CHECK-NEXT: "-fno-implicit-module-maps" // CHECK-NO-ABS-NOT: "-fmodule-file={{.*}}" // CHECK-ABS-NEXT: "-fmodule-file=[[PREFIX]]/module-cache{{(_clangcl)?}}/[[CONTEXT_HASH_H2]]/header1-{{[A-Z0-9]+}}.pcm" +// CHECK-CUSTOM-NEXT: "-fmodule-file=[[PREFIX]]/custom/[[CONTEXT_HASH_H2]]/header1-{{[A-Z0-9]+}}.pcm" // CHECK-NO-ABS-NOT: "-fmodule-map-file={{.*}}" // CHECK-ABS-NEXT: "-fmodule-map-file=[[PREFIX]]/Inputs/module.modulemap" +// CHECK-CUSTOM-NEXT: "-fmodule-map-file=[[PREFIX]]/Inputs/module.modulemap" // CHECK-NEXT: ], // CHECK-NEXT: "file-deps": [ // CHECK-NEXT: "[[PREFIX]]/modules_cdb_input.cpp" @@ -126,8 +136,10 @@ // CHECK-NEXT: "-fno-implicit-module-maps" // CHECK-NO-ABS-NOT: "-fmodule-file={{.*}}, // CHECK-ABS-NEXT: "-fmodule-file=[[PREFIX]]/module-cache{{(_clangcl)?}}/[[CONTEXT_HASH_H2]]/header1-{{[A-Z0-9]+}}.pcm" +// CHECK-CUSTOM-NEXT: "-fmodule-file=[[PREFIX]]/custom/[[CONTEXT_HASH_H2]]/header1-{{[A-Z0-9]+}}.pcm" // CHECK-NO-ABS-NOT: "-fmodule-map-file={{.*}} // CHECK-ABS-NEXT: "-fmodule-map-file=[[PREFIX]]/Inputs/module.modulemap" +// CHECK-CUSTOM-NEXT: "-fmodule-map-file=[[PREFIX]]/Inputs/module.modulemap" // CHECK-NEXT: ], // CHECK-NEXT: "file-deps": [ // CHECK-NEXT: "[[PREFIX]]/modules_cdb_input.cpp" @@ -147,8 +159,10 @@ // CHECK-NEXT: "-fno-implicit-module-maps" // CHECK-NO-ABS-NOT: "-fmodule-file={{.*}}" // CHECK-ABS-NEXT: "-fmodule-file=[[PREFIX]]/module-cache{{(_clangcl)?}}/[[CONTEXT_HASH_H2]]/header1-{{[A-Z0-9]+}}.pcm" +// CHECK-CUSTOM-NEXT: "-fmodule-file=[[PREFIX]]/custom/[[CONTEXT_HASH_H2]]/header1-{{[A-Z0-9]+}}.pcm" // CHECK-NO-ABS-NOT: "-fmodule-map-file={{.*}}" // CHECK-ABS-NEXT: "-fmodule-map-file=[[PREFIX]]/Inputs/module.modulemap" +// CHECK-CUSTOM-NEXT: "-fmodule-map-file=[[PREFIX]]/Inputs/module.modulemap" // CHECK-NEXT: ], // CHECK-NEXT: "file-deps": [ // CHECK-NEXT: "[[PREFIX]]/modules_cdb_input.cpp" @@ -169,9 +183,13 @@ // CHECK-NO-ABS-NOT: "-fmodule-file={{.*}}" // CHECK-ABS-NEXT: "-fmodule-file=[[PREFIX]]/module-cache{{(_clangcl)?}}/[[CONTEXT_HASH_H1]]/header2-{{[A-Z0-9]+}}.pcm" // CHECK-ABS-NEXT: "-fmodule-file=[[PREFIX]]/module-cache{{(_clangcl)?}}/[[CONTEXT_HASH_H1]]/header1-{{[A-Z0-9]+}}.pcm" +// CHECK-CUSTOM-NEXT: "-fmodule-file=[[PREFIX]]/custom/[[CONTEXT_HASH_H1]]/header2-{{[A-Z0-9]+}}.pcm" +// CHECK-CUSTOM-NEXT: "-fmodule-file=[[PREFIX]]/custom/[[CONTEXT_HASH_H1]]/header1-{{[A-Z0-9]+}}.pcm" // CHECK-NO-ABS-NOT: "-fmodule-map-file={{.*}}" // CHECK-ABS-NEXT: "-fmodule-map-file=[[PREFIX]]/Inputs/module.modulemap" // CHECK-ABS-NEXT: "-fmodule-map-file=[[PREFIX]]/Inputs/module.modulemap" +// CHECK-CUSTOM-NEXT: "-fmodule-map-file=[[PREFIX]]/Inputs/module.modulemap" +// CHECK-CUSTOM-NEXT: "-fmodule-map-file=[[PREFIX]]/Inputs/module.modulemap" // CHECK-NEXT: ], // CHECK-NEXT: "file-deps": [ // CHECK-NEXT: "[[PREFIX]]/modules_cdb_input2.cpp" diff --git a/clang/tools/clang-scan-deps/ClangScanDeps.cpp b/clang/tools/clang-scan-deps/ClangScanDeps.cpp --- a/clang/tools/clang-scan-deps/ClangScanDeps.cpp +++ b/clang/tools/clang-scan-deps/ClangScanDeps.cpp @@ -163,6 +163,13 @@ "'-fmodule-file=', '-o', '-fmodule-map-file='."), llvm::cl::init(false), llvm::cl::cat(DependencyScannerCategory)); +static llvm::cl::opt ModuleFilesDir( + "module-files-dir", + llvm::cl::desc("With '-generate-modules-path-args', paths to module files " + "in the generated command lines will begin with the " + "specified directory instead the module cache directory."), + llvm::cl::cat(DependencyScannerCategory)); + llvm::cl::opt NumThreads("j", llvm::cl::Optional, llvm::cl::desc("Number of worker threads to use (default: use " @@ -357,7 +364,22 @@ private: StringRef lookupPCMPath(ModuleID MID) { - return Modules[IndexedModuleID{MID, 0}].ImplicitModulePCMPath; + auto PCMPath = PCMPaths.insert({MID, ""}); + if (PCMPath.second) + PCMPath.first->second = constructPCMPath(lookupModuleDeps(MID)); + return PCMPath.first->second; + } + + /// Construct a path for the explicitly built PCM. + std::string constructPCMPath(const ModuleDeps &MD) const { + StringRef Filename = llvm::sys::path::filename(MD.ImplicitModulePCMPath); + + SmallString<256> ExplicitPCMPath( + !ModuleFilesDir.empty() + ? ModuleFilesDir + : MD.Invocation.getHeaderSearchOpts().ModuleCachePath); + llvm::sys::path::append(ExplicitPCMPath, MD.ID.ContextHash, Filename); + return std::string(ExplicitPCMPath); } const ModuleDeps &lookupModuleDeps(ModuleID MID) { @@ -395,6 +417,7 @@ std::mutex Lock; std::unordered_map Modules; + std::unordered_map PCMPaths; std::vector Inputs; };