diff --git a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h --- a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h +++ b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h @@ -47,10 +47,16 @@ /// be located. /// \param LookupModuleDeps This function is called to collect the full /// transitive set of dependencies for this - /// compilation. + /// compilation and fill in `-fmodule-map-file=` + /// arguments. std::vector getAdditionalCommandLine( std::function LookupPCMPath, std::function LookupModuleDeps) const; + + /// Get additional arguments suitable for appending to the original Clang + /// command line except flags containing absolute paths: `-fmodule-file=`, + /// `-fmodule-map-file`. + std::vector getAdditionalCommandLine() const; }; struct FullDependenciesResult { 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 @@ -87,10 +87,15 @@ /// be located. /// \param LookupModuleDeps This function is called to collect the full /// transitive set of dependencies for this - /// compilation. + /// compilation and fill in `-fmodule-map-file=` + /// arguments. std::vector getFullCommandLine( std::function LookupPCMPath, std::function LookupModuleDeps) const; + + /// Gets the full command line suitable for passing to clang except flags + /// containing absolute paths: `-fmodule-file=`, `-o`, `-fmodule-map-file`. + std::vector getFullCommandLine() const; }; namespace detail { diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp @@ -33,6 +33,13 @@ return Ret; } +std::vector FullDependencies::getAdditionalCommandLine() const { + return { + "-fno-implicit-modules", + "-fno-implicit-module-maps", + }; +} + DependencyScanningTool::DependencyScanningTool( DependencyScanningService &Service) : Worker(Service) {} diff --git a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp --- a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp +++ b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp @@ -64,6 +64,12 @@ return serializeCompilerInvocation(CI); } +std::vector ModuleDeps::getFullCommandLine() const { + CompilerInvocation CI(makeInvocationForModuleBuildWithoutPaths(*this)); + + return serializeCompilerInvocation(CI); +} + void dependencies::detail::collectPCMAndModuleMapPaths( llvm::ArrayRef Modules, std::function LookupPCMPath, 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 @@ -13,12 +13,17 @@ // RUN: echo %t.dir > %t.result // RUN: clang-scan-deps -compilation-database %t.cdb -j 4 -format experimental-full \ // RUN: -mode preprocess-minimized-sources >> %t.result -// RUN: cat %t.result | sed 's/\\/\//g' | FileCheck --check-prefixes=CHECK %s - +// RUN: cat %t.result | sed 's/\\/\//g' | FileCheck --check-prefixes=CHECK,CHECK-NO-ABS %s +// +// RUN: echo %t.dir > %t.result +// RUN: clang-scan-deps -compilation-database %t.cdb -j 4 -format experimental-full \ +// RUN: -generate-absolute-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_clangcl.result // RUN: clang-scan-deps -compilation-database %t_clangcl.cdb -j 4 -format experimental-full \ // RUN: -mode preprocess-minimized-sources >> %t_clangcl.result -// RUN: cat %t_clangcl.result | sed 's/\\/\//g' | FileCheck --check-prefixes=CHECK %s +// RUN: cat %t_clangcl.result | sed 's/\\/\//g' | FileCheck --check-prefixes=CHECK,CHECK-NO-ABS %s // FIXME: Backslash issues. // XFAIL: system-windows @@ -37,13 +42,15 @@ // CHECK-NEXT: ], // CHECK-NEXT: "clang-modulemap-file": "[[PREFIX]]/Inputs/module.modulemap", // CHECK-NEXT: "command-line": [ -// CHECK-NEXT: "-cc1", -// CHECK: "-fmodule-map-file=[[PREFIX]]/Inputs/module.modulemap", -// CHECK: "-emit-module", -// CHECK: "-fmodule-file=[[PREFIX]]/module-cache{{(_clangcl)?}}/[[CONTEXT_HASH_H1]]/header2-{{[A-Z0-9]+}}.pcm", -// CHECK-NOT: "-fimplicit-module-maps", -// CHECK: "-fmodule-name=header1", -// CHECK: "-fno-implicit-modules", +// CHECK-NEXT: "-cc1" +// CHECK-NO-ABS-NOT: "-fmodule-map-file={{.*}}" +// CHECK-ABS: "-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-NOT: "-fimplicit-module-maps" +// CHECK: "-fmodule-name=header1" +// CHECK: "-fno-implicit-modules" // CHECK: ], // CHECK-NEXT: "context-hash": "[[CONTEXT_HASH_H1]]", // CHECK-NEXT: "file-deps": [ @@ -97,10 +104,12 @@ // CHECK-NEXT: } // CHECK-NEXT: ], // CHECK-NEXT: "command-line": [ -// CHECK-NEXT: "-fno-implicit-modules", -// CHECK-NEXT: "-fno-implicit-module-maps", -// CHECK-NEXT: "-fmodule-file=[[PREFIX]]/module-cache{{(_clangcl)?}}/[[CONTEXT_HASH_H2]]/header1-{{[A-Z0-9]+}}.pcm", -// CHECK-NEXT: "-fmodule-map-file=[[PREFIX]]/Inputs/module.modulemap" +// CHECK-NEXT: "-fno-implicit-modules" +// 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-NO-ABS-NOT: "-fmodule-map-file={{.*}}" +// CHECK-ABS-NEXT: "-fmodule-map-file=[[PREFIX]]/Inputs/module.modulemap" // CHECK-NEXT: ], // CHECK-NEXT: "file-deps": [ // CHECK-NEXT: "[[PREFIX]]/modules_cdb_input.cpp" @@ -116,10 +125,12 @@ // CHECK-NEXT: } // CHECK-NEXT: ], // CHECK-NEXT: "command-line": [ -// CHECK-NEXT: "-fno-implicit-modules", -// CHECK-NEXT: "-fno-implicit-module-maps", -// CHECK-NEXT: "-fmodule-file=[[PREFIX]]/module-cache{{(_clangcl)?}}/[[CONTEXT_HASH_H2]]/header1-{{[A-Z0-9]+}}.pcm", -// CHECK-NEXT: "-fmodule-map-file=[[PREFIX]]/Inputs/module.modulemap" +// CHECK-NEXT: "-fno-implicit-modules" +// 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-NO-ABS-NOT: "-fmodule-map-file={{.*}} +// CHECK-ABS-NEXT: "-fmodule-map-file=[[PREFIX]]/Inputs/module.modulemap" // CHECK-NEXT: ], // CHECK-NEXT: "file-deps": [ // CHECK-NEXT: "[[PREFIX]]/modules_cdb_input.cpp" @@ -135,10 +146,12 @@ // CHECK-NEXT: } // CHECK-NEXT: ], // CHECK-NEXT: "command-line": [ -// CHECK-NEXT: "-fno-implicit-modules", -// CHECK-NEXT: "-fno-implicit-module-maps", -// CHECK-NEXT: "-fmodule-file=[[PREFIX]]/module-cache{{(_clangcl)?}}/[[CONTEXT_HASH_H2]]/header1-{{[A-Z0-9]+}}.pcm", -// CHECK-NEXT: "-fmodule-map-file=[[PREFIX]]/Inputs/module.modulemap" +// CHECK-NEXT: "-fno-implicit-modules" +// 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-NO-ABS-NOT: "-fmodule-map-file={{.*}}" +// CHECK-ABS-NEXT: "-fmodule-map-file=[[PREFIX]]/Inputs/module.modulemap" // CHECK-NEXT: ], // CHECK-NEXT: "file-deps": [ // CHECK-NEXT: "[[PREFIX]]/modules_cdb_input.cpp" @@ -154,12 +167,14 @@ // CHECK-NEXT: } // CHECK-NEXT: ], // CHECK-NEXT: "command-line": [ -// CHECK-NEXT: "-fno-implicit-modules", -// CHECK-NEXT: "-fno-implicit-module-maps", -// CHECK-NEXT: "-fmodule-file=[[PREFIX]]/module-cache{{(_clangcl)?}}/[[CONTEXT_HASH_H1]]/header2-{{[A-Z0-9]+}}.pcm", -// CHECK-NEXT: "-fmodule-file=[[PREFIX]]/module-cache{{(_clangcl)?}}/[[CONTEXT_HASH_H1]]/header1-{{[A-Z0-9]+}}.pcm", -// CHECK-NEXT: "-fmodule-map-file=[[PREFIX]]/Inputs/module.modulemap", -// CHECK-NEXT: "-fmodule-map-file=[[PREFIX]]/Inputs/module.modulemap" +// CHECK-NEXT: "-fno-implicit-modules" +// CHECK-NEXT: "-fno-implicit-module-maps" +// 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-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-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 @@ -138,6 +138,20 @@ llvm::cl::init(ScanningOutputFormat::Make), llvm::cl::cat(DependencyScannerCategory)); +// Note: This is only useful when experimenting with explicit modules during +// development. Build tools are not expected to use the absolute paths +// generated in this mode, since they point into module cache. Instead, +// build tools are expected to customize the paths via the `LookupPCMPath` +// and `LookupModuleDeps` callbacks when using the C++ API, or append them +// to the command-line generated without absolute paths. +static llvm::cl::opt GenerateAbsolutePathArgs( + "generate-absolute-path-args", + llvm::cl::desc( + "With '-format experimental-full', include arguments containing " + "absolute paths in the generated command lines: '-fmodule-file=', " + "'-o', '-fmodule-map-file='."), + llvm::cl::init(false), llvm::cl::cat(DependencyScannerCategory)); + llvm::cl::opt NumThreads("j", llvm::cl::Optional, llvm::cl::desc("Number of worker threads to use (default: use " @@ -260,11 +274,14 @@ Modules.insert(I, {{MD.ID, InputIndex}, std::move(MD)}); } - ID.AdditonalCommandLine = FD.getAdditionalCommandLine( - [&](ModuleID MID) { return lookupPCMPath(MID); }, - [&](ModuleID MID) -> const ModuleDeps & { - return lookupModuleDeps(MID); - }); + ID.AdditionalCommandLine = + GenerateAbsolutePathArgs + ? FD.getAdditionalCommandLine( + [&](ModuleID MID) { return lookupPCMPath(MID); }, + [&](ModuleID MID) -> const ModuleDeps & { + return lookupModuleDeps(MID); + }) + : FD.getAdditionalCommandLine(); Inputs.push_back(std::move(ID)); } @@ -295,11 +312,14 @@ {"file-deps", toJSONSorted(MD.FileDeps)}, {"clang-module-deps", toJSONSorted(MD.ClangModuleDeps)}, {"clang-modulemap-file", MD.ClangModuleMapFile}, - {"command-line", MD.getFullCommandLine( - [&](ModuleID MID) { return lookupPCMPath(MID); }, - [&](ModuleID MID) -> const ModuleDeps & { - return lookupModuleDeps(MID); - })}, + {"command-line", + GenerateAbsolutePathArgs + ? MD.getFullCommandLine( + [&](ModuleID MID) { return lookupPCMPath(MID); }, + [&](ModuleID MID) -> const ModuleDeps & { + return lookupModuleDeps(MID); + }) + : MD.getFullCommandLine()}, }; OutModules.push_back(std::move(O)); } @@ -311,7 +331,7 @@ {"clang-context-hash", I.ContextHash}, {"file-deps", I.FileDeps}, {"clang-module-deps", toJSONSorted(I.ModuleDeps)}, - {"command-line", I.AdditonalCommandLine}, + {"command-line", I.AdditionalCommandLine}, }; TUs.push_back(std::move(O)); } @@ -358,7 +378,7 @@ std::string ContextHash; std::vector FileDeps; std::vector ModuleDeps; - std::vector AdditonalCommandLine; + std::vector AdditionalCommandLine; }; std::mutex Lock;