[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.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.factory.DefaultKotlinCompilationDependencyConfigurationsFactory
import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.factory.KotlinCompilationImplFactory
@@ -30,6 +31,14 @@ class KotlinCommonCompilationFactory internal constructor(
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.
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 java.util.concurrent.Callable
internal interface KotlinCompilationSourceSetInclusion {
fun include(compilation: InternalKotlinCompilation<*>, sourceSet: KotlinSourceSet)
}
internal class DefaultKotlinCompilationSourceSetInclusion(
internal class KotlinCompilationSourceSetInclusion(
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 */
if (!compilation.includedSourceSets.add(sourceSet)) return
addSourcesToCompileTask.addSources(
compilation, sourceSet,
addAsCommonSources = lazy {
compilation, sourceSet, addAsCommonSources = lazy {
compilation.project.kotlinExtension.sourceSets.any { otherSourceSet ->
sourceSet in otherSourceSet.dependsOn
}
@@ -79,7 +74,7 @@ internal class DefaultKotlinCompilationSourceSetInclusion(
* to avoid re-processing of unnecessary source sets!
*/
private val includedSourceSetsKey = extrasKeyOf<MutableSet<KotlinSourceSet>>(
DefaultKotlinCompilationSourceSetInclusion::class.java.name
KotlinCompilationSourceSetInclusion::class.java.name
)
val InternalKotlinCompilation<*>.includedSourceSets: MutableSet<KotlinSourceSet>
@@ -89,17 +84,18 @@ internal class DefaultKotlinCompilationSourceSetInclusion(
fun interface AddSourcesToCompileTask {
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 {
override fun addSources(compilation: KotlinCompilation<*>, sourceSet: KotlinSourceSet, addAsCommonSources: Lazy<Boolean>) {
return children.forEach { child -> child.addSources(compilation, sourceSet, addAsCommonSources) }
}
object DefaultAddSourcesToCompileTask : AddSourcesToCompileTask {
override fun addSources(
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 {
@@ -116,15 +112,20 @@ internal class DefaultKotlinCompilationSourceSetInclusion(
}
}
object DefaultAddSourcesToCompileTask : AddSourcesToCompileTask {
override fun addSources(
compilation: KotlinCompilation<*>, sourceSet: KotlinSourceSet, addAsCommonSources: Lazy<Boolean>
) = addSourcesToKotlinCompileTask(
project = compilation.project,
taskName = compilation.compileKotlinTaskName,
sourceFileExtensions = sourceSet.customSourceFilesExtensions,
addAsCommonSources = addAsCommonSources,
sources = { sourceSet.kotlin }
)
/**
* Will use the [delegate] to add sources to the compile task only if the source set was added directly to the compilation
* (not if the source set is just part of the dependsOn closure).
*
* This is necessary for metadata compilations, where dependsOn source sets will be binary dependencies.
* In contrast: Platform compilations (jvm, android, linuxX64, ...) will add *all* sources to the compile task
* and compiles them together.
*/
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(),
private val compilationSourceSetInclusion: KotlinCompilationSourceSetInclusion =
DefaultKotlinCompilationSourceSetInclusion(),
KotlinCompilationSourceSetInclusion(),
private val compilationOutputFactory: KotlinCompilationOutputFactory =
DefaultKotlinCompilationOutputFactory,
@@ -6,7 +6,7 @@
@file:Suppress("PackageDirectoryMismatch") // Old package for compatibility
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.factory.KotlinCompilationImplFactory
import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.factory.KotlinNativeCompilerOptionsFactory
@@ -26,8 +26,8 @@ open class KotlinNativeCompilationFactory internal constructor(
compilationDependencyConfigurationsFactory = NativeKotlinCompilationDependencyConfigurationsFactory,
compilerOptionsFactory = KotlinNativeCompilerOptionsFactory,
compilationAssociator = KotlinNativeCompilationAssociator,
compilationSourceSetInclusion = DefaultKotlinCompilationSourceSetInclusion(
DefaultKotlinCompilationSourceSetInclusion.NativeAddSourcesToCompileTask
compilationSourceSetInclusion = KotlinCompilationSourceSetInclusion(
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.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.KotlinNativeCompilationAssociator
import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.factory.DefaultKotlinCompilationDependencyConfigurationsFactory
@@ -31,8 +31,13 @@ open class KotlinSharedNativeCompilationFactory internal constructor(
compilerOptionsFactory = KotlinNativeCompilerOptionsFactory,
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(
@@ -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()
}