From de4c2d35ab888addb6c3d2b6b7345a3618486f43 Mon Sep 17 00:00:00 2001 From: Konstantin Tskhovrebov Date: Thu, 22 Jul 2021 10:58:32 +0300 Subject: [PATCH] Assemble fat framework if Xcode requires several architectures. #KT-47653 --- .../kotlin/gradle/AppleFrameworkIT.kt | 21 +++++++++ .../shared/build.gradle.kts | 19 +++++++- .../plugin/mpp/apple/AppleXcodeTasks.kt | 47 +++++++++++-------- 3 files changed, 67 insertions(+), 20 deletions(-) diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/AppleFrameworkIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/AppleFrameworkIT.kt index a51e25ba691..a9f790c5106 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/AppleFrameworkIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/AppleFrameworkIT.kt @@ -53,6 +53,27 @@ class AppleFrameworkIT : BaseGradleIT() { } } + @Test + fun `assemble fat AppleFrameworkForXcode tasks for Arm64 and X64 simulators`() { + with(Project("sharedAppleFramework")) { + val options: BuildOptions = defaultBuildOptions().copy( + customEnvironmentVariables = mapOf( + "CONFIGURATION" to "Release", + "SDK_NAME" to "iphonesimulator", + "ARCHS" to "arm64 x86_64" + ) + ) + build("assembleReleaseAppleFrameworkForXcode", options = options) { + assertSuccessful() + assertTasksExecuted(":shared:linkReleaseFrameworkIosSimulatorArm64") + assertTasksExecuted(":shared:linkReleaseFrameworkIosX64") + assertTasksExecuted(":shared:assembleReleaseAppleFrameworkForXcode") + assertFileExists("/shared/build/xcode-frameworks/Release/iphonesimulator/sdk.framework") + assertFileExists("/shared/build/xcode-frameworks/Release/iphonesimulator/sdk.framework.dSYM") + } + } + } + @Test fun `check there aren't Xcode tasks without Xcode environment`() { with(Project("sharedAppleFramework")) { diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/sharedAppleFramework/shared/build.gradle.kts b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/sharedAppleFramework/shared/build.gradle.kts index 832d659b34e..b0fea6d2995 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/sharedAppleFramework/shared/build.gradle.kts +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/sharedAppleFramework/shared/build.gradle.kts @@ -6,7 +6,10 @@ plugins { kotlin { android() - ios() { + val iosX64 = iosX64() + val iosSimulatorArm64 = iosSimulatorArm64() + val iosArm64 = iosArm64() + configure(listOf(iosX64, iosSimulatorArm64, iosArm64)) { binaries { framework { baseName = "sdk" @@ -16,6 +19,20 @@ kotlin { } } } + sourceSets { + val commonMain by getting + + val iosX64Main by getting + val iosSimulatorArm64Main by getting + val iosArm64Main by getting + + val iosMain by creating { + dependsOn(commonMain) + iosX64Main.dependsOn(this) + iosSimulatorArm64Main.dependsOn(this) + iosArm64Main.dependsOn(this) + } + } } android { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/apple/AppleXcodeTasks.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/apple/AppleXcodeTasks.kt index 82b8c19fba1..6b71b568154 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/apple/AppleXcodeTasks.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/apple/AppleXcodeTasks.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.gradle.plugin.mpp.apple import org.gradle.api.Project +import org.gradle.api.Task import org.gradle.api.plugins.BasePlugin import org.gradle.api.tasks.Copy import org.gradle.api.tasks.TaskProvider @@ -13,6 +14,9 @@ import org.jetbrains.kotlin.gradle.dsl.KotlinNativeBinaryContainer import org.jetbrains.kotlin.gradle.plugin.mpp.Framework import org.jetbrains.kotlin.gradle.plugin.mpp.NativeBuildType import org.jetbrains.kotlin.gradle.plugin.mpp.enabledOnCurrentHost +import org.jetbrains.kotlin.gradle.tasks.FatFrameworkTask +import org.jetbrains.kotlin.gradle.tasks.locateOrRegisterTask +import org.jetbrains.kotlin.gradle.tasks.locateTask import org.jetbrains.kotlin.gradle.tasks.registerTask import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName import org.jetbrains.kotlin.konan.target.KonanTarget @@ -59,17 +63,11 @@ private object XcodeEnvironment { val sign: String? get() = System.getenv("EXPANDED_CODE_SIGN_IDENTITY") } -private fun Project.registerAssembleAppleFrameworkTask(framework: Framework): TaskProvider? { +private fun Project.registerAssembleAppleFrameworkTask(framework: Framework): TaskProvider? { if (!framework.konanTarget.family.isAppleFamily || !framework.konanTarget.enabledOnCurrentHost) return null val envTargets = XcodeEnvironment.targets - if (envTargets.size > 1) { - logger.debug( - "Unable to register assemble Apple framework task because " + - "'ARCHS' contains more than one value." - ) - return null - } + val needFatFramework = envTargets.size > 1 val frameworkBuildType = framework.buildType val frameworkTarget = framework.target @@ -78,16 +76,15 @@ private fun Project.registerAssembleAppleFrameworkTask(framework: Framework): Ta framework.namePrefix, frameworkBuildType.getName(), "AppleFrameworkForXcode", - frameworkTarget.name + if (!needFatFramework) frameworkTarget.name else null ) val envBuildType = XcodeEnvironment.buildType - val envTarget = envTargets.firstOrNull() val envFrameworkSearchDir = XcodeEnvironment.frameworkSearchDir - if (envBuildType == null || envTarget == null || envFrameworkSearchDir == null) { + if (envBuildType == null || envTargets.isEmpty() || envFrameworkSearchDir == null) { val envConfiguration = System.getenv("CONFIGURATION") - if (envTarget != null && envConfiguration != null) { + if (envTargets.isNotEmpty() && envConfiguration != null) { logger.warn( "Unable to detect Kotlin framework build type for CONFIGURATION=$envConfiguration automatically. " + "Specify 'KOTLIN_FRAMEWORK_BUILD_TYPE' to 'debug' or 'release'" @@ -101,14 +98,25 @@ private fun Project.registerAssembleAppleFrameworkTask(framework: Framework): Ta return null } - if (frameworkBuildType != envBuildType || frameworkTarget.konanTarget != envTarget) return null + if (frameworkBuildType != envBuildType || !envTargets.contains(frameworkTarget.konanTarget)) return null - return registerTask(frameworkTaskName) { task -> - task.group = BasePlugin.BUILD_GROUP - task.description = "Packs $frameworkBuildType ${frameworkTarget.name} framework for Xcode" - task.dependsOn(framework.linkTaskName) - task.from(framework.outputDirectory) - task.into(appleFrameworkDir(envFrameworkSearchDir)) + return if (needFatFramework) { + locateOrRegisterTask(frameworkTaskName) { task -> + task.group = BasePlugin.BUILD_GROUP + task.description = "Packs $frameworkBuildType fat framework for Xcode" + task.baseName = framework.baseName + task.destinationDir = appleFrameworkDir(envFrameworkSearchDir) + }.also { + it.configure { task -> task.from(framework) } + } + } else { + registerTask(frameworkTaskName) { task -> + task.group = BasePlugin.BUILD_GROUP + task.description = "Packs $frameworkBuildType ${frameworkTarget.name} framework for Xcode" + task.dependsOn(framework.linkTaskName) + task.from(framework.outputDirectory) + task.into(appleFrameworkDir(envFrameworkSearchDir)) + } } } @@ -132,6 +140,7 @@ internal fun Project.registerEmbedAndSignAppleFrameworkTask(framework: Framework } if (framework.buildType != envBuildType || !envTargets.contains(framework.konanTarget)) return + if (locateTask(frameworkTaskName) != null) return registerTask(frameworkTaskName) { task -> task.group = "build"