Refactor how configurations and tasks are created in KPM
diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/DependencyGraphResolver.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/DependencyGraphResolver.kt
index dddf2b5..867a4d8 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/DependencyGraphResolver.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/DependencyGraphResolver.kt
@@ -11,17 +11,14 @@
 import org.gradle.api.artifacts.result.ResolvedDependencyResult
 import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
 import org.jetbrains.kotlin.gradle.dsl.topLevelExtension
+import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.configurations.ResolvableMetadataConfiguration
 import org.jetbrains.kotlin.gradle.plugin.mpp.resolvableMetadataConfiguration
 import org.jetbrains.kotlin.gradle.plugin.sources.KotlinDependencyScope
 import org.jetbrains.kotlin.project.model.*
 
-internal fun resolvableMetadataConfiguration(
-    module: KotlinGradleModule
-) = module.project.configurations.getByName(module.resolvableMetadataConfigurationName)
-
 internal fun configurationToResolveMetadataDependencies(project: Project, requestingModule: KotlinModule): Configuration =
     when (project.topLevelExtension) {
-        is KotlinPm20ProjectExtension -> resolvableMetadataConfiguration(requestingModule as KotlinGradleModule)
+        is KotlinPm20ProjectExtension -> (requestingModule as KotlinGradleModule).configuration(ResolvableMetadataConfiguration)
         else -> resolvableMetadataConfiguration(
             project,
             project.kotlinExtension.sourceSets, // take dependencies from all source sets; TODO introduce consistency scopes?
diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/GradlePlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/GradlePlugin.kt
index d2cecaf..60e1250 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/GradlePlugin.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/GradlePlugin.kt
@@ -14,6 +14,12 @@
 import org.jetbrains.kotlin.gradle.dsl.KotlinTopLevelExtension
 import org.jetbrains.kotlin.gradle.dsl.pm20Extension
 import org.jetbrains.kotlin.gradle.internal.customizeKotlinDependencies
+import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.configurations.MetadataElementsConfiguration
+import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.configurations.ResolvableMetadataConfiguration
+import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.configurations.SourcesElementsConfiguration
+import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.tasks.CompileAllTask
+import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.tasks.GeneratePsmTask
+import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.tasks.MetadataJarTask
 import org.jetbrains.kotlin.gradle.utils.checkGradleCompatibility
 import org.jetbrains.kotlin.project.model.KotlinModuleIdentifier
 import javax.inject.Inject
@@ -22,6 +28,19 @@
 abstract class KotlinPm20GradlePlugin @Inject constructor(
     @Inject private val softwareComponentFactory: SoftwareComponentFactory
 ) : Plugin<Project> {
+
+    private val PROTO_CONFIGURATIONS: List<ProtoConfiguration> = listOf(
+        ResolvableMetadataConfiguration,
+        MetadataElementsConfiguration,
+        SourcesElementsConfiguration,
+    )
+
+    private val PROTO_TASKS: List<ProtoTask<*>> = listOf(
+        CompileAllTask,
+        GeneratePsmTask,
+        MetadataJarTask, // needs to be after GeneratePsmTask
+    )
+
     override fun apply(project: Project) {
         checkGradleCompatibility("the Kotlin Multiplatform plugin", GradleVersion.version("6.1"))
 
@@ -31,10 +50,26 @@
         createDefaultModules(project)
         customizeKotlinDependencies(project)
         registerDefaultVariantFactories(project)
+
+        registerConfigurationByProtos(project, PROTO_CONFIGURATIONS)
+        registerTasksByProtos(project, PROTO_TASKS)
+
         setupFragmentsMetadata(project)
         setupPublication(project)
     }
 
+    private fun registerTasksByProtos(project: Project, protoTasks: List<ProtoTask<*>>) {
+        for (proto in protoTasks) {
+            proto.registerTask(project)
+        }
+    }
+
+    private fun registerConfigurationByProtos(project: Project, protoConfigurations: List<ProtoConfiguration>) {
+        for (proto in protoConfigurations) {
+            proto.registerInProject(project)
+        }
+    }
+
     private fun registerDefaultVariantFactories(project: Project) {
         project.pm20Extension.modules.configureEach { module ->
             module.fragments.registerFactory(
@@ -72,7 +107,6 @@
     private fun setupFragmentsMetadata(project: Project) {
         project.pm20Extension.modules.all { module ->
             configureMetadataResolutionAndBuild(module)
-            configureMetadataExposure(module)
         }
     }
 
@@ -85,8 +119,8 @@
     private fun setupPublicationForModule(module: KotlinGradleModule) {
         val project = module.project
 
-        val metadataElements = project.configurations.getByName(metadataElementsConfigurationName(module))
-        val sourceElements = project.configurations.getByName(sourceElementsConfigurationName(module))
+        val metadataElements = module.configuration(MetadataElementsConfiguration)
+        val sourceElements = module.configuration(SourcesElementsConfiguration)
 
         val componentName = rootPublicationComponentName(module)
         val rootSoftwareComponent = softwareComponentFactory.adhoc(componentName).also {
@@ -96,7 +130,6 @@
         }
 
         module.ifMadePublic {
-            val metadataDependencyConfiguration = resolvableMetadataConfiguration(module)
             project.pluginManager.withPlugin("maven-publish") {
                 project.extensions.getByType(PublishingExtension::class.java).publications.create(
                     componentName,
@@ -105,7 +138,7 @@
                     publication.from(rootSoftwareComponent)
                     publication.versionMapping { versionMapping ->
                         versionMapping.allVariants {
-                            it.fromResolutionOf(metadataDependencyConfiguration)
+                            it.fromResolutionOf(module.configuration(ResolvableMetadataConfiguration))
                         }
                     }
                 }
@@ -198,4 +231,4 @@
     fun inModule(module: KotlinGradleModule, configure: T.() -> Unit) {
         getOrCreateFragment(module).configure()
     }
-}
\ No newline at end of file
+}
diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinGradleModule.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinGradleModule.kt
index 713b8d0..a61dafa 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinGradleModule.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinGradleModule.kt
@@ -67,9 +67,6 @@
     override fun toString(): String = "$moduleIdentifier (Gradle)"
 }
 
-internal val KotlinGradleModule.resolvableMetadataConfigurationName: String
-    get() = lowerCamelCaseName(name, "DependenciesMetadata")
-
 internal val KotlinGradleModule.isMain
     get() = moduleIdentifier.moduleClassifier == null
 
@@ -77,4 +74,4 @@
     lowerCamelCaseName(moduleClassifier, simpleName)
 
 internal fun KotlinGradleModule.variantsContainingFragment(fragment: KotlinModuleFragment): Iterable<KotlinGradleVariant> =
-    variants.filter { fragment in it.refinesClosure }
\ No newline at end of file
+    variants.filter { fragment in it.refinesClosure }
diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinMetadataCompilationData.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinMetadataCompilationData.kt
index 04157a5..6cddfee 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinMetadataCompilationData.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinMetadataCompilationData.kt
@@ -17,6 +17,7 @@
 import org.jetbrains.kotlin.gradle.dsl.pm20Extension
 import org.jetbrains.kotlin.gradle.plugin.*
 import org.jetbrains.kotlin.gradle.plugin.mpp.*
+import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.configurations.ResolvableMetadataConfiguration
 import org.jetbrains.kotlin.gradle.plugin.sources.DefaultLanguageSettingsBuilder
 import org.jetbrains.kotlin.gradle.targets.metadata.ResolvedMetadataFilesProvider
 import org.jetbrains.kotlin.gradle.targets.metadata.createTransformedMetadataClasspath
@@ -61,7 +62,7 @@
     override val compileDependencyFiles: FileCollection by project.provider {
         createTransformedMetadataClasspath(
             project,
-            resolvableMetadataConfiguration(fragment.containingModule),
+            fragment.containingModule.configuration(ResolvableMetadataConfiguration),
             lazy { fragment.refinesClosure.minus(fragment).map { metadataCompilationRegistry.byFragment(it).output.classesDirs } },
             resolvedMetadataFiles
         )
@@ -202,4 +203,4 @@
         withAllCommonCallbacks += action
         withAllNativeCallbacks += action
     }
-}
\ No newline at end of file
+}
diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/ProtoConfiguration.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/ProtoConfiguration.kt
new file mode 100644
index 0000000..e2162f3
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/ProtoConfiguration.kt
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.gradle.plugin.mpp.pm20
+
+import org.gradle.api.Project
+import org.gradle.api.artifacts.Configuration
+
+interface ProtoConfiguration {
+    fun registerInProject(project: Project)
+    fun nameIn(module: KotlinGradleModule): String
+}
+
+fun KotlinGradleModule.configurationName(proto: ProtoConfiguration): String = proto.nameIn(this)
+fun KotlinGradleModule.configuration(proto: ProtoConfiguration): Configuration =
+    project.configurations.getByName(configurationName(proto))
diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/ProtoTask.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/ProtoTask.kt
new file mode 100644
index 0000000..c72f45b
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/ProtoTask.kt
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.gradle.plugin.mpp.pm20
+
+import org.gradle.api.Project
+import org.gradle.api.Task
+import org.gradle.api.tasks.TaskProvider
+
+interface ProtoTask<T : Task> {
+    fun registerTask(project: Project)
+
+    fun nameIn(module: KotlinGradleModule): String
+}
+
+fun <T : Task> KotlinGradleModule.taskName(proto: ProtoTask<T>): String = proto.nameIn(this)
+
+fun <T : Task> KotlinGradleModule.taskProvider(proto: ProtoTask<T>): TaskProvider<T> =
+    project.tasks.named(taskName(proto)) as TaskProvider<T>
diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/TransformKotlinGranularMetadataForFragment.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/TransformKotlinGranularMetadataForFragment.kt
index 75009e7..f95335f 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/TransformKotlinGranularMetadataForFragment.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/TransformKotlinGranularMetadataForFragment.kt
@@ -11,6 +11,7 @@
 import org.gradle.api.tasks.*
 import org.jetbrains.kotlin.gradle.plugin.mpp.ExtractableMetadataFiles
 import org.jetbrains.kotlin.gradle.plugin.mpp.MetadataDependencyResolution
+import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.configurations.ResolvableMetadataConfiguration
 import org.jetbrains.kotlin.gradle.targets.metadata.ResolvedMetadataFilesProvider
 import org.jetbrains.kotlin.gradle.utils.getValue
 import java.io.File
@@ -35,7 +36,7 @@
     @get:InputFiles
     @get:PathSensitive(PathSensitivity.RELATIVE)
     internal val allSourceSetsMetadataConfiguration: FileCollection by lazy {
-        project.files(resolvableMetadataConfiguration(fragment.containingModule))
+        project.files(fragment.containingModule.configuration(ResolvableMetadataConfiguration))
     }
 
     @Suppress("unused") // Gradle input
@@ -95,4 +96,4 @@
     override val buildDependencies: Iterable<TaskProvider<*>> = listOf(taskProvider)
     override val metadataResolutions: Iterable<MetadataDependencyResolution> by taskProvider.map { it.metadataDependencyResolutions }
     override val metadataFilesByResolution: Map<MetadataDependencyResolution, FileCollection> by taskProvider.map { it.filesByResolution }
-}
\ No newline at end of file
+}
diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/configurations/MetadataElementsConfiguration.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/configurations/MetadataElementsConfiguration.kt
new file mode 100644
index 0000000..20233d0
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/configurations/MetadataElementsConfiguration.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.gradle.plugin.mpp.pm20.configurations
+
+import org.gradle.api.Project
+import org.gradle.api.attributes.Usage
+import org.jetbrains.kotlin.gradle.dsl.pm20Extension
+import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
+import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinUsages
+import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.*
+import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.setModuleCapability
+import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.tasks.MetadataJarTask
+import org.jetbrains.kotlin.gradle.plugin.usageByName
+import org.jetbrains.kotlin.gradle.utils.addExtendsFromRelation
+
+object MetadataElementsConfiguration : ProtoConfiguration {
+    override fun registerInProject(project: Project) {
+        project.pm20Extension.modules.all { module ->
+            project.configurations.create(nameIn(module)) {
+                it.isCanBeConsumed = false
+                module.ifMadePublic {
+                    it.isCanBeConsumed = true
+                }
+
+                it.isCanBeResolved = false
+
+                project.artifacts.add(it.name, module.taskProvider(MetadataJarTask))
+
+                it.attributes.attribute(Usage.USAGE_ATTRIBUTE, project.usageByName(KotlinUsages.KOTLIN_METADATA))
+                it.attributes.attribute(KotlinPlatformType.attribute, KotlinPlatformType.common)
+
+                module.fragments.all { fragment ->
+                    // FIXME: native api-implementation
+                    project.addExtendsFromRelation(it.name, fragment.apiConfigurationName)
+                }
+
+                setModuleCapability(it, module)
+            }
+        }
+    }
+
+    override fun nameIn(module: KotlinGradleModule): String = module.disambiguateName("metadataElements")
+}
diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/configurations/ResolvableMetadataConfiguration.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/configurations/ResolvableMetadataConfiguration.kt
new file mode 100644
index 0000000..a725d29
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/configurations/ResolvableMetadataConfiguration.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.gradle.plugin.mpp.pm20.configurations
+
+import org.gradle.api.Project
+import org.gradle.api.artifacts.Configuration
+import org.gradle.api.attributes.Usage
+import org.jetbrains.kotlin.gradle.dsl.pm20Extension
+import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinUsages
+import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinGradleModule
+import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.ProtoConfiguration
+import org.jetbrains.kotlin.gradle.plugin.usageByName
+import org.jetbrains.kotlin.gradle.utils.addExtendsFromRelation
+import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
+
+object ResolvableMetadataConfiguration : ProtoConfiguration {
+    override fun registerInProject(project: Project) {
+        project.pm20Extension.modules.all { module ->
+            project.configurations.create(nameIn(module)).apply {
+                isCanBeConsumed = false
+                isCanBeResolved = true
+                attributes.attribute(Usage.USAGE_ATTRIBUTE, project.usageByName(KotlinUsages.KOTLIN_METADATA))
+                module.fragments.all { fragment ->
+                    project.addExtendsFromRelation(name, fragment.apiConfigurationName)
+                    project.addExtendsFromRelation(name, fragment.implementationConfigurationName)
+                }
+            }
+        }
+    }
+
+    override fun nameIn(module: KotlinGradleModule): String = lowerCamelCaseName(module.name, "DependenciesMetadata")
+}
diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/configurations/SourcesElementsConfiguration.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/configurations/SourcesElementsConfiguration.kt
new file mode 100644
index 0000000..277bbd2
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/configurations/SourcesElementsConfiguration.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.gradle.plugin.mpp.pm20.configurations
+
+import org.gradle.api.Project
+import org.gradle.api.attributes.Bundling
+import org.gradle.api.attributes.Category
+import org.gradle.api.attributes.DocsType
+import org.gradle.api.attributes.Usage
+import org.jetbrains.kotlin.gradle.dsl.pm20Extension
+import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinUsages
+import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinGradleModule
+import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.ProtoConfiguration
+import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.disambiguateName
+import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.taskProvider
+import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.tasks.SourcesJarTask
+import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.ComputedCapability
+import org.jetbrains.kotlin.gradle.plugin.usageByName
+
+object SourcesElementsConfiguration : ProtoConfiguration {
+    override fun registerInProject(project: Project) {
+        project.pm20Extension.modules.all { module ->
+            project.configurations.create(nameIn(module)).apply {
+                isCanBeResolved = false
+                isCanBeConsumed = true
+
+                attributes.attribute(Usage.USAGE_ATTRIBUTE, project.usageByName(KotlinUsages.KOTLIN_SOURCES))
+                attributes.attribute(Category.CATEGORY_ATTRIBUTE, project.objects.named(Category::class.java, Category.DOCUMENTATION))
+                attributes.attribute(Bundling.BUNDLING_ATTRIBUTE, project.objects.named(Bundling::class.java, Bundling.EXTERNAL))
+                attributes.attribute(DocsType.DOCS_TYPE_ATTRIBUTE, project.objects.named(DocsType::class.java, DocsType.SOURCES))
+
+                outgoing.artifact(module.taskProvider(SourcesJarTask).get()) {
+                    it.classifier = "sources"
+                }
+
+                ComputedCapability.fromModuleOrNull(module)?.let {
+                    outgoing.capability(it)
+                }
+            }
+        }
+    }
+
+    override fun nameIn(module: KotlinGradleModule): String = module.disambiguateName("sourceElements")
+}
diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/fragmentsMetadataCompilation.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/fragmentsMetadataCompilation.kt
index 1d39804..dd54b89 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/fragmentsMetadataCompilation.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/fragmentsMetadataCompilation.kt
@@ -5,32 +5,22 @@
 
 package org.jetbrains.kotlin.gradle.plugin.mpp.pm20
 
-import org.gradle.api.DefaultTask
 import org.gradle.api.Project
-import org.gradle.api.attributes.Usage
 import org.gradle.api.tasks.TaskProvider
-import org.gradle.jvm.tasks.Jar
 import org.jetbrains.kotlin.gradle.dsl.pm20Extension
 import org.jetbrains.kotlin.gradle.plugin.*
 import org.jetbrains.kotlin.gradle.plugin.KotlinCommonSourceSetProcessor
 import org.jetbrains.kotlin.gradle.plugin.mpp.*
-import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.ComputedCapability
-import org.jetbrains.kotlin.gradle.targets.metadata.createGenerateProjectStructureMetadataTask
-import org.jetbrains.kotlin.gradle.targets.metadata.filesWithUnpackedArchives
+import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.tasks.CompileAllTask
 import org.jetbrains.kotlin.gradle.tasks.*
 import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider
-import org.jetbrains.kotlin.gradle.tasks.registerTask
 import org.jetbrains.kotlin.gradle.tasks.withType
-import org.jetbrains.kotlin.gradle.utils.addExtendsFromRelation
-import org.jetbrains.kotlin.gradle.utils.dashSeparatedName
 import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
-import org.jetbrains.kotlin.library.KLIB_FILE_EXTENSION
 import org.jetbrains.kotlin.project.model.KotlinModuleFragment
 import java.util.concurrent.Callable
 
 internal fun configureMetadataResolutionAndBuild(module: KotlinGradleModule) {
     val project = module.project
-    createResolvableMetadataConfigurationForModule(module)
 
     val metadataCompilationRegistry = MetadataCompilationRegistry()
     project.pm20Extension.metadataCompilationRegistryByModuleId[module.moduleIdentifier] =
@@ -38,76 +28,11 @@
 
     configureMetadataCompilationsAndCreateRegistry(module, metadataCompilationRegistry)
 
-    configureMetadataJarTask(module, metadataCompilationRegistry)
-    generateAndExportProjectStructureMetadata(module)
-}
-
-internal fun configureMetadataExposure(module: KotlinGradleModule) {
-    val project = module.project
-    project.configurations.create(metadataElementsConfigurationName(module)).apply {
-        isCanBeConsumed = false
-        module.ifMadePublic {
-            isCanBeConsumed = true
-        }
-        isCanBeResolved = false
-        project.artifacts.add(name, project.tasks.named(metadataJarName(module)))
-        attributes.attribute(Usage.USAGE_ATTRIBUTE, project.usageByName(KotlinUsages.KOTLIN_METADATA))
-        attributes.attribute(KotlinPlatformType.attribute, KotlinPlatformType.common)
-        module.fragments.all { fragment ->
-            // FIXME: native api-implementation
-            project.addExtendsFromRelation(name, fragment.apiConfigurationName)
-        }
-        setModuleCapability(this, module)
-    }
-
-    val sourcesArtifactAppendix = dashSeparatedName(module.moduleClassifier, "all", "sources")
-    val sourcesArtifact = sourcesJarTaskNamed(
-        module.disambiguateName("allSourcesJar"),
-        project,
-        lazy { FragmentSourcesProvider().getAllFragmentSourcesAsMap(module).entries.associate { it.key.fragmentName to it.value.get() } },
-        sourcesArtifactAppendix
-    )
-    DocumentationVariantConfigurator().createSourcesElementsConfiguration(
-        project, sourceElementsConfigurationName(module),
-        sourcesArtifact.get(), "sources", ComputedCapability.fromModuleOrNull(module)
-    )
-}
-
-fun metadataElementsConfigurationName(module: KotlinGradleModule) =
-    module.disambiguateName("metadataElements")
-
-fun sourceElementsConfigurationName(module: KotlinGradleModule) =
-    module.disambiguateName("sourceElements")
-
-private fun generateAndExportProjectStructureMetadata(
-    module: KotlinGradleModule
-) {
-    val project = module.project
-    val projectStructureMetadata = project.createGenerateProjectStructureMetadataTask(module)
-    project.tasks.withType<Jar>().named(metadataJarName(module)).configure { jar ->
-        jar.from(projectStructureMetadata.map { it.resultFile }) { spec ->
-            spec.into("META-INF")
-                .rename { MULTIPLATFORM_PROJECT_METADATA_JSON_FILE_NAME }
-        }
-    }
     GlobalProjectStructureMetadataStorage.registerProjectStructureMetadata(project) {
         buildProjectStructureMetadata(module)
     }
 }
 
-private fun createResolvableMetadataConfigurationForModule(module: KotlinGradleModule) {
-    val project = module.project
-    project.configurations.create(module.resolvableMetadataConfigurationName).apply {
-        isCanBeConsumed = false
-        isCanBeResolved = true
-        attributes.attribute(Usage.USAGE_ATTRIBUTE, project.usageByName(KotlinUsages.KOTLIN_METADATA))
-        module.fragments.all { fragment ->
-            project.addExtendsFromRelation(name, fragment.apiConfigurationName)
-            project.addExtendsFromRelation(name, fragment.implementationConfigurationName)
-        }
-    }
-}
-
 private fun configureMetadataCompilationsAndCreateRegistry(
     module: KotlinGradleModule,
     metadataCompilationRegistry: MetadataCompilationRegistry
@@ -123,10 +48,9 @@
         metadataResolutionByFragment[fragment] = transformation
         createExtractMetadataTask(project, fragment, transformation)
     }
-    val compileAllTask = project.registerTask<DefaultTask>(lowerCamelCaseName(module.moduleClassifier, "metadataClasses"))
     module.fragments.all { fragment ->
-        createCommonMetadataCompilation(fragment, compileAllTask, metadataCompilationRegistry)
-        createNativeMetadataCompilation(fragment, compileAllTask, metadataCompilationRegistry)
+        createCommonMetadataCompilation(fragment, metadataCompilationRegistry)
+        createNativeMetadataCompilation(fragment, metadataCompilationRegistry)
     }
     metadataCompilationRegistry.withAll { compilation ->
         project.tasks.matching { it.name == compilation.compileKotlinTaskName }.configureEach { task ->
@@ -135,37 +59,8 @@
     }
 }
 
-private fun configureMetadataJarTask(
-    module: KotlinGradleModule,
-    registry: MetadataCompilationRegistry
-) {
-    val project = module.project
-    val allMetadataJar = project.registerTask<Jar>(metadataJarName(module)) { task ->
-        if (module.moduleClassifier != null) {
-            task.archiveClassifier.set(module.moduleClassifier)
-        }
-        task.archiveAppendix.set("metadata")
-        task.from()
-    }
-    module.fragments.all { fragment ->
-        allMetadataJar.configure { jar ->
-            val metadataOutput = project.files(Callable {
-                val compilationData = registry.byFragment(fragment)
-                project.filesWithUnpackedArchives(compilationData.output.allOutputs, setOf(KLIB_FILE_EXTENSION))
-            })
-            jar.from(metadataOutput) { spec ->
-                spec.into(fragment.fragmentName)
-            }
-        }
-    }
-}
-
-internal fun metadataJarName(module: KotlinGradleModule) =
-    lowerCamelCaseName(module.moduleClassifier, "metadataJar")
-
 private fun createCommonMetadataCompilation(
     fragment: KotlinGradleFragment,
-    compileAllTask: TaskProvider<DefaultTask>,
     metadataCompilationRegistry: MetadataCompilationRegistry
 ) {
     val module = fragment.containingModule
@@ -176,7 +71,7 @@
             project,
             fragment,
             module,
-            compileAllTask,
+            module.taskProvider(CompileAllTask),
             metadataCompilationRegistry,
             lazy { resolvedMetadataProviders(fragment) }
         )
@@ -186,7 +81,6 @@
 
 private fun createNativeMetadataCompilation(
     fragment: KotlinGradleFragment,
-    compileAllTask: TaskProvider<DefaultTask>,
     metadataCompilationRegistry: MetadataCompilationRegistry
 ) {
     val module = fragment.containingModule
@@ -197,7 +91,7 @@
             project,
             fragment,
             module,
-            compileAllTask,
+            module.taskProvider(CompileAllTask),
             metadataCompilationRegistry,
             lazy { resolvedMetadataProviders(fragment) }
         )
@@ -285,4 +179,4 @@
 }
 
 private fun transformFragmentMetadataTaskName(fragment: KotlinModuleFragment) =
-    lowerCamelCaseName("resolve", fragment.disambiguateName("Metadata"))
\ No newline at end of file
+    lowerCamelCaseName("resolve", fragment.disambiguateName("Metadata"))
diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/tasks/CompileAllTask.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/tasks/CompileAllTask.kt
new file mode 100644
index 0000000..e85c994
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/tasks/CompileAllTask.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.gradle.plugin.mpp.pm20.tasks
+
+import org.gradle.api.DefaultTask
+import org.gradle.api.Project
+import org.jetbrains.kotlin.gradle.dsl.pm20Extension
+import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinGradleModule
+import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.ProtoTask
+import org.jetbrains.kotlin.gradle.tasks.registerTask
+import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
+
+object CompileAllTask : ProtoTask<DefaultTask> {
+    override fun registerTask(project: Project) {
+        project.pm20Extension.modules.all { module -> module.project.registerTask<DefaultTask>(nameIn(module)) }
+    }
+
+    override fun nameIn(module: KotlinGradleModule): String {
+        return lowerCamelCaseName(module.moduleClassifier, "metadataClasses")
+    }
+}
diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/tasks/GeneratePsmTask.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/tasks/GeneratePsmTask.kt
new file mode 100644
index 0000000..563d3ec
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/tasks/GeneratePsmTask.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.gradle.plugin.mpp.pm20.tasks
+
+import org.gradle.api.Project
+import org.jetbrains.kotlin.gradle.dsl.pm20Extension
+import org.jetbrains.kotlin.gradle.plugin.mpp.GenerateProjectStructureMetadata
+import org.jetbrains.kotlin.gradle.plugin.mpp.buildProjectStructureMetadata
+import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinGradleModule
+import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.ProtoTask
+import org.jetbrains.kotlin.gradle.tasks.registerTask
+import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
+
+object GeneratePsmTask : ProtoTask<GenerateProjectStructureMetadata> {
+    override fun registerTask(project: Project) {
+        project.pm20Extension.modules.all { module ->
+            project.registerTask<GenerateProjectStructureMetadata>(nameIn(module)) { task ->
+                task.lazyKotlinProjectStructureMetadata = lazy { buildProjectStructureMetadata(module) }
+            }
+        }
+    }
+
+    override fun nameIn(module: KotlinGradleModule): String =
+        lowerCamelCaseName("generate", module.moduleClassifier, "ProjectStructureMetadata")
+}
+
+// TODO: move the task itself closer?
diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/tasks/MetadataJarTask.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/tasks/MetadataJarTask.kt
new file mode 100644
index 0000000..e8a81aa
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/tasks/MetadataJarTask.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.gradle.plugin.mpp.pm20.tasks
+
+import org.gradle.api.Project
+import org.gradle.jvm.tasks.Jar
+import org.jetbrains.kotlin.gradle.dsl.pm20Extension
+import org.jetbrains.kotlin.gradle.plugin.mpp.MULTIPLATFORM_PROJECT_METADATA_JSON_FILE_NAME
+import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinGradleModule
+import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.ProtoTask
+import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.taskProvider
+import org.jetbrains.kotlin.gradle.targets.metadata.filesWithUnpackedArchives
+import org.jetbrains.kotlin.gradle.tasks.registerTask
+import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
+import org.jetbrains.kotlin.library.KLIB_FILE_EXTENSION
+import java.util.concurrent.Callable
+
+internal object MetadataJarTask : ProtoTask<Jar> {
+    override fun registerTask(project: Project) {
+        project.pm20Extension.modules.all { module ->
+            val allMetadataJar = project.registerTask<Jar>(nameIn(module)) { task ->
+                if (module.moduleClassifier != null) {
+                    task.archiveClassifier.set(module.moduleClassifier)
+                }
+                task.archiveAppendix.set("metadata")
+                task.from() // TODO: ????
+                task.from(module.taskProvider(GeneratePsmTask).map { it.resultFile }) { spec ->
+                    spec.into("META-INF")
+                        .rename { MULTIPLATFORM_PROJECT_METADATA_JSON_FILE_NAME }
+                }
+            }
+
+            val registry = project.pm20Extension.metadataCompilationRegistryByModuleId[module.moduleIdentifier]!!
+
+            module.fragments.all { fragment ->
+                allMetadataJar.configure { jar ->
+                    val metadataOutput = project.files(Callable {
+                        val compilationData = registry.byFragment(fragment)
+                        project.filesWithUnpackedArchives(compilationData.output.allOutputs, setOf(KLIB_FILE_EXTENSION))
+                    })
+                    jar.from(metadataOutput) { spec ->
+                        spec.into(fragment.fragmentName)
+                    }
+                }
+            }
+        }
+    }
+
+    override fun nameIn(module: KotlinGradleModule): String =
+        lowerCamelCaseName(module.moduleClassifier, "metadataJar")
+}
diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/tasks/SourcesJarTask.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/tasks/SourcesJarTask.kt
new file mode 100644
index 0000000..6d1799d
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/tasks/SourcesJarTask.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.gradle.plugin.mpp.pm20.tasks
+
+import org.gradle.api.Project
+import org.gradle.jvm.tasks.Jar
+import org.jetbrains.kotlin.gradle.dsl.pm20Extension
+import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.FragmentSourcesProvider
+import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinGradleModule
+import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.ProtoTask
+import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.disambiguateName
+import org.jetbrains.kotlin.gradle.plugin.mpp.sourcesJarTaskNamed
+import org.jetbrains.kotlin.gradle.utils.dashSeparatedName
+
+object SourcesJarTask : ProtoTask<Jar> {
+    override fun registerTask(project: Project) {
+        project.pm20Extension.modules.all { module ->
+            val sourcesArtifactAppendix = dashSeparatedName(module.moduleClassifier, "all", "sources")
+
+            // not really nice, but can't remove sourcesJarTaskNamed because of other clients, and don't want to duplicate code either
+            sourcesJarTaskNamed(
+                module.disambiguateName("allSourcesJar"),
+                project,
+                lazy { FragmentSourcesProvider().getAllFragmentSourcesAsMap(module).entries.associate { it.key.fragmentName to it.value.get() } },
+                sourcesArtifactAppendix
+            )
+        }
+    }
+
+    override fun nameIn(module: KotlinGradleModule): String {
+        TODO("Not yet implemented")
+    }
+}
diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt
index 8b6d22e..c1a5147 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt
@@ -507,10 +507,6 @@
     override fun run() = Unit
 }
 
-internal fun Project.createGenerateProjectStructureMetadataTask(module: KotlinGradleModule): TaskProvider<GenerateProjectStructureMetadata> =
-    project.registerTask(lowerCamelCaseName("generate", module.moduleClassifier, "ProjectStructureMetadata")) { task ->
-        task.lazyKotlinProjectStructureMetadata = lazy { buildProjectStructureMetadata(module) }
-    }
 
 internal fun Project.createGenerateProjectStructureMetadataTask(): TaskProvider<GenerateProjectStructureMetadata> =
     project.registerTask(lowerCamelCaseName("generateProjectStructureMetadata")) { task ->