From 113fb3b0f12a6eaedb8d3ccb9531077b3f0c0980 Mon Sep 17 00:00:00 2001 From: Val Date: Wed, 1 Sep 2021 10:58:29 +0700 Subject: [PATCH 1/9] Specify kotlin version 1.5.30 --- build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 3d2a78e..d65adff 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -24,12 +24,12 @@ repositories { } dependencies { - compileOnly(kotlin("gradle-plugin")) + compileOnly(kotlin("gradle-plugin", "1.5.30")) testImplementation("io.kotest:kotest-runner-junit5:4.3.0") testImplementation("io.kotest:kotest-assertions-core:4.3.0") testImplementation("io.kotest:kotest-property:4.3.0") testImplementation("io.mockk:mockk:1.10.0") - testImplementation(kotlin("gradle-plugin")) + testImplementation(kotlin("gradle-plugin", "1.5.30")) } java { From 9b8c91983d3b7d38854cd45a685904517f5273e6 Mon Sep 17 00:00:00 2001 From: Val Date: Thu, 2 Sep 2021 20:48:37 +0700 Subject: [PATCH 2/9] Support arm simulator targets --- .../domain/TargetName.kt | 6 ++- .../domain/extensions.kt | 4 ++ .../dsl/TargetPlatformDsl.kt | 43 ++++++++++++++----- 3 files changed, 42 insertions(+), 11 deletions(-) diff --git a/src/main/kotlin/com/chromaticnoise/multiplatformswiftpackage/domain/TargetName.kt b/src/main/kotlin/com/chromaticnoise/multiplatformswiftpackage/domain/TargetName.kt index 8b61a88..f5a6a1e 100644 --- a/src/main/kotlin/com/chromaticnoise/multiplatformswiftpackage/domain/TargetName.kt +++ b/src/main/kotlin/com/chromaticnoise/multiplatformswiftpackage/domain/TargetName.kt @@ -3,13 +3,17 @@ package com.chromaticnoise.multiplatformswiftpackage.domain internal enum class TargetName(val identifier: String) { IOSarm64("iosArm64"), IOSx64("iosX64"), + IOSSimulatorArm64("iosSimulatorArm64"), WatchOSarm32("watchosArm32"), WatchOSarm64("watchosArm64"), WatchOSx86("watchosX86"), WatchOSx64("watchosX64"), + WatchOSSimulatorArm64("watchosSimulatorArm64"), TvOSarm64("tvosArm64"), TvOSx64("tvosX64"), - MacOSx64("macosX64"); + TvOSSimulatorArm64("tvosSimulatorArm64"), + MacOSx64("macosX64"), + MacOSArm64("macosArm64"); internal companion object { private val map = values().associateBy(TargetName::identifier) diff --git a/src/main/kotlin/com/chromaticnoise/multiplatformswiftpackage/domain/extensions.kt b/src/main/kotlin/com/chromaticnoise/multiplatformswiftpackage/domain/extensions.kt index 89d82a0..8764362 100644 --- a/src/main/kotlin/com/chromaticnoise/multiplatformswiftpackage/domain/extensions.kt +++ b/src/main/kotlin/com/chromaticnoise/multiplatformswiftpackage/domain/extensions.kt @@ -20,11 +20,15 @@ internal val Collection KonanTarget.IOS_ARM64 TargetName.IOSx64 -> KonanTarget.IOS_X64 + TargetName.IOSSimulatorArm64 -> KonanTarget.IOS_SIMULATOR_ARM64 TargetName.WatchOSarm32 -> KonanTarget.WATCHOS_ARM32 TargetName.WatchOSarm64 -> KonanTarget.WATCHOS_ARM64 TargetName.WatchOSx86 -> KonanTarget.WATCHOS_X86 TargetName.WatchOSx64 -> KonanTarget.WATCHOS_X64 + TargetName.WatchOSSimulatorArm64 -> KonanTarget.WATCHOS_SIMULATOR_ARM64 TargetName.TvOSarm64 -> KonanTarget.TVOS_ARM64 TargetName.TvOSx64 -> KonanTarget.TVOS_X64 + TargetName.TvOSSimulatorArm64 -> KonanTarget.TVOS_SIMULATOR_ARM64 TargetName.MacOSx64 -> KonanTarget.MACOS_X64 + TargetName.MacOSArm64 -> KonanTarget.MACOS_ARM64 } diff --git a/src/main/kotlin/com/chromaticnoise/multiplatformswiftpackage/dsl/TargetPlatformDsl.kt b/src/main/kotlin/com/chromaticnoise/multiplatformswiftpackage/dsl/TargetPlatformDsl.kt index ab846c8..5faaff0 100644 --- a/src/main/kotlin/com/chromaticnoise/multiplatformswiftpackage/dsl/TargetPlatformDsl.kt +++ b/src/main/kotlin/com/chromaticnoise/multiplatformswiftpackage/dsl/TargetPlatformDsl.kt @@ -10,8 +10,8 @@ import groovy.lang.Closure import org.gradle.util.ConfigureUtil /** -* DSL to create instances of [TargetPlatform]. -*/ + * DSL to create instances of [TargetPlatform]. + */ public class TargetPlatformDsl { internal var targetPlatforms = mutableListOf, TargetPlatform>>() @@ -21,7 +21,14 @@ public class TargetPlatformDsl { * @param version builder for an instance of [PlatformVersion] */ public fun iOS(version: PlatformVersionDsl.() -> Unit) { - targetsInternal(listOf(Either.Right(TargetName.IOSarm64), Either.Right(TargetName.IOSx64)), version) + targetsInternal( + listOf( + Either.Right(TargetName.IOSarm64), + Either.Right(TargetName.IOSx64), + Either.Right(TargetName.IOSSimulatorArm64) + ), + version + ) } public fun iOS(version: Closure) { @@ -34,11 +41,14 @@ public class TargetPlatformDsl { * @param version builder for an instance of [PlatformVersion] */ public fun watchOS(version: PlatformVersionDsl.() -> Unit) { - targetsInternal(listOf( - Either.Right(TargetName.WatchOSarm32), - Either.Right(TargetName.WatchOSarm64), - Either.Right(TargetName.WatchOSx86), - Either.Right(TargetName.WatchOSx64)), + targetsInternal( + listOf( + Either.Right(TargetName.WatchOSarm32), + Either.Right(TargetName.WatchOSarm64), + Either.Right(TargetName.WatchOSx86), + Either.Right(TargetName.WatchOSx64), + Either.Right(TargetName.WatchOSSimulatorArm64) + ), version ) } @@ -53,7 +63,14 @@ public class TargetPlatformDsl { * @param version builder for an instance of [PlatformVersion] */ public fun tvOS(version: PlatformVersionDsl.() -> Unit) { - targetsInternal(listOf(Either.Right(TargetName.TvOSarm64), Either.Right(TargetName.TvOSx64)), version) + targetsInternal( + listOf( + Either.Right(TargetName.TvOSarm64), + Either.Right(TargetName.TvOSx64), + Either.Right(TargetName.TvOSSimulatorArm64) + ), + version + ) } public fun tvOS(version: Closure) { @@ -66,7 +83,13 @@ public class TargetPlatformDsl { * @param version builder for an instance of [PlatformVersion] */ public fun macOS(version: PlatformVersionDsl.() -> Unit) { - targetsInternal(listOf(Either.Right(TargetName.MacOSx64)), version) + targetsInternal( + listOf( + Either.Right(TargetName.MacOSx64), + Either.Right(TargetName.MacOSArm64) + ), + version + ) } public fun macOS(version: Closure) { From 315300c1b35fdf9fbb1da9f1f0a521bc577acd9f Mon Sep 17 00:00:00 2001 From: Val Date: Thu, 2 Sep 2021 20:48:53 +0700 Subject: [PATCH 3/9] Add tests for arm simulator targets --- .../dsl/TargetPlatformDslTest.kt | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/test/kotlin/com/chromaticnoise/multiplatformswiftpackage/dsl/TargetPlatformDslTest.kt b/src/test/kotlin/com/chromaticnoise/multiplatformswiftpackage/dsl/TargetPlatformDslTest.kt index 9f01774..fba47ce 100644 --- a/src/test/kotlin/com/chromaticnoise/multiplatformswiftpackage/dsl/TargetPlatformDslTest.kt +++ b/src/test/kotlin/com/chromaticnoise/multiplatformswiftpackage/dsl/TargetPlatformDslTest.kt @@ -25,6 +25,11 @@ class TargetPlatformDslTest : StringSpec() { .shouldHaveTarget("iosX64") } + "adding ios targets should add arm 64 simulator target" { + TargetPlatformDsl().apply { iOS(someVersion) }.targetPlatforms + .shouldHaveTarget("iosSimulatorArm64") + } + "adding watchOS targets should add arm 32 target" { TargetPlatformDsl().apply { watchOS(someVersion) }.targetPlatforms .shouldHaveTarget("watchosArm32") @@ -40,6 +45,11 @@ class TargetPlatformDslTest : StringSpec() { .shouldHaveTarget("watchosX86") } + "adding watchOS targets should add arm 64 simulator target" { + TargetPlatformDsl().apply { watchOS(someVersion) }.targetPlatforms + .shouldHaveTarget("watchosSimulatorArm64") + } + "adding tvOS targets should add arm 64 target" { TargetPlatformDsl().apply { tvOS(someVersion) }.targetPlatforms .shouldHaveTarget("tvosArm64") @@ -50,11 +60,21 @@ class TargetPlatformDslTest : StringSpec() { .shouldHaveTarget("tvosX64") } + "adding tvOS targets should add arm 64 simulator target" { + TargetPlatformDsl().apply { tvOS(someVersion) }.targetPlatforms + .shouldHaveTarget("tvosSimulatorArm64") + } + "adding macOS targets should add x64 target" { TargetPlatformDsl().apply { macOS(someVersion) }.targetPlatforms .shouldHaveTarget("macosX64") } + "adding macOS targets should add arm 64 target" { + TargetPlatformDsl().apply { macOS(someVersion) }.targetPlatforms + .shouldHaveTarget("macosArm64") + } + "adding target without names should not add a platform target" { TargetPlatformDsl().apply { targets(version = someVersion) }.targetPlatforms .shouldBeEmpty() From 00b2b6f127c7b5e460249250629bf61dd38d58ea Mon Sep 17 00:00:00 2001 From: Luca Spinazzola Date: Fri, 29 Apr 2022 00:09:35 -0400 Subject: [PATCH 4/9] desktop (arm64, x64, and x86) binaries need to be packed in a fat framworks building XCFramworks --- api/multiplatform-swiftpackage.api | 1 - build.gradle.kts | 17 +- gradle/wrapper/gradle-wrapper.properties | 2 +- .../MultiplatformSwiftPackagePlugin.kt | 6 + .../domain/AppleFramework.kt | 7 +- .../task/CreateXCFrameworkTask.kt | 209 +++++++++++++++++- .../domain/PluginConfigurationTest.kt | 2 +- 7 files changed, 226 insertions(+), 18 deletions(-) diff --git a/api/multiplatform-swiftpackage.api b/api/multiplatform-swiftpackage.api index e806c27..1e366cc 100644 --- a/api/multiplatform-swiftpackage.api +++ b/api/multiplatform-swiftpackage.api @@ -1,5 +1,4 @@ public final class com/chromaticnoise/multiplatformswiftpackage/MultiplatformSwiftPackagePlugin : org/gradle/api/Plugin { - public static final field Companion Lcom/chromaticnoise/multiplatformswiftpackage/MultiplatformSwiftPackagePlugin$Companion; public fun ()V public synthetic fun apply (Ljava/lang/Object;)V public fun apply (Lorg/gradle/api/Project;)V diff --git a/build.gradle.kts b/build.gradle.kts index d65adff..20630ae 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,10 +1,9 @@ buildscript { repositories { mavenCentral() - jcenter() } dependencies { - classpath("org.jetbrains.kotlinx:binary-compatibility-validator:0.2.4") + classpath("org.jetbrains.kotlinx:binary-compatibility-validator:0.9.0") } } @@ -20,16 +19,16 @@ plugins { version = "2.0.3" repositories { - jcenter() + mavenCentral() } dependencies { - compileOnly(kotlin("gradle-plugin", "1.5.30")) - testImplementation("io.kotest:kotest-runner-junit5:4.3.0") - testImplementation("io.kotest:kotest-assertions-core:4.3.0") - testImplementation("io.kotest:kotest-property:4.3.0") - testImplementation("io.mockk:mockk:1.10.0") - testImplementation(kotlin("gradle-plugin", "1.5.30")) + compileOnly(kotlin("gradle-plugin", "1.6.21")) + testImplementation("io.kotest:kotest-runner-junit5:5.2.3") + testImplementation("io.kotest:kotest-assertions-core:5.2.3") + testImplementation("io.kotest:kotest-property:5.2.3") + testImplementation("io.mockk:mockk:1.12.3") + testImplementation(kotlin("gradle-plugin", "1.6.21")) } java { diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 4d9ca16..aa991fc 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/src/main/kotlin/com/chromaticnoise/multiplatformswiftpackage/MultiplatformSwiftPackagePlugin.kt b/src/main/kotlin/com/chromaticnoise/multiplatformswiftpackage/MultiplatformSwiftPackagePlugin.kt index 01c7919..e56a58c 100644 --- a/src/main/kotlin/com/chromaticnoise/multiplatformswiftpackage/MultiplatformSwiftPackagePlugin.kt +++ b/src/main/kotlin/com/chromaticnoise/multiplatformswiftpackage/MultiplatformSwiftPackagePlugin.kt @@ -2,7 +2,9 @@ package com.chromaticnoise.multiplatformswiftpackage import com.chromaticnoise.multiplatformswiftpackage.domain.AppleTarget import com.chromaticnoise.multiplatformswiftpackage.domain.platforms +import com.chromaticnoise.multiplatformswiftpackage.task.* import com.chromaticnoise.multiplatformswiftpackage.task.registerCreateSwiftPackageTask +import com.chromaticnoise.multiplatformswiftpackage.task.registerCreateUniversalIosSimulatorFrameworkTask import com.chromaticnoise.multiplatformswiftpackage.task.registerCreateXCFrameworkTask import com.chromaticnoise.multiplatformswiftpackage.task.registerCreateZipFileTask import org.gradle.api.Plugin @@ -25,6 +27,10 @@ public class MultiplatformSwiftPackagePlugin : Plugin { nativeTargets = kmpExtension.targets.toList(), platforms = extension.targetPlatforms.platforms ) + project.registerCreateUniversalMacosFrameworkTask() + project.registerCreateUniversalIosSimulatorFrameworkTask() + project.registerCreateUniversalWatchosSimulatorFrameworkTask() + project.registerCreateUniversalTvosSimulatorFrameworkTask() project.registerCreateXCFrameworkTask() project.registerCreateZipFileTask() project.registerCreateSwiftPackageTask() diff --git a/src/main/kotlin/com/chromaticnoise/multiplatformswiftpackage/domain/AppleFramework.kt b/src/main/kotlin/com/chromaticnoise/multiplatformswiftpackage/domain/AppleFramework.kt index 07a34f5..a9d8584 100644 --- a/src/main/kotlin/com/chromaticnoise/multiplatformswiftpackage/domain/AppleFramework.kt +++ b/src/main/kotlin/com/chromaticnoise/multiplatformswiftpackage/domain/AppleFramework.kt @@ -1,12 +1,14 @@ package com.chromaticnoise.multiplatformswiftpackage.domain +import org.jetbrains.kotlin.gradle.plugin.mpp.Framework import org.jetbrains.kotlin.gradle.plugin.mpp.NativeBinary import java.io.File internal class AppleFramework( val outputFile: AppleFrameworkOutputFile, val name: AppleFrameworkName, - val linkTask: AppleFrameworkLinkTask + val linkTask: AppleFrameworkLinkTask, + val framework: Framework? = null ) { val dsymFile: File get() = File(outputFile.parent, "${name.value}.framework.dSYM") @@ -18,7 +20,8 @@ internal fun AppleFramework.Companion.of(binary: NativeBinary?): AppleFramework? AppleFramework( AppleFrameworkOutputFile(it.outputFile), AppleFrameworkName(it.baseName), - AppleFrameworkLinkTask(it.linkTaskName) + AppleFrameworkLinkTask(it.linkTaskName), + binary as Framework ) } diff --git a/src/main/kotlin/com/chromaticnoise/multiplatformswiftpackage/task/CreateXCFrameworkTask.kt b/src/main/kotlin/com/chromaticnoise/multiplatformswiftpackage/task/CreateXCFrameworkTask.kt index e2a7e42..45b435a 100644 --- a/src/main/kotlin/com/chromaticnoise/multiplatformswiftpackage/task/CreateXCFrameworkTask.kt +++ b/src/main/kotlin/com/chromaticnoise/multiplatformswiftpackage/task/CreateXCFrameworkTask.kt @@ -1,32 +1,233 @@ package com.chromaticnoise.multiplatformswiftpackage.task +import com.chromaticnoise.multiplatformswiftpackage.domain.* +import com.chromaticnoise.multiplatformswiftpackage.domain.PluginConfiguration import com.chromaticnoise.multiplatformswiftpackage.domain.getConfigurationOrThrow import org.gradle.api.Project import org.gradle.api.tasks.Exec +import org.gradle.kotlin.dsl.task +import org.jetbrains.kotlin.gradle.tasks.FatFrameworkTask import java.io.File + +internal fun getMacosFrameworks(configuration: PluginConfiguration): List { + return configuration.appleTargets.mapNotNull { it.getFramework(configuration.buildConfiguration) } + .filter { + it.linkTask.name.contains("MacosX64") || it.linkTask.name.contains("MacosArm64") + } +} + +internal fun getIosSimulatorFrameworks(configuration: PluginConfiguration): List { + return configuration.appleTargets.mapNotNull { it.getFramework(configuration.buildConfiguration) } + .filter { + it.linkTask.name.contains("IosX64") || it.linkTask.name.contains("IosSimulatorArm64") + } +} + +internal fun getWatchosSimulatorFrameworks(configuration: PluginConfiguration): List { + return configuration.appleTargets.mapNotNull { it.getFramework(configuration.buildConfiguration) } + .filter { + it.linkTask.name.contains("watchosX86") + || it.linkTask.name.contains("watchosX64") + || it.linkTask.name.contains("watchosSimulatorArm64") + } +} + +internal fun getTvosSimulatorFrameworks(configuration: PluginConfiguration): List { + return configuration.appleTargets.mapNotNull { it.getFramework(configuration.buildConfiguration) } + .filter { + it.linkTask.name.contains("tvosX64") || it.linkTask.name.contains("tvosSimulatorArm64") + } +} + +internal fun Project.registerCreateUniversalMacosFrameworkTask() = + task("createUniversalMacosFramework") { + // Can't use FatFrameworkTask 🙃 + // https://youtrack.jetbrains.com/issue/KT-47355/Support-macos-target-for-FatFramework-task + // workaround: + // https://gist.github.com/JUSTINMKAUFMAN/6627c3c8571563b36efc9c832f6fa2b1 + group = "multiplatform-swift-package" + description = "Creates a universal (fat) macos framework" + val configuration = getConfigurationOrThrow() + onlyIf{ getMacosFrameworks(configuration).size > 1 } + val targets = getMacosFrameworks(configuration) + dependsOn(targets.map { it.linkTask.name }) + doLast { + if (targets.isNotEmpty()) { + delete(buildDir.resolve("bin/macosUniversal")) + val buildType = if (targets[0].linkTask.name.contains("Release")) "release" else "debug" + val frameworkName = targets[0].name.value + val destinationDir = buildDir.resolve("bin/macosUniversal/${buildType}Framework") + mkdir(destinationDir.parent) + mkdir(destinationDir) + val tempUniversalBinaryLocation = File(destinationDir, frameworkName) + exec { + commandLine( + "lipo", + "-create", + "${targets[0].outputFile.path}/Versions/A/${frameworkName}", + "${targets[1].outputFile.path}/Versions/A/${frameworkName}", + "-output", + tempUniversalBinaryLocation.path + ) + } + val aFramework = targets[0].outputFile.path + copy { + from(aFramework) + into(File(destinationDir, "$frameworkName.framework")) + } + // delete the old mono framework binary we copied here + val binaryFinalLocation = File(destinationDir, "${frameworkName}.framework/Versions/A/$frameworkName") + val binaryFinalSymlinkLocation = File(destinationDir, "${frameworkName}.framework/$frameworkName") + delete(binaryFinalLocation) + delete(binaryFinalSymlinkLocation) + // copy new universal binary to binaryFinalSymlinkLocation + copy { + from(tempUniversalBinaryLocation) + into(File(destinationDir, "$frameworkName.framework/Versions/A")) + } + delete(tempUniversalBinaryLocation) + exec { + //recreate the symlink normally to the binary normally in framework folder + commandLine( + "ln", + "-s", + binaryFinalLocation.toPath(), + binaryFinalSymlinkLocation.toPath() + ) + } + } + } + } + +internal fun Project.registerCreateUniversalIosSimulatorFrameworkTask() = + task("createUniversalIosSimulatorFramework") { + group = "multiplatform-swift-package" + description = "Creates a universal (fat) ios simulator framework" + val configuration = getConfigurationOrThrow() + onlyIf{ getIosSimulatorFrameworks(configuration).size > 1 } + val targets = getIosSimulatorFrameworks(configuration) + dependsOn(targets.map { it.linkTask.name }) + if (targets.isNotEmpty()) { + val buildType = if (targets[0].linkTask.name.contains("Release")) "release" else "debug" + destinationDir = buildDir.resolve("bin/iosSimulatorUniversal/${buildType}Framework") + from(targets.map { it.framework!! } ) + } + } + +internal fun Project.registerCreateUniversalWatchosSimulatorFrameworkTask() = + tasks.register("createUniversalWatchosSimulatorFramework", FatFrameworkTask::class.java) { + group = "multiplatform-swift-package" + description = "Creates a universal (fat) watchos simulator framework" + val configuration = getConfigurationOrThrow() + onlyIf{ getWatchosSimulatorFrameworks(configuration).size > 1 } + val targets = getWatchosSimulatorFrameworks(configuration) + dependsOn(targets.map { it.linkTask.name }) + if (targets.isNotEmpty()) { + val buildType = if (targets[0].linkTask.name.contains("Release")) "release" else "debug" + destinationDir = buildDir.resolve("bin/watchosSimulatorUniversal/$buildType") + from(targets.map { it.framework!! }) + } + } + +internal fun Project.registerCreateUniversalTvosSimulatorFrameworkTask() = + tasks.register("createUniversalTvosSimulatorFramework", FatFrameworkTask::class.java) { + group = "multiplatform-swift-package" + description = "Creates a universal (fat) tvos simulator framework" + val configuration = getConfigurationOrThrow() + onlyIf{ getTvosSimulatorFrameworks(configuration).size > 1 } + val targets = getTvosSimulatorFrameworks(configuration) + dependsOn(targets.map { it.linkTask.name }) + if (targets.isNotEmpty()) { + val buildType = if (targets[0].linkTask.name.contains("Release")) "release" else "debug" + destinationDir = buildDir.resolve("bin/tvosSimulatorUniversal/$buildType") + from(targets.map { it.framework!! }) + } + } + + +internal fun removeMonoFrameworksAndAddUniversalFrameworkIfNeeded( + binFolderPrefix: String, + buildDir: File, + monoFrameworks: List, + outputFrameworks: MutableList) +{ + if (monoFrameworks.size > 1){ + monoFrameworks.forEach { mono -> + outputFrameworks.removeIf{ mono.outputFile == it.outputFile} + } + val frameworkName = monoFrameworks[0].name + val buildType = if (monoFrameworks[0].linkTask.name.contains("Release")) "release" else "debug" + val destinationDir = buildDir.resolve("bin/${binFolderPrefix}Universal/${buildType}Framework") + val outputFile = AppleFrameworkOutputFile(File(destinationDir ,"${frameworkName.value}.framework")) + outputFrameworks.add( + AppleFramework( + outputFile, + frameworkName, + AppleFrameworkLinkTask("") + ) + ) + } +} + + + internal fun Project.registerCreateXCFrameworkTask() = tasks.register("createXCFramework", Exec::class.java) { group = "multiplatform-swift-package" description = "Creates an XCFramework for all declared Apple targets" val configuration = getConfigurationOrThrow() val xcFrameworkDestination = File(configuration.outputDirectory.value, "${configuration.packageName.value}.xcframework") - val frameworks = configuration.appleTargets.mapNotNull { it.getFramework(configuration.buildConfiguration) } + val outputFrameworks = configuration.appleTargets.mapNotNull { it.getFramework(configuration.buildConfiguration) }.toMutableList() + + dependsOn(outputFrameworks.map { it.linkTask.name }) + dependsOn("createUniversalMacosFramework") + dependsOn("createUniversalIosSimulatorFramework") + dependsOn("createUniversalWatchosSimulatorFramework") + dependsOn("createUniversalTvosSimulatorFramework") + + val macosFrameworks = getMacosFrameworks(configuration) + removeMonoFrameworksAndAddUniversalFrameworkIfNeeded( + "macos", + buildDir, + macosFrameworks, + outputFrameworks + ) + val iosSimulatorFrameworks = getIosSimulatorFrameworks(configuration) + removeMonoFrameworksAndAddUniversalFrameworkIfNeeded( + "iosSimulator", + buildDir, + iosSimulatorFrameworks, + outputFrameworks + ) + val watchosSimulatorFrameworks = getWatchosSimulatorFrameworks(configuration) + removeMonoFrameworksAndAddUniversalFrameworkIfNeeded( + "watchosSimulator", + buildDir, + watchosSimulatorFrameworks, + outputFrameworks + ) + val tvosSimulatorFrameworks = getTvosSimulatorFrameworks(configuration) + removeMonoFrameworksAndAddUniversalFrameworkIfNeeded( + "tvosSimulator", + buildDir, + tvosSimulatorFrameworks, + outputFrameworks + ) - dependsOn(frameworks.map { it.linkTask.name }) executable = "xcodebuild" args(mutableListOf().apply { add("-create-xcframework") add("-output") add(xcFrameworkDestination.path) - frameworks.forEach { framework -> + outputFrameworks.forEach { framework -> add("-framework") add(framework.outputFile.path) framework.dsymFile.takeIf { it.exists() }?.let { dsymFile -> add("-debug-symbols") - add(dsymFile.path) + add(dsymFile.absolutePath) } } }) diff --git a/src/test/kotlin/com/chromaticnoise/multiplatformswiftpackage/domain/PluginConfigurationTest.kt b/src/test/kotlin/com/chromaticnoise/multiplatformswiftpackage/domain/PluginConfigurationTest.kt index 340a86b..ca3291b 100644 --- a/src/test/kotlin/com/chromaticnoise/multiplatformswiftpackage/domain/PluginConfigurationTest.kt +++ b/src/test/kotlin/com/chromaticnoise/multiplatformswiftpackage/domain/PluginConfigurationTest.kt @@ -95,7 +95,7 @@ class PluginConfigurationTest : BehaviorSpec() { private lateinit var project: Project - override fun beforeTest(testCase: TestCase) { + override suspend fun beforeTest(testCase: TestCase) { project = mockk(relaxed = true) { every { projectDir } returns File("") } From cd63a7f87fb283357ce1df2847cf59b63e5e0d31 Mon Sep 17 00:00:00 2001 From: Luca Spinazzola Date: Sat, 30 Apr 2022 14:00:24 -0400 Subject: [PATCH 5/9] Duplicate workaround https://github.com/gradle/gradle/issues/17236 Entry META-INF/gradle-plugins/com.chromaticnoise.multiplatform-swiftpackage.properties is a duplicate but no duplicate handling strategy has been set. --- build.gradle.kts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/build.gradle.kts b/build.gradle.kts index 20630ae..5f93b26 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -43,6 +43,11 @@ tasks.withType { useJUnitPlatform() } +project.tasks.named("processResources", Copy::class.java) { + // https://github.com/gradle/gradle/issues/17236 + duplicatesStrategy = DuplicatesStrategy.INCLUDE +} + extensions.findByName("buildScan")?.withGroovyBuilder { setProperty("termsOfServiceUrl", "https://gradle.com/terms-of-service") setProperty("termsOfServiceAgree", "yes") From dbf3d5c87140a8b9d9f53d5c01e4a6c1054faa0f Mon Sep 17 00:00:00 2001 From: Luca Spinazzola Date: Sat, 30 Apr 2022 14:04:39 -0400 Subject: [PATCH 6/9] use mapNotNull --- .../multiplatformswiftpackage/task/CreateXCFrameworkTask.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/com/chromaticnoise/multiplatformswiftpackage/task/CreateXCFrameworkTask.kt b/src/main/kotlin/com/chromaticnoise/multiplatformswiftpackage/task/CreateXCFrameworkTask.kt index 45b435a..a09663b 100644 --- a/src/main/kotlin/com/chromaticnoise/multiplatformswiftpackage/task/CreateXCFrameworkTask.kt +++ b/src/main/kotlin/com/chromaticnoise/multiplatformswiftpackage/task/CreateXCFrameworkTask.kt @@ -111,7 +111,7 @@ internal fun Project.registerCreateUniversalIosSimulatorFrameworkTask() = if (targets.isNotEmpty()) { val buildType = if (targets[0].linkTask.name.contains("Release")) "release" else "debug" destinationDir = buildDir.resolve("bin/iosSimulatorUniversal/${buildType}Framework") - from(targets.map { it.framework!! } ) + from(targets.mapNotNull { it.framework } ) } } @@ -126,7 +126,7 @@ internal fun Project.registerCreateUniversalWatchosSimulatorFrameworkTask() = if (targets.isNotEmpty()) { val buildType = if (targets[0].linkTask.name.contains("Release")) "release" else "debug" destinationDir = buildDir.resolve("bin/watchosSimulatorUniversal/$buildType") - from(targets.map { it.framework!! }) + from(targets.mapNotNull { it.framework }) } } @@ -141,7 +141,7 @@ internal fun Project.registerCreateUniversalTvosSimulatorFrameworkTask() = if (targets.isNotEmpty()) { val buildType = if (targets[0].linkTask.name.contains("Release")) "release" else "debug" destinationDir = buildDir.resolve("bin/tvosSimulatorUniversal/$buildType") - from(targets.map { it.framework!! }) + from(targets.mapNotNull { it.framework }) } } From ab93bed017e48e12ab34e88f1dc2f83d1eb998a8 Mon Sep 17 00:00:00 2001 From: Luca Spinazzola Date: Sat, 30 Apr 2022 14:19:59 -0400 Subject: [PATCH 7/9] format code --- .../task/CreateXCFrameworkTask.kt | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/main/kotlin/com/chromaticnoise/multiplatformswiftpackage/task/CreateXCFrameworkTask.kt b/src/main/kotlin/com/chromaticnoise/multiplatformswiftpackage/task/CreateXCFrameworkTask.kt index a09663b..563f78d 100644 --- a/src/main/kotlin/com/chromaticnoise/multiplatformswiftpackage/task/CreateXCFrameworkTask.kt +++ b/src/main/kotlin/com/chromaticnoise/multiplatformswiftpackage/task/CreateXCFrameworkTask.kt @@ -49,7 +49,7 @@ internal fun Project.registerCreateUniversalMacosFrameworkTask() = group = "multiplatform-swift-package" description = "Creates a universal (fat) macos framework" val configuration = getConfigurationOrThrow() - onlyIf{ getMacosFrameworks(configuration).size > 1 } + onlyIf { getMacosFrameworks(configuration).size > 1 } val targets = getMacosFrameworks(configuration) dependsOn(targets.map { it.linkTask.name }) doLast { @@ -105,13 +105,13 @@ internal fun Project.registerCreateUniversalIosSimulatorFrameworkTask() = group = "multiplatform-swift-package" description = "Creates a universal (fat) ios simulator framework" val configuration = getConfigurationOrThrow() - onlyIf{ getIosSimulatorFrameworks(configuration).size > 1 } + onlyIf { getIosSimulatorFrameworks(configuration).size > 1 } val targets = getIosSimulatorFrameworks(configuration) dependsOn(targets.map { it.linkTask.name }) if (targets.isNotEmpty()) { val buildType = if (targets[0].linkTask.name.contains("Release")) "release" else "debug" destinationDir = buildDir.resolve("bin/iosSimulatorUniversal/${buildType}Framework") - from(targets.mapNotNull { it.framework } ) + from(targets.mapNotNull { it.framework }) } } @@ -120,7 +120,7 @@ internal fun Project.registerCreateUniversalWatchosSimulatorFrameworkTask() = group = "multiplatform-swift-package" description = "Creates a universal (fat) watchos simulator framework" val configuration = getConfigurationOrThrow() - onlyIf{ getWatchosSimulatorFrameworks(configuration).size > 1 } + onlyIf { getWatchosSimulatorFrameworks(configuration).size > 1 } val targets = getWatchosSimulatorFrameworks(configuration) dependsOn(targets.map { it.linkTask.name }) if (targets.isNotEmpty()) { @@ -135,7 +135,7 @@ internal fun Project.registerCreateUniversalTvosSimulatorFrameworkTask() = group = "multiplatform-swift-package" description = "Creates a universal (fat) tvos simulator framework" val configuration = getConfigurationOrThrow() - onlyIf{ getTvosSimulatorFrameworks(configuration).size > 1 } + onlyIf { getTvosSimulatorFrameworks(configuration).size > 1 } val targets = getTvosSimulatorFrameworks(configuration) dependsOn(targets.map { it.linkTask.name }) if (targets.isNotEmpty()) { @@ -150,16 +150,16 @@ internal fun removeMonoFrameworksAndAddUniversalFrameworkIfNeeded( binFolderPrefix: String, buildDir: File, monoFrameworks: List, - outputFrameworks: MutableList) -{ - if (monoFrameworks.size > 1){ + outputFrameworks: MutableList +) { + if (monoFrameworks.size > 1) { monoFrameworks.forEach { mono -> - outputFrameworks.removeIf{ mono.outputFile == it.outputFile} + outputFrameworks.removeIf { mono.outputFile == it.outputFile } } val frameworkName = monoFrameworks[0].name val buildType = if (monoFrameworks[0].linkTask.name.contains("Release")) "release" else "debug" val destinationDir = buildDir.resolve("bin/${binFolderPrefix}Universal/${buildType}Framework") - val outputFile = AppleFrameworkOutputFile(File(destinationDir ,"${frameworkName.value}.framework")) + val outputFile = AppleFrameworkOutputFile(File(destinationDir, "${frameworkName.value}.framework")) outputFrameworks.add( AppleFramework( outputFile, @@ -171,14 +171,15 @@ internal fun removeMonoFrameworksAndAddUniversalFrameworkIfNeeded( } - internal fun Project.registerCreateXCFrameworkTask() = tasks.register("createXCFramework", Exec::class.java) { group = "multiplatform-swift-package" description = "Creates an XCFramework for all declared Apple targets" val configuration = getConfigurationOrThrow() - val xcFrameworkDestination = File(configuration.outputDirectory.value, "${configuration.packageName.value}.xcframework") - val outputFrameworks = configuration.appleTargets.mapNotNull { it.getFramework(configuration.buildConfiguration) }.toMutableList() + val xcFrameworkDestination = + File(configuration.outputDirectory.value, "${configuration.packageName.value}.xcframework") + val outputFrameworks = + configuration.appleTargets.mapNotNull { it.getFramework(configuration.buildConfiguration) }.toMutableList() dependsOn(outputFrameworks.map { it.linkTask.name }) dependsOn("createUniversalMacosFramework") From e251a091803d1d94b26ae1386510e0f16c8896d8 Mon Sep 17 00:00:00 2001 From: Luca Spinazzola Date: Sat, 30 Apr 2022 14:23:33 -0400 Subject: [PATCH 8/9] set baseName --- .../multiplatformswiftpackage/task/CreateXCFrameworkTask.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/kotlin/com/chromaticnoise/multiplatformswiftpackage/task/CreateXCFrameworkTask.kt b/src/main/kotlin/com/chromaticnoise/multiplatformswiftpackage/task/CreateXCFrameworkTask.kt index 563f78d..63f89b1 100644 --- a/src/main/kotlin/com/chromaticnoise/multiplatformswiftpackage/task/CreateXCFrameworkTask.kt +++ b/src/main/kotlin/com/chromaticnoise/multiplatformswiftpackage/task/CreateXCFrameworkTask.kt @@ -110,6 +110,7 @@ internal fun Project.registerCreateUniversalIosSimulatorFrameworkTask() = dependsOn(targets.map { it.linkTask.name }) if (targets.isNotEmpty()) { val buildType = if (targets[0].linkTask.name.contains("Release")) "release" else "debug" + baseName = configuration.packageName.value destinationDir = buildDir.resolve("bin/iosSimulatorUniversal/${buildType}Framework") from(targets.mapNotNull { it.framework }) } @@ -125,6 +126,7 @@ internal fun Project.registerCreateUniversalWatchosSimulatorFrameworkTask() = dependsOn(targets.map { it.linkTask.name }) if (targets.isNotEmpty()) { val buildType = if (targets[0].linkTask.name.contains("Release")) "release" else "debug" + baseName = configuration.packageName.value destinationDir = buildDir.resolve("bin/watchosSimulatorUniversal/$buildType") from(targets.mapNotNull { it.framework }) } @@ -140,6 +142,7 @@ internal fun Project.registerCreateUniversalTvosSimulatorFrameworkTask() = dependsOn(targets.map { it.linkTask.name }) if (targets.isNotEmpty()) { val buildType = if (targets[0].linkTask.name.contains("Release")) "release" else "debug" + baseName = configuration.packageName.value destinationDir = buildDir.resolve("bin/tvosSimulatorUniversal/$buildType") from(targets.mapNotNull { it.framework }) } From c447734661495c15212ade8157c284e0eeba08c5 Mon Sep 17 00:00:00 2001 From: Val Date: Fri, 3 Jun 2022 13:53:42 +0700 Subject: [PATCH 9/9] Set name of Universal framework same as baseName configurated binaries --- .../multiplatformswiftpackage/task/CreateXCFrameworkTask.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/com/chromaticnoise/multiplatformswiftpackage/task/CreateXCFrameworkTask.kt b/src/main/kotlin/com/chromaticnoise/multiplatformswiftpackage/task/CreateXCFrameworkTask.kt index 63f89b1..7c9ef29 100644 --- a/src/main/kotlin/com/chromaticnoise/multiplatformswiftpackage/task/CreateXCFrameworkTask.kt +++ b/src/main/kotlin/com/chromaticnoise/multiplatformswiftpackage/task/CreateXCFrameworkTask.kt @@ -110,7 +110,7 @@ internal fun Project.registerCreateUniversalIosSimulatorFrameworkTask() = dependsOn(targets.map { it.linkTask.name }) if (targets.isNotEmpty()) { val buildType = if (targets[0].linkTask.name.contains("Release")) "release" else "debug" - baseName = configuration.packageName.value + baseName = checkNotNull(targets.first().name.value) destinationDir = buildDir.resolve("bin/iosSimulatorUniversal/${buildType}Framework") from(targets.mapNotNull { it.framework }) } @@ -126,7 +126,7 @@ internal fun Project.registerCreateUniversalWatchosSimulatorFrameworkTask() = dependsOn(targets.map { it.linkTask.name }) if (targets.isNotEmpty()) { val buildType = if (targets[0].linkTask.name.contains("Release")) "release" else "debug" - baseName = configuration.packageName.value + baseName = checkNotNull(targets.first().name.value) destinationDir = buildDir.resolve("bin/watchosSimulatorUniversal/$buildType") from(targets.mapNotNull { it.framework }) } @@ -142,7 +142,7 @@ internal fun Project.registerCreateUniversalTvosSimulatorFrameworkTask() = dependsOn(targets.map { it.linkTask.name }) if (targets.isNotEmpty()) { val buildType = if (targets[0].linkTask.name.contains("Release")) "release" else "debug" - baseName = configuration.packageName.value + baseName = checkNotNull(targets.first().name.value) destinationDir = buildDir.resolve("bin/tvosSimulatorUniversal/$buildType") from(targets.mapNotNull { it.framework }) }