Assemble fat framework if Xcode requires several architectures.

#KT-47653
This commit is contained in:
Konstantin Tskhovrebov
2021-07-22 10:58:32 +03:00
committed by Space
parent 68a3c5f378
commit de4c2d35ab
3 changed files with 67 additions and 20 deletions
@@ -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 @Test
fun `check there aren't Xcode tasks without Xcode environment`() { fun `check there aren't Xcode tasks without Xcode environment`() {
with(Project("sharedAppleFramework")) { with(Project("sharedAppleFramework")) {
@@ -6,7 +6,10 @@ plugins {
kotlin { kotlin {
android() android()
ios() { val iosX64 = iosX64()
val iosSimulatorArm64 = iosSimulatorArm64()
val iosArm64 = iosArm64()
configure(listOf(iosX64, iosSimulatorArm64, iosArm64)) {
binaries { binaries {
framework { framework {
baseName = "sdk" 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 { android {
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.gradle.plugin.mpp.apple package org.jetbrains.kotlin.gradle.plugin.mpp.apple
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.plugins.BasePlugin import org.gradle.api.plugins.BasePlugin
import org.gradle.api.tasks.Copy import org.gradle.api.tasks.Copy
import org.gradle.api.tasks.TaskProvider 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.Framework
import org.jetbrains.kotlin.gradle.plugin.mpp.NativeBuildType import org.jetbrains.kotlin.gradle.plugin.mpp.NativeBuildType
import org.jetbrains.kotlin.gradle.plugin.mpp.enabledOnCurrentHost 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.tasks.registerTask
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
import org.jetbrains.kotlin.konan.target.KonanTarget import org.jetbrains.kotlin.konan.target.KonanTarget
@@ -59,17 +63,11 @@ private object XcodeEnvironment {
val sign: String? get() = System.getenv("EXPANDED_CODE_SIGN_IDENTITY") val sign: String? get() = System.getenv("EXPANDED_CODE_SIGN_IDENTITY")
} }
private fun Project.registerAssembleAppleFrameworkTask(framework: Framework): TaskProvider<Copy>? { private fun Project.registerAssembleAppleFrameworkTask(framework: Framework): TaskProvider<out Task>? {
if (!framework.konanTarget.family.isAppleFamily || !framework.konanTarget.enabledOnCurrentHost) return null if (!framework.konanTarget.family.isAppleFamily || !framework.konanTarget.enabledOnCurrentHost) return null
val envTargets = XcodeEnvironment.targets val envTargets = XcodeEnvironment.targets
if (envTargets.size > 1) { val needFatFramework = envTargets.size > 1
logger.debug(
"Unable to register assemble Apple framework task because " +
"'ARCHS' contains more than one value."
)
return null
}
val frameworkBuildType = framework.buildType val frameworkBuildType = framework.buildType
val frameworkTarget = framework.target val frameworkTarget = framework.target
@@ -78,16 +76,15 @@ private fun Project.registerAssembleAppleFrameworkTask(framework: Framework): Ta
framework.namePrefix, framework.namePrefix,
frameworkBuildType.getName(), frameworkBuildType.getName(),
"AppleFrameworkForXcode", "AppleFrameworkForXcode",
frameworkTarget.name if (!needFatFramework) frameworkTarget.name else null
) )
val envBuildType = XcodeEnvironment.buildType val envBuildType = XcodeEnvironment.buildType
val envTarget = envTargets.firstOrNull()
val envFrameworkSearchDir = XcodeEnvironment.frameworkSearchDir val envFrameworkSearchDir = XcodeEnvironment.frameworkSearchDir
if (envBuildType == null || envTarget == null || envFrameworkSearchDir == null) { if (envBuildType == null || envTargets.isEmpty() || envFrameworkSearchDir == null) {
val envConfiguration = System.getenv("CONFIGURATION") val envConfiguration = System.getenv("CONFIGURATION")
if (envTarget != null && envConfiguration != null) { if (envTargets.isNotEmpty() && envConfiguration != null) {
logger.warn( logger.warn(
"Unable to detect Kotlin framework build type for CONFIGURATION=$envConfiguration automatically. " + "Unable to detect Kotlin framework build type for CONFIGURATION=$envConfiguration automatically. " +
"Specify 'KOTLIN_FRAMEWORK_BUILD_TYPE' to 'debug' or 'release'" "Specify 'KOTLIN_FRAMEWORK_BUILD_TYPE' to 'debug' or 'release'"
@@ -101,14 +98,25 @@ private fun Project.registerAssembleAppleFrameworkTask(framework: Framework): Ta
return null return null
} }
if (frameworkBuildType != envBuildType || frameworkTarget.konanTarget != envTarget) return null if (frameworkBuildType != envBuildType || !envTargets.contains(frameworkTarget.konanTarget)) return null
return registerTask(frameworkTaskName) { task -> return if (needFatFramework) {
task.group = BasePlugin.BUILD_GROUP locateOrRegisterTask<FatFrameworkTask>(frameworkTaskName) { task ->
task.description = "Packs $frameworkBuildType ${frameworkTarget.name} framework for Xcode" task.group = BasePlugin.BUILD_GROUP
task.dependsOn(framework.linkTaskName) task.description = "Packs $frameworkBuildType fat framework for Xcode"
task.from(framework.outputDirectory) task.baseName = framework.baseName
task.into(appleFrameworkDir(envFrameworkSearchDir)) task.destinationDir = appleFrameworkDir(envFrameworkSearchDir)
}.also {
it.configure { task -> task.from(framework) }
}
} else {
registerTask<Copy>(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 (framework.buildType != envBuildType || !envTargets.contains(framework.konanTarget)) return
if (locateTask<Copy>(frameworkTaskName) != null) return
registerTask<Copy>(frameworkTaskName) { task -> registerTask<Copy>(frameworkTaskName) { task ->
task.group = "build" task.group = "build"