[Gradle] Replace 'configureArchivesAndComponent' with KotlinTargetArtifact

KT-61634
diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/mpp/MppCompositeBuildIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/mpp/MppCompositeBuildIT.kt
index 753da1a..7cded6a 100644
--- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/mpp/MppCompositeBuildIT.kt
+++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/mpp/MppCompositeBuildIT.kt
@@ -176,6 +176,8 @@
             buildGradleKts.replaceText("<kgp_version>", KOTLIN_VERSION)
             projectPath.resolve("included-build/build.gradle.kts").replaceText("<kgp_version>", KOTLIN_VERSION)
 
+            makeSnapshotTo("/Users/sebastiansellmair/tmp")
+
             build("assemble") {
                 assertTasksExecuted(":compileCommonMainKotlinMetadata")
                 assertTasksExecuted(":compileKotlinJvm")
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinTargetConfigurator.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinTargetConfigurator.kt
index 37ebd10..1a3d8b4 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinTargetConfigurator.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinTargetConfigurator.kt
@@ -9,20 +9,15 @@
 import org.gradle.api.NamedDomainObjectContainer
 import org.gradle.api.Project
 import org.gradle.api.artifacts.Configuration
-import org.gradle.api.artifacts.Dependency
-import org.gradle.api.artifacts.PublishArtifact
 import org.gradle.api.artifacts.type.ArtifactTypeDefinition
 import org.gradle.api.attributes.*
-import org.gradle.api.attributes.Usage.USAGE_ATTRIBUTE
 import org.gradle.api.plugins.BasePlugin
 import org.gradle.api.plugins.ExtensionAware
 import org.gradle.api.plugins.JavaBasePlugin
 import org.gradle.api.tasks.TaskProvider
 import org.gradle.api.tasks.bundling.Jar
 import org.gradle.api.tasks.bundling.Zip
-import org.jetbrains.kotlin.gradle.plugin.internal.artifactTypeAttribute
 import org.jetbrains.kotlin.gradle.plugin.mpp.*
-import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.KotlinCompilationSideEffect
 import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.runKotlinCompilationSideEffects
 import org.jetbrains.kotlin.gradle.targets.js.KotlinJsCompilerAttribute
 import org.jetbrains.kotlin.gradle.targets.js.KotlinWasmTargetAttribute
@@ -39,14 +34,12 @@
     fun configureTarget(
         target: KotlinTargetType,
     ) {
-        target.runKotlinTargetSideEffects()
         target.runKotlinCompilationSideEffects()
-        configureArchivesAndComponent(target)
+        target.runKotlinTargetSideEffects()
         configureBuild(target)
         configurePlatformSpecificModel(target)
     }
 
-    fun configureArchivesAndComponent(target: KotlinTargetType)
     fun configureBuild(target: KotlinTargetType)
     fun configurePlatformSpecificModel(target: KotlinTargetType) = Unit
 }
@@ -95,68 +88,7 @@
 
 abstract class KotlinOnlyTargetConfigurator<KotlinCompilationType : KotlinCompilation<*>, KotlinTargetType : KotlinOnlyTarget<KotlinCompilationType>>(
     createTestCompilation: Boolean,
-) : AbstractKotlinTargetConfigurator<KotlinTargetType>(createTestCompilation) {
-    open val archiveType: String = ArtifactTypeDefinition.JAR_TYPE
-
-    open val archiveTaskType: Class<out Zip>
-        get() = Jar::class.java
-
-    /** The implementations are expected to create a [Zip] task under the name [KotlinTarget.artifactsTaskName] of the [target]. */
-    protected open fun createArchiveTasks(target: KotlinTargetType): TaskProvider<out Zip> {
-        return target.project.registerTask(
-            target.artifactsTaskName,
-            archiveTaskType
-        ) {
-            it.description = "Assembles an archive containing the main classes."
-            it.group = BasePlugin.BUILD_GROUP
-            it.from(target.compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME).output.allOutputs)
-            it.isPreserveFileTimestamps = false
-            it.isReproducibleFileOrder = true
-
-            target.disambiguationClassifier?.let { classifier ->
-                it.archiveAppendix.set(classifier.toLowerCaseAsciiOnly())
-            }
-        }
-    }
-
-    override fun configureArchivesAndComponent(target: KotlinTargetType) {
-        val project = target.project
-
-        val mainCompilation = target.compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME)
-
-        val task = createArchiveTasks(target)
-
-        // Workaround: adding the artifact during configuration seems to interfere with the Java plugin, which results into missing
-        // task dependency 'assemble -> jar' if the Java plugin is applied after this steps
-        project.afterEvaluate {
-            project.artifacts.add(Dependency.ARCHIVES_CONFIGURATION, task) { jarArtifact ->
-                jarArtifact.builtBy(task)
-                jarArtifact.type = archiveType
-
-                val apiElementsConfiguration = project.configurations.getByName(target.apiElementsConfigurationName)
-                // If the target adds its own artifact to this configuration until this happens, don't add another one:
-                addJarIfNoArtifactsPresent(project, apiElementsConfiguration, jarArtifact)
-
-                if (mainCompilation is KotlinCompilationToRunnableFiles<*>) {
-                    val runtimeConfiguration = mainCompilation.internal.configurations.deprecatedRuntimeConfiguration
-                    val runtimeElementsConfiguration = project.configurations.getByName(target.runtimeElementsConfigurationName)
-                    runtimeConfiguration?.let { addJarIfNoArtifactsPresent(project, runtimeConfiguration, jarArtifact) }
-                    addJarIfNoArtifactsPresent(project, runtimeElementsConfiguration, jarArtifact)
-                }
-            }
-        }
-    }
-
-    private fun addJarIfNoArtifactsPresent(project: Project, configuration: Configuration, jarArtifact: PublishArtifact) {
-        if (configuration.artifacts.isEmpty()) {
-            val publications = configuration.outgoing
-
-            // Configure an implicit variant
-            publications.artifacts.add(jarArtifact)
-            publications.attributes.attribute(project.artifactTypeAttribute, archiveType)
-        }
-    }
-}
+) : AbstractKotlinTargetConfigurator<KotlinTargetType>(createTestCompilation)
 
 internal interface KotlinTargetWithTestsConfigurator<R : KotlinTargetTestRun<*>, T : KotlinTargetWithTests<*, R>>
     : KotlinTargetConfigurator<T> {
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/compilationImpl/KotlinCompilationProcessorSideEffect.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/compilationImpl/KotlinCompilationProcessorSideEffect.kt
index 40b0a2d..59cf531 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/compilationImpl/KotlinCompilationProcessorSideEffect.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/compilationImpl/KotlinCompilationProcessorSideEffect.kt
@@ -11,18 +11,15 @@
 import org.jetbrains.kotlin.gradle.plugin.KotlinJsIrSourceSetProcessor
 import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinCommonCompilation
 import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmCompilation
-import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinSharedNativeCompilation
 import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrCompilation
-import org.jetbrains.kotlin.gradle.targets.metadata.NativeSharedCompilationProcessor
 import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider
 
 internal val KotlinCompilationProcessorSideEffect = KotlinCompilationSideEffect { compilation ->
     val processor = when (compilation) {
         is KotlinCommonCompilation -> KotlinCommonSourceSetProcessor(KotlinCompilationInfo(compilation), KotlinTasksProvider())
-        is KotlinSharedNativeCompilation -> NativeSharedCompilationProcessor(compilation)
         is KotlinJvmCompilation -> Kotlin2JvmSourceSetProcessor(KotlinTasksProvider(), KotlinCompilationInfo(compilation))
         is KotlinJsIrCompilation -> KotlinJsIrSourceSetProcessor(KotlinTasksProvider(), KotlinCompilationInfo(compilation))
         else -> null
     }
     processor?.run()
-}
\ No newline at end of file
+}
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/compilationImpl/KotlinCreateNativeCompileTasksSideEffect.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/compilationImpl/KotlinCreateNativeCompileTasksSideEffect.kt
new file mode 100644
index 0000000..797e8fb
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/compilationImpl/KotlinCreateNativeCompileTasksSideEffect.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2010-2023 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.plugin.mpp.compilationImpl
+
+import org.gradle.api.plugins.BasePlugin
+import org.gradle.language.base.plugins.LifecycleBasePlugin
+import org.jetbrains.kotlin.gradle.dsl.ExplicitApiMode
+import org.jetbrains.kotlin.gradle.dsl.topLevelExtension
+import org.jetbrains.kotlin.gradle.plugin.KotlinCompilationInfo
+import org.jetbrains.kotlin.gradle.plugin.KotlinPluginLifecycle
+import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.Companion.kotlinPropertiesProvider
+import org.jetbrains.kotlin.gradle.plugin.SubpluginEnvironment
+import org.jetbrains.kotlin.gradle.plugin.launchInStage
+import org.jetbrains.kotlin.gradle.plugin.mpp.AbstractKotlinNativeCompilation
+import org.jetbrains.kotlin.gradle.plugin.mpp.enabledOnCurrentHost
+import org.jetbrains.kotlin.gradle.targets.klibOutputDirectory
+import org.jetbrains.kotlin.gradle.tasks.KotlinNativeCompile
+import org.jetbrains.kotlin.gradle.tasks.dependsOn
+import org.jetbrains.kotlin.gradle.tasks.registerTask
+
+/**
+ * Will register (and configure) the corresponding [KotlinNativeCompile] task for a given
+ * [AbstractKotlinNativeCompilation] (which includes shared native metadata and 'platform compilations')
+ */
+internal val KotlinCreateNativeCompileTasksSideEffect = KotlinCompilationSideEffect<AbstractKotlinNativeCompilation> { compilation ->
+    val project = compilation.project
+    val extension = project.topLevelExtension
+    val compilationInfo = KotlinCompilationInfo(compilation)
+
+    val kotlinNativeCompile = project.registerTask<KotlinNativeCompile>(
+        compilation.compileKotlinTaskName,
+        listOf(compilationInfo, compilation.compilerOptions.options)
+    ) { task ->
+        task.group = BasePlugin.BUILD_GROUP
+        task.description = "Compiles a klibrary from the '${compilationInfo.compilationName}' " +
+                "compilation in target '${compilationInfo.targetDisambiguationClassifier}'."
+        task.enabled = compilation.konanTarget.enabledOnCurrentHost
+
+        task.destinationDirectory.set(project.klibOutputDirectory(compilationInfo).dir("klib"))
+        if (project.kotlinPropertiesProvider.useK2 == true) {
+            task.compilerOptions.useK2.set(true)
+        }
+        task.runViaBuildToolsApi.value(false).disallowChanges() // K/N is not yet supported
+
+        task.explicitApiMode.value(
+            project.providers.provider {
+                // Plugin explicitly does not configures 'explicitApi' mode for test sources
+                // compilation, as test sources are not published
+                if (compilationInfo.isMain) {
+                    extension.explicitApi
+                } else {
+                    ExplicitApiMode.Disabled
+                }
+            }
+        ).finalizeValueOnRead()
+    }
+
+    compilationInfo.classesDirs.from(kotlinNativeCompile.map { it.outputFile })
+    project.tasks.named(compilation.compileAllTaskName).dependsOn(kotlinNativeCompile)
+    project.tasks.named(LifecycleBasePlugin.ASSEMBLE_TASK_NAME).dependsOn(kotlinNativeCompile)
+    compilation.addCompilerPlugins()
+}
+
+private fun AbstractKotlinNativeCompilation.addCompilerPlugins() {
+    val project = target.project
+
+    project.launchInStage(KotlinPluginLifecycle.Stage.AfterEvaluateBuildscript) {
+        SubpluginEnvironment
+            .loadSubplugins(project)
+            .addSubpluginOptions(project, this@addCompilerPlugins)
+
+        compileTaskProvider.configure {
+            it.compilerPluginClasspath = this@addCompilerPlugins.configurations.pluginConfiguration
+        }
+    }
+}
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/registerKotlinPluginExtensions.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/registerKotlinPluginExtensions.kt
index de246978..2a55170 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/registerKotlinPluginExtensions.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/registerKotlinPluginExtensions.kt
@@ -49,10 +49,12 @@
 import org.jetbrains.kotlin.gradle.plugin.sources.LanguageSettingsSetupAction
 import org.jetbrains.kotlin.gradle.plugin.statistics.MultiplatformBuildStatsReportSetupAction
 import org.jetbrains.kotlin.gradle.scripting.internal.ScriptingGradleSubpluginSetupAction
+import org.jetbrains.kotlin.gradle.targets.*
+import org.jetbrains.kotlin.gradle.targets.CreateArtifactsSideEffect
 import org.jetbrains.kotlin.gradle.targets.CreateDefaultCompilationsSideEffect
 import org.jetbrains.kotlin.gradle.targets.CreateTargetConfigurationsSideEffect
-import org.jetbrains.kotlin.gradle.targets.NativeForwardImplementationToApiElementsSideEffect
 import org.jetbrains.kotlin.gradle.targets.KotlinTargetSideEffect
+import org.jetbrains.kotlin.gradle.targets.NativeForwardImplementationToApiElementsSideEffect
 import org.jetbrains.kotlin.gradle.targets.js.npm.AddNpmDependencyExtensionProjectSetupAction
 import org.jetbrains.kotlin.gradle.targets.metadata.KotlinMetadataTargetSetupAction
 import org.jetbrains.kotlin.gradle.targets.native.CreateFatFrameworksSetupAction
@@ -100,15 +102,26 @@
         register(project, CreateDefaultCompilationsSideEffect)
         register(project, CreateTargetConfigurationsSideEffect)
         register(project, NativeForwardImplementationToApiElementsSideEffect)
+        register(project, CreateArtifactsSideEffect)
     }
 
     KotlinCompilationSideEffect.extensionPoint.apply {
         register(project, KotlinCreateSourcesJarTaskSideEffect)
         register(project, KotlinCreateResourcesTaskSideEffect)
         register(project, KotlinCreateLifecycleTasksSideEffect)
+        register(project, KotlinCreateNativeCompileTasksSideEffect)
         register(project, KotlinCompilationProcessorSideEffect)
     }
 
+    KotlinTargetArtifact.extensionPoint.apply {
+        register(project, KotlinTargetMetadataArtifact)
+        register(project, KotlinLegacyCompatibilityMetadataArtifact)
+        register(project, KotlinJvmJarTargetArtifact)
+        register(project, KotlinJsKlibTargetArtifact)
+        register(project, KotlinNativeKlibTargetArtifact)
+        register(project, KotlinNativeHostSpecificMetadataArtifact)
+    }
+
     KotlinGradleProjectChecker.extensionPoint.apply {
         register(project, CommonMainOrTestWithDependsOnChecker)
         register(project, DeprecatedKotlinNativeTargetsChecker)
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/CreateArtifactsSideEffect.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/CreateArtifactsSideEffect.kt
new file mode 100644
index 0000000..7fe6cc8
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/CreateArtifactsSideEffect.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2010-2023 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
+
+import org.jetbrains.kotlin.gradle.plugin.launch
+
+
+/**
+ * Creates target level artifacts (and exposes them in the 'apiElements' and 'runtimeElements' configurations)
+ * The corresponding task for jvm would be called 'jvmJar'
+ */
+internal val CreateArtifactsSideEffect = KotlinTargetSideEffect { target ->
+    val apiElements = target.project.configurations.getByName(target.apiElementsConfigurationName)
+    val runtimeElements = target.project.configurations.findByName(target.runtimeElementsConfigurationName)
+    KotlinTargetArtifact.extensionPoint[target.project].forEach { artifact ->
+        target.project.launch {
+            artifact.createArtifact(target, apiElements, runtimeElements)
+        }
+    }
+}
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/KotlinJsKlibTargetArtifact.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/KotlinJsKlibTargetArtifact.kt
new file mode 100644
index 0000000..8d4b94c
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/KotlinJsKlibTargetArtifact.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2010-2023 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
+
+import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
+import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
+import org.jetbrains.kotlin.gradle.targets.js.ir.KLIB_TYPE
+import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrTarget
+import org.jetbrains.kotlin.gradle.targets.js.ir.wasmDecamelizedDefaultNameOrNull
+import org.jetbrains.kotlin.gradle.utils.decamelize
+import org.jetbrains.kotlin.gradle.utils.libsDirectory
+
+internal val KotlinJsKlibTargetArtifact = KotlinTargetArtifact { target, apiElements, runtimeElements ->
+    if (target !is KotlinJsIrTarget) return@KotlinTargetArtifact
+
+    val jsKlibTask = target.createArtifactsTask {
+        it.from(target.compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME).output.allOutputs)
+        it.archiveExtension.set(KLIB_TYPE)
+        it.destinationDirectory.set(target.project.libsDirectory)
+
+        if (target.platformType == KotlinPlatformType.wasm) {
+            if (target.wasmDecamelizedDefaultNameOrNull() != null) {
+                target.disambiguationClassifier?.let { classifier ->
+                    it.archiveAppendix.set(classifier.decamelize())
+                }
+            }
+        }
+    }
+
+    target.createPublishArtifact(jsKlibTask, KLIB_TYPE, apiElements, runtimeElements)
+}
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/KotlinJvmJarTargetArtifact.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/KotlinJvmJarTargetArtifact.kt
new file mode 100644
index 0000000..9225315
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/KotlinJvmJarTargetArtifact.kt
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2010-2023 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
+
+import org.gradle.api.artifacts.type.ArtifactTypeDefinition.JAR_TYPE
+import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation.Companion.MAIN_COMPILATION_NAME
+import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget
+
+internal val KotlinJvmJarTargetArtifact = KotlinTargetArtifact { target, apiElements, runtimeElements ->
+    if (target !is KotlinJvmTarget) return@KotlinTargetArtifact
+    val mainCompilation = target.compilations.getByName(MAIN_COMPILATION_NAME)
+
+    val jvmJarTask = target.createArtifactsTask { jar ->
+        jar.from(mainCompilation.output.allOutputs)
+    }
+
+    target.createPublishArtifact(jvmJarTask, JAR_TYPE, apiElements, runtimeElements)
+}
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/KotlinLegacyCompatibilityMetadataArtifact.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/KotlinLegacyCompatibilityMetadataArtifact.kt
new file mode 100644
index 0000000..b682517
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/KotlinLegacyCompatibilityMetadataArtifact.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2010-2023 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
+
+import org.gradle.api.artifacts.type.ArtifactTypeDefinition.JAR_TYPE
+import org.gradle.api.tasks.bundling.Jar
+import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
+import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMetadataTarget
+import org.jetbrains.kotlin.gradle.targets.metadata.isCompatibilityMetadataVariantEnabled
+import org.jetbrains.kotlin.gradle.targets.metadata.isKotlinGranularMetadataEnabled
+import org.jetbrains.kotlin.gradle.tasks.registerTask
+
+internal val KotlinLegacyCompatibilityMetadataArtifact = KotlinTargetArtifact { target, apiElements, _ ->
+    if (target !is KotlinMetadataTarget) return@KotlinTargetArtifact
+    if (!target.project.isKotlinGranularMetadataEnabled) return@KotlinTargetArtifact
+    if (!target.project.isCompatibilityMetadataVariantEnabled) return@KotlinTargetArtifact
+
+    val legacyJar = target.project.registerTask<Jar>(target.legacyArtifactsTaskName)
+    legacyJar.configure {
+        // Capture it here to use in onlyIf spec. Direct usage causes serialization of target attempt when configuration cache is enabled
+        it.description = "Assembles an archive containing the Kotlin metadata of the commonMain source set."
+        it.from(target.compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME).output.allOutputs)
+    }
+
+    target.createPublishArtifact(legacyJar, JAR_TYPE, apiElements)
+}
\ No newline at end of file
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/KotlinMetadataTargetArtifact.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/KotlinMetadataTargetArtifact.kt
new file mode 100644
index 0000000..9ea1e9b
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/KotlinMetadataTargetArtifact.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2010-2023 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
+
+import org.gradle.api.artifacts.Dependency.ARCHIVES_CONFIGURATION
+import org.gradle.api.artifacts.type.ArtifactTypeDefinition.JAR_TYPE
+import org.gradle.api.attributes.Category
+import org.gradle.api.attributes.Usage
+import org.jetbrains.kotlin.gradle.plugin.categoryByName
+import org.jetbrains.kotlin.gradle.plugin.internal.artifactTypeAttribute
+import org.jetbrains.kotlin.gradle.plugin.mpp.*
+import org.jetbrains.kotlin.gradle.plugin.usageByName
+import org.jetbrains.kotlin.gradle.targets.metadata.createGenerateProjectStructureMetadataTask
+import org.jetbrains.kotlin.gradle.targets.metadata.filesWithUnpackedArchives
+import org.jetbrains.kotlin.gradle.targets.metadata.isCompatibilityMetadataVariantEnabled
+import org.jetbrains.kotlin.gradle.targets.metadata.isKotlinGranularMetadataEnabled
+import org.jetbrains.kotlin.gradle.targets.native.internal.includeCommonizedCInteropMetadata
+
+internal val KotlinTargetMetadataArtifact = KotlinTargetArtifact { target, apiElements, _ ->
+    if (target !is KotlinMetadataTarget || !target.project.isKotlinGranularMetadataEnabled) return@KotlinTargetArtifact
+
+    apiElements.attributes.attribute(Usage.USAGE_ATTRIBUTE, target.project.usageByName(KotlinUsages.KOTLIN_METADATA))
+    apiElements.attributes.attribute(Category.CATEGORY_ATTRIBUTE, target.project.categoryByName(Category.LIBRARY))
+
+    val metadataJarTask = target.createArtifactsTask { jar ->
+        jar.description = "Assembles a jar archive containing the metadata for all Kotlin source sets."
+        if (target.project.isCompatibilityMetadataVariantEnabled) {
+            jar.archiveClassifier.set("all")
+        }
+    }
+
+    /* Include 'KotlinProjectStructureMetadata' file */
+    val generateMetadata = target.project.createGenerateProjectStructureMetadataTask()
+    metadataJarTask.configure { jar ->
+        jar.from(generateMetadata.map { it.resultFile }) { spec ->
+            spec.into("META-INF").rename { MULTIPLATFORM_PROJECT_METADATA_JSON_FILE_NAME }
+        }
+    }
+
+    /* Include output of metadata compilations into metadata jar (including commonizer output if available */
+    val hostSpecificSourceSets = getHostSpecificSourceSets(target.project)
+    target.compilations.all { compilation ->
+        if (compilation.defaultSourceSet in hostSpecificSourceSets) return@all
+        val metadataContent = target.project.filesWithUnpackedArchives(compilation.output.allOutputs, setOf("klib"))
+        metadataJarTask.configure { it.from(metadataContent) { spec -> spec.into(compilation.defaultSourceSet.name) } }
+        if (compilation is KotlinSharedNativeCompilation) {
+            target.project.includeCommonizedCInteropMetadata(metadataJarTask, compilation)
+        }
+    }
+
+    target.createPublishArtifact(metadataJarTask, JAR_TYPE, apiElements)
+}
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/KotlinNativeHostSpecificMetadataArtifact.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/KotlinNativeHostSpecificMetadataArtifact.kt
new file mode 100644
index 0000000..eef8498
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/KotlinNativeHostSpecificMetadataArtifact.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2010-2023 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
+
+import org.gradle.api.artifacts.Dependency
+import org.gradle.api.attributes.Usage
+import org.gradle.api.plugins.BasePlugin
+import org.gradle.jvm.tasks.Jar
+import org.jetbrains.kotlin.gradle.plugin.launch
+import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
+import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinSharedNativeCompilation
+import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinUsages
+import org.jetbrains.kotlin.gradle.plugin.mpp.getHostSpecificSourceSets
+import org.jetbrains.kotlin.gradle.plugin.usageByName
+import org.jetbrains.kotlin.gradle.targets.metadata.filesWithUnpackedArchives
+import org.jetbrains.kotlin.gradle.targets.metadata.findMetadataCompilation
+import org.jetbrains.kotlin.gradle.targets.metadata.isKotlinGranularMetadataEnabled
+import org.jetbrains.kotlin.gradle.targets.native.internal.includeCommonizedCInteropMetadata
+import org.jetbrains.kotlin.gradle.tasks.locateOrRegisterTask
+import org.jetbrains.kotlin.gradle.utils.copyAttributes
+import org.jetbrains.kotlin.util.capitalizeDecapitalize.toLowerCaseAsciiOnly
+
+internal val KotlinNativeHostSpecificMetadataArtifact = KotlinTargetArtifact { target, apiElements, _ ->
+    if (target !is KotlinNativeTarget) return@KotlinTargetArtifact
+    if (!target.project.isKotlinGranularMetadataEnabled) return@KotlinTargetArtifact
+    val project = target.project
+
+    target.project.configurations.create(target.hostSpecificMetadataElementsConfigurationName) { configuration ->
+        configuration.isCanBeConsumed = true
+        configuration.isCanBeResolved = false
+
+        configuration.extendsFrom(*apiElements.extendsFrom.toTypedArray())
+
+        copyAttributes(from = apiElements.attributes, to = configuration.attributes)
+        configuration.attributes.attribute(Usage.USAGE_ATTRIBUTE, target.project.usageByName(KotlinUsages.KOTLIN_METADATA))
+    }
+
+    val hostSpecificSourceSets = getHostSpecificSourceSets(target.project)
+    if (hostSpecificSourceSets.isEmpty()) return@KotlinTargetArtifact
+
+    val hostSpecificMetadataJar = project.locateOrRegisterTask<Jar>(target.hostSpecificMetadataElementsConfigurationName) { metadataJar ->
+        metadataJar.archiveAppendix.set(project.provider { target.disambiguationClassifier.orEmpty().toLowerCaseAsciiOnly() })
+        metadataJar.archiveClassifier.set("metadata")
+        metadataJar.group = BasePlugin.BUILD_GROUP
+        metadataJar.description = "Assembles Kotlin metadata of target '${target.name}'."
+
+        val publishable = target.publishable
+        metadataJar.onlyIf { publishable }
+
+        project.launch {
+            val metadataCompilations = hostSpecificSourceSets.mapNotNull {
+                project.findMetadataCompilation(it)
+            }
+
+            metadataCompilations.forEach { compilation ->
+                metadataJar.from(project.filesWithUnpackedArchives(compilation.output.allOutputs, setOf("klib"))) { spec ->
+                    spec.into(compilation.name)
+                }
+                metadataJar.dependsOn(compilation.output.classesDirs)
+
+                if (compilation is KotlinSharedNativeCompilation) {
+                    project.includeCommonizedCInteropMetadata(metadataJar, compilation)
+                }
+            }
+        }
+    }
+    project.artifacts.add(Dependency.ARCHIVES_CONFIGURATION, hostSpecificMetadataJar)
+    project.artifacts.add(target.hostSpecificMetadataElementsConfigurationName, hostSpecificMetadataJar) { artifact ->
+        artifact.classifier = "metadata"
+    }
+}
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/KotlinNativeKlibTargetArtifact.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/KotlinNativeKlibTargetArtifact.kt
new file mode 100644
index 0000000..c7c648f
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/KotlinNativeKlibTargetArtifact.kt
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2010-2023 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
+
+import org.gradle.api.DefaultTask
+import org.gradle.api.Project
+import org.gradle.api.file.DirectoryProperty
+import org.gradle.api.internal.plugins.DefaultArtifactPublicationSet
+import org.gradle.api.plugins.BasePlugin
+import org.gradle.api.provider.Provider
+import org.gradle.api.tasks.TaskProvider
+import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
+import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation.Companion.MAIN_COMPILATION_NAME
+import org.jetbrains.kotlin.gradle.plugin.KotlinCompilationInfo
+import org.jetbrains.kotlin.gradle.plugin.KotlinNativeTargetConfigurator.NativeArtifactFormat
+import org.jetbrains.kotlin.gradle.plugin.internal.artifactTypeAttribute
+import org.jetbrains.kotlin.gradle.plugin.mpp.AbstractKotlinNativeCompilation
+import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
+import org.jetbrains.kotlin.gradle.plugin.mpp.enabledOnCurrentHost
+import org.jetbrains.kotlin.gradle.tasks.dependsOn
+import org.jetbrains.kotlin.gradle.tasks.registerTask
+import java.io.File
+
+internal val KotlinNativeKlibTargetArtifact = KotlinTargetArtifact { target, apiElements, _ ->
+    if (target !is KotlinNativeTarget) return@KotlinTargetArtifact
+    /* Just registering a dummy placeholder that other tasks can use as umbrella */
+    val artifactsTask = target.project.registerTask<DefaultTask>(target.artifactsTaskName) {
+        it.group = BasePlugin.BUILD_GROUP
+        it.description = "Assembles outputs for target '${target.name}'."
+    }
+
+    apiElements.outgoing.attributes.attribute(target.project.artifactTypeAttribute, NativeArtifactFormat.KLIB)
+
+    target.compilations.getByName(MAIN_COMPILATION_NAME).let { mainCompilation ->
+        artifactsTask.dependsOn(mainCompilation.compileTaskProvider)
+        createRegularKlibArtifact(mainCompilation)
+    }
+}
+
+internal fun createRegularKlibArtifact(compilation: AbstractKotlinNativeCompilation) = createKlibArtifact(
+    compilation = compilation,
+    artifactFile = compilation.compileTaskProvider.map { it.outputFile.get() },
+    classifier = null,
+    producingTask = compilation.compileTaskProvider
+)
+
+internal fun createKlibArtifact(
+    compilation: AbstractKotlinNativeCompilation,
+    artifactFile: Provider<File>,
+    classifier: String?,
+    producingTask: TaskProvider<*>,
+) {
+    if (!compilation.konanTarget.enabledOnCurrentHost) {
+        return
+    }
+
+    val apiElementsName = compilation.target.apiElementsConfigurationName
+    with(compilation.project.configurations.getByName(apiElementsName)) {
+        val klibArtifact = compilation.project.artifacts.add(name, artifactFile) { artifact ->
+            artifact.name = compilation.compilationName
+            artifact.extension = "klib"
+            artifact.type = "klib"
+            artifact.classifier = classifier
+            artifact.builtBy(producingTask)
+        }
+        compilation.project.extensions.getByType(DefaultArtifactPublicationSet::class.java).addCandidate(klibArtifact)
+        artifacts.add(klibArtifact)
+        attributes.attribute(compilation.project.artifactTypeAttribute, NativeArtifactFormat.KLIB)
+    }
+}
+
+internal fun Project.klibOutputDirectory(
+    compilation: KotlinCompilationInfo,
+): DirectoryProperty {
+    val targetSubDirectory = compilation.targetDisambiguationClassifier?.let { "$it/" }.orEmpty()
+    return project.objects.directoryProperty().value(
+        layout.buildDirectory.dir("classes/kotlin/$targetSubDirectory${compilation.compilationName}")
+    )
+}
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/KotlinTargetArtifact.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/KotlinTargetArtifact.kt
new file mode 100644
index 0000000..f77255f
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/KotlinTargetArtifact.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2010-2023 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
+
+import org.gradle.api.artifacts.Configuration
+import org.gradle.api.artifacts.Dependency.ARCHIVES_CONFIGURATION
+import org.gradle.api.artifacts.PublishArtifact
+import org.gradle.api.plugins.BasePlugin
+import org.gradle.api.tasks.TaskProvider
+import org.gradle.jvm.tasks.Jar
+import org.jetbrains.kotlin.gradle.plugin.KotlinGradlePluginExtensionPoint
+import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
+import org.jetbrains.kotlin.gradle.plugin.internal.artifactTypeAttribute
+import org.jetbrains.kotlin.gradle.tasks.registerTask
+import org.jetbrains.kotlin.util.capitalizeDecapitalize.toLowerCaseAsciiOnly
+
+internal fun interface KotlinTargetArtifact {
+    suspend fun createArtifact(target: KotlinTarget, apiElements: Configuration, runtimeElements: Configuration?)
+
+    companion object {
+        val extensionPoint = KotlinGradlePluginExtensionPoint<KotlinTargetArtifact>()
+    }
+}
+
+internal fun KotlinTarget.createArtifactsTask(configure: (Jar) -> Unit = {}): TaskProvider<Jar> {
+    return project.registerTask<Jar>(artifactsTaskName) { jar ->
+        jar.description = "Assembles an archive containing the main classes."
+        jar.group = BasePlugin.BUILD_GROUP
+        jar.isPreserveFileTimestamps = false
+        jar.isReproducibleFileOrder = true
+
+        disambiguationClassifier?.let { classifier ->
+            jar.archiveAppendix.set(classifier.toLowerCaseAsciiOnly())
+        }
+
+        configure(jar)
+    }
+}
+
+internal fun KotlinTarget.createPublishArtifact(
+    artifactTask: TaskProvider<*>,
+    artifactType: String,
+    vararg elementsConfiguration: Configuration?,
+): PublishArtifact {
+    val artifact = project.artifacts.add(ARCHIVES_CONFIGURATION, artifactTask) { artifact ->
+        artifact.builtBy(artifactTask)
+        artifact.type = artifactType
+    }
+
+    elementsConfiguration.filterNotNull().forEach { configuration ->
+        configuration.outgoing.artifacts.add(artifact)
+        configuration.outgoing.attributes.attribute(project.artifactTypeAttribute, artifactType)
+    }
+
+    return artifact
+}
\ No newline at end of file
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrTargetConfigurator.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrTargetConfigurator.kt
index fba7b8f..c3a6d68 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrTargetConfigurator.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrTargetConfigurator.kt
@@ -5,9 +5,6 @@
 
 package org.jetbrains.kotlin.gradle.targets.js.ir
 
-import org.gradle.api.tasks.TaskProvider
-import org.gradle.api.tasks.bundling.Jar
-import org.gradle.api.tasks.bundling.Zip
 import org.jetbrains.kotlin.gradle.dsl.JsModuleKind
 import org.jetbrains.kotlin.gradle.dsl.JsSourceMapEmbedMode
 import org.jetbrains.kotlin.gradle.dsl.KotlinJsCompilerOptions
@@ -17,8 +14,6 @@
 import org.jetbrains.kotlin.gradle.targets.js.KotlinJsReportAggregatingTestRun
 import org.jetbrains.kotlin.gradle.testing.internal.kotlinTestRegistry
 import org.jetbrains.kotlin.gradle.testing.testTaskName
-import org.jetbrains.kotlin.gradle.utils.decamelize
-import org.jetbrains.kotlin.gradle.utils.libsDirectory
 
 open class KotlinJsIrTargetConfigurator :
     KotlinOnlyTargetConfigurator<KotlinJsIrCompilation, KotlinJsIrTarget>(true),
@@ -28,12 +23,6 @@
 
     override val testRunClass: Class<KotlinJsReportAggregatingTestRun> get() = KotlinJsReportAggregatingTestRun::class.java
 
-    override val archiveType: String
-        get() = KLIB_TYPE
-
-    override val archiveTaskType: Class<out Zip>
-        get() = Jar::class.java
-
     override fun createTestRun(
         name: String,
         target: KotlinJsIrTarget
@@ -61,24 +50,6 @@
         return result
     }
 
-    override fun createArchiveTasks(target: KotlinJsIrTarget): TaskProvider<out Zip> {
-        val libsDirectory = target.project.libsDirectory
-        return super.createArchiveTasks(target).apply {
-            configure {
-                it.archiveExtension.set(KLIB_TYPE)
-                it.destinationDirectory.set(libsDirectory)
-
-                if (target.platformType == KotlinPlatformType.wasm) {
-                    if (target.wasmDecamelizedDefaultNameOrNull() != null) {
-                        target.disambiguationClassifier?.let { classifier ->
-                            it.archiveAppendix.set(classifier.decamelize())
-                        }
-                    }
-                }
-            }
-        }
-    }
-
 
     internal companion object {
         internal fun KotlinJsCompilerOptions.configureJsDefaultOptions(
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolver/KotlinCompilationNpmResolver.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolver/KotlinCompilationNpmResolver.kt
index 88c7d28..4e4ad64 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolver/KotlinCompilationNpmResolver.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolver/KotlinCompilationNpmResolver.kt
@@ -92,9 +92,10 @@
             if (compilation.isMain()) {
                 project.tasks
                     .withType(Zip::class.java)
-                    .named(npmProject.target.artifactsTaskName)
-                    .configure {
-                        it.dependsOn(packageJsonTask)
+                    .configureEach {
+                        if (it.name == npmProject.target.artifactsTaskName) {
+                            it.dependsOn(packageJsonTask)
+                        }
                     }
 
                 val publicPackageJsonConfiguration = createPublicPackageJsonConfiguration()
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt
index b5d493a..73d2935 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt
@@ -12,12 +12,9 @@
 import org.gradle.api.attributes.Category.CATEGORY_ATTRIBUTE
 import org.gradle.api.attributes.Usage.USAGE_ATTRIBUTE
 import org.gradle.api.file.FileCollection
-import org.gradle.api.plugins.BasePlugin
 import org.gradle.api.tasks.TaskProvider
 import org.gradle.api.tasks.bundling.Jar
-import org.gradle.api.tasks.bundling.Zip
 import org.jetbrains.kotlin.commonizer.SharedCommonizerTarget
-import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions
 import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
 import org.jetbrains.kotlin.gradle.dsl.metadataTarget
 import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
@@ -28,14 +25,10 @@
 import org.jetbrains.kotlin.gradle.targets.native.internal.createCInteropMetadataDependencyClasspath
 import org.jetbrains.kotlin.gradle.targets.native.internal.includeCommonizedCInteropMetadata
 import org.jetbrains.kotlin.gradle.targets.native.internal.sharedCommonizerTarget
-import org.jetbrains.kotlin.gradle.tasks.KotlinNativeCompile
-import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider
 import org.jetbrains.kotlin.gradle.tasks.registerTask
-import org.jetbrains.kotlin.gradle.utils.whenEvaluated
 import org.jetbrains.kotlin.gradle.utils.*
 import org.jetbrains.kotlin.statistics.metrics.BooleanMetrics
 import org.jetbrains.kotlin.tooling.core.extrasLazyProperty
-import org.jetbrains.kotlin.util.capitalizeDecapitalize.toLowerCaseAsciiOnly
 
 internal const val COMMON_MAIN_ELEMENTS_CONFIGURATION_NAME = "commonMainMetadataElements"
 
@@ -90,22 +83,10 @@
                 compileKotlinTaskProvider.configure { it.onlyIf { isCompatibilityMetadataVariantEnabled } }
             }
 
-            val allMetadataJar = target.project.tasks.named<Jar>(ALL_METADATA_JAR_NAME)
-            createMetadataCompilationsForCommonSourceSets(target, allMetadataJar)
-
-            configureProjectStructureMetadataGeneration(target.project, allMetadataJar)
+            createMetadataCompilationsForCommonSourceSets(target)
 
             configureMetadataDependenciesConfigurationsForCommonSourceSets(target)
 
-            target.project.configurations.getByName(target.apiElementsConfigurationName).run {
-                attributes.attribute(USAGE_ATTRIBUTE, target.project.usageByName(KotlinUsages.KOTLIN_METADATA))
-                attributes.attribute(CATEGORY_ATTRIBUTE, target.project.categoryByName(Category.LIBRARY))
-                /** Note: to add this artifact here is enough to avoid duplicate artifacts in this configuration: the default artifact
-                 * won't be added (later) if there's already an artifact in the configuration, see
-                 * [KotlinOnlyTargetConfigurator.configureArchivesAndComponent] */
-                target.project.artifacts.add(target.apiElementsConfigurationName, allMetadataJar)
-            }
-
             if (target.project.isCompatibilityMetadataVariantEnabled) {
                 createCommonMainElementsConfiguration(target)
             }
@@ -115,47 +96,6 @@
         }
     }
 
-    override fun createArchiveTasks(target: KotlinMetadataTarget): TaskProvider<out Zip> {
-        if (!target.project.isKotlinGranularMetadataEnabled)
-            return super.createArchiveTasks(target)
-
-        val result = target.project.registerTask<Jar>(target.artifactsTaskName) {
-            it.group = BasePlugin.BUILD_GROUP
-            it.isReproducibleFileOrder = true
-            it.isPreserveFileTimestamps = false
-            /** The content is added to this JAR in [KotlinMetadataTargetConfigurator.configureTarget]. */
-        }
-
-        result.configure { allMetadataJar ->
-            allMetadataJar.description = "Assembles a jar archive containing the metadata for all Kotlin source sets."
-            allMetadataJar.group = BasePlugin.BUILD_GROUP
-
-            if (target.project.isCompatibilityMetadataVariantEnabled) {
-                allMetadataJar.archiveClassifier.set("all")
-            }
-
-            target.disambiguationClassifier?.let { classifier ->
-                allMetadataJar.archiveAppendix.set(classifier.toLowerCaseAsciiOnly())
-            }
-        }
-
-        if (target.project.isCompatibilityMetadataVariantEnabled) {
-            val legacyJar = target.project.registerTask<Jar>(target.legacyArtifactsTaskName)
-            legacyJar.configure {
-                // Capture it here to use in onlyIf spec. Direct usage causes serialization of target attempt when configuration cache is enabled
-                val isCompatibilityMetadataVariantEnabled = target.project.isCompatibilityMetadataVariantEnabled
-                it.description = "Assembles an archive containing the Kotlin metadata of the commonMain source set."
-                if (!isCompatibilityMetadataVariantEnabled) {
-                    it.archiveClassifier.set("commonMain")
-                }
-                it.onlyIf { isCompatibilityMetadataVariantEnabled }
-                it.from(target.compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME).output.allOutputs)
-            }
-        }
-
-        return result
-    }
-
     private fun configureMetadataDependenciesConfigurationsForCommonSourceSets(target: KotlinMetadataTarget) {
         target.project.whenEvaluated {
             kotlinExtension.sourceSets.all { sourceSet ->
@@ -169,7 +109,6 @@
 
     private fun createMetadataCompilationsForCommonSourceSets(
         target: KotlinMetadataTarget,
-        allMetadataJar: TaskProvider<out Jar>,
     ) = target.project.launchInStage(KotlinPluginLifecycle.Stage.AfterFinaliseDsl) {
         withRestrictedStages(KotlinPluginLifecycle.Stage.upTo(KotlinPluginLifecycle.Stage.FinaliseCompilations)) {
             // Do this after all targets are configured by the user build script
@@ -179,7 +118,7 @@
 
             val sourceSetsWithMetadataCompilations: Map<KotlinSourceSet, KotlinCompilation<*>> = publishedCommonSourceSets
                 .associateWith { sourceSet ->
-                    createMetadataCompilation(target, sourceSet, allMetadataJar, sourceSet in hostSpecificSourceSets)
+                    createMetadataCompilation(target, sourceSet, sourceSet in hostSpecificSourceSets)
                 }
                 .onEach { (sourceSet, compilation) ->
                     if (!isMetadataCompilationSupported(sourceSet)) {
@@ -224,16 +163,6 @@
         return true
     }
 
-    private fun configureProjectStructureMetadataGeneration(project: Project, allMetadataJar: TaskProvider<out Jar>) {
-        val generateMetadata = project.createGenerateProjectStructureMetadataTask()
-
-        allMetadataJar.configure {
-            it.from(generateMetadata.map { it.resultFile }) { spec ->
-                spec.into("META-INF").rename { MULTIPLATFORM_PROJECT_METADATA_JSON_FILE_NAME }
-            }
-        }
-    }
-
     private fun exportDependenciesForPublishing(
         compilation: KotlinCompilation<*>,
     ) {
@@ -274,7 +203,6 @@
     private suspend fun createMetadataCompilation(
         target: KotlinMetadataTarget,
         sourceSet: KotlinSourceSet,
-        allMetadataJar: TaskProvider<out Jar>,
         isHostSpecific: Boolean,
     ): KotlinCompilation<*> {
         val project = target.project
@@ -300,13 +228,7 @@
 
             configureMetadataDependenciesForCompilation(this@apply)
 
-            if (!isHostSpecific) {
-                val metadataContent = project.filesWithUnpackedArchives(this@apply.output.allOutputs, setOf("klib"))
-                allMetadataJar.configure { it.from(metadataContent) { spec -> spec.into(this@apply.defaultSourceSet.name) } }
-                if (this is KotlinSharedNativeCompilation) {
-                    project.includeCommonizedCInteropMetadata(allMetadataJar, this)
-                }
-            } else {
+            if (isHostSpecific) {
                 if (platformCompilations.filterIsInstance<KotlinNativeCompilation>().none { it.konanTarget.enabledOnCurrentHost }) {
                     // Then we don't have any platform module to put this compiled source set to, so disable the compilation task:
                     compileKotlinTaskProvider.configure { it.enabled = false }
@@ -365,15 +287,6 @@
     }
 }
 
-internal class NativeSharedCompilationProcessor(
-    private val compilation: KotlinSharedNativeCompilation,
-) : KotlinCompilationProcessor<KotlinNativeCompile>(KotlinCompilationInfo(compilation)) {
-
-    override val kotlinTask: TaskProvider<out KotlinNativeCompile> =
-        KotlinNativeTargetConfigurator.createKlibCompilationTask(compilationInfo, compilation.konanTarget)
-
-    override fun run() = Unit
-}
 
 internal fun Project.createGenerateProjectStructureMetadataTask(): TaskProvider<GenerateProjectStructureMetadata> =
     project.registerTask(lowerCamelCaseName("generateProjectStructureMetadata")) { task ->
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTarget.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTarget.kt
index de7828f..f2c8168 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTarget.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTarget.kt
@@ -36,7 +36,7 @@
 
 abstract class KotlinNativeTarget @Inject constructor(
     project: Project,
-    val konanTarget: KonanTarget
+    val konanTarget: KonanTarget,
 ) : KotlinTargetWithBinaries<KotlinNativeCompilation, KotlinNativeBinaryContainer>(
     project,
     KotlinPlatformType.native
@@ -64,44 +64,11 @@
                 .intersect(mainCompilation.allKotlinSourceSets)
 
             if (hostSpecificSourceSets.isNotEmpty()) {
-                val hostSpecificMetadataJar = project.locateOrRegisterTask<Jar>(hostSpecificMetadataJarTaskName) { metadataJar ->
-                    metadataJar.archiveAppendix.set(project.provider { disambiguationClassifier.orEmpty().toLowerCaseAsciiOnly() })
-                    metadataJar.archiveClassifier.set("metadata")
-                    metadataJar.group = BasePlugin.BUILD_GROUP
-                    metadataJar.description = "Assembles Kotlin metadata of target '${name}'."
-
-                    val publishable = this@KotlinNativeTarget.publishable
-                    metadataJar.onlyIf { publishable }
-
-                    launch {
-                        val metadataCompilations = hostSpecificSourceSets.mapNotNull {
-                            project.findMetadataCompilation(it)
-                        }
-
-                        metadataCompilations.forEach { compilation ->
-                            metadataJar.from(project.filesWithUnpackedArchives(compilation.output.allOutputs, setOf("klib"))) { spec ->
-                                spec.into(compilation.name)
-                            }
-                            metadataJar.dependsOn(compilation.output.classesDirs)
-
-                            if (compilation is KotlinSharedNativeCompilation) {
-                                project.includeCommonizedCInteropMetadata(metadataJar, compilation)
-                            }
-                        }
-                    }
-                }
-                project.artifacts.add(Dependency.ARCHIVES_CONFIGURATION, hostSpecificMetadataJar)
-
-                val metadataConfiguration = project.configurations.getByName(hostSpecificMetadataElementsConfigurationName)
-                project.artifacts.add(metadataConfiguration.name, hostSpecificMetadataJar) { artifact ->
-                    artifact.classifier = "metadata"
-                }
-
                 mutableUsageContexts.add(
                     DefaultKotlinUsageContext(
                         mainCompilation,
                         KotlinUsageContext.MavenScope.COMPILE,
-                        metadataConfiguration.name,
+                        hostSpecificMetadataElementsConfigurationName,
                         includeIntoProjectStructureMetadata = false
                     )
                 )
@@ -196,7 +163,7 @@
 private suspend fun <T> getHostSpecificElements(
     fragments: Iterable<T>,
     isNativeShared: suspend (T) -> Boolean,
-    getKonanTargets: suspend (T) -> Set<KonanTarget>
+    getKonanTargets: suspend (T) -> Set<KonanTarget>,
 ): Set<T> = fragments.filterTo(mutableSetOf()) { isNativeShared(it) && isHostSpecificKonanTargetsSet(getKonanTargets(it)) }
 
 internal suspend fun getHostSpecificSourceSets(project: Project): Set<KotlinSourceSet> {
@@ -234,7 +201,7 @@
 
 abstract class KotlinNativeTargetWithTests<T : KotlinNativeBinaryTestRun>(
     project: Project,
-    konanTarget: KonanTarget
+    konanTarget: KonanTarget,
 ) : KotlinNativeTarget(project, konanTarget), KotlinTargetWithTests<NativeBinaryTestRunSource, T> {
 
     override lateinit var testRuns: NamedDomainObjectContainer<T>
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTargetConfigurator.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTargetConfigurator.kt
index f44e404..c58efcfe 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTargetConfigurator.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTargetConfigurator.kt
@@ -32,6 +32,8 @@
 import org.jetbrains.kotlin.gradle.plugin.mpp.apple.XcodeVersionTask
 import org.jetbrains.kotlin.gradle.plugin.mpp.apple.registerEmbedAndSignAppleFrameworkTask
 import org.jetbrains.kotlin.gradle.plugin.mpp.apple.version
+import org.jetbrains.kotlin.gradle.targets.createKlibArtifact
+import org.jetbrains.kotlin.gradle.targets.klibOutputDirectory
 import org.jetbrains.kotlin.gradle.targets.metadata.isKotlinGranularMetadataEnabled
 import org.jetbrains.kotlin.gradle.targets.native.*
 import org.jetbrains.kotlin.gradle.targets.native.internal.*
@@ -150,8 +152,7 @@
 
                     // Add the interop library in publication.
                     createKlibArtifact(
-                        compilationInfo = compilationInfo,
-                        konanTarget = konanTarget,
+                        compilation,
                         artifactFile = interopTask.map { it.outputFile },
                         classifier = "cinterop-${interop.name}",
                         producingTask = interopTask,
@@ -187,30 +188,6 @@
         }
     }
 
-    override fun configureArchivesAndComponent(target: T): Unit = with(target.project) {
-        registerTask<DefaultTask>(target.artifactsTaskName) {
-            it.group = BasePlugin.BUILD_GROUP
-            it.description = "Assembles outputs for target '${target.name}'."
-        }
-        target.compilations.all { createKlibCompilationTask(KotlinCompilationInfo(it), it.konanTarget) }
-
-        val apiElements = configurations.getByName(target.apiElementsConfigurationName)
-
-        apiElements.outgoing.attributes.attribute(artifactTypeAttribute, NativeArtifactFormat.KLIB)
-
-        if (project.isKotlinGranularMetadataEnabled) {
-            project.configurations.create(target.hostSpecificMetadataElementsConfigurationName) { configuration ->
-                configuration.isCanBeConsumed = true
-                configuration.isCanBeResolved = false
-
-                configuration.extendsFrom(*apiElements.extendsFrom.toTypedArray())
-
-                copyAttributes(from = apiElements.attributes, to = configuration.attributes)
-                configuration.attributes.attribute(USAGE_ATTRIBUTE, objects.named(Usage::class.java, KotlinUsages.KOTLIN_METADATA))
-            }
-        }
-    }
-
     protected fun configureCInterops(target: KotlinNativeTarget): Unit = with(target.project) {
         locateOrCreateCInteropApiElementsConfiguration(target)
         target.compilations.all { compilation ->
@@ -352,130 +329,7 @@
         const val INTEROP_GROUP = "interop"
         const val RUN_GROUP = "run"
 
-        internal fun createKlibCompilationTask(
-            compilationInfo: KotlinCompilationInfo,
-            konanTarget: KonanTarget,
-        ): TaskProvider<KotlinNativeCompile> {
-            val project = compilationInfo.project
-            val ext = project.topLevelExtension
-            val compileTaskProvider = project.registerTask<KotlinNativeCompile>(
-                compilationInfo.compileKotlinTaskName,
-                listOf(
-                    compilationInfo,
-                    compilationInfo.compilerOptions.options as KotlinNativeCompilerOptions
-                )
-            ) {
-                it.group = BasePlugin.BUILD_GROUP
-                it.description = "Compiles a klibrary from the '${compilationInfo.compilationName}' " +
-                        "compilation in target '${compilationInfo.targetDisambiguationClassifier}'."
-                it.enabled = konanTarget.enabledOnCurrentHost
 
-                it.destinationDirectory.set(project.klibOutputDirectory(compilationInfo).dir("klib"))
-                val propertiesProvider = PropertiesProvider(project)
-                if (propertiesProvider.useK2 == true) {
-                    it.compilerOptions.useK2.set(true)
-                }
-                it.runViaBuildToolsApi.value(false).disallowChanges() // K/N is not yet supported
-
-                it.explicitApiMode
-                    .value(
-                        project.providers.provider {
-                            // Plugin explicitly does not configures 'explicitApi' mode for test sources
-                            // compilation, as test sources are not published
-                            if (compilationInfo.isMain) {
-                                ext.explicitApi
-                            } else {
-                                ExplicitApiMode.Disabled
-                            }
-                        }
-                    )
-                    .finalizeValueOnRead()
-
-            }
-
-            compilationInfo.classesDirs.from(compileTaskProvider.map { it.outputFile })
-
-            project.project.tasks.named(compilationInfo.compileAllTaskName).dependsOn(compileTaskProvider)
-
-            if (compilationInfo.isMain) {
-                if (compilationInfo is KotlinCompilationInfo.TCS && compilationInfo.compilation is KotlinNativeCompilation) {
-                    project.project.tasks.named(compilationInfo.compilation.target.artifactsTaskName).dependsOn(compileTaskProvider)
-                }
-
-                project.project.tasks.named(LifecycleBasePlugin.ASSEMBLE_TASK_NAME).dependsOn(compileTaskProvider)
-            }
-
-            val shouldAddCompileOutputsToElements = compilationInfo.isMain
-            if (shouldAddCompileOutputsToElements) {
-                createRegularKlibArtifact(compilationInfo, konanTarget, compileTaskProvider)
-            }
-
-            if (compilationInfo is KotlinCompilationInfo.TCS && compilationInfo.compilation is AbstractKotlinNativeCompilation) {
-                // FIXME: support compiler plugins for PM20
-                addCompilerPlugins(compilationInfo.compilation)
-            }
-
-            return compileTaskProvider
-        }
-
-        private fun Project.klibOutputDirectory(
-            compilation: KotlinCompilationInfo,
-        ): DirectoryProperty {
-            val targetSubDirectory = compilation.targetDisambiguationClassifier?.let { "$it/" }.orEmpty()
-            return project.objects.directoryProperty().value(
-                layout.buildDirectory.dir("classes/kotlin/$targetSubDirectory${compilation.compilationName}")
-            )
-        }
-
-        private fun addCompilerPlugins(compilation: AbstractKotlinNativeCompilation) {
-            val project = compilation.target.project
-
-            project.whenEvaluated {
-                SubpluginEnvironment
-                    .loadSubplugins(project)
-                    .addSubpluginOptions(project, compilation)
-
-                compilation.compileKotlinTaskProvider.configure {
-                    it.compilerPluginClasspath = compilation.configurations.pluginConfiguration
-                }
-            }
-        }
-
-        internal fun createRegularKlibArtifact(
-            compilation: KotlinCompilationInfo,
-            konanTarget: KonanTarget,
-            compileTask: TaskProvider<out KotlinNativeCompile>,
-        ) = createKlibArtifact(compilation, konanTarget, compileTask.map { it.outputFile.get() }, null, compileTask)
-
-        private fun createKlibArtifact(
-            compilationInfo: KotlinCompilationInfo,
-            konanTarget: KonanTarget,
-            artifactFile: Provider<File>,
-            classifier: String?,
-            producingTask: TaskProvider<*>,
-        ) {
-            val project = compilationInfo.project
-            if (!konanTarget.enabledOnCurrentHost) {
-                return
-            }
-
-            val apiElementsName = when (compilationInfo) {
-                is KotlinCompilationInfo.TCS -> compilationInfo.compilation.target.apiElementsConfigurationName
-            }
-
-            with(project.configurations.getByName(apiElementsName)) {
-                val klibArtifact = project.project.artifacts.add(name, artifactFile) { artifact ->
-                    artifact.name = compilationInfo.compilationName
-                    artifact.extension = "klib"
-                    artifact.type = "klib"
-                    artifact.classifier = classifier
-                    artifact.builtBy(producingTask)
-                }
-                project.project.extensions.getByType(DefaultArtifactPublicationSet::class.java).addCandidate(klibArtifact)
-                artifacts.add(klibArtifact)
-                attributes.attribute(project.artifactTypeAttribute, NativeArtifactFormat.KLIB)
-            }
-        }
     }
 }
 
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/createKotlinKlibCompilationTask.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/createKotlinKlibCompilationTask.kt
new file mode 100644
index 0000000..894a2dc
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/createKotlinKlibCompilationTask.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2010-2023 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
+
+import org.gradle.api.Project
+import org.gradle.api.file.DirectoryProperty
+import org.gradle.api.internal.plugins.DefaultArtifactPublicationSet
+import org.gradle.api.plugins.BasePlugin
+import org.gradle.api.provider.Provider
+import org.gradle.api.tasks.TaskProvider
+import org.gradle.language.base.plugins.LifecycleBasePlugin
+import org.jetbrains.kotlin.gradle.dsl.ExplicitApiMode
+import org.jetbrains.kotlin.gradle.dsl.KotlinNativeCompilerOptions
+import org.jetbrains.kotlin.gradle.dsl.topLevelExtension
+import org.jetbrains.kotlin.gradle.plugin.*
+import org.jetbrains.kotlin.gradle.plugin.KotlinCompilationInfo
+import org.jetbrains.kotlin.gradle.plugin.KotlinPluginLifecycle.Stage.AfterEvaluateBuildscript
+import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
+import org.jetbrains.kotlin.gradle.plugin.internal.artifactTypeAttribute
+import org.jetbrains.kotlin.gradle.plugin.launchInStage
+import org.jetbrains.kotlin.gradle.plugin.mpp.AbstractKotlinNativeCompilation
+import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeCompilation
+import org.jetbrains.kotlin.gradle.plugin.mpp.enabledOnCurrentHost
+import org.jetbrains.kotlin.gradle.tasks.KotlinNativeCompile
+import org.jetbrains.kotlin.gradle.tasks.dependsOn
+import org.jetbrains.kotlin.gradle.tasks.registerTask
+import org.jetbrains.kotlin.konan.target.KonanTarget
+import java.io.File
+