WIP
diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/apple/XCFrameworkTask.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/apple/XCFrameworkTask.kt
index efdd156..88dea25 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/apple/XCFrameworkTask.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/apple/XCFrameworkTask.kt
@@ -8,16 +8,12 @@
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 @@
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 @@
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.
@@ -156,21 +153,15 @@
@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 data class XCFrameworkFile(val file: File, val isStatic: Boolean)
+ private val groupedFrameworkFiles: MutableMap<AppleTarget, MutableList<XCFrameworkFile>> = 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,33 +188,32 @@
require(framework.konanTarget.family.isAppleFamily) {
"XCFramework supports Apple frameworks only"
}
- allFrameworks.add(framework)
+ val group = AppleTarget.values().first { it.targets.contains(framework.konanTarget) }
+ groupedFrameworkFiles.getOrPut(group, { mutableListOf() }).add(XCFrameworkFile(framework.outputFile, framework.isStatic))
dependsOn(framework.linkTask)
}
}
+ fun from(target: KonanTarget, frameworkFile: File, isStatic: Boolean) {
+ val group = AppleTarget.values().first { it.targets.contains(target) }
+ groupedFrameworkFiles.getOrPut(group, { mutableListOf() }).add(XCFrameworkFile(frameworkFile, isStatic))
+ }
+
@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 -> XCFrameworkFile(
+ fatFrameworksDir.resolve(group.targetName).resolve("${xcFrameworkName.get()}.framework"),
+ files.all { it.isStatic }
+ )
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) {
if (output.exists()) output.deleteRecursively()
diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/artifact/KotlinNativeOutputFramework.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/artifact/KotlinNativeOutputFramework.kt
index 9b33239..1b405b0 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/artifact/KotlinNativeOutputFramework.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/artifact/KotlinNativeOutputFramework.kt
@@ -8,12 +8,19 @@
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.plugins.BasePlugin
+import org.gradle.api.tasks.TaskProvider
import org.jetbrains.kotlin.gradle.plugin.mpp.BitcodeEmbeddingMode
+import org.jetbrains.kotlin.gradle.plugin.mpp.NativeBuildType
import org.jetbrains.kotlin.gradle.plugin.mpp.NativeOutputKind
+import org.jetbrains.kotlin.gradle.plugin.mpp.apple.*
+import org.jetbrains.kotlin.gradle.plugin.mpp.apple.AppleTarget
+import org.jetbrains.kotlin.gradle.plugin.mpp.apple.XCFrameworkTaskHolder
import org.jetbrains.kotlin.gradle.plugin.mpp.enabledOnCurrentHost
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 org.jetbrains.kotlin.konan.target.presetName
import org.jetbrains.kotlin.konan.util.visibleName
@@ -46,35 +53,102 @@
val librariesConfigurationName = project.registerLibsDependencies(target, name, config.exportDeps)
val exportConfigurationName = project.registerExportDependencies(target, name, config.exportDeps)
config.modes.forEach { buildType ->
- val targetTask = project.registerTask<KotlinNativeLinkArtifactTask>(
+ val targetTask = project.registerLinkFrameworkTask(
lowerCamelCaseName("assemble", buildType.visibleName, kind.taskNameClassifier, name, target.presetName),
- listOf(target, kind.compilerOutputKind)
- ) { task ->
- task.group = BasePlugin.BUILD_GROUP
- task.description = "Assemble ${kind.description} '$name' for a target '${target.name}'."
- task.enabled = target.enabledOnCurrentHost && kind.availableFor(target)
-
- task.baseName = name
- task.optimized = buildType.optimized
- task.debuggable = buildType.debuggable
- task.linkerOptions = config.linkerOptions
- task.binaryOptions = config.binaryOptions
-
- task.isStaticFramework = config.isStatic
- task.embedBitcode = frameworkConfig.embedBitcode ?: buildType.embedBitcode(target)
-
- task.librariesConfiguration = librariesConfigurationName
- task.exportLibrariesConfiguration = exportConfigurationName
-
- task.languageSettings(config.languageSettingsFn)
- task.kotlinOptions(config.kotlinOptionsFn)
- }
+ target,
+ buildType,
+ config,
+ librariesConfigurationName,
+ exportConfigurationName,
+ frameworkConfig.embedBitcode
+ )
resultTask.dependsOn(targetTask)
}
}
}
}
+private class KotlinNativeOutputXCFramework(
+ val frameworkConfig: KotlinNativeFrameworkConfig
+) : KotlinNativeLibraryArtifact {
+ override fun registerAssembleTask(
+ project: Project,
+ name: String,
+ config: KotlinNativeLibraryConfig
+ ) {
+ val kind = NativeOutputKind.FRAMEWORK
+
+ config.targets.firstOrNull { !kind.availableFor(it) }?.let { target ->
+ project.logger.error("Native library '${name}' wasn't configured because ${kind.description} is not available for ${target.visibleName}")
+ return
+ }
+
+ val parentTask = project.registerTask<Task>(lowerCamelCaseName("assemble", name, "XCFramework")) {
+ it.group = "build"
+ it.description = "Assemble all types of registered '$name' XCFramework"
+ }
+ config.modes.forEach { buildType ->
+ val holder = XCFrameworkTaskHolder.create(project, name, buildType).also {
+ parentTask.dependsOn(it.task)
+ }
+ config.targets.forEach { target ->
+ val librariesConfigurationName = project.registerLibsDependencies(target, name, config.exportDeps)
+ val exportConfigurationName = project.registerExportDependencies(target, name, config.exportDeps)
+ project.registerLinkFrameworkTask(
+ lowerCamelCaseName("assemble", buildType.visibleName, kind.taskNameClassifier, name, target.presetName),
+ target,
+ buildType,
+ config,
+ librariesConfigurationName,
+ exportConfigurationName,
+ frameworkConfig.embedBitcode
+ ).configure { targetTask ->
+ holder.task.configure { xcFrameworkTask ->
+ xcFrameworkTask.from(target, targetTask.outputFile, targetTask.isStaticFramework)
+ xcFrameworkTask.dependsOn(targetTask)
+ }
+// val group = AppleTarget.values().firstOrNull { it.targets.contains(target) }
+// holder.fatTasks[group]?.configure { fatTask ->
+// fatTask.from(framework)
+// }
+ }
+ }
+ }
+ }
+}
+
+private fun Project.registerLinkFrameworkTask(
+ name: String,
+ target: KonanTarget,
+ buildType: NativeBuildType,
+ config: KotlinNativeLibraryConfig,
+ librariesConfigurationName: String,
+ exportConfigurationName: String,
+ embedBitcode: BitcodeEmbeddingMode?
+): TaskProvider<KotlinNativeLinkArtifactTask> {
+ val kind = NativeOutputKind.FRAMEWORK
+ return registerTask(name, listOf(target, kind.compilerOutputKind)) { task ->
+ task.group = BasePlugin.BUILD_GROUP
+ task.description = "Assemble ${kind.description} '$name' for a target '${target.name}'."
+ task.enabled = target.enabledOnCurrentHost && kind.availableFor(target)
+
+ task.baseName = name
+ task.optimized = buildType.optimized
+ task.debuggable = buildType.debuggable
+ task.linkerOptions = config.linkerOptions
+ task.binaryOptions = config.binaryOptions
+
+ task.isStaticFramework = config.isStatic
+ task.embedBitcode = embedBitcode ?: buildType.embedBitcode(target)
+
+ task.librariesConfiguration = librariesConfigurationName
+ task.exportLibrariesConfiguration = exportConfigurationName
+
+ task.languageSettings(config.languageSettingsFn)
+ task.kotlinOptions(config.kotlinOptionsFn)
+ }
+}
+
//DSL
val KotlinNativeLibraryConfig.framework: () -> KotlinNativeLibraryArtifact get() = framework {}
fun KotlinNativeLibraryConfig.framework(
@@ -83,4 +157,13 @@
val frameworkConfig = KotlinNativeFrameworkConfig()
frameworkConfig.fn()
KotlinNativeOutputFramework(frameworkConfig)
+}
+
+val KotlinNativeLibraryConfig.xcframework: () -> KotlinNativeLibraryArtifact get() = xcframework {}
+fun KotlinNativeLibraryConfig.xcframework(
+ fn: KotlinNativeFrameworkConfig.() -> Unit
+): () -> KotlinNativeLibraryArtifact = {
+ val frameworkConfig = KotlinNativeFrameworkConfig()
+ frameworkConfig.fn()
+ KotlinNativeOutputXCFramework(frameworkConfig)
}
\ No newline at end of file