Skip to content

Commit 66c1f14

Browse files
committed
[Explicit Module Builds] Use a stable hash to encode build arguments into PCM filenames
When generating build jobs for explicit module dependencies, we must distinguish multiple versions of the same Clang module/pcm by encoding the arguments used to build it (e.g. target triple) into the pcm filename. So far, we have been using an unstable hash, which means that these filenames were not stable across invocations and were being needlessly re-built in some scenarios (e.g. many-target builds). Switching to a stable hash (SHA256 in this instance) ensures that the same Clang module, built with the same command line, will produce the same .pcm filename. This will allow the client build system (such as SwiftPM) to deduplicate identical compilation jobs because their output filenames will now also match.
1 parent a4b7055 commit 66c1f14

File tree

3 files changed

+24
-13
lines changed

3 files changed

+24
-13
lines changed

Sources/SwiftDriver/Explicit Module Builds/ExplicitDependencyBuildPlanner.swift

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -449,9 +449,18 @@ extension ExplicitDependencyBuildPlanner {
449449
/// is to be constructed with.
450450
public static func targetEncodedClangModuleName(for moduleName: String,
451451
pcmArgs: [String]) throws -> String {
452-
var hasher = Hasher()
453-
pcmArgs.forEach { hasher.combine($0) }
454-
return moduleName + String(hasher.finalize())
452+
let hashInput = pcmArgs.sorted().joined()
453+
let hashedArguments: String
454+
#if os(macOS)
455+
if #available(macOS 10.15, iOS 13, *) {
456+
hashedArguments = CryptoKitSHA256().hash(hashInput).hexadecimalRepresentation
457+
} else {
458+
hashedArguments = SHA256().hash(hashInput).hexadecimalRepresentation
459+
}
460+
#else
461+
hashedArguments = SHA256().hash(hashInput).hexadecimalRepresentation
462+
#endif
463+
return moduleName + hashedArguments
455464
}
456465
}
457466

Sources/SwiftDriver/Explicit Module Builds/PlaceholderDependencyResolution.swift

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -101,16 +101,10 @@ fileprivate extension InterModuleDependencyGraph {
101101
// For all dependencies of this placeholder (direct and transitive), insert them
102102
// into this module's graph.
103103
// - Swift dependencies are inserted as-is
104-
// - Clang dependencies, because PCM modules file names encode the specific pcmArguments
105-
// of their dependees, we cannot use pre-built files here because we do not always know
106-
// which target they corrspond to, nor do we have a way to map from a certain target to a
107-
// specific pcm file. Because of this, all PCM dependencies, direct and transitive, have to
108-
// be built for all modules. We merge moduleInfos of such dependencies with ones that are
109-
// already in the current graph, in order to obtain a super-set of their dependencies
110-
// at all possible PCMArgs variants.
111-
// FIXME: Implement a stable hash for generated .pcm filenames in order to be able to re-use
112-
// modules built by external dependencies here.
113-
104+
// - Clang dependencies are inserted as-is, if a matching Clang module is already found
105+
// in this module's graph, we merge moduleInfos of the two modules, in order to obtain
106+
// a super-set of their dependencies at all possible PCMArgs variants.
107+
//
114108
// The placeholder is resolved into a .swiftPrebuiltExternal module in the dependency graph.
115109
// The placeholder's corresponding module may appear in the externalModuleInfoMap as either
116110
// a .swift module or a .swiftPrebuiltExternal module if it had been resolved earlier

Sources/SwiftDriver/Incremental Compilation/BuildRecordInfo.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,15 @@ import SwiftOptions
6565
.map { $0.option.spelling }
6666
.sorted()
6767
.joined()
68+
#if os(macOS)
69+
if #available(macOS 10.15, iOS 13, *) {
70+
return CryptoKitSHA256().hash(hashInput).hexadecimalRepresentation
71+
} else {
72+
return SHA256().hash(hashInput).hexadecimalRepresentation
73+
}
74+
#else
6875
return SHA256().hash(hashInput).hexadecimalRepresentation
76+
#endif
6977
}
7078

7179
/// Determine the input and output path for the build record

0 commit comments

Comments
 (0)