Skip to content

Commit 162954a

Browse files
committed
[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. (cherry picked from commit 13386c6) # Conflicts: # clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
1 parent ce58f69 commit 162954a

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
@@ -345,7 +345,8 @@ void ModuleDepCollector::applyDiscoveredDependencies(CompilerInvocation &CI) {
345345

346346
static std::string getModuleContextHash(const ModuleDeps &MD,
347347
const CowCompilerInvocation &CI,
348-
bool EagerLoadModules) {
348+
bool EagerLoadModules,
349+
llvm::vfs::FileSystem &VFS) {
349350
llvm::HashBuilder<llvm::TruncatedBLAKE3<16>,
350351
llvm::support::endianness::native>
351352
HashBuilder;
@@ -371,6 +372,9 @@ static std::string getModuleContextHash(const ModuleDeps &MD,
371372
// will be readable.
372373
HashBuilder.add(getClangFullRepositoryVersion());
373374
HashBuilder.add(serialization::VERSION_MAJOR, serialization::VERSION_MINOR);
375+
llvm::ErrorOr<std::string> CWD = VFS.getCurrentWorkingDirectory();
376+
if (CWD)
377+
HashBuilder.add(*CWD);
374378

375379
// Save and restore options that should not affect the hash, e.g. the exact
376380
// contents of input files, or prefix mappings.
@@ -428,7 +432,8 @@ static void checkCompileCacheKeyMatch(cas::ObjectStore &CAS,
428432

429433
void ModuleDepCollector::associateWithContextHash(
430434
const CowCompilerInvocation &CI, ModuleDeps &Deps) {
431-
Deps.ID.ContextHash = getModuleContextHash(Deps, CI, EagerLoadModules);
435+
Deps.ID.ContextHash = getModuleContextHash(
436+
Deps, CI, EagerLoadModules, ScanInstance.getVirtualFileSystem());
432437
bool Inserted = ModuleDepsByID.insert({Deps.ID, &Deps}).second;
433438
(void)Inserted;
434439
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)