jansvoboda11 created this revision. jansvoboda11 added reviewers: Bigcheese, benlangmuir. Herald added a subscriber: ributzka. Herald added a project: All. jansvoboda11 requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits.
When scanning dependencies of a module, the command line we're given doesn't have an input file, which the driver needs to be happy. We've been creating a fake in-memory input file named after the module. However, this can hide files/directories on the actual filesystem, leading to errors. This patch works around that issue by generating a unique file name, which won't collide with the actual file system. We could also change the driver APIs so that we're able to specify an "assumed" input file. This would be more work, though, since the driver assumes the input name comes from the actual command-line. Depends on D140176 <https://reviews.llvm.org/D140176>. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D140177 Files: clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp clang/test/ClangScanDeps/modules-full-by-mod-name.c clang/test/ClangScanDeps/modules-full-by-mod-name.cpp
Index: clang/test/ClangScanDeps/modules-full-by-mod-name.cpp =================================================================== --- clang/test/ClangScanDeps/modules-full-by-mod-name.cpp +++ /dev/null @@ -1,79 +0,0 @@ -// UNSUPPORTED: target=powerpc64-ibm-aix{{.*}} -// RUN: rm -rf %t.dir -// RUN: rm -rf %t.cdb -// RUN: mkdir -p %t.dir -// RUN: cp %s %t.dir/modules_cdb_input.cpp -// RUN: cp %s %t.dir/modules_cdb_input2.cpp -// RUN: mkdir %t.dir/Inputs -// RUN: cp %S/Inputs/header.h %t.dir/Inputs/header.h -// RUN: cp %S/Inputs/header2.h %t.dir/Inputs/header2.h -// RUN: cp %S/Inputs/module.modulemap %t.dir/Inputs/module.modulemap -// RUN: sed -e "s|DIR|%/t.dir|g" %S/Inputs/modules_cdb_by_mod_name.json > %t.cdb -// RUN: sed -e "s|DIR|%/t.dir|g" %S/Inputs/modules_cdb_clangcl_by_mod_name.json > %t_clangcl.cdb -// -// RUN: clang-scan-deps -compilation-database %t.cdb -j 1 -format experimental-full \ -// RUN: -mode preprocess-dependency-directives -module-name=header1 > %t.result -// RUN: cat %t.result | sed 's:\\\\\?:/:g' | FileCheck -DPREFIX=%/t.dir --check-prefixes=CHECK %s -// -// RUN: clang-scan-deps -compilation-database %t_clangcl.cdb -j 4 -format experimental-full \ -// RUN: -mode preprocess-dependency-directives -module-name=header1 > %t_clangcl.result -// RUN: cat %t_clangcl.result | sed 's:\\\\\?:/:g' | FileCheck -DPREFIX=%/t.dir --check-prefixes=CHECK %s - -// CHECK: { -// CHECK-NEXT: "modules": [ -// CHECK-NEXT: { -// CHECK-NEXT: "clang-module-deps": [ -// CHECK-NEXT: { -// CHECK-NEXT: "context-hash": "[[HASH_H2_DINCLUDE:[A-Z0-9]+]]", -// CHECK-NEXT: "module-name": "header2" -// CHECK-NEXT: } -// CHECK-NEXT: ], -// CHECK-NEXT: "clang-modulemap-file": "[[PREFIX]]/Inputs/module.modulemap", -// CHECK-NEXT: "command-line": [ -// CHECK-NEXT: "-cc1" -// CHECK: "-emit-module" -// CHECK: "-fmodule-name=header1" -// CHECK: "-fno-implicit-modules" -// CHECK: ], -// CHECK-NEXT: "context-hash": "[[HASH_H1_DINCLUDE:[A-Z0-9]+]]", -// CHECK-NEXT: "file-deps": [ -// CHECK-NEXT: "[[PREFIX]]/Inputs/header.h", -// CHECK-NEXT: "[[PREFIX]]/Inputs/module.modulemap" -// CHECK-NEXT: ], -// CHECK-NEXT: "name": "header1" -// CHECK-NEXT: }, -// CHECK-NEXT: { -// CHECK-NEXT: "clang-module-deps": [], -// CHECK-NEXT: "clang-modulemap-file": "[[PREFIX]]/Inputs/module.modulemap", -// CHECK-NEXT: "command-line": [ -// CHECK-NEXT: "-cc1", -// CHECK: "-emit-module", -// CHECK: "-fmodule-name=header1", -// CHECK: "-fno-implicit-modules", -// CHECK: ], -// CHECK-NEXT: "context-hash": "[[HASH_H1:[A-Z0-9]+]]", -// CHECK-NEXT: "file-deps": [ -// CHECK-NEXT: "[[PREFIX]]/Inputs/header.h", -// CHECK-NEXT: "[[PREFIX]]/Inputs/module.modulemap" -// CHECK-NEXT: ], -// CHECK-NEXT: "name": "header1" -// CHECK-NEXT: }, -// CHECK-NEXT: { -// CHECK-NEXT: "clang-module-deps": [], -// CHECK-NEXT: "clang-modulemap-file": "[[PREFIX]]/Inputs/module.modulemap", -// CHECK-NEXT: "command-line": [ -// CHECK-NEXT: "-cc1", -// CHECK: "-emit-module", -// CHECK: "-fmodule-name=header2", -// CHECK: "-fno-implicit-modules", -// CHECK: ], -// CHECK-NEXT: "context-hash": "[[HASH_H2_DINCLUDE]]", -// CHECK-NEXT: "file-deps": [ -// CHECK-NEXT: "[[PREFIX]]/Inputs/header2.h", -// CHECK-NEXT: "[[PREFIX]]/Inputs/module.modulemap" -// CHECK-NEXT: ], -// CHECK-NEXT: "name": "header2" -// CHECK-NEXT: } -// CHECK-NEXT: ], -// CHECK-NEXT: "translation-units": [] -// CHECK-NEXT: } Index: clang/test/ClangScanDeps/modules-full-by-mod-name.c =================================================================== --- /dev/null +++ clang/test/ClangScanDeps/modules-full-by-mod-name.c @@ -0,0 +1,82 @@ +// UNSUPPORTED: target=powerpc64-ibm-aix{{.*}} + +// RUN: rm -rf %t +// RUN: split-file %s %t + +//--- module.modulemap +module root { header "root.h" } +module direct { header "direct.h" } +module transitive { header "transitive.h" } +//--- root.h +#include "direct.h" +//--- direct.h +#include "transitive.h" +//--- transitive.h +// empty + +//--- root/empty +// This is here to verify that the "root" directory doesn't confuse scanner when +// looking for dependencies of the "root" module. + +//--- cdb.json.template +[{ + "file": "", + "directory": "", + "command": "clang -fmodules -fmodules-cache-path=DIR/cache -I DIR -x c" +}] + +// RUN: sed "s|DIR|%/t|g" %t/cdb.json.template > %t/cdb.json +// RUN: clang-scan-deps -compilation-database %t/cdb.json -format experimental-full -module-name=root > %t/result.json +// RUN: cat %t/result.json | sed 's:\\\\\?:/:g' | FileCheck -DPREFIX=%/t %s + +// CHECK: { +// CHECK-NEXT: "modules": [ +// CHECK-NEXT: { +// CHECK-NEXT: "clang-module-deps": [ +// CHECK-NEXT: { +// CHECK-NEXT: "context-hash": "{{.*}}", +// CHECK-NEXT: "module-name": "transitive" +// CHECK-NEXT: } +// CHECK-NEXT: ], +// CHECK-NEXT: "clang-modulemap-file": "[[PREFIX]]/module.modulemap", +// CHECK-NEXT: "command-line": [ +// CHECK: ], +// CHECK-NEXT: "context-hash": "{{.*}}", +// CHECK-NEXT: "file-deps": [ +// CHECK-NEXT: "[[PREFIX]]/direct.h", +// CHECK-NEXT: "[[PREFIX]]/module.modulemap" +// CHECK-NEXT: ], +// CHECK-NEXT: "name": "direct" +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "clang-module-deps": [ +// CHECK-NEXT: { +// CHECK-NEXT: "context-hash": "{{.*}}", +// CHECK-NEXT: "module-name": "direct" +// CHECK-NEXT: } +// CHECK-NEXT: ], +// CHECK-NEXT: "clang-modulemap-file": "[[PREFIX]]/module.modulemap", +// CHECK-NEXT: "command-line": [ +// CHECK: ], +// CHECK-NEXT: "context-hash": "{{.*}}", +// CHECK-NEXT: "file-deps": [ +// CHECK-NEXT: "[[PREFIX]]/module.modulemap", +// CHECK-NEXT: "[[PREFIX]]/root.h" +// CHECK-NEXT: ], +// CHECK-NEXT: "name": "root" +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "clang-module-deps": [], +// CHECK-NEXT: "clang-modulemap-file": "[[PREFIX]]/module.modulemap", +// CHECK-NEXT: "command-line": [ +// CHECK: ], +// CHECK-NEXT: "context-hash": "{{.*}}", +// CHECK-NEXT: "file-deps": [ +// CHECK-NEXT: "[[PREFIX]]/module.modulemap", +// CHECK-NEXT: "[[PREFIX]]/transitive.h" +// CHECK-NEXT: ], +// CHECK-NEXT: "name": "transitive" +// CHECK-NEXT: } +// CHECK-NEXT: ], +// CHECK-NEXT: "translation-units": [] +// CHECK-NEXT: } Index: clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp =================================================================== --- clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp +++ clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp @@ -392,30 +392,40 @@ Optional<std::vector<std::string>> ModifiedCommandLine; llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> ModifiedFS; - if (ModuleName) { - ModifiedCommandLine = CommandLine; - ModifiedCommandLine->emplace_back(*ModuleName); + // If we're scanning based on a module name alone, we don't expect the client + // to provide us with an input file. However, the driver really wants to have + // one. Let's just make it up to make the driver happy. + if (ModuleName) { auto OverlayFS = llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(BaseFS); auto InMemoryFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>(); InMemoryFS->setCurrentWorkingDirectory(WorkingDirectory); - InMemoryFS->addFile(*ModuleName, 0, llvm::MemoryBuffer::getMemBuffer("")); OverlayFS->pushOverlay(InMemoryFS); ModifiedFS = OverlayFS; + + SmallString<128> FakeInputPath; + // TODO: We should retry the creation if the path already exists. + llvm::sys::fs::createUniquePath(*ModuleName + "-%%%%%%%%.input", + FakeInputPath, + /*MakeAbsolute=*/false); + InMemoryFS->addFile(FakeInputPath, 0, llvm::MemoryBuffer::getMemBuffer("")); + + ModifiedCommandLine = CommandLine; + ModifiedCommandLine->emplace_back(FakeInputPath); } const std::vector<std::string> &FinalCommandLine = ModifiedCommandLine ? *ModifiedCommandLine : CommandLine; + auto &FinalFS = ModifiedFS ? ModifiedFS : BaseFS; FileSystemOptions FSOpts; FSOpts.WorkingDir = WorkingDirectory.str(); - auto FileMgr = llvm::makeIntrusiveRefCnt<FileManager>( - FSOpts, ModifiedFS ? ModifiedFS : BaseFS); + auto FileMgr = llvm::makeIntrusiveRefCnt<FileManager>(FSOpts, FinalFS); - std::vector<const char *> FinalCCommandLine(CommandLine.size(), nullptr); - llvm::transform(CommandLine, FinalCCommandLine.begin(), + std::vector<const char *> FinalCCommandLine(FinalCommandLine.size(), nullptr); + llvm::transform(FinalCommandLine, FinalCCommandLine.begin(), [](const std::string &Str) { return Str.c_str(); }); auto DiagOpts = CreateAndPopulateDiagOpts(FinalCCommandLine);
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits