Skip to content

Commit 13386c6

Browse files
authored
[clang][DependencyScanner] Include the working directory in the context hash (llvm#73719)
The working directory is included in the PCM, but is not currently part of the context hash. This causes problems because different builds of a PCM with exactly the same command line can end up with different binary content for a PCM. If a build system tracks tasks by both working directory and command line, it may build a given PCM multiple times, causing a "module file out of date" error when loading the PCM due to different sizes.
1 parent 7fbdee0 commit 13386c6

File tree

2 files changed

+114
-2
lines changed

2 files changed

+114
-2
lines changed

clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,8 @@ void ModuleDepCollector::applyDiscoveredDependencies(CompilerInvocation &CI) {
316316

317317
static std::string getModuleContextHash(const ModuleDeps &MD,
318318
const CowCompilerInvocation &CI,
319-
bool EagerLoadModules) {
319+
bool EagerLoadModules,
320+
llvm::vfs::FileSystem &VFS) {
320321
llvm::HashBuilder<llvm::TruncatedBLAKE3<16>, llvm::endianness::native>
321322
HashBuilder;
322323
SmallString<32> Scratch;
@@ -325,6 +326,9 @@ static std::string getModuleContextHash(const ModuleDeps &MD,
325326
// will be readable.
326327
HashBuilder.add(getClangFullRepositoryVersion());
327328
HashBuilder.add(serialization::VERSION_MAJOR, serialization::VERSION_MINOR);
329+
llvm::ErrorOr<std::string> CWD = VFS.getCurrentWorkingDirectory();
330+
if (CWD)
331+
HashBuilder.add(*CWD);
328332

329333
// Hash the BuildInvocation without any input files.
330334
SmallString<0> ArgVec;
@@ -356,7 +360,8 @@ static std::string getModuleContextHash(const ModuleDeps &MD,
356360

357361
void ModuleDepCollector::associateWithContextHash(
358362
const CowCompilerInvocation &CI, ModuleDeps &Deps) {
359-
Deps.ID.ContextHash = getModuleContextHash(Deps, CI, EagerLoadModules);
363+
Deps.ID.ContextHash = getModuleContextHash(
364+
Deps, CI, EagerLoadModules, ScanInstance.getVirtualFileSystem());
360365
bool Inserted = ModuleDepsByID.insert({Deps.ID, &Deps}).second;
361366
(void)Inserted;
362367
assert(Inserted && "duplicate module mapping");
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
// RUN: rm -rf %t
2+
// RUN: split-file %s %t
3+
// RUN: sed -e "s|DIR|%/t|g" %t/build/compile-commands.json.in > %t/build/compile-commands.json
4+
// RUN: clang-scan-deps -compilation-database %t/build/compile-commands.json \
5+
// RUN: -j 1 -format experimental-full --optimize-args=all > %t/deps.db
6+
// RUN: cat %t/deps.db | sed 's:\\\\\?:/:g' | FileCheck %s -DPREFIX=%/t
7+
8+
// Check that there are two separate modules hashes. One for each working dir.
9+
10+
// CHECK: {
11+
// CHECK-NEXT: "modules": [
12+
// CHECK-NEXT: {
13+
// CHECK-NEXT: "clang-module-deps":
14+
// CHECK-NEXT: "clang-modulemap-file":
15+
// CHECK-NEXT: "command-line": [
16+
// CHECK: ],
17+
// CHECK-NEXT: "context-hash": "{{.*}}",
18+
// CHECK-NEXT: "file-deps": [
19+
// CHECK: ],
20+
// CHECK-NEXT: "name": "A"
21+
// CHECK-NEXT: },
22+
// CHECK-NEXT: {
23+
// CHECK-NEXT: "clang-module-deps":
24+
// CHECK-NEXT: "clang-modulemap-file":
25+
// CHECK-NEXT: "command-line": [
26+
// CHECK: ],
27+
// CHECK-NEXT: "context-hash": "{{.*}}",
28+
// CHECK-NEXT: "file-deps": [
29+
// CHECK: ],
30+
// CHECK-NEXT: "name": "A"
31+
// CHECK-NEXT: },
32+
// CHECK-NEXT: {
33+
// CHECK-NEXT: "clang-module-deps":
34+
// CHECK: ],
35+
// CHECK-NEXT: "clang-modulemap-file":
36+
// CHECK-NEXT: "command-line": [
37+
// CHECK: ],
38+
// CHECK-NEXT: "context-hash": "{{.*}}",
39+
// CHECK-NEXT: "file-deps": [
40+
// CHECK: ],
41+
// CHECK-NEXT: "name": "B"
42+
// CHECK-NEXT: },
43+
// CHECK-NEXT: {
44+
// CHECK-NEXT: "clang-module-deps":
45+
// CHECK: ],
46+
// CHECK-NEXT: "clang-modulemap-file":
47+
// CHECK-NEXT: "command-line": [
48+
// CHECK: ],
49+
// CHECK-NEXT: "context-hash": "{{.*}}",
50+
// CHECK-NEXT: "file-deps": [
51+
// CHECK: ],
52+
// CHECK-NEXT: "name": "B"
53+
// CHECK-NEXT: }
54+
// CHECK-NEXT: ],
55+
// CHECK-NEXT: "translation-units": [
56+
// CHECK: ]
57+
// CHECK: }
58+
59+
//--- build/compile-commands.json.in
60+
61+
[
62+
{
63+
"directory": "DIR/build",
64+
"command": "clang -c DIR/A.m -IDIR/modules/A -IDIR/modules/B -fmodules -fmodules-cache-path=DIR/module-cache -fimplicit-module-maps",
65+
"file": "DIR/A.m"
66+
},
67+
{
68+
"directory": "DIR",
69+
"command": "clang -c DIR/B.m -IDIR/modules/A -IDIR/modules/B -fmodules -fmodules-cache-path=DIR/module-cache -fimplicit-module-maps",
70+
"file": "DIR/B.m"
71+
}
72+
]
73+
74+
75+
//--- modules/A/module.modulemap
76+
77+
module A {
78+
umbrella header "A.h"
79+
}
80+
81+
//--- modules/A/A.h
82+
83+
typedef int A_t;
84+
85+
//--- modules/B/module.modulemap
86+
87+
module B {
88+
umbrella header "B.h"
89+
}
90+
91+
//--- modules/B/B.h
92+
93+
#include <A.h>
94+
95+
typedef int B_t;
96+
97+
//--- A.m
98+
99+
#include <B.h>
100+
101+
A_t a = 0;
102+
103+
//--- B.m
104+
105+
#include <B.h>
106+
107+
B_t b = 0;

0 commit comments

Comments
 (0)