Skip to content

Commit

Permalink
Support Swift6
Browse files Browse the repository at this point in the history
  • Loading branch information
Ryu0118 committed Jul 10, 2024
1 parent 3baf5e1 commit 1bb3d13
Showing 1 changed file with 60 additions and 36 deletions.
96 changes: 60 additions & 36 deletions Sources/ScipioKit/DescriptionPackage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,52 @@ struct DescriptionPackage {
}

extension DescriptionPackage {
func resolveBuildProducts() throws -> [BuildProduct] {
let resolver = BuildProductsResolver(descriptionPackage: self)
return try resolver.resolveBuildProducts()
}
}

struct BuildProduct: Hashable, Sendable {
var package: ResolvedPackage
var target: ScipioResolvedModule

var frameworkName: String {
"\(target.name.packageNamed()).xcframework"
}

var binaryTarget: ScipioBinaryModule? {
target.underlying as? ScipioBinaryModule
}

func hash(into hasher: inout Hasher) {
// Important: Relevant for swift-6.0+ toolchain versions. For the versions below
// this change has no effect as SwiftPM provides its own proper `Hashable`
// implementations for both `ResolvedPackage` and `ResolvedTarget`.
//
// We cannot directly use `ResolvedModule.id` here as `id` also includes `BuildTriple`.
// The reason for this is that `ResolvedModule.buildTriple` is parent-dependent; more
// specifically, the same `ResolvedModule` will have a different build triple depending
// on whether it is in a root or dependency position.
// For more context, see `ResolvedModule.updateBuildTriplesOfDependencies`.
//
// At the same time, build triples remain irrelevant for the `Scipio` use case where the
// build product must be the same regardless of the triple. Meanwhile, the target name and
// package identity remain relevant and unambiguously identify the build product.
hasher.combine(target.name)
hasher.combine(package.identity)
}
}


private final class BuildProductsResolver {
private var buildProductsCache: [BuildProduct: Set<BuildProduct>] = [:]
let descriptionPackage: DescriptionPackage

init(descriptionPackage: DescriptionPackage) {
self.descriptionPackage = descriptionPackage
}

func resolveBuildProducts() throws -> [BuildProduct] {
let targetsToBuild = try targetsToBuild()
var products = try targetsToBuild.flatMap(resolveBuildProduct(from:))
Expand Down Expand Up @@ -181,7 +227,7 @@ extension DescriptionPackage {
}
} catch {
switch error {
case GraphError.unexpectedCycle: throw Error.cycleDetected
case GraphError.unexpectedCycle: throw DescriptionPackage.Error.cycleDetected
default: throw error
}
}
Expand All @@ -190,7 +236,7 @@ extension DescriptionPackage {
}

private func targetsToBuild() throws -> [ScipioResolvedModule] {
switch mode {
switch descriptionPackage.mode {
case .createPackage:
// In create mode, all products should be built
// In future update, users will be enable to specify products want to build
Expand All @@ -214,8 +260,8 @@ extension DescriptionPackage {
}

private func fetchRootPackage() throws -> ResolvedPackage {
guard let rootPackage = graph.rootPackages.first else {
throw Error.packageNotDefined
guard let rootPackage = descriptionPackage.graph.rootPackages.first else {
throw DescriptionPackage.Error.packageNotDefined
}
return rootPackage
}
Expand All @@ -229,7 +275,7 @@ extension DescriptionPackage {
.flatMap(buildProducts(from:)))
#endif

switch mode {
switch descriptionPackage.mode {
case .createPackage:
// In create mode, rootTarget should be built
let rootTargetProducts = try buildProducts(from: rootTarget)
Expand All @@ -241,47 +287,25 @@ extension DescriptionPackage {
}

private func buildProducts(from target: ScipioResolvedModule) throws -> Set<BuildProduct> {
guard let package = graph.package(for: target) else {
guard let package = descriptionPackage.graph.package(for: target) else {
return []
}

let rootTargetProduct = BuildProduct(package: package, target: target)

if let buildProducts = buildProductsCache[rootTargetProduct] {
return buildProducts
}

#if compiler(>=6.0)
let dependencyProducts = try target.recursiveDependencies().compactMap(\.module).flatMap(buildProducts(from:))
#else
let dependencyProducts = try target.recursiveDependencies().compactMap(\.target).flatMap(buildProducts(from:))
#endif
return Set([rootTargetProduct] + dependencyProducts)
}
}

struct BuildProduct: Hashable, Sendable {
var package: ResolvedPackage
var target: ScipioResolvedModule

var frameworkName: String {
"\(target.name.packageNamed()).xcframework"
}
let buildProducts = Set([rootTargetProduct] + dependencyProducts)
buildProductsCache.updateValue(buildProducts, forKey: rootTargetProduct)

var binaryTarget: ScipioBinaryModule? {
target.underlying as? ScipioBinaryModule
}

func hash(into hasher: inout Hasher) {
// Important: Relevant for swift-6.0+ toolchain versions. For the versions below
// this change has no effect as SwiftPM provides its own proper `Hashable`
// implementations for both `ResolvedPackage` and `ResolvedTarget`.
//
// We cannot directly use `ResolvedModule.id` here as `id` also includes `BuildTriple`.
// The reason for this is that `ResolvedModule.buildTriple` is parent-dependent; more
// specifically, the same `ResolvedModule` will have a different build triple depending
// on whether it is in a root or dependency position.
// For more context, see `ResolvedModule.updateBuildTriplesOfDependencies`.
//
// At the same time, build triples remain irrelevant for the `Scipio` use case where the
// build product must be the same regardless of the triple. Meanwhile, the target name and
// package identity remain relevant and unambiguously identify the build product.
hasher.combine(target.name)
hasher.combine(package.identity)
return buildProducts
}
}

0 comments on commit 1bb3d13

Please sign in to comment.