Support -Xcommon-sources in new MPP

In new MPP, add source sets taking part in more than one compilation to
the tasks' `commonSourceSet` in order to pass them as -Xcommon-sources

Issue #KT-26515 Fixed
This commit is contained in:
Sergey Igushkin
2018-08-30 17:47:52 +03:00
parent 5e6148c970
commit 0ee19cf28f
2 changed files with 68 additions and 4 deletions
@@ -369,4 +369,38 @@ class NewMultiplatformIT : BaseGradleIT() {
}
}
}
@Test
fun testOptionalExpectations() = with(Project("new-mpp-lib-with-tests", gradleVersion)) {
setupWorkingDir()
projectDir.resolve("src/commonMain/kotlin/Optional.kt").writeText(
"""
@file:Suppress("EXPERIMENTAL_API_USAGE_ERROR")
@OptionalExpectation
expect annotation class Optional(val value: String)
@Optional("optionalAnnotationValue")
class OptionalCommonUsage
""".trimIndent()
)
build("compileKotlinJvmWithoutJava") {
assertSuccessful()
assertFileExists(targetClassesDir("jvmWithoutJava") + "OptionalCommonUsage.class")
}
projectDir.resolve("src/jvmWithoutJavaMain/kotlin/OptionalImpl.kt").writeText(
"\n" + """
@Optional("should fail, see KT-25196")
class OptionalPlatformUsage
""".trimIndent()
)
build("compileKotlinJvmWithoutJava") {
assertFailed()
assertContains("Declaration annotated with '@OptionalExpectation' can only be used in common module sources")
}
}
}
@@ -12,6 +12,7 @@ import org.gradle.api.file.FileCollection
import org.gradle.api.tasks.SourceSet
import org.gradle.api.tasks.SourceSetOutput
import org.gradle.util.ConfigureUtil
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.sources.defaultSourceSetLanguageSettingsChecker
@@ -19,6 +20,7 @@ import org.jetbrains.kotlin.gradle.plugin.sources.getSourceSetHierarchy
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile
import org.jetbrains.kotlin.gradle.utils.addExtendsFromRelation
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
import java.util.*
internal fun KotlinCompilation.composeName(prefix: String? = null, suffix: String? = null): String {
val compilationNamePart = compilationName.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME }
@@ -62,8 +64,12 @@ abstract class AbstractKotlinCompilation(
override val kotlinSourceSets: MutableSet<KotlinSourceSet> = mutableSetOf()
open fun addSourcesToCompileTask(sourceSet: KotlinSourceSet) {
(target.project.tasks.getByName(compileKotlinTaskName) as AbstractKotlinCompile<*>).source(sourceSet.kotlin)
open fun addSourcesToCompileTask(sourceSet: KotlinSourceSet, addAsCommonSources: Boolean) {
val compileTask = target.project.tasks.getByName(compileKotlinTaskName) as AbstractKotlinCompile<*>
compileTask.source(sourceSet.kotlin)
if (addAsCommonSources) {
compileTask.commonSourceSet += sourceSet.kotlin
}
}
override fun source(sourceSet: KotlinSourceSet) {
@@ -71,7 +77,10 @@ abstract class AbstractKotlinCompilation(
with(target.project) {
whenEvaluated {
sourceSet.getSourceSetHierarchy().forEach { sourceSet ->
addSourcesToCompileTask(sourceSet)
val isCommonSource =
CompilationSourceSetUtil.sourceSetsInMultipleCompilations(project)?.contains(sourceSet) ?: false
addSourcesToCompileTask(sourceSet, addAsCommonSources = isCommonSource)
// Use `forced = false` since `api`, `implementation`, and `compileOnly` may be missing in some cases like
// old Java & Android projects:
@@ -295,7 +304,8 @@ class KotlinNativeCompilation(
"klibrary"
)
override fun addSourcesToCompileTask(sourceSet: KotlinSourceSet) {
override fun addSourcesToCompileTask(sourceSet: KotlinSourceSet, addAsCommonSources: Boolean) {
// TODO: support optional expectations
allSources += sourceSet.kotlin
}
@@ -308,4 +318,24 @@ class KotlinNativeCompilation(
val FRAMEWORK = NativeOutputKind.FRAMEWORK
}
}
private object CompilationSourceSetUtil {
// Cache the results per project
private val projectSourceSetsInMultipleCompilationsCache = WeakHashMap<Project, Set<KotlinSourceSet>>()
fun sourceSetsInMultipleCompilations(project: Project) =
projectSourceSetsInMultipleCompilationsCache.computeIfAbsent(project) { _ ->
check(project.state.executed) { "Should only be computed after the project is evaluated" }
val compilations = (project.kotlinExtension as? KotlinMultiplatformExtension)?.targets?.flatMap { it.compilations }
?: return@computeIfAbsent null
compilations
.flatMap { compilation -> compilation.allKotlinSourceSets.map { sourceSet -> compilation to sourceSet } }
.groupingBy { (_, sourceSet) -> sourceSet }
.eachCount()
.filterValues { it > 1 }
.keys
}
}