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