Model mapping: support Metadata target

Add compilations to the metadata target according to the content
of the KPM metadata compilation registry (`main` module only)
This commit is contained in:
Sergey Igushkin
2022-02-01 01:08:47 +04:00
committed by Space
parent 289c42f431
commit 4aeef7169d
12 changed files with 158 additions and 24 deletions
@@ -14,6 +14,7 @@ import org.gradle.api.file.SourceDirectorySet
import org.gradle.api.tasks.SourceSet
import org.gradle.api.tasks.TaskProvider
import org.gradle.api.tasks.bundling.AbstractArchiveTask
import org.gradle.kotlin.dsl.withType
import org.jetbrains.kotlin.gradle.dsl.*
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptionsImpl
import org.jetbrains.kotlin.gradle.plugin.*
@@ -25,6 +26,7 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.ofVariantCompileDependen
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.unambiguousNameInProject
import org.jetbrains.kotlin.gradle.plugin.sources.defaultSourceSetLanguageSettingsChecker
import org.jetbrains.kotlin.gradle.plugin.sources.getVisibleSourceSetsFromAssociateCompilations
import org.jetbrains.kotlin.gradle.plugin.sources.kpm.FragmentMappedKotlinSourceSet
import org.jetbrains.kotlin.gradle.plugin.sources.resolveAllDependsOnSourceSets
import org.jetbrains.kotlin.gradle.plugin.sources.withAllDependsOnSourceSets
import org.jetbrains.kotlin.gradle.targets.js.KotlinJsTarget
@@ -403,6 +405,39 @@ internal open class SharedNativeCompilationDetails(
}
}
internal open class MetadataMappedCompilationDetails<T : KotlinCommonOptions>(
override val target: KotlinMetadataTarget,
final override val compilationData: AbstractKotlinFragmentMetadataCompilationData<T>
) : CompilationDetails<T> {
override val compileDependencyFilesHolder: DependencyFilesHolder =
DependencyFilesHolder.ofMetadataCompilationDependencies(compilationData)
override val kotlinDependenciesHolder: HasKotlinDependencies
get() = compilationData.fragment
override fun associateWith(other: CompilationDetails<*>) {
throw UnsupportedOperationException("not supported in the mapped model")
}
override val associateCompilations: Set<CompilationDetails<*>>
get() = emptySet()
override fun source(sourceSet: KotlinSourceSet) {
throw UnsupportedOperationException("metadata compilations have predefined sources")
}
private val underlyingSourceSet: FragmentMappedKotlinSourceSet
get() = target.project.kotlinExtension.sourceSets.withType<FragmentMappedKotlinSourceSet>().single {
it.underlyingFragment == compilationData.fragment
}
override val directlyIncludedKotlinSourceSets: MutableSet<KotlinSourceSet>
get() = Collections.unmodifiableSet(hashSetOf(underlyingSourceSet))
override val defaultSourceSetName: String
get() = underlyingSourceSet.name
}
internal open class VariantMappedCompilationDetails<T : KotlinCommonOptions>(
open val variant: KotlinGradleVariantInternal,
override val target: KotlinTarget
@@ -19,11 +19,12 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompileCommon
interface KotlinMetadataCompilation<T : KotlinCommonOptions> : KotlinCompilation<T>
class KotlinCommonCompilation(
target: KotlinTarget,
name: String
) : AbstractKotlinCompilation<KotlinMultiplatformCommonOptions>(
MetadataCompilationDetails(target, name)
), KotlinMetadataCompilation<KotlinMultiplatformCommonOptions> {
compilationDetails: CompilationDetails<KotlinMultiplatformCommonOptions>
) : AbstractKotlinCompilation<KotlinMultiplatformCommonOptions>(compilationDetails),
KotlinMetadataCompilation<KotlinMultiplatformCommonOptions> {
override fun getName() =
if (compilationDetails is MetadataMappedCompilationDetails) defaultSourceSetName else super.compilationPurpose
override val compileKotlinTask: KotlinCompileCommon
get() = super.compileKotlinTask as KotlinCompileCommon
@@ -20,5 +20,5 @@ class KotlinCommonCompilationFactory(
get() = KotlinCommonCompilation::class.java
override fun create(name: String): KotlinCommonCompilation =
KotlinCommonCompilation(target, name)
KotlinCommonCompilation(MetadataCompilationDetails(target, name))
}
@@ -93,7 +93,7 @@ abstract class AbstractKotlinCompilation<T : KotlinCommonOptions>(
compilationDetails.source(sourceSet)
}
override fun toString(): String = "compilation '$compilationPurpose' ($target)"
override fun toString(): String = "compilation '$name' ($target)"
override fun associateWith(other: KotlinCompilation<*>) {
compilationDetails.associateWith((other as AbstractKotlinCompilation<*>).compilationDetails)
@@ -19,6 +19,8 @@ import org.jetbrains.kotlin.gradle.targets.metadata.ResolvedMetadataFilesProvide
import org.jetbrains.kotlin.gradle.targets.metadata.createMetadataDependencyTransformationClasspath
import org.jetbrains.kotlin.gradle.utils.getValue
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
import org.jetbrains.kotlin.gradle.utils.newProperty
import org.jetbrains.kotlin.gradle.utils.setValue
import org.jetbrains.kotlin.konan.target.HostManager
import org.jetbrains.kotlin.konan.target.KonanTarget
@@ -55,7 +57,7 @@ internal abstract class AbstractKotlinFragmentMetadataCompilationData<T : Kotlin
override val compileAllTaskName: String
get() = compileAllTask.name
override val compileDependencyFiles: FileCollection by project.provider {
override var compileDependencyFiles: FileCollection by project.newProperty {
createMetadataDependencyTransformationClasspath(
project,
resolvableMetadataConfiguration(fragment.containingModule),
@@ -199,7 +201,7 @@ internal class MetadataCompilationRegistry {
withAllNativeCallbacks.forEach { it.invoke(compilationData) }
}
fun getForFragmentOrNull(fragment: KotlinGradleFragment): KotlinMetadataCompilationData<*>? =
fun getForFragmentOrNull(fragment: KotlinGradleFragment): AbstractKotlinFragmentMetadataCompilationData<*>? =
listOf(commonCompilationDataPerFragment.getValue(fragment), nativeCompilationDataPerFragment.getValue(fragment)).singleOrNull {
it.isActive
}
@@ -30,9 +30,9 @@ internal open class KpmAwareTargetConfigurator<T : KotlinTarget>(
}
override fun configureCompilations(target: T) {
target.compilations.create(KotlinCompilation.MAIN_COMPILATION_NAME)
target.compilations.maybeCreate(KotlinCompilation.MAIN_COMPILATION_NAME)
if (legacyModelTargetConfigurator.createTestCompilation) {
target.compilations.create(KotlinCompilation.TEST_COMPILATION_NAME)
target.compilations.maybeCreate(KotlinCompilation.TEST_COMPILATION_NAME)
}
}
@@ -7,8 +7,10 @@ package org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util
import org.gradle.api.Project
import org.gradle.api.file.FileCollection
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.AbstractKotlinFragmentMetadataCompilationData
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinGradleVariant
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinGradleVariantWithRuntime
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.resolvableMetadataConfigurationName
interface DependencyFilesHolder {
val dependencyConfigurationName: String
@@ -35,6 +37,17 @@ internal fun DependencyFilesHolder.Companion.ofVariantRuntimeDependencies(varian
set(value) { variant.runtimeDependencyFiles = value }
}
internal fun DependencyFilesHolder.Companion.ofMetadataCompilationDependencies(
compilationData: AbstractKotlinFragmentMetadataCompilationData<*>
) = object : DependencyFilesHolder {
override val dependencyConfigurationName: String
get() = compilationData.fragment.containingModule.resolvableMetadataConfigurationName
override var dependencyFiles: FileCollection
get() = compilationData.compileDependencyFiles
set(value) { compilationData.compileDependencyFiles = value }
}
class SimpleDependencyFilesHolder(
override val dependencyConfigurationName: String,
override var dependencyFiles: FileCollection
@@ -21,9 +21,9 @@ import org.jetbrains.kotlin.gradle.dsl.*
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.mpp.*
import org.jetbrains.kotlin.gradle.plugin.mpp.CompilationSourceSetUtil.compilationsBySourceSets
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinGradleModule
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinNativeFragmentMetadataCompilationData
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.*
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.hasKpmModel
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.metadataCompilationRegistryByModuleId
import org.jetbrains.kotlin.gradle.plugin.sources.*
import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService
import org.jetbrains.kotlin.gradle.targets.native.internal.*
@@ -70,7 +70,7 @@ class KotlinMetadataTargetConfigurator :
override fun configureTarget(target: KotlinMetadataTarget) {
super.configureTarget(target)
if (target.project.isKotlinGranularMetadataEnabled && !target.project.hasKpmModel) {
if (target.project.isKotlinGranularMetadataEnabled) {
KotlinBuildStatsService.getInstance()?.report(BooleanMetrics.ENABLED_HMPP, true)
target.compilations.withType(KotlinCommonCompilation::class.java).getByName(KotlinCompilation.MAIN_COMPILATION_NAME).run {
@@ -9,8 +9,11 @@ package org.jetbrains.kotlin.gradle.plugin.mpp
import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KpmAwareTargetConfigurator
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.hasKpmModel
import org.jetbrains.kotlin.gradle.plugin.sources.applyLanguageSettingsToKotlinOptions
import org.jetbrains.kotlin.gradle.targets.metadata.KotlinMetadataTargetConfigurator
import org.jetbrains.kotlin.gradle.targets.metadata.KpmMetadataTargetConfigurator
class KotlinMetadataTargetPreset(
project: Project
@@ -37,8 +40,12 @@ class KotlinMetadataTargetPreset(
const val PRESET_NAME = "metadata"
}
override fun createKotlinTargetConfigurator(): KotlinOnlyTargetConfigurator<AbstractKotlinCompilation<*>, KotlinMetadataTarget> =
KotlinMetadataTargetConfigurator()
override fun createKotlinTargetConfigurator(): AbstractKotlinTargetConfigurator<KotlinMetadataTarget> {
val metadataConfigurator = KotlinMetadataTargetConfigurator()
return if (project.hasKpmModel)
KpmMetadataTargetConfigurator(metadataConfigurator)
else metadataConfigurator
}
override fun instantiateTarget(name: String): KotlinMetadataTarget {
return project.objects.newInstance(KotlinMetadataTarget::class.java, project)
@@ -52,9 +59,11 @@ class KotlinMetadataTargetPreset(
mainCompilation.source(commonMainSourceSet)
project.whenEvaluated {
// Since there's no default source set, apply language settings from commonMain:
mainCompilation.compileKotlinTaskProvider.configure { compileKotlinMetadata ->
applyLanguageSettingsToKotlinOptions(commonMainSourceSet.languageSettings, compileKotlinMetadata.kotlinOptions)
if (!project.hasKpmModel) {
// Since there's no default source set, apply language settings from commonMain:
mainCompilation.compileKotlinTaskProvider.configure { compileKotlinMetadata ->
applyLanguageSettingsToKotlinOptions(commonMainSourceSet.languageSettings, compileKotlinMetadata.kotlinOptions)
}
}
}
}
@@ -0,0 +1,68 @@
/*
* Copyright 2010-2022 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.metadata
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformCommonOptions
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.*
import org.jetbrains.kotlin.gradle.plugin.mpp.MetadataMappedCompilationDetails
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.*
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KpmAwareTargetConfigurator
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.kpmModules
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.metadataCompilationRegistryByModuleId
import org.jetbrains.kotlin.gradle.plugin.whenEvaluated
internal class KpmMetadataTargetConfigurator(private val metadataTargetConfigurator: KotlinMetadataTargetConfigurator) :
KpmAwareTargetConfigurator<KotlinMetadataTarget>(metadataTargetConfigurator) {
override fun configureTarget(target: KotlinMetadataTarget) {
super.configureTarget(target)
configureTargetWithKpm(target)
}
override fun configureCompilationDefaults(target: KotlinMetadataTarget) {
super.configureCompilationDefaults(target)
// we still want to configure the legacy "main" compilation
run {
val mainCompilation = target.compilations.create(KotlinCompilation.MAIN_COMPILATION_NAME)
defineConfigurationsForCompilation(mainCompilation)
createLifecycleTask(mainCompilation)
metadataTargetConfigurator
.buildCompilationProcessor(mainCompilation)
.run()
mainCompilation.compileKotlinTaskProvider.configure { it.enabled = false }
}
}
private fun configureTargetWithKpm(target: KotlinMetadataTarget) {
target.project.whenEvaluated {
val mainModule = target.project.kpmModules.getByName(KotlinGradleModule.MAIN_MODULE_NAME)
val metadataCompilations = target.project.metadataCompilationRegistryByModuleId.getValue(mainModule.moduleIdentifier)
mainModule.fragments.forEach { fragment ->
val compilationData = metadataCompilations.getForFragmentOrNull(fragment) ?: return@forEach
if (!compilationData.isActive) return@forEach
val compilationDetails = MetadataMappedCompilationDetails(target, compilationData)
val isNative = compilationData is KotlinNativeFragmentMetadataCompilationData
@Suppress("UNCHECKED_CAST")
val compilation = when {
isNative -> {
val konanTargets =
mainModule.variantsContainingFragment(fragment).map { (it as KotlinNativeVariantInternal).konanTarget }
KotlinSharedNativeCompilation(konanTargets, compilationDetails as CompilationDetails<KotlinCommonOptions>)
}
else -> KotlinCommonCompilation(compilationDetails as CompilationDetails<KotlinMultiplatformCommonOptions>)
}
target.compilations.add(compilation)
}
}
}
}
@@ -118,18 +118,21 @@ class KotlinNativeCompilation(
}
class KotlinSharedNativeCompilation(
target: KotlinMetadataTarget,
val konanTargets: List<KonanTarget>, name: String) :
KotlinNativeFragmentMetadataCompilationData,
val konanTargets: List<KonanTarget>,
compilationDetails: CompilationDetails<KotlinCommonOptions>
) : KotlinNativeFragmentMetadataCompilationData,
AbstractKotlinNativeCompilation(
// TODO: this will end up as '-target' argument passed to K2Native, which is wrong.
// Rewrite this when we'll compile native-shared source-sets against commonized platform libs
// We find any konan target that is enabled on the current host in order to pass the checks that avoid compiling the code otherwise.
konanTargets.find { it.enabledOnCurrentHost } ?: konanTargets.first(),
SharedNativeCompilationDetails(target, name) { NativeCompileOptions { defaultSourceSet.languageSettings } }
compilationDetails
),
KotlinMetadataCompilation<KotlinCommonOptions> {
override fun getName() =
if (compilationDetails is MetadataMappedCompilationDetails) defaultSourceSetName else super.compilationPurpose
override val target: KotlinMetadataTarget get() = super.target as KotlinMetadataTarget
override val isActive: Boolean
@@ -36,5 +36,8 @@ class KotlinSharedNativeCompilationFactory(
get() = KotlinSharedNativeCompilation::class.java
override fun create(name: String): KotlinSharedNativeCompilation =
KotlinSharedNativeCompilation(target, konanTargets, name)
KotlinSharedNativeCompilation(
konanTargets,
SharedNativeCompilationDetails(target, name) { NativeCompileOptions { defaultSourceSet.languageSettings } }
)
}