[Gradle] Implement KotlinJvmAndroidCompilation with underlying KotlinCompilationImpl

KT-54312
This commit is contained in:
Sebastian Sellmair
2022-10-04 14:38:30 +02:00
committed by Space Team
parent 0069457b94
commit e890e8178b
10 changed files with 209 additions and 63 deletions
@@ -27,13 +27,9 @@ import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.isKap
import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.isUseJvmIr
import org.jetbrains.kotlin.gradle.model.builder.KaptModelBuilder
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.mpp.AbstractKotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmAndroidCompilation
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompileTool
import org.jetbrains.kotlin.gradle.tasks.*
import org.jetbrains.kotlin.gradle.tasks.configuration.*
import org.jetbrains.kotlin.gradle.tasks.locateTask
import org.jetbrains.kotlin.gradle.tasks.registerTask
import org.jetbrains.kotlin.gradle.utils.SingleWarningPerBuild
import java.io.ByteArrayOutputStream
import java.io.File
@@ -231,7 +227,7 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To
val javaCompile: TaskProvider<out AbstractCompile>?,
val variantData: Any?,
val sourceSetName: String,
val kotlinCompilation: AbstractKotlinCompilation<*>,
val kotlinCompilation: KotlinCompilation<*>,
val kaptExtension: KaptExtension,
val kaptClasspathConfigurations: List<Configuration>
) {
@@ -282,7 +278,7 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To
val context = Kapt3SubpluginContext(
project, javaCompileOrNull,
androidVariantData, sourceSetName, kotlinCompilation as AbstractKotlinCompilation<*>/*TODO?*/, kaptExtension, nonEmptyKaptConfigurations
androidVariantData, sourceSetName, kotlinCompilation, kaptExtension, nonEmptyKaptConfigurations
)
val kaptGenerateStubsTaskProvider: TaskProvider<KaptGenerateStubsTask> = context.createKaptGenerateStubsTask()
@@ -30,7 +30,6 @@ import org.gradle.language.jvm.tasks.ProcessResources
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions
import org.jetbrains.kotlin.gradle.internal.reorderPluginClasspathDependencies
import org.jetbrains.kotlin.gradle.plugin.mpp.*
import org.jetbrains.kotlin.gradle.plugin.sources.internal
import org.jetbrains.kotlin.gradle.targets.js.KotlinJsCompilerAttribute
import org.jetbrains.kotlin.gradle.targets.js.KotlinJsTarget
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrTarget
@@ -107,10 +106,6 @@ abstract class AbstractKotlinTargetConfigurator<KotlinTargetType : KotlinTarget>
val project = target.project
target.compilations.all { compilation ->
compilation.internal.allKotlinSourceSets.forAll { sourceSet ->
sourceSet.internal.compilations.add(compilation)
}
defineConfigurationsForCompilation(compilation)
compilation.internal.processResourcesTaskName?.let { processResourcesTaskName ->
@@ -34,9 +34,14 @@ internal interface InternalKotlinCompilation<out T : KotlinCommonOptions> : Kotl
override val runtimeDependencyFiles: FileCollection? get() = null
override val runtimeDependencyConfigurationName: String? get() = null
val processResourcesTaskName: String? get() = null
}
internal inline val <reified T : KotlinCommonOptions> InternalKotlinCompilation<T>.decoratorInstance: InternalKotlinCompilation<T>
get() = target.compilations.getByName(compilationName).internal.castKotlinOptionsType()
internal inline val <reified T : KotlinCommonOptions> InternalKotlinCompilation<T>.decoratorInstanceOrNull: InternalKotlinCompilation<T>?
get() = target.compilations.findByName(compilationName)?.internal?.castKotlinOptionsType()
internal val <T : KotlinCommonOptions> KotlinCompilation<T>.internal: InternalKotlinCompilation<T>
get() = (this as? InternalKotlinCompilation<T>) ?: throw IllegalArgumentException(
"KotlinCompilation($name) ${this::class} does not implement ${InternalKotlinCompilation::class}"
@@ -50,26 +50,6 @@ internal object DefaultKotlinCompilationAssociator : KotlinCompilationAssociator
second.runtimeOnlyConfigurationName
)
}
/**
* Adds `allDependencies` of configurations mentioned in `configurationNames` to configuration named [this] in
* a lazy manner
*/
private fun String.addAllDependenciesFromOtherConfigurations(project: Project, vararg configurationNames: String) {
project.configurations.named(this).configure { receiverConfiguration ->
receiverConfiguration.dependencies.addAllLater(
project.objects.listProperty(Dependency::class.java).apply {
set(
project.provider {
configurationNames
.map { project.configurations.getByName(it) }
.flatMap { it.allDependencies }
}
)
}
)
}
}
}
internal object NativeKotlinCompilationAssociator : KotlinCompilationAssociator {
@@ -96,4 +76,44 @@ internal object JvmKotlinCompilationAssociator : KotlinCompilationAssociator {
}
}
/*
* Example of how multiplatform dependencies from common would get to Android test classpath:
* commonMainImplementation -> androidDebugImplementation -> debugImplementation -> debugAndroidTestCompileClasspath
* After the fix for KT-35916 MPP compilation configurations receive a 'compilation' postfix for disambiguation.
* androidDebugImplementation remains a source set configuration, but no longer contains compilation dependencies.
* Therefore, it doesn't get dependencies from common source sets.
* We now explicitly add associate compilation dependencies to the Kotlin test compilation configurations (test classpaths).
* This helps, because the Android test classpath configurations extend from the Kotlin test compilations' directly.
*/
internal object AndroidKotlinCompilationAssociator : KotlinCompilationAssociator {
override fun associate(target: KotlinTarget, first: InternalKotlinCompilation<*>, second: InternalKotlinCompilation<*>) {
target.project.kotlinCompilationModuleManager.unionModules(first.compilationModule, second.compilationModule)
first.compileDependencyConfigurationName.addAllDependenciesFromOtherConfigurations(
target.project,
second.apiConfigurationName,
second.implementationConfigurationName,
second.compileOnlyConfigurationName
)
}
}
/**
* Adds `allDependencies` of configurations mentioned in `configurationNames` to configuration named [this] in
* a lazy manner
*/
private fun String.addAllDependenciesFromOtherConfigurations(project: Project, vararg configurationNames: String) {
project.configurations.named(this).configure { receiverConfiguration ->
receiverConfiguration.dependencies.addAllLater(
project.objects.listProperty(Dependency::class.java).apply {
set(
project.provider {
configurationNames
.map { project.configurations.getByName(it) }
.flatMap { it.allDependencies }
}
)
}
)
}
}
@@ -8,9 +8,7 @@ package org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl
import org.gradle.api.file.FileCollection
import org.gradle.api.tasks.TaskProvider
import org.gradle.api.tasks.bundling.AbstractArchiveTask
import org.jetbrains.kotlin.gradle.plugin.mpp.InternalKotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.associateWithClosure
import org.jetbrains.kotlin.gradle.plugin.mpp.isMain
import org.jetbrains.kotlin.gradle.plugin.mpp.*
import org.jetbrains.kotlin.gradle.plugin.sources.getVisibleSourceSetsFromAssociateCompilations
import org.jetbrains.kotlin.gradle.plugin.sources.internal
import org.jetbrains.kotlin.gradle.targets.metadata.getMetadataCompilationForSourceSet
@@ -89,4 +87,10 @@ internal class DefaultKotlinCompilationFriendPathsResolver(
)
}
}
object AdditionalAndroidFriendArtifactResolver : FriendArtifactResolver {
override fun resolveFriendArtifacts(compilation: InternalKotlinCompilation<*>): FileCollection {
return compilation.project.files((compilation.decoratorInstance as KotlinJvmAndroidCompilation).testedVariantArtifacts)
}
}
}
@@ -0,0 +1,24 @@
/*
* 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.plugin.mpp.compilationImpl.factory
import com.android.build.gradle.api.BaseVariant
import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget
import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.KotlinCompilationSourceSetsContainer
import org.jetbrains.kotlin.gradle.plugin.sources.android.kotlinAndroidSourceSetLayout
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
internal class AndroidCompilationSourceSetsContainerFactory(
private val target: KotlinAndroidTarget, private val variant: BaseVariant
) : KotlinCompilationImplFactory.KotlinCompilationSourceSetsContainerFactory {
override fun create(target: KotlinTarget, compilationName: String): KotlinCompilationSourceSetsContainer {
val sourceSetName = target.project.kotlinAndroidSourceSetLayout.naming.defaultKotlinSourceSetName(this.target, variant)
?: lowerCamelCaseName(target.disambiguationClassifier, compilationName)
return KotlinCompilationSourceSetsContainer(target.project.kotlinExtension.sourceSets.maybeCreate(sourceSetName))
}
}
@@ -0,0 +1,18 @@
/*
* 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.plugin.mpp.compilationImpl.factory
import org.jetbrains.kotlin.gradle.plugin.mpp.InternalKotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.sources.internal
internal object DefaultKotlinCompilationPostConfigure : KotlinCompilationImplFactory.PostConfigure {
override fun configure(compilation: InternalKotlinCompilation<*>) {
/* Ensure proper tracking of compilations in the source sets */
compilation.allKotlinSourceSets.forAll { sourceSet ->
sourceSet.internal.compilations.add(compilation)
}
}
}
@@ -9,8 +9,10 @@ import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions
import org.jetbrains.kotlin.gradle.plugin.HasCompilerOptions
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilationOutput
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
import org.jetbrains.kotlin.gradle.plugin.mpp.InternalKotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.*
import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.KotlinCompilationModuleManager.CompilationModule
import org.jetbrains.kotlin.gradle.plugin.mpp.internal
internal class KotlinCompilationImplFactory(
private val compilerOptionsFactory: CompilerOptionsFactory,
@@ -40,7 +42,13 @@ internal class KotlinCompilationImplFactory(
DefaultKotlinCompilationTaskNamesContainerFactory,
private val processResourcesTaskNameFactory: ProcessResourcesTaskNameFactory =
DefaultProcessResourcesTaskNameFactory
DefaultProcessResourcesTaskNameFactory,
private val preConfigureAction: PreConfigure =
EmptyPreConfigure,
private val postConfigureAction: PostConfigure =
DefaultKotlinCompilationPostConfigure
) {
fun interface CompilationModuleFactory {
fun create(target: KotlinTarget, compilationName: String): CompilationModule
@@ -72,9 +80,25 @@ internal class KotlinCompilationImplFactory(
fun create(target: KotlinTarget, compilationName: String): Options
}
fun interface PreConfigure {
fun configure(compilation: KotlinCompilationImpl)
companion object {
fun composite(vararg elements: PreConfigure?): PreConfigure = CompositePreConfigure(listOfNotNull(*elements))
}
}
fun interface PostConfigure {
fun configure(compilation: InternalKotlinCompilation<*>)
companion object {
fun composite(vararg elements: PostConfigure?): PostConfigure = CompositePostConfigure(listOfNotNull(*elements))
}
}
fun create(target: KotlinTarget, compilationName: String): KotlinCompilationImpl {
val options = compilerOptionsFactory.create(target, compilationName)
return KotlinCompilationImpl(
val compilation = KotlinCompilationImpl(
KotlinCompilationImpl.Params(
target = target,
compilationModule = compilationModuleFactory.create(target, compilationName),
@@ -90,5 +114,40 @@ internal class KotlinCompilationImplFactory(
compilationSourceSetInclusion = compilationSourceSetInclusion
)
)
preConfigureAction.configure(compilation)
/* Wire up post-configure action: Release reference once executed */
var postConfigureAction: PostConfigure? = this.postConfigureAction
target.compilations.whenObjectAdded { added ->
if (added.compilationName == compilationName) {
postConfigureAction?.configure(added.internal)
postConfigureAction = null
}
}
return compilation
}
}
private class CompositePreConfigure(
private val elements: List<KotlinCompilationImplFactory.PreConfigure>
) : KotlinCompilationImplFactory.PreConfigure {
override fun configure(compilation: KotlinCompilationImpl) {
elements.forEach { element -> element.configure(compilation) }
}
}
private class CompositePostConfigure(
private val elements: List<KotlinCompilationImplFactory.PostConfigure>
) : KotlinCompilationImplFactory.PostConfigure {
override fun configure(compilation: InternalKotlinCompilation<*>) {
elements.forEach { element -> element.configure(compilation) }
}
}
private object EmptyPreConfigure : KotlinCompilationImplFactory.PreConfigure {
override fun configure(compilation: KotlinCompilationImpl) = Unit
}
@@ -11,35 +11,56 @@ import org.gradle.api.file.FileCollection
import org.gradle.api.provider.Property
import org.gradle.api.tasks.TaskProvider
import org.gradle.api.tasks.compile.JavaCompile
import org.jetbrains.kotlin.gradle.dsl.*
import org.jetbrains.kotlin.gradle.dsl.CompilerJvmOptions
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions
import org.jetbrains.kotlin.gradle.plugin.HasCompilerOptions
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilationToRunnableFiles
import org.jetbrains.kotlin.gradle.plugin.getJavaTaskProvider
import org.jetbrains.kotlin.gradle.plugin.mpp.compilationDetailsImpl.AndroidCompilationDetails
import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.KotlinCompilationImpl
import org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask
import javax.inject.Inject
abstract class KotlinJvmAndroidCompilation @Inject internal constructor(
final override val compilationDetails: AndroidCompilationDetails
) : AbstractKotlinCompilationToRunnableFiles<KotlinJvmOptions>(compilationDetails) {
open class KotlinJvmAndroidCompilation @Inject internal constructor(
private val compilation: KotlinCompilationImpl,
val androidVariant: BaseVariant
) : InternalKotlinCompilation<KotlinJvmOptions> by compilation.castKotlinOptionsType(),
KotlinCompilationToRunnableFiles<KotlinJvmOptions> {
val androidVariant: BaseVariant = compilationDetails.androidVariant
override val target: KotlinAndroidTarget = compilation.target as KotlinAndroidTarget
override val compilerOptions: HasCompilerOptions<CompilerJvmOptions> =
compilation.compilerOptions.castCompilerOptionsType()
internal val testedVariantArtifacts: Property<FileCollection> =
compilationDetails.target.project.objects.property(FileCollection::class.java)
compilation.project.objects.property(FileCollection::class.java)
@Suppress("DEPRECATION")
@Deprecated("Accessing task instance directly is deprecated", replaceWith = ReplaceWith("compileTaskProvider"))
override val compileKotlinTask: org.jetbrains.kotlin.gradle.tasks.KotlinCompile
get() = super.compileKotlinTask as org.jetbrains.kotlin.gradle.tasks.KotlinCompile
get() = compilation.compileKotlinTask as org.jetbrains.kotlin.gradle.tasks.KotlinCompile
@Suppress("UNCHECKED_CAST", "DEPRECATION")
@Deprecated("Replaced with compileTaskProvider", replaceWith = ReplaceWith("compileTaskProvider"))
override val compileKotlinTaskProvider: TaskProvider<out org.jetbrains.kotlin.gradle.tasks.KotlinCompile>
get() = super.compileKotlinTaskProvider as TaskProvider<out org.jetbrains.kotlin.gradle.tasks.KotlinCompile>
get() = compilation.compileKotlinTaskProvider as TaskProvider<out org.jetbrains.kotlin.gradle.tasks.KotlinCompile>
@Suppress("UNCHECKED_CAST")
override val compileTaskProvider: TaskProvider<out KotlinCompilationTask<KotlinJvmCompilerOptions>>
get() = super.compileTaskProvider as TaskProvider<KotlinCompilationTask<KotlinJvmCompilerOptions>>
override val compileTaskProvider: TaskProvider<out KotlinCompilationTask<CompilerJvmOptions>>
get() = compilation.compileTaskProvider as TaskProvider<KotlinCompilationTask<CompilerJvmOptions>>
val compileJavaTaskProvider: TaskProvider<out JavaCompile>
get() = androidVariant.getJavaTaskProvider()
}
override val runtimeDependencyConfigurationName: String
get() = compilation.runtimeDependencyConfigurationName ?: error("Missing 'runtimeDependencyConfigurationName'")
override var runtimeDependencyFiles: FileCollection = compilation.runtimeDependencyFiles ?: error("Missing 'runtimeDependencyFiles'")
override val relatedConfigurationNames: List<String>
get() = compilation.relatedConfigurationNames + listOf(
"${androidVariant.name}ApiElements",
"${androidVariant.name}RuntimeElements",
androidVariant.compileConfiguration.name,
androidVariant.runtimeConfiguration.name
)
}
@@ -7,28 +7,32 @@
package org.jetbrains.kotlin.gradle.plugin.mpp
import com.android.build.gradle.api.BaseVariant
import org.jetbrains.kotlin.gradle.plugin.mpp.compilationDetailsImpl.AndroidCompilationDetails
import org.jetbrains.kotlin.gradle.plugin.sources.android.kotlinAndroidSourceSetLayout
import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.AndroidKotlinCompilationAssociator
import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.DefaultKotlinCompilationFriendPathsResolver
import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.factory.AndroidCompilationSourceSetsContainerFactory
import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.factory.JvmCompilerOptionsFactory
import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.factory.KotlinCompilationImplFactory
class KotlinJvmAndroidCompilationFactory(
class KotlinJvmAndroidCompilationFactory internal constructor(
override val target: KotlinAndroidTarget,
private val variant: BaseVariant,
private val compilationImplFactory: KotlinCompilationImplFactory = KotlinCompilationImplFactory(
compilerOptionsFactory = JvmCompilerOptionsFactory,
compilationFriendPathsResolver = DefaultKotlinCompilationFriendPathsResolver(
friendArtifactResolver = DefaultKotlinCompilationFriendPathsResolver.FriendArtifactResolver.composite(
DefaultKotlinCompilationFriendPathsResolver.DefaultFriendArtifactResolver,
DefaultKotlinCompilationFriendPathsResolver.AdditionalAndroidFriendArtifactResolver
)
),
compilationAssociator = AndroidKotlinCompilationAssociator,
compilationSourceSetsContainerFactory = AndroidCompilationSourceSetsContainerFactory(target, variant)
)
) : KotlinCompilationFactory<KotlinJvmAndroidCompilation> {
override val itemClass: Class<KotlinJvmAndroidCompilation>
get() = KotlinJvmAndroidCompilation::class.java
override fun defaultSourceSetName(compilationName: String): String {
return project.kotlinAndroidSourceSetLayout.naming.defaultKotlinSourceSetName(target, variant)
?: super.defaultSourceSetName(compilationName)
}
override fun create(name: String): KotlinJvmAndroidCompilation {
lateinit var result: KotlinJvmAndroidCompilation
val details = AndroidCompilationDetails(target, name, getOrCreateDefaultSourceSet(name), variant) { result }
result = project.objects.newInstance(KotlinJvmAndroidCompilation::class.java, details)
return result
return project.objects.newInstance(itemClass, compilationImplFactory.create(target, name), variant)
}
}