From 66c1f14a3f3f12b8159fed22800b8b8efbc3f140 Mon Sep 17 00:00:00 2001 From: Artem Chikin Date: Wed, 11 Nov 2020 11:48:10 -0800 Subject: [PATCH] [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. --- .../ExplicitDependencyBuildPlanner.swift | 15 ++++++++++++--- .../PlaceholderDependencyResolution.swift | 14 ++++---------- .../Incremental Compilation/BuildRecordInfo.swift | 8 ++++++++ 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/Sources/SwiftDriver/Explicit Module Builds/ExplicitDependencyBuildPlanner.swift b/Sources/SwiftDriver/Explicit Module Builds/ExplicitDependencyBuildPlanner.swift index dbe1ce6bb..9271fd012 100644 --- a/Sources/SwiftDriver/Explicit Module Builds/ExplicitDependencyBuildPlanner.swift +++ b/Sources/SwiftDriver/Explicit Module Builds/ExplicitDependencyBuildPlanner.swift @@ -449,9 +449,18 @@ extension ExplicitDependencyBuildPlanner { /// is to be constructed with. public static func targetEncodedClangModuleName(for moduleName: String, pcmArgs: [String]) throws -> String { - var hasher = Hasher() - pcmArgs.forEach { hasher.combine($0) } - return moduleName + String(hasher.finalize()) + let hashInput = pcmArgs.sorted().joined() + let hashedArguments: String + #if os(macOS) + if #available(macOS 10.15, iOS 13, *) { + hashedArguments = CryptoKitSHA256().hash(hashInput).hexadecimalRepresentation + } else { + hashedArguments = SHA256().hash(hashInput).hexadecimalRepresentation + } + #else + hashedArguments = SHA256().hash(hashInput).hexadecimalRepresentation + #endif + return moduleName + hashedArguments } } diff --git a/Sources/SwiftDriver/Explicit Module Builds/PlaceholderDependencyResolution.swift b/Sources/SwiftDriver/Explicit Module Builds/PlaceholderDependencyResolution.swift index 869461d21..070f95c0b 100644 --- a/Sources/SwiftDriver/Explicit Module Builds/PlaceholderDependencyResolution.swift +++ b/Sources/SwiftDriver/Explicit Module Builds/PlaceholderDependencyResolution.swift @@ -101,16 +101,10 @@ fileprivate extension InterModuleDependencyGraph { // For all dependencies of this placeholder (direct and transitive), insert them // into this module's graph. // - Swift dependencies are inserted as-is - // - Clang dependencies, because PCM modules file names encode the specific pcmArguments - // of their dependees, we cannot use pre-built files here because we do not always know - // which target they corrspond to, nor do we have a way to map from a certain target to a - // specific pcm file. Because of this, all PCM dependencies, direct and transitive, have to - // be built for all modules. We merge moduleInfos of such dependencies with ones that are - // already in the current graph, in order to obtain a super-set of their dependencies - // at all possible PCMArgs variants. - // FIXME: Implement a stable hash for generated .pcm filenames in order to be able to re-use - // modules built by external dependencies here. - + // - Clang dependencies are inserted as-is, if a matching Clang module is already found + // in this module's graph, we merge moduleInfos of the two modules, in order to obtain + // a super-set of their dependencies at all possible PCMArgs variants. + // // The placeholder is resolved into a .swiftPrebuiltExternal module in the dependency graph. // The placeholder's corresponding module may appear in the externalModuleInfoMap as either // a .swift module or a .swiftPrebuiltExternal module if it had been resolved earlier diff --git a/Sources/SwiftDriver/Incremental Compilation/BuildRecordInfo.swift b/Sources/SwiftDriver/Incremental Compilation/BuildRecordInfo.swift index bca483b34..b25b18716 100644 --- a/Sources/SwiftDriver/Incremental Compilation/BuildRecordInfo.swift +++ b/Sources/SwiftDriver/Incremental Compilation/BuildRecordInfo.swift @@ -65,7 +65,15 @@ import SwiftOptions .map { $0.option.spelling } .sorted() .joined() + #if os(macOS) + if #available(macOS 10.15, iOS 13, *) { + return CryptoKitSHA256().hash(hashInput).hexadecimalRepresentation + } else { + return SHA256().hash(hashInput).hexadecimalRepresentation + } + #else return SHA256().hash(hashInput).hexadecimalRepresentation + #endif } /// Determine the input and output path for the build record