Skip to content

Commit 576cc8c

Browse files
committed
[Caching] Use clang to prefix-map -fmodule-file-cache-key paths
When prefix mapping paths that are used in clang, ensure we are consistently using the same prefix mapper from clang. This prevents mismatches that could cause modules to fail to load. rdar://123324072
1 parent d6824a7 commit 576cc8c

File tree

7 files changed

+115
-36
lines changed

7 files changed

+115
-36
lines changed

include/swift/AST/ModuleDependencies.h

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,11 @@ class ClangModuleDependencyStorage : public ModuleDependencyInfoStorageBase {
366366
public:
367367
/// Destination output path
368368
const std::string pcmOutputPath;
369-
369+
370+
/// Same as \c pcmOutputPath, but possibly prefix-mapped using clang's prefix
371+
/// mapper.
372+
const std::string mappedPCMPath;
373+
370374
/// The module map file used to generate the Clang module.
371375
const std::string moduleMapFile;
372376

@@ -390,6 +394,7 @@ class ClangModuleDependencyStorage : public ModuleDependencyInfoStorageBase {
390394
std::string CASClangIncludeTreeRootID;
391395

392396
ClangModuleDependencyStorage(const std::string &pcmOutputPath,
397+
const std::string &mappedPCMPath,
393398
const std::string &moduleMapFile,
394399
const std::string &contextHash,
395400
const std::vector<std::string> &buildCommandLine,
@@ -400,9 +405,10 @@ class ClangModuleDependencyStorage : public ModuleDependencyInfoStorageBase {
400405
const std::string &moduleCacheKey)
401406
: ModuleDependencyInfoStorageBase(ModuleDependencyKind::Clang,
402407
moduleCacheKey),
403-
pcmOutputPath(pcmOutputPath), moduleMapFile(moduleMapFile),
404-
contextHash(contextHash), buildCommandLine(buildCommandLine),
405-
fileDependencies(fileDependencies), capturedPCMArgs(capturedPCMArgs),
408+
pcmOutputPath(pcmOutputPath), mappedPCMPath(mappedPCMPath),
409+
moduleMapFile(moduleMapFile), contextHash(contextHash),
410+
buildCommandLine(buildCommandLine), fileDependencies(fileDependencies),
411+
capturedPCMArgs(capturedPCMArgs),
406412
CASFileSystemRootID(CASFileSystemRootID),
407413
CASClangIncludeTreeRootID(clangIncludeTreeRoot) {}
408414

@@ -526,20 +532,18 @@ class ModuleDependencyInfo {
526532
/// Describe the module dependencies for a Clang module that can be
527533
/// built from a module map and headers.
528534
static ModuleDependencyInfo forClangModule(
529-
const std::string &pcmOutputPath,
530-
const std::string &moduleMapFile,
531-
const std::string &contextHash,
535+
const std::string &pcmOutputPath, const std::string &mappedPCMPath,
536+
const std::string &moduleMapFile, const std::string &contextHash,
532537
const std::vector<std::string> &nonPathCommandLine,
533538
const std::vector<std::string> &fileDependencies,
534539
const std::vector<std::string> &capturedPCMArgs,
535540
const std::string &CASFileSystemRootID,
536541
const std::string &clangIncludeTreeRoot,
537542
const std::string &moduleCacheKey) {
538-
return ModuleDependencyInfo(
539-
std::make_unique<ClangModuleDependencyStorage>(
540-
pcmOutputPath, moduleMapFile, contextHash,
541-
nonPathCommandLine, fileDependencies, capturedPCMArgs,
542-
CASFileSystemRootID, clangIncludeTreeRoot, moduleCacheKey));
543+
return ModuleDependencyInfo(std::make_unique<ClangModuleDependencyStorage>(
544+
pcmOutputPath, mappedPCMPath, moduleMapFile, contextHash,
545+
nonPathCommandLine, fileDependencies, capturedPCMArgs,
546+
CASFileSystemRootID, clangIncludeTreeRoot, moduleCacheKey));
543547
}
544548

545549
/// Describe a placeholder dependency swift module.

include/swift/ClangImporter/ClangImporter.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,9 @@ class ClangImporter final : public ClangModuleLoader {
446446
void verifyAllModules() override;
447447

448448
using RemapPathCallback = llvm::function_ref<std::string(StringRef)>;
449-
llvm::SmallVector<std::pair<ModuleDependencyID, ModuleDependencyInfo>, 1> bridgeClangModuleDependencies(
449+
llvm::SmallVector<std::pair<ModuleDependencyID, ModuleDependencyInfo>, 1>
450+
bridgeClangModuleDependencies(
451+
clang::tooling::dependencies::DependencyScanningTool &clangScanningTool,
450452
clang::tooling::dependencies::ModuleDepsGraph &clangDependencies,
451453
StringRef moduleOutputPath, RemapPathCallback remapPath = nullptr);
452454

include/swift/DependencyScan/SerializedModuleDependencyCacheFormat.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ using llvm::BCVBR;
3939

4040
/// Every .moddepcache file begins with these 4 bytes, for easy identification.
4141
const unsigned char MODULE_DEPENDENCY_CACHE_FORMAT_SIGNATURE[] = {'I', 'M', 'D','C'};
42-
const unsigned MODULE_DEPENDENCY_CACHE_FORMAT_VERSION_MAJOR = 5; // optionalModuleImports
42+
const unsigned MODULE_DEPENDENCY_CACHE_FORMAT_VERSION_MAJOR =
43+
6; // mappedPCMPath
4344
/// Increment this on every change.
4445
const unsigned MODULE_DEPENDENCY_CACHE_FORMAT_VERSION_MINOR = 1;
4546

@@ -182,6 +183,7 @@ using SwiftPlaceholderModuleDetailsLayout =
182183
using ClangModuleDetailsLayout =
183184
BCRecordLayout<CLANG_MODULE_DETAILS_NODE, // ID
184185
FileIDField, // pcmOutputPath
186+
FileIDField, // mappedPCMPath
185187
FileIDField, // moduleMapPath
186188
ContextHashIDField, // contextHash
187189
FlagIDArrayIDField, // commandLine

lib/ClangImporter/ClangModuleDependencyScanner.cpp

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -127,9 +127,29 @@ static std::vector<std::string> getClangDepScanningInvocationArguments(
127127
return commandLineArgs;
128128
}
129129

130+
static std::unique_ptr<llvm::PrefixMapper>
131+
getClangPrefixMapper(DependencyScanningTool &clangScanningTool,
132+
ModuleDeps &clangModuleDep,
133+
clang::CompilerInvocation &depsInvocation) {
134+
std::unique_ptr<llvm::PrefixMapper> Mapper;
135+
if (clangModuleDep.IncludeTreeID) {
136+
Mapper = std::make_unique<llvm::PrefixMapper>();
137+
} else if (clangModuleDep.CASFileSystemRootID) {
138+
assert(clangScanningTool.getCachingFileSystem());
139+
Mapper = std::make_unique<llvm::TreePathPrefixMapper>(
140+
clangScanningTool.getCachingFileSystem());
141+
}
142+
143+
if (Mapper)
144+
DepscanPrefixMapping::configurePrefixMapper(depsInvocation, *Mapper);
145+
146+
return Mapper;
147+
}
148+
130149
ModuleDependencyVector ClangImporter::bridgeClangModuleDependencies(
131-
clang::tooling::dependencies::ModuleDepsGraph &clangDependencies,
132-
StringRef moduleOutputPath, RemapPathCallback callback) {
150+
clang::tooling::dependencies::DependencyScanningTool &clangScanningTool,
151+
clang::tooling::dependencies::ModuleDepsGraph &clangDependencies,
152+
StringRef moduleOutputPath, RemapPathCallback callback) {
133153
const auto &ctx = Impl.SwiftContext;
134154
ModuleDependencyVector result;
135155

@@ -206,6 +226,10 @@ ModuleDependencyVector ClangImporter::bridgeClangModuleDependencies(
206226
(void)success;
207227
assert(success && "clang option from dep scanner round trip failed");
208228

229+
// Create a prefix mapper that matches clang's configuration.
230+
auto Mapper =
231+
getClangPrefixMapper(clangScanningTool, clangModuleDep, depsInvocation);
232+
209233
// Clear the cache key for module. The module key is computed from clang
210234
// invocation, not swift invocation.
211235
depsInvocation.getFrontendOpts().ModuleCacheKeys.clear();
@@ -251,10 +275,14 @@ ModuleDependencyVector ClangImporter::bridgeClangModuleDependencies(
251275
swiftArgs.push_back(IncludeTree);
252276
}
253277

278+
std::string mappedPCMPath = pcmPath;
279+
if (Mapper)
280+
Mapper->mapInPlace(mappedPCMPath);
281+
254282
// Module-level dependencies.
255283
llvm::StringSet<> alreadyAddedModules;
256284
auto dependencies = ModuleDependencyInfo::forClangModule(
257-
pcmPath, clangModuleDep.ClangModuleMapFile,
285+
pcmPath, mappedPCMPath, clangModuleDep.ClangModuleMapFile,
258286
clangModuleDep.ID.ContextHash, swiftArgs, fileDeps, capturedPCMArgs,
259287
RootID, IncludeTree, /*module-cache-key*/ "");
260288
for (const auto &moduleName : clangModuleDep.ClangModuleDeps) {
@@ -414,7 +442,8 @@ ClangImporter::getModuleDependencies(Identifier moduleName,
414442
return {};
415443
}
416444

417-
return bridgeClangModuleDependencies(*clangModuleDependencies,
445+
return bridgeClangModuleDependencies(clangScanningTool,
446+
*clangModuleDependencies,
418447
moduleOutputPath, [&](StringRef path) {
419448
if (mapper)
420449
return mapper->mapToString(path);
@@ -479,8 +508,8 @@ bool ClangImporter::addBridgingHeaderDependencies(
479508

480509
// Record module dependencies for each new module we found.
481510
auto bridgedDeps = bridgeClangModuleDependencies(
482-
clangModuleDependencies->ModuleGraph, cache.getModuleOutputPath(),
483-
[&cache](StringRef path) {
511+
clangScanningTool, clangModuleDependencies->ModuleGraph,
512+
cache.getModuleOutputPath(), [&cache](StringRef path) {
484513
return cache.getScanService().remapPath(path);
485514
});
486515
cache.recordDependencies(bridgedDeps);

lib/DependencyScan/ModuleDependencyCacheSerialization.cpp

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -557,19 +557,20 @@ bool ModuleDependenciesCacheDeserializer::readGraph(SwiftDependencyScanningServi
557557
if (!hasCurrentModule)
558558
llvm::report_fatal_error("Unexpected CLANG_MODULE_DETAILS_NODE record");
559559
cache.configureForContextHash(getContextHash());
560-
unsigned pcmOutputPathID, moduleMapPathID, contextHashID, commandLineArrayID,
561-
fileDependenciesArrayID, capturedPCMArgsArrayID, CASFileSystemRootID,
562-
clangIncludeTreeRootID, moduleCacheKeyID;
563-
ClangModuleDetailsLayout::readRecord(Scratch, pcmOutputPathID, moduleMapPathID,
564-
contextHashID, commandLineArrayID,
565-
fileDependenciesArrayID,
566-
capturedPCMArgsArrayID,
567-
CASFileSystemRootID,
568-
clangIncludeTreeRootID,
569-
moduleCacheKeyID);
560+
unsigned pcmOutputPathID, mappedPCMPathID, moduleMapPathID, contextHashID,
561+
commandLineArrayID, fileDependenciesArrayID, capturedPCMArgsArrayID,
562+
CASFileSystemRootID, clangIncludeTreeRootID, moduleCacheKeyID;
563+
ClangModuleDetailsLayout::readRecord(
564+
Scratch, pcmOutputPathID, mappedPCMPathID, moduleMapPathID,
565+
contextHashID, commandLineArrayID, fileDependenciesArrayID,
566+
capturedPCMArgsArrayID, CASFileSystemRootID, clangIncludeTreeRootID,
567+
moduleCacheKeyID);
570568
auto pcmOutputPath = getIdentifier(pcmOutputPathID);
571569
if (!pcmOutputPath)
572570
llvm::report_fatal_error("Bad pcm output path");
571+
auto mappedPCMPath = getIdentifier(mappedPCMPathID);
572+
if (!mappedPCMPath)
573+
llvm::report_fatal_error("Bad mapped pcm path");
573574
auto moduleMapPath = getIdentifier(moduleMapPathID);
574575
if (!moduleMapPath)
575576
llvm::report_fatal_error("Bad module map path");
@@ -597,9 +598,9 @@ bool ModuleDependenciesCacheDeserializer::readGraph(SwiftDependencyScanningServi
597598

598599
// Form the dependencies storage object
599600
auto moduleDep = ModuleDependencyInfo::forClangModule(
600-
*pcmOutputPath, *moduleMapPath, *contextHash, *commandLineArgs,
601-
*fileDependencies, *capturedPCMArgs, *rootFileSystemID,
602-
*clangIncludeTreeRoot, *moduleCacheKey);
601+
*pcmOutputPath, *mappedPCMPath, *moduleMapPath, *contextHash,
602+
*commandLineArgs, *fileDependencies, *capturedPCMArgs,
603+
*rootFileSystemID, *clangIncludeTreeRoot, *moduleCacheKey);
603604

604605
// Add dependencies of this module
605606
for (const auto &moduleName : *currentModuleImports)
@@ -1036,6 +1037,7 @@ void ModuleDependenciesCacheSerializer::writeModuleInfo(
10361037
ClangModuleDetailsLayout::emitRecord(
10371038
Out, ScratchRecord, AbbrCodes[ClangModuleDetailsLayout::Code],
10381039
getIdentifier(clangDeps->pcmOutputPath),
1040+
getIdentifier(clangDeps->mappedPCMPath),
10391041
getIdentifier(clangDeps->moduleMapFile),
10401042
getIdentifier(clangDeps->contextHash),
10411043
getArrayID(moduleID, ModuleIdentifierArrayKind::NonPathCommandLine),
@@ -1240,6 +1242,7 @@ void ModuleDependenciesCacheSerializer::collectStringsAndArrays(
12401242
auto clangDeps = dependencyInfo->getAsClangModule();
12411243
assert(clangDeps);
12421244
addIdentifier(clangDeps->pcmOutputPath);
1245+
addIdentifier(clangDeps->mappedPCMPath);
12431246
addIdentifier(clangDeps->moduleMapFile);
12441247
addIdentifier(clangDeps->contextHash);
12451248
addStringArray(moduleID, ModuleIdentifierArrayKind::NonPathCommandLine,

lib/DependencyScan/ScanDependencies.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ static llvm::Error resolveExplicitModuleInputs(
285285
if (!resolvingDepInfo.isClangModule()) {
286286
commandLine.push_back("-Xcc");
287287
commandLine.push_back("-fmodule-file=" + depModuleID.ModuleName + "=" +
288-
remapPath(clangDepDetails->pcmOutputPath));
288+
clangDepDetails->mappedPCMPath);
289289
if (!instance.getInvocation()
290290
.getClangImporterOptions()
291291
.UseClangIncludeTree) {
@@ -306,7 +306,7 @@ static llvm::Error resolveExplicitModuleInputs(
306306
appendXclang();
307307
commandLine.push_back("-fmodule-file-cache-key");
308308
appendXclang();
309-
commandLine.push_back(remapPath(clangDepDetails->pcmOutputPath));
309+
commandLine.push_back(clangDepDetails->mappedPCMPath);
310310
appendXclang();
311311
commandLine.push_back(clangDepDetails->moduleCacheKey);
312312
}
@@ -372,7 +372,7 @@ static llvm::Error resolveExplicitModuleInputs(
372372
newCommandLine.push_back("-Xcc");
373373
newCommandLine.push_back("-fmodule-file-cache-key");
374374
newCommandLine.push_back("-Xcc");
375-
newCommandLine.push_back(remapPath(clangDep->pcmOutputPath));
375+
newCommandLine.push_back(clangDep->mappedPCMPath);
376376
newCommandLine.push_back("-Xcc");
377377
newCommandLine.push_back(clangDep->moduleCacheKey);
378378
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Test that after compiling a module to a path containing a symlink we still
2+
// get the same scanner output.
3+
4+
// REQUIRES: OS=macosx
5+
6+
// RUN: %empty-directory(%t)
7+
// RUN: split-file %s %t
8+
// RUN: mkdir %t/module-outputs
9+
// RUN: ln -s module-outputs %t/symlink
10+
11+
// RUN: %target-swift-frontend -scan-dependencies %t/a.swift -o %t/deps.json -module-name A -emit-dependencies -emit-dependencies-path %t/deps.d -disable-implicit-concurrency-module-import -disable-implicit-string-processing-module-import -I %t -module-cache-path %t/symlink -verify -cache-compile-job -cas-path %t/cas
12+
// Check the contents of the JSON output
13+
// RUN: %validate-json %t/deps.json | %FileCheck %s
14+
15+
// CHECK: "-fmodule-file=C=[[PCM_PATH:.*symlink.*C-.*.pcm]]"
16+
// CHECK: "-fmodule-file-cache-key"
17+
// CHECK-NEXT: "-Xcc"
18+
// CHECK-NEXT: "[[PCM_PATH]]"
19+
// CHECK-NEXT: "-Xcc"
20+
// CHECK-NEXT: "llvmcas://
21+
22+
// Emit one of the modules, which will be in the symlinked path.
23+
// RUN: %{python} %S/../CAS/Inputs/BuildCommandExtractor.py %t/deps.json clang:C > %t/C.cmd
24+
// RUN: %swift_frontend_plain @%t/C.cmd
25+
26+
// RUN: %target-swift-frontend -scan-dependencies %t/a.swift -o %t/deps2.json -module-name A -emit-dependencies -emit-dependencies-path %t/deps.d -disable-implicit-concurrency-module-import -disable-implicit-string-processing-module-import -I %t -module-cache-path %t/symlink -verify -cache-compile-job -cas-path %t/cas
27+
// RUN: diff -u %t/deps.json %t/deps2.json
28+
29+
//--- module.modulemap
30+
module B { header "B.h" }
31+
module C { header "C.h" }
32+
33+
//--- B.h
34+
#include "C.h"
35+
36+
//--- C.h
37+
38+
//--- a.swift
39+
import B

0 commit comments

Comments
 (0)