[Gradle] Only add 'directly included' source sets to metadata compile tasks

Contrary to platform compilations, metadata based compile tasks
are expected to only compile the directly associated source sets w/o
their dependsOn closure. DependsOn source sets will be represented
as .klib binary dependencies instead.

^KT-54981 Verification Pending
This commit is contained in:
Sebastian Sellmair
2022-11-18 14:50:03 +01:00
committed by Space Team
parent 9330018390
commit 55ef9a6bad
6 changed files with 185 additions and 36 deletions
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.gradle.plugin.mpp
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.DefaultKotlinCompilationFriendPathsResolver import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.DefaultKotlinCompilationFriendPathsResolver
import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.KotlinCompilationSourceSetInclusion
import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.KotlinCompilationSourceSetsContainer import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.KotlinCompilationSourceSetsContainer
import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.factory.DefaultKotlinCompilationDependencyConfigurationsFactory import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.factory.DefaultKotlinCompilationDependencyConfigurationsFactory
import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.factory.KotlinCompilationImplFactory import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.factory.KotlinCompilationImplFactory
@@ -30,6 +31,14 @@ class KotlinCommonCompilationFactory internal constructor(
DefaultKotlinCompilationFriendPathsResolver.AdditionalMetadataFriendArtifactResolver DefaultKotlinCompilationFriendPathsResolver.AdditionalMetadataFriendArtifactResolver
) )
), ),
/*
Metadata compilation will only include directly added source sets to the compile task
*/
compilationSourceSetInclusion = KotlinCompilationSourceSetInclusion(
addSourcesToCompileTask = KotlinCompilationSourceSetInclusion.AddSourcesWithoutDependsOnClosure()
),
/* /*
Metadata compilations are created *because* of a pre-existing SourceSet. Metadata compilations are created *because* of a pre-existing SourceSet.
We therefore can create the container inline We therefore can create the container inline
@@ -19,21 +19,16 @@ import org.jetbrains.kotlin.tooling.core.extrasKeyOf
import org.jetbrains.kotlin.tooling.core.getOrPut import org.jetbrains.kotlin.tooling.core.getOrPut
import java.util.concurrent.Callable import java.util.concurrent.Callable
internal interface KotlinCompilationSourceSetInclusion { internal class KotlinCompilationSourceSetInclusion(
fun include(compilation: InternalKotlinCompilation<*>, sourceSet: KotlinSourceSet)
}
internal class DefaultKotlinCompilationSourceSetInclusion(
private val addSourcesToCompileTask: AddSourcesToCompileTask = DefaultAddSourcesToCompileTask private val addSourcesToCompileTask: AddSourcesToCompileTask = DefaultAddSourcesToCompileTask
) : KotlinCompilationSourceSetInclusion { ) {
override fun include(compilation: InternalKotlinCompilation<*>, sourceSet: KotlinSourceSet) { fun include(compilation: InternalKotlinCompilation<*>, sourceSet: KotlinSourceSet) {
/* Check if the source set was already included */ /* Check if the source set was already included */
if (!compilation.includedSourceSets.add(sourceSet)) return if (!compilation.includedSourceSets.add(sourceSet)) return
addSourcesToCompileTask.addSources( addSourcesToCompileTask.addSources(
compilation, sourceSet, compilation, sourceSet, addAsCommonSources = lazy {
addAsCommonSources = lazy {
compilation.project.kotlinExtension.sourceSets.any { otherSourceSet -> compilation.project.kotlinExtension.sourceSets.any { otherSourceSet ->
sourceSet in otherSourceSet.dependsOn sourceSet in otherSourceSet.dependsOn
} }
@@ -79,7 +74,7 @@ internal class DefaultKotlinCompilationSourceSetInclusion(
* to avoid re-processing of unnecessary source sets! * to avoid re-processing of unnecessary source sets!
*/ */
private val includedSourceSetsKey = extrasKeyOf<MutableSet<KotlinSourceSet>>( private val includedSourceSetsKey = extrasKeyOf<MutableSet<KotlinSourceSet>>(
DefaultKotlinCompilationSourceSetInclusion::class.java.name KotlinCompilationSourceSetInclusion::class.java.name
) )
val InternalKotlinCompilation<*>.includedSourceSets: MutableSet<KotlinSourceSet> val InternalKotlinCompilation<*>.includedSourceSets: MutableSet<KotlinSourceSet>
@@ -89,17 +84,18 @@ internal class DefaultKotlinCompilationSourceSetInclusion(
fun interface AddSourcesToCompileTask { fun interface AddSourcesToCompileTask {
fun addSources(compilation: KotlinCompilation<*>, sourceSet: KotlinSourceSet, addAsCommonSources: Lazy<Boolean>) fun addSources(compilation: KotlinCompilation<*>, sourceSet: KotlinSourceSet, addAsCommonSources: Lazy<Boolean>)
companion object {
fun composite(vararg elements: AddSourcesToCompileTask?): AddSourcesToCompileTask =
CompositeAddSourcesToCompileTask(listOfNotNull(*elements))
}
} }
private class CompositeAddSourcesToCompileTask(private val children: List<AddSourcesToCompileTask>) : AddSourcesToCompileTask { object DefaultAddSourcesToCompileTask : AddSourcesToCompileTask {
override fun addSources(compilation: KotlinCompilation<*>, sourceSet: KotlinSourceSet, addAsCommonSources: Lazy<Boolean>) { override fun addSources(
return children.forEach { child -> child.addSources(compilation, sourceSet, addAsCommonSources) } compilation: KotlinCompilation<*>, sourceSet: KotlinSourceSet, addAsCommonSources: Lazy<Boolean>
} ) = addSourcesToKotlinCompileTask(
project = compilation.project,
taskName = compilation.compileKotlinTaskName,
sourceFileExtensions = sourceSet.customSourceFilesExtensions,
addAsCommonSources = addAsCommonSources,
sources = { sourceSet.kotlin }
)
} }
object NativeAddSourcesToCompileTask : AddSourcesToCompileTask { object NativeAddSourcesToCompileTask : AddSourcesToCompileTask {
@@ -116,15 +112,20 @@ internal class DefaultKotlinCompilationSourceSetInclusion(
} }
} }
object DefaultAddSourcesToCompileTask : AddSourcesToCompileTask { /**
override fun addSources( * Will use the [delegate] to add sources to the compile task only if the source set was added directly to the compilation
compilation: KotlinCompilation<*>, sourceSet: KotlinSourceSet, addAsCommonSources: Lazy<Boolean> * (not if the source set is just part of the dependsOn closure).
) = addSourcesToKotlinCompileTask( *
project = compilation.project, * This is necessary for metadata compilations, where dependsOn source sets will be binary dependencies.
taskName = compilation.compileKotlinTaskName, * In contrast: Platform compilations (jvm, android, linuxX64, ...) will add *all* sources to the compile task
sourceFileExtensions = sourceSet.customSourceFilesExtensions, * and compiles them together.
addAsCommonSources = addAsCommonSources, */
sources = { sourceSet.kotlin } class AddSourcesWithoutDependsOnClosure(
) private val delegate: AddSourcesToCompileTask = DefaultAddSourcesToCompileTask
) : AddSourcesToCompileTask {
override fun addSources(compilation: KotlinCompilation<*>, sourceSet: KotlinSourceSet, addAsCommonSources: Lazy<Boolean>) {
if (sourceSet !in compilation.kotlinSourceSets) return
delegate.addSources(compilation, sourceSet, addAsCommonSources)
}
} }
} }
@@ -30,7 +30,7 @@ internal class KotlinCompilationImplFactory(
DefaultKotlinCompilationFriendPathsResolver(), DefaultKotlinCompilationFriendPathsResolver(),
private val compilationSourceSetInclusion: KotlinCompilationSourceSetInclusion = private val compilationSourceSetInclusion: KotlinCompilationSourceSetInclusion =
DefaultKotlinCompilationSourceSetInclusion(), KotlinCompilationSourceSetInclusion(),
private val compilationOutputFactory: KotlinCompilationOutputFactory = private val compilationOutputFactory: KotlinCompilationOutputFactory =
DefaultKotlinCompilationOutputFactory, DefaultKotlinCompilationOutputFactory,
@@ -6,7 +6,7 @@
@file:Suppress("PackageDirectoryMismatch") // Old package for compatibility @file:Suppress("PackageDirectoryMismatch") // Old package for compatibility
package org.jetbrains.kotlin.gradle.plugin.mpp package org.jetbrains.kotlin.gradle.plugin.mpp
import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.DefaultKotlinCompilationSourceSetInclusion import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.KotlinCompilationSourceSetInclusion
import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.KotlinNativeCompilationAssociator import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.KotlinNativeCompilationAssociator
import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.factory.KotlinCompilationImplFactory import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.factory.KotlinCompilationImplFactory
import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.factory.KotlinNativeCompilerOptionsFactory import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.factory.KotlinNativeCompilerOptionsFactory
@@ -26,8 +26,8 @@ open class KotlinNativeCompilationFactory internal constructor(
compilationDependencyConfigurationsFactory = NativeKotlinCompilationDependencyConfigurationsFactory, compilationDependencyConfigurationsFactory = NativeKotlinCompilationDependencyConfigurationsFactory,
compilerOptionsFactory = KotlinNativeCompilerOptionsFactory, compilerOptionsFactory = KotlinNativeCompilerOptionsFactory,
compilationAssociator = KotlinNativeCompilationAssociator, compilationAssociator = KotlinNativeCompilationAssociator,
compilationSourceSetInclusion = DefaultKotlinCompilationSourceSetInclusion( compilationSourceSetInclusion = KotlinCompilationSourceSetInclusion(
DefaultKotlinCompilationSourceSetInclusion.NativeAddSourcesToCompileTask KotlinCompilationSourceSetInclusion.NativeAddSourcesToCompileTask
), ),
) )
@@ -8,7 +8,7 @@ package org.jetbrains.kotlin.gradle.plugin.mpp
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.DefaultKotlinCompilationFriendPathsResolver import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.DefaultKotlinCompilationFriendPathsResolver
import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.DefaultKotlinCompilationSourceSetInclusion import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.KotlinCompilationSourceSetInclusion
import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.KotlinCompilationSourceSetsContainer import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.KotlinCompilationSourceSetsContainer
import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.KotlinNativeCompilationAssociator import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.KotlinNativeCompilationAssociator
import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.factory.DefaultKotlinCompilationDependencyConfigurationsFactory import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.factory.DefaultKotlinCompilationDependencyConfigurationsFactory
@@ -31,8 +31,13 @@ open class KotlinSharedNativeCompilationFactory internal constructor(
compilerOptionsFactory = KotlinNativeCompilerOptionsFactory, compilerOptionsFactory = KotlinNativeCompilerOptionsFactory,
compilationAssociator = KotlinNativeCompilationAssociator, compilationAssociator = KotlinNativeCompilationAssociator,
compilationSourceSetInclusion = DefaultKotlinCompilationSourceSetInclusion( /*
DefaultKotlinCompilationSourceSetInclusion.NativeAddSourcesToCompileTask Metadata compilation will only include directly added source sets to the compile task
*/
compilationSourceSetInclusion = KotlinCompilationSourceSetInclusion(
addSourcesToCompileTask = KotlinCompilationSourceSetInclusion.AddSourcesWithoutDependsOnClosure(
KotlinCompilationSourceSetInclusion.NativeAddSourcesToCompileTask
)
), ),
compilationFriendPathsResolver = DefaultKotlinCompilationFriendPathsResolver( compilationFriendPathsResolver = DefaultKotlinCompilationFriendPathsResolver(
@@ -0,0 +1,134 @@
/*
* 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.
*/
@file:Suppress("FunctionName")
package org.jetbrains.kotlin.gradle
import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinCommonCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinSharedNativeCompilation
import org.jetbrains.kotlin.gradle.tasks.KotlinCompileCommon
import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile
import org.jetbrains.kotlin.gradle.tasks.KotlinNativeCompile
import java.io.File
import kotlin.test.Test
import kotlin.test.assertEquals
class KotlinCompileTaskSourcesTest {
@Test
fun `test - sources - shared native compile - KT-54995`() {
val project = buildProjectWithMPP()
val kotlin = project.multiplatformExtension
kotlin.targetHierarchy.default()
kotlin.linuxX64()
kotlin.linuxArm64()
kotlin.jvm()
val commonMainSourceFile = project.file("src/commonMain/kotlin/CommonMain.kt")
val linuxMainSourceFile = project.file("src/linuxMain/kotlin/LinuxMain.kt")
commonMainSourceFile.parentFile.mkdirs()
linuxMainSourceFile.parentFile.mkdirs()
commonMainSourceFile.writeText("object CommonMain")
linuxMainSourceFile.writeText("object LinuxMain")
project.evaluate()
/* Check sources of linuxMain compilation */
val linuxMainCompilation = kotlin.metadata().compilations.getByName("linuxMain") as KotlinSharedNativeCompilation
val linuxMainCompileTask = linuxMainCompilation.compileTaskProvider.get()
assertEquals(
setOf(linuxMainSourceFile).relativeTo(project),
linuxMainCompileTask.sources.files.relativeTo(project)
)
/* Check sources of commonMain compilation */
val commonMainCompilation = kotlin.metadata().compilations.getByName("commonMain") as KotlinCommonCompilation
val commonMainCompileTask = commonMainCompilation.compileTaskProvider.get() as KotlinCompileCommon
assertEquals(
setOf(commonMainSourceFile).relativeTo(project),
commonMainCompileTask.sources.files.relativeTo(project)
)
}
@Test
fun `test - sources - linux and jvm`() {
val project = buildProjectWithMPP()
val kotlin = project.multiplatformExtension
kotlin.targetHierarchy.default {
common {
group("jvmAndLinux") {
anyLinux()
jvm()
}
}
}
kotlin.linuxArm64()
kotlin.jvm()
val commonMainSourceFile = project.file("src/commonMain/kotlin/Common.kt")
val jvmAndLinuxMainSourceFile = project.file("src/jvmAndLinuxMain/kotlin/JvmAndLinuxMain.kt")
val linuxArm64MainSourceFile = project.file("src/linuxArm64Main/kotlin/Linux.kt")
val jvmMainSourceFile = project.file("src/jvmMain/kotlin/Jvm.kt")
commonMainSourceFile.parentFile.mkdirs()
jvmAndLinuxMainSourceFile.parentFile.mkdirs()
linuxArm64MainSourceFile.parentFile.mkdirs()
jvmMainSourceFile.parentFile.mkdirs()
commonMainSourceFile.writeText("object CommonMain")
jvmAndLinuxMainSourceFile.writeText("object JvmAndLinuxMain")
linuxArm64MainSourceFile.writeText("object Linux")
jvmMainSourceFile.writeText("object Jvm")
project.evaluate()
/* Check sources of commonMain compile task */
val commonMainCompileTask = kotlin.metadata().compilations.getByName("commonMain")
.compileTaskProvider.get() as KotlinCompileCommon
assertEquals(
setOf(commonMainSourceFile).relativeTo(project),
commonMainCompileTask.sources.files.relativeTo(project)
)
/* Check sources of jvmAndLinuxMain compile task */
val jvmAndLinuxMainCompileTask = kotlin.metadata().compilations.getByName("jvmAndLinuxMain")
.compileTaskProvider.get() as KotlinCompileCommon
assertEquals(
setOf(jvmAndLinuxMainSourceFile).relativeTo(project),
jvmAndLinuxMainCompileTask.sources.files.relativeTo(project)
)
/* Check sources of jvm compile task */
val jvmMainCompileTask = kotlin.jvm().compilations.getByName("main")
.compileTaskProvider.get() as KotlinJvmCompile
assertEquals(
setOf(commonMainSourceFile, jvmAndLinuxMainSourceFile, jvmMainSourceFile).relativeTo(project),
jvmMainCompileTask.sources.files.relativeTo(project)
)
/* Check sources of linuxArm64 compile task */
val linuxArm64CompileTask = kotlin.linuxArm64().compilations.getByName("main")
.compileTaskProvider.get() as KotlinNativeCompile
assertEquals(
setOf(commonMainSourceFile, jvmAndLinuxMainSourceFile, linuxArm64MainSourceFile).relativeTo(project),
linuxArm64CompileTask.sources.files.relativeTo(project)
)
}
private fun Set<File>.relativeTo(project: Project): Set<File> = map { it.relativeTo(project.projectDir) }.toSet()
}