Add new DSL for configuring K/N xcframework artifact.
This commit is contained in:
committed by
TeamCityServer
parent
43fe1e52c9
commit
2e86fbd2b5
+8
-8
@@ -43,9 +43,9 @@ class XCFrameworkIT : BaseGradleIT() {
|
||||
assertTasksExecuted(":shared:assembleSdkDebugWatchosFatFrameworkForXCFramework")
|
||||
assertTasksExecuted(":shared:assembleSdkDebugXCFramework")
|
||||
assertFileExists("/shared/build/XCFrameworks/debug/sdk.xcframework")
|
||||
assertFileExists("/shared/build/XCFrameworks/debug/sdk.xcframework/ios-arm64/dSYMs/sdk.framework.dSYM")
|
||||
assertFileExists("/shared/build/fat-framework/debug/sdk/watchos/sdk.framework")
|
||||
assertFileExists("/shared/build/fat-framework/debug/sdk/watchos/sdk.framework.dSYM")
|
||||
assertFileExists("/shared/build/XCFrameworks/debug/sdk.xcframework/ios-arm64/dSYMs/shared.framework.dSYM")
|
||||
assertFileExists("/shared/build/sdkXCFrameworkTemp/fatframework/debug/watchos/sdk.framework")
|
||||
assertFileExists("/shared/build/sdkXCFrameworkTemp/fatframework/debug/watchos/sdk.framework.dSYM")
|
||||
}
|
||||
|
||||
build("assembleSdkDebugXCFramework") {
|
||||
@@ -68,12 +68,12 @@ class XCFrameworkIT : BaseGradleIT() {
|
||||
assertSuccessful()
|
||||
assertTasksExecuted(":shared:linkReleaseFrameworkIosArm64")
|
||||
assertTasksExecuted(":shared:linkReleaseFrameworkIosX64")
|
||||
assertTasksExecuted(":shared:assembleReleaseXCFramework")
|
||||
assertTasksExecuted(":shared:assembleSharedReleaseXCFramework")
|
||||
assertFileExists("/shared/build/XCFrameworks/release/shared.xcframework")
|
||||
assertFileExists("/shared/build/XCFrameworks/release/shared.xcframework/ios-arm64/dSYMs/shared.framework.dSYM")
|
||||
assertTasksExecuted(":shared:linkDebugFrameworkIosArm64")
|
||||
assertTasksExecuted(":shared:linkDebugFrameworkIosX64")
|
||||
assertTasksExecuted(":shared:assembleDebugXCFramework")
|
||||
assertTasksExecuted(":shared:assembleSharedDebugXCFramework")
|
||||
assertFileExists("/shared/build/XCFrameworks/debug/shared.xcframework")
|
||||
assertFileExists("/shared/build/XCFrameworks/debug/shared.xcframework/ios-arm64/dSYMs/shared.framework.dSYM")
|
||||
}
|
||||
@@ -86,8 +86,8 @@ class XCFrameworkIT : BaseGradleIT() {
|
||||
build("tasks") {
|
||||
assertSuccessful()
|
||||
assertTasksNotRegistered(
|
||||
":shared:assembleDebugXCFramework",
|
||||
":shared:assembleReleaseXCFramework",
|
||||
":shared:assembleSharedDebugXCFramework",
|
||||
":shared:assembleSharedReleaseXCFramework",
|
||||
":shared:assembleXCFramework"
|
||||
)
|
||||
}
|
||||
@@ -105,7 +105,7 @@ class XCFrameworkIT : BaseGradleIT() {
|
||||
|
||||
build("tasks") {
|
||||
assertFailed()
|
||||
assertContains("Cannot add task 'assembleReleaseXCFramework' as a task with that name already exists.")
|
||||
assertContains("Cannot add task 'assembleSharedReleaseXCFramework' as a task with that name already exists.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+31
-38
@@ -8,16 +8,12 @@ package org.jetbrains.kotlin.gradle.plugin.mpp.apple
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.file.FileTree
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.api.tasks.*
|
||||
import org.jetbrains.kotlin.gradle.plugin.cocoapods.asValidFrameworkName
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.Framework
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.NativeBuildType
|
||||
import org.jetbrains.kotlin.gradle.tasks.*
|
||||
import org.jetbrains.kotlin.gradle.tasks.dependsOn
|
||||
import org.jetbrains.kotlin.gradle.tasks.locateOrRegisterTask
|
||||
import org.jetbrains.kotlin.gradle.tasks.registerTask
|
||||
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import java.io.File
|
||||
@@ -43,10 +39,7 @@ internal class XCFrameworkTaskHolder(
|
||||
companion object {
|
||||
fun create(project: Project, xcFrameworkName: String, buildType: NativeBuildType): XCFrameworkTaskHolder {
|
||||
require(xcFrameworkName.isNotBlank())
|
||||
|
||||
val parentTask = project.parentAssembleXCFrameworkTask(xcFrameworkName)
|
||||
val task = project.registerAssembleXCFrameworkTask(xcFrameworkName, buildType)
|
||||
parentTask.dependsOn(task)
|
||||
|
||||
val fatTasks = AppleTarget.values().associate { fatTarget ->
|
||||
val fatTask = project.registerAssembleFatForXCFrameworkTask(xcFrameworkName, buildType, fatTarget)
|
||||
@@ -62,13 +55,17 @@ internal class XCFrameworkTaskHolder(
|
||||
class XCFrameworkConfig {
|
||||
private val taskHolders: List<XCFrameworkTaskHolder>
|
||||
|
||||
constructor(project: Project, xcFrameworkName: String) {
|
||||
taskHolders = NativeBuildType.values().map { buildType ->
|
||||
XCFrameworkTaskHolder.create(project, xcFrameworkName, buildType)
|
||||
constructor(project: Project, xcFrameworkName: String, buildTypes: Set<NativeBuildType>) {
|
||||
val parentTask = project.parentAssembleXCFrameworkTask(xcFrameworkName)
|
||||
taskHolders = buildTypes.map { buildType ->
|
||||
XCFrameworkTaskHolder.create(project, xcFrameworkName, buildType).also {
|
||||
parentTask.dependsOn(it.task)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constructor(project: Project) : this(project, project.name)
|
||||
constructor(project: Project, xcFrameworkName: String) : this(project, xcFrameworkName, NativeBuildType.values().toSet())
|
||||
|
||||
/**
|
||||
* Adds the specified frameworks in this XCFramework.
|
||||
@@ -106,7 +103,7 @@ private fun Project.registerAssembleXCFrameworkTask(
|
||||
): TaskProvider<XCFrameworkTask> {
|
||||
val taskName = lowerCamelCaseName(
|
||||
"assemble",
|
||||
eraseIfDefault(xcFrameworkName),
|
||||
xcFrameworkName,
|
||||
buildType.getName(),
|
||||
"XCFramework"
|
||||
)
|
||||
@@ -156,21 +153,14 @@ abstract class XCFrameworkTask : DefaultTask() {
|
||||
@Input
|
||||
var buildType: NativeBuildType = NativeBuildType.RELEASE
|
||||
|
||||
/**
|
||||
* A collection of frameworks used ot build the XCFramework.
|
||||
*/
|
||||
private val allFrameworks: MutableSet<Framework> = mutableSetOf()
|
||||
|
||||
@get:Internal // We take it into account as an input in the inputFrameworkFiles property.
|
||||
val frameworks: List<Framework>
|
||||
get() = allFrameworks.filter { it.buildType == buildType }
|
||||
private val groupedFrameworkFiles: MutableMap<AppleTarget, MutableList<FrameworkDescriptor>> = mutableMapOf()
|
||||
|
||||
@get:IgnoreEmptyDirectories
|
||||
@get:InputFiles
|
||||
@get:PathSensitive(PathSensitivity.ABSOLUTE)
|
||||
@get:SkipWhenEmpty
|
||||
protected val inputFrameworkFiles: Iterable<FileTree>
|
||||
get() = frameworks.map { project.fileTree(it.outputFile) }
|
||||
val inputFrameworkFiles: Collection<File>
|
||||
get() = groupedFrameworkFiles.values.flatten().map { it.file }
|
||||
|
||||
/**
|
||||
* A parent directory for the XCFramework.
|
||||
@@ -197,34 +187,37 @@ abstract class XCFrameworkTask : DefaultTask() {
|
||||
require(framework.konanTarget.family.isAppleFamily) {
|
||||
"XCFramework supports Apple frameworks only"
|
||||
}
|
||||
allFrameworks.add(framework)
|
||||
dependsOn(framework.linkTask)
|
||||
}
|
||||
fromFrameworkDescriptors(frameworks.map { FrameworkDescriptor(it) })
|
||||
}
|
||||
|
||||
fun fromFrameworkDescriptors(vararg frameworks: FrameworkDescriptor) = fromFrameworkDescriptors(frameworks.toList())
|
||||
|
||||
fun fromFrameworkDescriptors(frameworks: Iterable<FrameworkDescriptor>) {
|
||||
frameworks.forEach { framework ->
|
||||
val group = AppleTarget.values().first { it.targets.contains(framework.target) }
|
||||
groupedFrameworkFiles.getOrPut(group, { mutableListOf() }).add(framework)
|
||||
}
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
fun assemble() {
|
||||
val frameworksForXCFramework = AppleTarget.values().mapNotNull { appleTarget ->
|
||||
val group = frameworks.filter { it.konanTarget in appleTarget.targets }
|
||||
val frameworksForXCFramework = groupedFrameworkFiles.entries.mapNotNull { (group, files) ->
|
||||
when {
|
||||
group.size == 1 -> {
|
||||
XCFrameworkFile(group.first().outputFile, group.first().isStatic)
|
||||
}
|
||||
group.size > 1 -> {
|
||||
XCFrameworkFile(
|
||||
fatFrameworksDir.resolve(appleTarget.targetName).resolve("${xcFrameworkName.get()}.framework"),
|
||||
group.all { it.isStatic }
|
||||
)
|
||||
}
|
||||
files.size == 1 -> files.first()
|
||||
files.size > 1 -> FrameworkDescriptor(
|
||||
fatFrameworksDir.resolve(group.targetName).resolve("${xcFrameworkName.get()}.framework"),
|
||||
files.all { it.isStatic },
|
||||
group.targets.first() //will be not used
|
||||
)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
createXCFramework(frameworksForXCFramework, outputXCFrameworkFile, buildType)
|
||||
}
|
||||
|
||||
private data class XCFrameworkFile (val file: File, val isStatic: Boolean)
|
||||
|
||||
private fun createXCFramework(frameworkFiles: List<XCFrameworkFile>, output: File, buildType: NativeBuildType) {
|
||||
private fun createXCFramework(frameworkFiles: List<FrameworkDescriptor>, output: File, buildType: NativeBuildType) {
|
||||
if (output.exists()) output.deleteRecursively()
|
||||
|
||||
val cmdArgs = mutableListOf("xcodebuild", "-create-xcframework")
|
||||
@@ -251,9 +244,9 @@ abstract class XCFrameworkTask : DefaultTask() {
|
||||
buildType: NativeBuildType,
|
||||
appleTarget: AppleTarget? = null
|
||||
) = project.buildDir
|
||||
.resolve("fat-framework")
|
||||
.resolve(xcFrameworkName + "XCFrameworkTemp")
|
||||
.resolve("fatframework")
|
||||
.resolve(buildType.getName())
|
||||
.resolve(xcFrameworkName)
|
||||
.resolveIfNotNull(appleTarget?.targetName)
|
||||
|
||||
private fun File.resolveIfNotNull(relative: String?): File = if (relative == null) this else this.resolve(relative)
|
||||
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.gradle.targets.native.tasks.artifact
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.language.base.plugins.LifecycleBasePlugin
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.BitcodeEmbeddingMode
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.NativeOutputKind
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.AppleTarget
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.XCFrameworkTaskHolder
|
||||
import org.jetbrains.kotlin.gradle.tasks.FrameworkDescriptor
|
||||
import org.jetbrains.kotlin.gradle.tasks.dependsOn
|
||||
import org.jetbrains.kotlin.gradle.tasks.registerTask
|
||||
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
|
||||
class KotlinNativeXCFramework : KotlinNativeArtifact() {
|
||||
var targets: Set<KonanTarget> = emptySet()
|
||||
var embedBitcode: BitcodeEmbeddingMode? = null
|
||||
|
||||
private val kind = NativeOutputKind.FRAMEWORK
|
||||
|
||||
override fun validate(project: Project, name: String): Boolean {
|
||||
val logger = project.logger
|
||||
if (!super.validate(project, name)) return false
|
||||
if (targets.isEmpty()) {
|
||||
logger.error("Native library '${name}' wasn't configured because it requires at least one target")
|
||||
return false
|
||||
}
|
||||
targets.firstOrNull { !kind.availableFor(it) }?.let { target ->
|
||||
logger.error("Native library '${name}' wasn't configured because ${kind.description} is not available for ${target.visibleName}")
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun registerAssembleTask(project: Project, name: String) {
|
||||
val parentTask = project.registerTask<Task>(lowerCamelCaseName("assemble", name, "XCFramework")) {
|
||||
it.group = "build"
|
||||
it.description = "Assemble all types of registered '$name' XCFramework"
|
||||
}
|
||||
project.tasks.named(LifecycleBasePlugin.ASSEMBLE_TASK_NAME).dependsOn(parentTask)
|
||||
|
||||
modes.forEach { buildType ->
|
||||
val holder = XCFrameworkTaskHolder.create(project, name, buildType).also {
|
||||
parentTask.dependsOn(it.task)
|
||||
}
|
||||
|
||||
val nameSuffix = "ForXCF"
|
||||
val frameworkDescriptors: List<FrameworkDescriptor> = targets.map { target ->
|
||||
val librariesConfigurationName = project.registerLibsDependencies(target, name + nameSuffix, modules)
|
||||
val exportConfigurationName = project.registerExportDependencies(target, name + nameSuffix, modules)
|
||||
val targetTask = registerLinkFrameworkTask(
|
||||
project,
|
||||
name,
|
||||
target,
|
||||
buildType,
|
||||
librariesConfigurationName,
|
||||
exportConfigurationName,
|
||||
embedBitcode,
|
||||
"${name}XCFrameworkTemp",
|
||||
nameSuffix
|
||||
)
|
||||
holder.task.dependsOn(targetTask)
|
||||
val frameworkFileProvider = targetTask.map { it.outputFile }
|
||||
val descriptor = FrameworkDescriptor(frameworkFileProvider.get(), isStatic, target)
|
||||
|
||||
val group = AppleTarget.values().firstOrNull { it.targets.contains(target) }
|
||||
holder.fatTasks[group]?.configure { fatTask ->
|
||||
fatTask.fromFrameworkDescriptors(listOf(descriptor))
|
||||
fatTask.dependsOn(targetTask)
|
||||
}
|
||||
descriptor
|
||||
}
|
||||
holder.task.configure {
|
||||
it.fromFrameworkDescriptors(frameworkDescriptors)
|
||||
it.outputDir = project.buildDir.resolve("out/xcframework")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user