Skip to content

Commit d579027

Browse files
Merge pull request #84442 from cachemeifyoucan/eng/PR-issue-84088
[Caching] Allow prefix mapping for generated bridging header
2 parents 9c9a840 + b7329f4 commit d579027

16 files changed

+241
-82
lines changed

include/swift/Serialization/SerializedModuleLoader.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -583,9 +583,9 @@ bool extractCompilerFlagsFromInterface(
583583
llvm::VersionTuple extractUserModuleVersionFromInterface(StringRef moduleInterfacePath);
584584

585585
/// Extract embedded bridging header from binary module.
586-
std::string
586+
std::unique_ptr<llvm::MemoryBuffer>
587587
extractEmbeddedBridgingHeaderContent(std::unique_ptr<llvm::MemoryBuffer> file,
588-
ASTContext &Context);
588+
StringRef headerPath, ASTContext &Context);
589589
} // end namespace swift
590590

591591
#endif

lib/DependencyScan/ModuleDependencyScanner.cpp

Lines changed: 95 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1364,12 +1364,8 @@ void ModuleDependencyScanner::resolveHeaderDependenciesForModule(
13641364
if (!moduleBuf)
13651365
return nullptr;
13661366

1367-
auto content = extractEmbeddedBridgingHeaderContent(std::move(*moduleBuf),
1368-
ScanASTContext);
1369-
if (content.empty())
1370-
return nullptr;
1371-
1372-
return llvm::MemoryBuffer::getMemBufferCopy(content, header);
1367+
return extractEmbeddedBridgingHeaderContent(std::move(*moduleBuf), header,
1368+
ScanASTContext);
13731369
};
13741370

13751371
if (isBinaryModuleWithHeaderInput) {
@@ -1643,85 +1639,116 @@ void ModuleDependencyScanner::resolveCrossImportOverlayDependencies(
16431639
allModules.end(), action);
16441640
}
16451641

1642+
static void appendHeaderContent(llvm::raw_ostream &OS,
1643+
llvm::MemoryBufferRef buffer,
1644+
ModuleDependencyID fromModule) {
1645+
// Use preprocessor directives to add some clues for where the content is
1646+
// coming from.
1647+
OS << "# 1 \"<module-" << fromModule.ModuleName << ">/"
1648+
<< llvm::sys::path::filename(buffer.getBufferIdentifier()) << "\" 1\n";
1649+
OS << buffer.getBuffer();
1650+
}
1651+
16461652
llvm::Error ModuleDependencyScanner::performBridgingHeaderChaining(
16471653
const ModuleDependencyID &rootModuleID, ModuleDependenciesCache &cache,
16481654
ModuleDependencyIDSetVector &allModules) {
16491655
if (rootModuleID.Kind != ModuleDependencyKind::SwiftSource)
16501656
return llvm::Error::success();
16511657

1652-
bool hasBridgingHeader = false;
1653-
llvm::vfs::OnDiskOutputBackend outputBackend;
1654-
1655-
SmallString<256> outputPath(
1656-
ScanCompilerInvocation.getFrontendOptions().ScannerOutputDir);
1657-
1658-
if (outputPath.empty())
1659-
outputPath = "/<compiler-generated>";
1660-
1661-
llvm::sys::path::append(
1662-
outputPath, ScanCompilerInvocation.getFrontendOptions().ModuleName + "-" +
1663-
ScanCompilerInvocation.getModuleScanningHash() +
1664-
"-ChainedBridgingHeader.h");
1665-
1666-
llvm::SmallString<256> sourceBuf;
1667-
llvm::raw_svector_ostream outOS(sourceBuf);
1658+
llvm::SmallString<256> chainedHeaderBuffer;
1659+
llvm::raw_svector_ostream outOS(chainedHeaderBuffer);
16681660

16691661
// Iterate through all the modules and collect all the bridging header
16701662
// and chain them into a single file. The allModules list is in the order of
16711663
// discover, thus providing stable ordering for a deterministic generated
16721664
// buffer.
16731665
auto FS = ScanASTContext.SourceMgr.getFileSystem();
16741666
for (const auto &moduleID : allModules) {
1675-
if (moduleID.Kind != ModuleDependencyKind::SwiftSource &&
1676-
moduleID.Kind != ModuleDependencyKind::SwiftBinary)
1667+
if (moduleID.Kind != ModuleDependencyKind::SwiftBinary)
16771668
continue;
16781669

16791670
auto moduleDependencyInfo = cache.findKnownDependency(moduleID);
16801671
if (auto *binaryMod = moduleDependencyInfo.getAsSwiftBinaryModule()) {
16811672
if (!binaryMod->headerImport.empty()) {
1682-
hasBridgingHeader = true;
1683-
if (FS->exists(binaryMod->headerImport)) {
1684-
outOS << "#include \"" << binaryMod->headerImport << "\"\n";
1673+
if (auto buffer= FS->getBufferForFile(binaryMod->headerImport)) {
1674+
appendHeaderContent(outOS, (*buffer)->getMemBufferRef(), moduleID);
16851675
} else {
16861676
// Extract the embedded bridging header
16871677
auto moduleBuf = FS->getBufferForFile(binaryMod->compiledModulePath);
16881678
if (!moduleBuf)
16891679
return llvm::errorCodeToError(moduleBuf.getError());
16901680

16911681
auto content = extractEmbeddedBridgingHeaderContent(
1692-
std::move(*moduleBuf), ScanASTContext);
1693-
if (content.empty())
1682+
std::move(*moduleBuf), /*headerPath=*/"", ScanASTContext);
1683+
if (!content)
16941684
return llvm::createStringError("can't load embedded header from " +
16951685
binaryMod->compiledModulePath);
16961686

1697-
outOS << content << "\n";
1687+
outOS << content->getBuffer() << "\n";
16981688
}
16991689
}
1700-
} else if (auto *srcMod = moduleDependencyInfo.getAsSwiftSourceModule()) {
1701-
if (srcMod->textualModuleDetails.bridgingHeaderFile) {
1702-
hasBridgingHeader = true;
1703-
outOS << "#include \""
1704-
<< *srcMod->textualModuleDetails.bridgingHeaderFile << "\"\n";
1705-
}
17061690
}
17071691
}
17081692

1709-
if (!hasBridgingHeader)
1710-
return llvm::Error::success();
1693+
// Handle bridging header in main module.
1694+
auto mainModuleDeps = cache.findKnownDependency(rootModuleID);
1695+
auto *mainModule = mainModuleDeps.getAsSwiftSourceModule();
1696+
assert(mainModule && "expect main module to be a swift source module");
1697+
std::unique_ptr<llvm::MemoryBuffer> sourceBuffer;
1698+
bool needChainedHeader = !chainedHeaderBuffer.empty();
1699+
if (!needChainedHeader) {
1700+
// There is no bridging header chained from dependencies.
1701+
// If main module also has no bridging header, ther is nothing to scan.
1702+
if (!mainModule->textualModuleDetails.bridgingHeaderFile)
1703+
return llvm::Error::success();
1704+
1705+
// Otherwise, there is no chaining needed. Just use the bridging header from
1706+
// main module.
1707+
if (auto headerBuffer = FS->getBufferForFile(
1708+
*mainModule->textualModuleDetails.bridgingHeaderFile))
1709+
sourceBuffer = std::move(*headerBuffer);
1710+
else
1711+
return llvm::errorCodeToError(headerBuffer.getError());
1712+
} else {
1713+
// There are bridging header needed to be chained. Append the bridging
1714+
// header from main module if needed and create use a new source buffer.
1715+
if (mainModule->textualModuleDetails.bridgingHeaderFile) {
1716+
auto srcBuf = FS->getBufferForFile(
1717+
*mainModule->textualModuleDetails.bridgingHeaderFile);
1718+
if (!srcBuf)
1719+
return llvm::errorCodeToError(srcBuf.getError());
1720+
appendHeaderContent(outOS, (*srcBuf)->getMemBufferRef(), rootModuleID);
1721+
}
17111722

1712-
if (ScanCompilerInvocation.getFrontendOptions().WriteScannerOutput) {
1713-
auto outFile = outputBackend.createFile(outputPath);
1714-
if (!outFile)
1715-
return outFile.takeError();
1716-
*outFile << sourceBuf;
1717-
if (auto err = outFile->keep())
1718-
return err;
1723+
SmallString<256> outputPath(
1724+
ScanCompilerInvocation.getFrontendOptions().ScannerOutputDir);
1725+
1726+
if (outputPath.empty())
1727+
outputPath = "/<compiler-generated>";
1728+
1729+
// Use the hash of the file content to differentiate the chained header.
1730+
auto fileHash =
1731+
llvm::toString(llvm::APInt(64, llvm::hash_value(chainedHeaderBuffer)),
1732+
36, /*Signed=*/false);
1733+
llvm::sys::path::append(
1734+
outputPath, ScanCompilerInvocation.getFrontendOptions().ModuleName +
1735+
"-" + fileHash + "-ChainedBridgingHeader.h");
1736+
1737+
if (ScanCompilerInvocation.getFrontendOptions().WriteScannerOutput) {
1738+
llvm::vfs::OnDiskOutputBackend outputBackend;
1739+
auto outFile = outputBackend.createFile(outputPath);
1740+
if (!outFile)
1741+
return outFile.takeError();
1742+
*outFile << chainedHeaderBuffer;
1743+
if (auto err = outFile->keep())
1744+
return err;
1745+
}
1746+
1747+
sourceBuffer =
1748+
llvm::MemoryBuffer::getMemBufferCopy(chainedHeaderBuffer, outputPath);
17191749
}
17201750

1721-
auto sourceBuffer =
1722-
llvm::MemoryBuffer::getMemBufferCopy(sourceBuf, outputPath);
17231751
// Scan and update the main module dependency.
1724-
auto mainModuleDeps = cache.findKnownDependency(rootModuleID);
17251752
ModuleDependencyIDSetVector headerClangModuleDependencies;
17261753
std::optional<std::string> includeTreeID;
17271754
auto err = withDependencyScanningWorker(
@@ -1740,7 +1767,8 @@ llvm::Error ModuleDependencyScanner::performBridgingHeaderChaining(
17401767

17411768
if (!headerScanResult)
17421769
return llvm::createStringError(
1743-
"failed to scan generated bridging header " + outputPath);
1770+
"failed to scan generated bridging header " +
1771+
sourceBuffer->getBufferIdentifier());
17441772

17451773
// Record module dependencies for each new module we found.
17461774
cache.recordClangDependencies(
@@ -1781,9 +1809,25 @@ llvm::Error ModuleDependencyScanner::performBridgingHeaderChaining(
17811809
}
17821810
mainModuleDeps.updateBridgingHeaderCommandLine(
17831811
bridgingHeaderCommandLine);
1812+
if (needChainedHeader) {
1813+
// As only the chained bridging header is scanned, the dependency will
1814+
// not include the original bridging header passed by user. Fixup the
1815+
// headerFileInputs to include original bridging header and not
1816+
// include the generated header so build system can correctly computes
1817+
// the dependencies.
1818+
auto generated =
1819+
llvm::find(headerFileInputs, sourceBuffer->getBufferIdentifier());
1820+
if (generated != headerFileInputs.end()) {
1821+
if (mainModule->textualModuleDetails.bridgingHeaderFile)
1822+
*generated = *mainModule->textualModuleDetails.bridgingHeaderFile;
1823+
else
1824+
headerFileInputs.erase(generated);
1825+
}
1826+
}
17841827
mainModuleDeps.setHeaderSourceFiles(headerFileInputs);
1785-
mainModuleDeps.setChainedBridgingHeaderBuffer(
1786-
outputPath, sourceBuffer->getBuffer());
1828+
if (needChainedHeader)
1829+
mainModuleDeps.setChainedBridgingHeaderBuffer(
1830+
sourceBuffer->getBufferIdentifier(), sourceBuffer->getBuffer());
17871831
// Update the set of visible Clang modules
17881832
mainModuleDeps.addVisibleClangModules(headerScanResult->VisibleModules);
17891833

lib/Serialization/ModuleFileSharedCore.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -675,9 +675,9 @@ class ModuleFileSharedCore {
675675
}
676676

677677
/// Get embedded bridging header.
678-
std::string getEmbeddedHeader() const {
678+
StringRef getEmbeddedHeader() const {
679679
// Don't include the '\0' in the end.
680-
return importedHeaderInfo.contents.drop_back().str();
680+
return importedHeaderInfo.contents.drop_back();
681681
}
682682

683683
/// If the module-defining `.swiftinterface` file is an SDK-relative path,

lib/Serialization/SerializedModuleLoader.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1492,8 +1492,9 @@ swift::extractUserModuleVersionFromInterface(StringRef moduleInterfacePath) {
14921492
return result;
14931493
}
14941494

1495-
std::string swift::extractEmbeddedBridgingHeaderContent(
1496-
std::unique_ptr<llvm::MemoryBuffer> file, ASTContext &Context) {
1495+
std::unique_ptr<llvm::MemoryBuffer> swift::extractEmbeddedBridgingHeaderContent(
1496+
std::unique_ptr<llvm::MemoryBuffer> file, StringRef headerPath,
1497+
ASTContext &Context) {
14971498
std::shared_ptr<const ModuleFileSharedCore> loadedModuleFile;
14981499
serialization::ValidationInfo loadInfo = ModuleFileSharedCore::load(
14991500
"", "", std::move(file), nullptr, nullptr, false,
@@ -1503,9 +1504,10 @@ std::string swift::extractEmbeddedBridgingHeaderContent(
15031504
loadedModuleFile);
15041505

15051506
if (loadInfo.status != serialization::Status::Valid)
1506-
return {};
1507+
return nullptr;;
15071508

1508-
return loadedModuleFile->getEmbeddedHeader();
1509+
return llvm::MemoryBuffer::getMemBufferCopy(
1510+
loadedModuleFile->getEmbeddedHeader(), headerPath);
15091511
}
15101512

15111513
bool SerializedModuleLoaderBase::canImportModule(

test/CAS/Inputs/BuildCommandExtractor.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ def printCmd(cmd):
3131
cmd = info["bridgingHeader"]["commandLine"][1:]
3232
printCmd(cmd)
3333
# print input file name.
34-
print(info["chainedBridgingHeaderPath"])
34+
if "chainedBridgingHeaderPath" in info:
35+
print(info["chainedBridgingHeaderPath"])
3536
else:
3637
module_names = deps["modules"][::2]
3738
module_details = deps["modules"][1::2]

test/CAS/Inputs/SwiftDepsExtractor.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,17 @@
1010
key = sys.argv[3]
1111

1212
mode = 'swift'
13+
is_bridging_header = False
1314

1415
if module_name.startswith('clang:'):
1516
mode = 'clang'
1617
module_name = module_name[6:]
1718
elif module_name.startswith('swiftPrebuiltExternal:'):
1819
mode = 'swiftPrebuiltExternal'
1920
module_name = module_name[22:]
21+
elif module_name.startswith('bridgingHeader:'):
22+
is_bridging_header = True
23+
module_name = module_name[15:]
2024

2125
with open(input_json, 'r') as file:
2226
deps = json.load(file)
@@ -30,5 +34,10 @@
3034
json.dump(detail[key], sys.stdout, indent=2)
3135
break
3236

37+
if is_bridging_header:
38+
json.dump(detail['details'][mode]['bridgingHeader']
39+
[key], sys.stdout, indent=2)
40+
break
41+
3342
json.dump(detail['details'][mode][key], sys.stdout, indent=2)
3443
break
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: split-file %s %t
3+
4+
/// Test prefix mapped bridging header path will result in the same cache key.
5+
6+
// RUN: %target-swift-frontend -scan-dependencies -module-name Test -module-cache-path %t/clang-module-cache -O \
7+
// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import \
8+
// RUN: %t/test.swift -o %t/deps-1.json -auto-bridging-header-chaining -cache-compile-job -cas-path %t/cas \
9+
// RUN: -scanner-prefix-map-paths %swift_src_root /^src -scanner-prefix-map-paths %t /^tmp \
10+
// RUN: -scanner-prefix-map-paths %t/header-1 /^header \
11+
// RUN: -scanner-output-dir %t/header-1 -import-objc-header %t/header-1/Bridging.h
12+
13+
// RUN: %target-swift-frontend -scan-dependencies -module-name Test -module-cache-path %t/clang-module-cache -O \
14+
// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import \
15+
// RUN: %t/test.swift -o %t/deps-2.json -auto-bridging-header-chaining -cache-compile-job -cas-path %t/cas \
16+
// RUN: -scanner-prefix-map-paths %swift_src_root /^src -scanner-prefix-map-paths %t /^tmp \
17+
// RUN: -scanner-prefix-map-paths %t/header-2 /^header \
18+
// RUN: -scanner-output-dir %t/header-2 -import-objc-header %t/header-2/Bridging.h
19+
20+
// RUN: %{python} %S/Inputs/SwiftDepsExtractor.py %t/deps-1.json bridgingHeader:Test includeTree > %t/includeTree-1.casid
21+
// RUN: %{python} %S/Inputs/SwiftDepsExtractor.py %t/deps-2.json bridgingHeader:Test includeTree > %t/includeTree-2.casid
22+
// RUN: diff %t/includeTree-1.casid %t/includeTree-2.casid
23+
24+
// RUN: %{python} %S/Inputs/SwiftDepsExtractor.py %t/deps-1.json Test casFSRootID > %t/root-1.casid
25+
// RUN: %{python} %S/Inputs/SwiftDepsExtractor.py %t/deps-2.json Test casFSRootID > %t/root-2.casid
26+
// RUN: diff %t/root-1.casid %t/root-2.casid
27+
28+
// RUN: %{python} %S/Inputs/BuildCommandExtractor.py %t/deps-1.json clang:SwiftShims > %t/shim.cmd
29+
// RUN: %swift_frontend_plain @%t/shim.cmd
30+
// RUN: %{python} %S/Inputs/BuildCommandExtractor.py %t/deps-1.json bridgingHeader > %t/header.cmd
31+
// RUN: %target-swift-frontend @%t/header.cmd /^header/Bridging.h -disable-implicit-swift-modules -O -o %t/bridging.pch
32+
// RUN: %cache-tool -cas-path %t/cas -cache-tool-action print-output-keys -- \
33+
// RUN: %target-swift-frontend @%t/header.cmd /^header/Bridging.h -disable-implicit-swift-modules -O -o %t/bridging.pch > %t/keys.json
34+
// RUN: %{python} %S/Inputs/ExtractOutputKey.py %t/keys.json > %t/key
35+
36+
// RUN: %{python} %S/Inputs/BuildCommandExtractor.py %t/deps-1.json Test > %t/MyApp.cmd
37+
// RUN: echo "\"-disable-implicit-string-processing-module-import\"" >> %t/MyApp.cmd
38+
// RUN: echo "\"-disable-implicit-concurrency-module-import\"" >> %t/MyApp.cmd
39+
// RUN: echo "\"-disable-implicit-swift-modules\"" >> %t/MyApp.cmd
40+
// RUN: echo "\"-import-objc-header\"" >> %t/MyApp.cmd
41+
// RUN: echo "\"/^header/Bridging.h\"" >> %t/MyApp.cmd
42+
// RUN: echo "\"-import-pch\"" >> %t/MyApp.cmd
43+
// RUN: echo "\"%t/bridging.pch\"" >> %t/MyApp.cmd
44+
// RUN: echo "\"-bridging-header-pch-key\"" >> %t/MyApp.cmd
45+
// RUN: echo "\"@%t/key\"" >> %t/MyApp.cmd
46+
// RUN: echo "\"-explicit-swift-module-map-file\"" >> %t/MyApp.cmd
47+
// RUN: echo "\"@%t/map.casid\"" >> %t/MyApp.cmd
48+
// RUN: %{python} %S/Inputs/GenerateExplicitModuleMap.py %t/deps-1.json > %t/map.json
49+
// RUN: llvm-cas --cas %t/cas --make-blob --data %t/map.json > %t/map.casid
50+
// RUN: %target-swift-frontend -cache-compile-job -module-name Test -O -cas-path %t/cas @%t/MyApp.cmd /^tmp/test.swift \
51+
// RUN: -emit-module -o %t/Test.swiftmodule
52+
53+
// RUN: %target-swift-frontend -scan-dependencies -module-name User -module-cache-path %t/clang-module-cache -O \
54+
// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import \
55+
// RUN: %t/user.swift -o %t/deps-3.json -auto-bridging-header-chaining -cache-compile-job -cas-path %t/cas \
56+
// RUN: -scanner-prefix-map-paths %swift_src_root /^src -scanner-prefix-map-paths %t /^tmp \
57+
// RUN: -scanner-prefix-map-paths %t/header-1 /^header \
58+
// RUN: -scanner-output-dir %t/header-1 -I %t
59+
60+
// RUN: %target-swift-frontend -scan-dependencies -module-name User -module-cache-path %t/clang-module-cache -O \
61+
// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import \
62+
// RUN: %t/user.swift -o %t/deps-4.json -auto-bridging-header-chaining -cache-compile-job -cas-path %t/cas \
63+
// RUN: -scanner-prefix-map-paths %swift_src_root /^src -scanner-prefix-map-paths %t /^tmp \
64+
// RUN: -scanner-prefix-map-paths %t/header-2 /^header \
65+
// RUN: -scanner-output-dir %t/header-2 -I %t
66+
67+
// RUN: %{python} %S/Inputs/SwiftDepsExtractor.py %t/deps-3.json bridgingHeader:Test includeTree > %t/includeTree-3.casid
68+
// RUN: %{python} %S/Inputs/SwiftDepsExtractor.py %t/deps-4.json bridgingHeader:Test includeTree > %t/includeTree-4.casid
69+
// RUN: diff %t/includeTree-3.casid %t/includeTree-4.casid
70+
71+
72+
73+
//--- test.swift
74+
public func test() {
75+
b()
76+
}
77+
78+
//--- user.swift
79+
import Test
80+
81+
//--- header-1/Bridging.h
82+
#include "Foo.h"
83+
//--- header-1/Foo.h
84+
void b(void);
85+
//--- header-2/Bridging.h
86+
#include "Foo.h"
87+
//--- header-2/Foo.h
88+
void b(void);

0 commit comments

Comments
 (0)