Introduce Java support in JVM MPP targets (KT-26256)
Deprecate the `jvmWithJava` preset, add warning. Add a function `withJava()` to JVM MPP targets which applies the 'java' plugin and sets up the Kotlin & Java interoperation. Issue #KT-26256 Fixed Signed-off-by: Sergey Igushkin <hotkeytlt@gmail.com>
This commit is contained in:
+2
-7
@@ -21,22 +21,17 @@ internal const val MPP_PACKAGE = "org.jetbrains.kotlin.gradle.plugin.mpp"
|
|||||||
internal const val KOTLIN_NATIVE_TARGET_PRESET_CLASS_FQNAME = "$MPP_PACKAGE.KotlinNativeTargetPreset"
|
internal const val KOTLIN_NATIVE_TARGET_PRESET_CLASS_FQNAME = "$MPP_PACKAGE.KotlinNativeTargetPreset"
|
||||||
internal const val KOTLIN_NATIVE_TARGET_CLASS_FQNAME = "$MPP_PACKAGE.KotlinNativeTarget"
|
internal const val KOTLIN_NATIVE_TARGET_CLASS_FQNAME = "$MPP_PACKAGE.KotlinNativeTarget"
|
||||||
|
|
||||||
private const val KOTLIN_ONLY_TARGET_CLASS_FQNAME = "$MPP_PACKAGE.KotlinOnlyTarget"
|
|
||||||
|
|
||||||
internal val jvmPresetEntry = KotlinPresetEntry(
|
internal val jvmPresetEntry = KotlinPresetEntry(
|
||||||
"jvm",
|
"jvm",
|
||||||
typeName("$MPP_PACKAGE.KotlinJvmTargetPreset"),
|
typeName("$MPP_PACKAGE.KotlinJvmTargetPreset"),
|
||||||
typeName(
|
typeName("org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget")
|
||||||
KOTLIN_ONLY_TARGET_CLASS_FQNAME,
|
|
||||||
"$MPP_PACKAGE.KotlinJvmCompilation"
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
internal val jsPresetEntry = KotlinPresetEntry(
|
internal val jsPresetEntry = KotlinPresetEntry(
|
||||||
"js",
|
"js",
|
||||||
typeName("$MPP_PACKAGE.KotlinJsTargetPreset"),
|
typeName("$MPP_PACKAGE.KotlinJsTargetPreset"),
|
||||||
typeName(
|
typeName(
|
||||||
KOTLIN_ONLY_TARGET_CLASS_FQNAME,
|
"$MPP_PACKAGE.KotlinOnlyTarget",
|
||||||
"$MPP_PACKAGE.KotlinJsCompilation"
|
"$MPP_PACKAGE.KotlinJsCompilation"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
+119
-38
@@ -5,11 +5,13 @@
|
|||||||
package org.jetbrains.kotlin.gradle
|
package org.jetbrains.kotlin.gradle
|
||||||
|
|
||||||
import org.jetbrains.kotlin.gradle.plugin.ProjectLocalConfigurations
|
import org.jetbrains.kotlin.gradle.plugin.ProjectLocalConfigurations
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmWithJavaTargetPreset
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMultiplatformPlugin
|
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMultiplatformPlugin
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.NativeOutputKind
|
import org.jetbrains.kotlin.gradle.plugin.mpp.NativeOutputKind
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.UnusedSourceSetsChecker
|
import org.jetbrains.kotlin.gradle.plugin.mpp.UnusedSourceSetsChecker
|
||||||
import org.jetbrains.kotlin.gradle.plugin.sources.METADATA_CONFIGURATION_NAME_SUFFIX
|
import org.jetbrains.kotlin.gradle.plugin.sources.METADATA_CONFIGURATION_NAME_SUFFIX
|
||||||
import org.jetbrains.kotlin.gradle.plugin.sources.SourceSetConsistencyChecks
|
import org.jetbrains.kotlin.gradle.plugin.sources.SourceSetConsistencyChecks
|
||||||
|
import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget
|
||||||
import org.jetbrains.kotlin.gradle.util.*
|
import org.jetbrains.kotlin.gradle.util.*
|
||||||
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
||||||
import org.jetbrains.kotlin.konan.target.HostManager
|
import org.jetbrains.kotlin.konan.target.HostManager
|
||||||
@@ -299,52 +301,131 @@ class NewMultiplatformIT : BaseGradleIT() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testJvmWithJavaEquivalence() = with(Project("sample-lib", gradleVersion, "new-mpp-lib-and-app")) {
|
fun testJvmWithJavaEquivalence() = doTestJvmWithJava(testJavaSupportInJvmTargets = false)
|
||||||
lateinit var classesWithoutJava: Set<String>
|
|
||||||
|
|
||||||
fun getFilePathsSet(inDirectory: String): Set<String> {
|
@Test
|
||||||
val dir = projectDir.resolve(inDirectory)
|
fun testJavaSupportInJvmTargets() = doTestJvmWithJava(testJavaSupportInJvmTargets = true)
|
||||||
return dir.walk().filter { it.isFile }.map { it.relativeTo(dir).path.replace('\\', '/') }.toSet()
|
|
||||||
}
|
|
||||||
|
|
||||||
build("assemble") {
|
private fun doTestJvmWithJava(testJavaSupportInJvmTargets: Boolean) =
|
||||||
assertSuccessful()
|
with(Project("sample-lib", GradleVersionRequired.AtLeast("5.0"), "new-mpp-lib-and-app")) {
|
||||||
classesWithoutJava = getFilePathsSet("build/classes")
|
lateinit var classesWithoutJava: Set<String>
|
||||||
}
|
|
||||||
|
|
||||||
gradleBuildScript().modify {
|
fun getFilePathsSet(inDirectory: String): Set<String> {
|
||||||
it.replace("presets.jvm", "presets.jvmWithJava").replace("jvm(", "targetFromPreset(presets.jvmWithJava, ")
|
val dir = projectDir.resolve(inDirectory)
|
||||||
}
|
return dir.walk().filter { it.isFile }.map { it.relativeTo(dir).invariantSeparatorsPath }.toSet()
|
||||||
|
}
|
||||||
|
|
||||||
projectDir.resolve("src/main/java").apply {
|
build("assemble") {
|
||||||
mkdirs()
|
assertSuccessful()
|
||||||
mkdir()
|
classesWithoutJava = getFilePathsSet("build/classes")
|
||||||
// Check that Java can access the dependencies (kotlin-stdlib):
|
}
|
||||||
resolve("JavaClassInJava.java").writeText("""
|
|
||||||
package com.example.lib;
|
gradleBuildScript().modify {
|
||||||
import kotlin.sequences.Sequence;
|
if (testJavaSupportInJvmTargets) {
|
||||||
class JavaClassInJava {
|
it + "\nkotlin.jvm(\"jvm6\").${KotlinJvmTarget::withJava.name}()"
|
||||||
Sequence<String> makeSequence() { throw new UnsupportedOperationException(); }
|
} else {
|
||||||
|
it.replace("presets.jvm", "presets.jvmWithJava").replace("jvm(", "targetFromPreset(presets.jvmWithJava, ")
|
||||||
|
}.plus(
|
||||||
|
"\n" + """
|
||||||
|
buildscript {
|
||||||
|
repositories {
|
||||||
|
maven { url 'https://plugins.gradle.org/m2/' }
|
||||||
|
}
|
||||||
|
dependencies {
|
||||||
|
classpath 'com.github.jengelman.gradle.plugins:shadow:5.0.0'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
apply plugin: 'com.github.johnrengelman.shadow'
|
||||||
|
apply plugin: 'application'
|
||||||
|
|
||||||
|
mainClassName = 'com.example.lib.CommonKt'
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun javaSourceRootForCompilation(compilationName: String) =
|
||||||
|
if (testJavaSupportInJvmTargets) "src/jvm6${compilationName.capitalize()}/java" else "src/$compilationName/java"
|
||||||
|
|
||||||
|
val javaMainSrcDir = javaSourceRootForCompilation("main")
|
||||||
|
val javaTestSrcDir = javaSourceRootForCompilation("test")
|
||||||
|
|
||||||
|
projectDir.resolve(javaMainSrcDir).apply {
|
||||||
|
mkdirs()
|
||||||
|
// Check that Java can access the dependencies (kotlin-stdlib):
|
||||||
|
resolve("JavaClassInJava.java").writeText(
|
||||||
|
"""
|
||||||
|
package com.example.lib;
|
||||||
|
import kotlin.sequences.Sequence;
|
||||||
|
class JavaClassInJava {
|
||||||
|
Sequence<String> makeSequence() { throw new UnsupportedOperationException(); }
|
||||||
|
}
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
|
||||||
|
// Add a Kotlin source file in the Java source root and check that it is compiled:
|
||||||
|
resolve("KotlinClassInJava.kt").writeText(
|
||||||
|
"""
|
||||||
|
package com.example.lib
|
||||||
|
class KotlinClassInJava
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
projectDir.resolve(javaTestSrcDir).apply {
|
||||||
|
mkdirs()
|
||||||
|
resolve("JavaTest.java").writeText(
|
||||||
|
"""
|
||||||
|
package com.example.lib;
|
||||||
|
import org.junit.*;
|
||||||
|
public class JavaTest {
|
||||||
|
@Test
|
||||||
|
public void testAccessKotlin() {
|
||||||
|
MainKt.expectedFun();
|
||||||
|
MainKt.x();
|
||||||
|
new KotlinClassInJava();
|
||||||
|
new JavaClassInJava();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
build("clean", "build", "run", "shadowJar") {
|
||||||
|
assertSuccessful()
|
||||||
|
val expectedMainClasses =
|
||||||
|
classesWithoutJava + setOf(
|
||||||
|
"kotlin/jvm6/main/com/example/lib/KotlinClassInJava.class",
|
||||||
|
"java/main/com/example/lib/JavaClassInJava.class",
|
||||||
|
"java/test/com/example/lib/JavaTest.class"
|
||||||
|
)
|
||||||
|
val actualClasses = getFilePathsSet("build/classes")
|
||||||
|
Assert.assertEquals(expectedMainClasses, actualClasses)
|
||||||
|
|
||||||
|
val jvmTestTaskName = if (testJavaSupportInJvmTargets) "jvm6Test" else "test"
|
||||||
|
assertTasksExecuted(":$jvmTestTaskName")
|
||||||
|
assertFileExists("build/reports/tests/$jvmTestTaskName/classes/com.example.lib.JavaTest.html")
|
||||||
|
|
||||||
|
if (testJavaSupportInJvmTargets) {
|
||||||
|
assertNotContains(KotlinJvmWithJavaTargetPreset.DEPRECATION_WARNING)
|
||||||
|
} else {
|
||||||
|
assertContains(KotlinJvmWithJavaTargetPreset.DEPRECATION_WARNING)
|
||||||
}
|
}
|
||||||
""".trimIndent())
|
|
||||||
|
|
||||||
// Add a Kotlin source file in the Java source root and check that it is compiled:
|
assertTasksExecuted(":run")
|
||||||
resolve("KotlinClassInJava.kt").writeText("""
|
assertContains(">>> Common.kt >>> main()")
|
||||||
package com.example.lib
|
|
||||||
class KotlinClassInJava
|
|
||||||
""".trimIndent())
|
|
||||||
}
|
|
||||||
|
|
||||||
build("clean", "assemble") {
|
assertTasksExecuted(":shadowJar")
|
||||||
assertSuccessful()
|
val entries = ZipFile(projectDir.resolve("build/libs/sample-lib-1.0-all.jar")).use { zip ->
|
||||||
val expectedClasses =
|
zip.entries().asSequence().map { it.name }.toSet()
|
||||||
classesWithoutJava +
|
}
|
||||||
"kotlin/jvm6/main/com/example/lib/KotlinClassInJava.class" +
|
assertTrue { "kotlin/Pair.class" in entries }
|
||||||
"java/main/com/example/lib/JavaClassInJava.class"
|
assertTrue { "com/example/lib/CommonKt.class" in entries }
|
||||||
val actualClasses = getFilePathsSet("build/classes")
|
assertTrue { "com/example/lib/MainKt.class" in entries }
|
||||||
Assert.assertEquals(expectedClasses, actualClasses)
|
assertTrue { "com/example/lib/JavaClassInJava.class" in entries }
|
||||||
|
assertTrue { "com/example/lib/KotlinClassInJava.class" in entries }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testLibWithTests() = doTestLibWithTests(Project("new-mpp-lib-with-tests", gradleVersion))
|
fun testLibWithTests() = doTestLibWithTests(Project("new-mpp-lib-with-tests", gradleVersion))
|
||||||
|
|||||||
+11
@@ -63,12 +63,23 @@ kotlin {
|
|||||||
api 'org.jetbrains.kotlin:kotlin-stdlib-common'
|
api 'org.jetbrains.kotlin:kotlin-stdlib-common'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
commonTest {
|
||||||
|
dependencies {
|
||||||
|
implementation kotlin("test-common")
|
||||||
|
implementation kotlin("test-annotations-common")
|
||||||
|
}
|
||||||
|
}
|
||||||
jvm6Main {
|
jvm6Main {
|
||||||
dependencies {
|
dependencies {
|
||||||
api 'org.jetbrains.kotlin:kotlin-stdlib'
|
api 'org.jetbrains.kotlin:kotlin-stdlib'
|
||||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:0.23.4'
|
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:0.23.4'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
jvm6Test {
|
||||||
|
dependencies {
|
||||||
|
implementation kotlin("test-junit")
|
||||||
|
}
|
||||||
|
}
|
||||||
nodeJsMain {
|
nodeJsMain {
|
||||||
dependencies {
|
dependencies {
|
||||||
api 'org.jetbrains.kotlin:kotlin-stdlib-js'
|
api 'org.jetbrains.kotlin:kotlin-stdlib-js'
|
||||||
|
|||||||
+4
@@ -3,3 +3,7 @@ package com.example.lib
|
|||||||
fun <T> id(t: T): T = t
|
fun <T> id(t: T): T = t
|
||||||
|
|
||||||
expect fun expectedFun(): Unit
|
expect fun expectedFun(): Unit
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
println(">>> Common.kt >>> main()")
|
||||||
|
}
|
||||||
+3
-3
@@ -7,11 +7,11 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget
|
|||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTargetPreset
|
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTargetPreset
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation
|
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsTargetPreset
|
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsTargetPreset
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmCompilation
|
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmTargetPreset
|
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmTargetPreset
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
|
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTargetPreset
|
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTargetPreset
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinOnlyTarget
|
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinOnlyTarget
|
||||||
|
import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget
|
||||||
|
|
||||||
// DO NOT EDIT MANUALLY! Generated by org.jetbrains.kotlin.generators.gradle.dsl.MppPresetFunctionsCodegenKt
|
// DO NOT EDIT MANUALLY! Generated by org.jetbrains.kotlin.generators.gradle.dsl.MppPresetFunctionsCodegenKt
|
||||||
|
|
||||||
@@ -19,8 +19,8 @@ interface KotlinTargetContainerWithPresetFunctions : KotlinTargetsContainerWithP
|
|||||||
|
|
||||||
fun jvm(
|
fun jvm(
|
||||||
name: String = "jvm",
|
name: String = "jvm",
|
||||||
configure: KotlinOnlyTarget<KotlinJvmCompilation>.() -> Unit = { }
|
configure: KotlinJvmTarget.() -> Unit = { }
|
||||||
): KotlinOnlyTarget<KotlinJvmCompilation> =
|
): KotlinJvmTarget =
|
||||||
configureOrCreate(
|
configureOrCreate(
|
||||||
name,
|
name,
|
||||||
presets.getByName("jvm") as KotlinJvmTargetPreset,
|
presets.getByName("jvm") as KotlinJvmTargetPreset,
|
||||||
|
|||||||
+16
-9
@@ -2,6 +2,7 @@ package org.jetbrains.kotlin.gradle.plugin
|
|||||||
|
|
||||||
import com.android.build.gradle.BaseExtension
|
import com.android.build.gradle.BaseExtension
|
||||||
import com.android.build.gradle.BasePlugin
|
import com.android.build.gradle.BasePlugin
|
||||||
|
import com.android.build.gradle.api.AndroidSourceSet
|
||||||
import com.android.build.gradle.api.BaseVariant
|
import com.android.build.gradle.api.BaseVariant
|
||||||
import com.android.builder.model.SourceProvider
|
import com.android.builder.model.SourceProvider
|
||||||
import groovy.lang.Closure
|
import groovy.lang.Closure
|
||||||
@@ -430,8 +431,9 @@ internal abstract class AbstractKotlinPlugin(
|
|||||||
jarTask.dependsOn(inspectTask.getTaskOrProvider())
|
jarTask.dependsOn(inspectTask.getTaskOrProvider())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setUpJavaSourceSets(
|
internal fun setUpJavaSourceSets(
|
||||||
kotlinTarget: KotlinWithJavaTarget<*>
|
kotlinTarget: KotlinTarget,
|
||||||
|
duplicateJavaSourceSetsAsKotlinSourceSets: Boolean = true
|
||||||
) {
|
) {
|
||||||
val project = kotlinTarget.project
|
val project = kotlinTarget.project
|
||||||
val javaSourceSets = project.convention.getPlugin(JavaPluginConvention::class.java).sourceSets
|
val javaSourceSets = project.convention.getPlugin(JavaPluginConvention::class.java).sourceSets
|
||||||
@@ -442,22 +444,27 @@ internal abstract class AbstractKotlinPlugin(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Workaround for indirect mutual recursion between the two `all { ... }` handlers:
|
// Workaround for indirect mutual recursion between the two `all { ... }` handlers:
|
||||||
val compilationsUnderConstruction = mutableMapOf<String, KotlinWithJavaCompilation<*>>()
|
val compilationsUnderConstruction = mutableMapOf<String, KotlinCompilation<*>>()
|
||||||
|
|
||||||
javaSourceSets.all { javaSourceSet ->
|
javaSourceSets.all { javaSourceSet ->
|
||||||
val kotlinCompilation =
|
val kotlinCompilation =
|
||||||
compilationsUnderConstruction[javaSourceSet.name] ?: kotlinTarget.compilations.maybeCreate(javaSourceSet.name)
|
compilationsUnderConstruction[javaSourceSet.name] ?: kotlinTarget.compilations.maybeCreate(javaSourceSet.name)
|
||||||
kotlinCompilation.javaSourceSet = javaSourceSet
|
(kotlinCompilation as? KotlinWithJavaCompilation<*>)?.javaSourceSet = javaSourceSet
|
||||||
val kotlinSourceSet = project.kotlinExtension.sourceSets.maybeCreate(kotlinCompilation.name)
|
|
||||||
javaSourceSet.addConvention(kotlinSourceSetDslName, kotlinSourceSet)
|
if (duplicateJavaSourceSetsAsKotlinSourceSets) {
|
||||||
kotlinSourceSet.kotlin.source(javaSourceSet.java)
|
val kotlinSourceSet = project.kotlinExtension.sourceSets.maybeCreate(kotlinCompilation.name)
|
||||||
kotlinCompilation.source(kotlinSourceSet)
|
kotlinSourceSet.kotlin.source(javaSourceSet.java)
|
||||||
|
kotlinCompilation.source(kotlinSourceSet)
|
||||||
|
javaSourceSet.addConvention(kotlinSourceSetDslName, kotlinSourceSet)
|
||||||
|
} else {
|
||||||
|
javaSourceSet.addConvention(kotlinSourceSetDslName, kotlinCompilation.defaultSourceSet)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlinTarget.compilations.all { kotlinCompilation ->
|
kotlinTarget.compilations.all { kotlinCompilation ->
|
||||||
val sourceSetName = kotlinCompilation.name
|
val sourceSetName = kotlinCompilation.name
|
||||||
compilationsUnderConstruction[sourceSetName] = kotlinCompilation
|
compilationsUnderConstruction[sourceSetName] = kotlinCompilation
|
||||||
kotlinCompilation.javaSourceSet = javaSourceSets.maybeCreate(sourceSetName)
|
(kotlinCompilation as? KotlinWithJavaCompilation<*>)?.javaSourceSet = javaSourceSets.maybeCreate(sourceSetName)
|
||||||
|
|
||||||
// Another Kotlin source set following the other convention, named according to the compilation, not the Java source set:
|
// Another Kotlin source set following the other convention, named according to the compilation, not the Java source set:
|
||||||
val kotlinSourceSet = project.kotlinExtension.sourceSets.maybeCreate(kotlinCompilation.defaultSourceSetName)
|
val kotlinSourceSet = project.kotlinExtension.sourceSets.maybeCreate(kotlinCompilation.defaultSourceSetName)
|
||||||
|
|||||||
+3
@@ -301,6 +301,9 @@ internal val KotlinCompilation<*>.deprecatedCompileConfigurationName: String
|
|||||||
internal val KotlinCompilationToRunnableFiles<*>.deprecatedRuntimeConfigurationName: String
|
internal val KotlinCompilationToRunnableFiles<*>.deprecatedRuntimeConfigurationName: String
|
||||||
get() = disambiguateName("runtime")
|
get() = disambiguateName("runtime")
|
||||||
|
|
||||||
|
internal val KotlinTarget.testTaskName: String
|
||||||
|
get() = lowerCamelCaseName(targetName, AbstractKotlinTargetConfigurator.testTaskNameSuffix)
|
||||||
|
|
||||||
abstract class KotlinTargetConfigurator<KotlinCompilationType : KotlinCompilation<*>>(
|
abstract class KotlinTargetConfigurator<KotlinCompilationType : KotlinCompilation<*>>(
|
||||||
createDefaultSourceSets: Boolean,
|
createDefaultSourceSets: Boolean,
|
||||||
createTestCompilation: Boolean,
|
createTestCompilation: Boolean,
|
||||||
|
|||||||
+10
-5
@@ -6,20 +6,25 @@
|
|||||||
package org.jetbrains.kotlin.gradle.plugin.mpp
|
package org.jetbrains.kotlin.gradle.plugin.mpp
|
||||||
|
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
import org.jetbrains.kotlin.gradle.plugin.*
|
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.KotlinTargetConfigurator
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.KotlinTargetPreset
|
||||||
|
|
||||||
abstract class KotlinOnlyTargetPreset<T : KotlinCompilation<*>>(
|
abstract class KotlinOnlyTargetPreset<R : KotlinOnlyTarget<T>, T : KotlinCompilation<*>>(
|
||||||
protected val project: Project,
|
protected val project: Project,
|
||||||
protected val kotlinPluginVersion: String
|
protected val kotlinPluginVersion: String
|
||||||
) : KotlinTargetPreset<KotlinOnlyTarget<T>> {
|
) : KotlinTargetPreset<R> {
|
||||||
|
|
||||||
protected abstract fun createKotlinTargetConfigurator(): KotlinTargetConfigurator<T>
|
protected abstract fun createKotlinTargetConfigurator(): KotlinTargetConfigurator<T>
|
||||||
|
|
||||||
protected open fun provideTargetDisambiguationClassifier(target: KotlinOnlyTarget<T>): String? =
|
protected open fun provideTargetDisambiguationClassifier(target: KotlinOnlyTarget<T>): String? =
|
||||||
target.targetName
|
target.targetName
|
||||||
|
|
||||||
override fun createTarget(name: String): KotlinOnlyTarget<T> {
|
abstract protected fun instantiateTarget(): R
|
||||||
val result = KotlinOnlyTarget<T>(project, platformType).apply {
|
|
||||||
|
override fun createTarget(name: String): R {
|
||||||
|
val result = instantiateTarget().apply {
|
||||||
targetName = name
|
targetName = name
|
||||||
disambiguationClassifier = provideTargetDisambiguationClassifier(this@apply)
|
disambiguationClassifier = provideTargetDisambiguationClassifier(this@apply)
|
||||||
preset = this@KotlinOnlyTargetPreset
|
preset = this@KotlinOnlyTargetPreset
|
||||||
|
|||||||
+3
-1
@@ -13,10 +13,12 @@ import org.jetbrains.kotlin.gradle.targets.js.KotlinJsTargetConfigurator
|
|||||||
open class KotlinJsTargetPreset(
|
open class KotlinJsTargetPreset(
|
||||||
project: Project,
|
project: Project,
|
||||||
kotlinPluginVersion: String
|
kotlinPluginVersion: String
|
||||||
) : KotlinOnlyTargetPreset<KotlinJsCompilation>(
|
) : KotlinOnlyTargetPreset<KotlinOnlyTarget<KotlinJsCompilation>, KotlinJsCompilation>(
|
||||||
project,
|
project,
|
||||||
kotlinPluginVersion
|
kotlinPluginVersion
|
||||||
) {
|
) {
|
||||||
|
override fun instantiateTarget() = KotlinOnlyTarget<KotlinJsCompilation>(project, KotlinPlatformType.js)
|
||||||
|
|
||||||
override fun createKotlinTargetConfigurator() = KotlinJsTargetConfigurator(kotlinPluginVersion)
|
override fun createKotlinTargetConfigurator() = KotlinJsTargetConfigurator(kotlinPluginVersion)
|
||||||
|
|
||||||
override fun getName(): String = PRESET_NAME
|
override fun getName(): String = PRESET_NAME
|
||||||
|
|||||||
+162
@@ -0,0 +1,162 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. 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.jvm
|
||||||
|
|
||||||
|
import org.gradle.api.InvalidUserCodeException
|
||||||
|
import org.gradle.api.Project
|
||||||
|
import org.gradle.api.file.ConfigurableFileCollection
|
||||||
|
import org.gradle.api.plugins.JavaPlugin
|
||||||
|
import org.gradle.api.plugins.JavaPluginConvention
|
||||||
|
import org.gradle.api.tasks.SourceSet
|
||||||
|
import org.gradle.api.tasks.compile.AbstractCompile
|
||||||
|
import org.gradle.api.tasks.testing.Test
|
||||||
|
import org.gradle.jvm.tasks.Jar
|
||||||
|
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.*
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmCompilation
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinOnlyTarget
|
||||||
|
import org.jetbrains.kotlin.gradle.utils.addExtendsFromRelation
|
||||||
|
import java.util.concurrent.Callable
|
||||||
|
|
||||||
|
class KotlinJvmTarget(
|
||||||
|
project: Project
|
||||||
|
) : KotlinOnlyTarget<KotlinJvmCompilation>(
|
||||||
|
project, KotlinPlatformType.jvm
|
||||||
|
) {
|
||||||
|
var withJavaEnabled = false
|
||||||
|
private set
|
||||||
|
|
||||||
|
@Suppress("unused") // user DSL
|
||||||
|
fun withJava() {
|
||||||
|
project.multiplatformExtension.targets.find { it is KotlinJvmTarget && it.withJavaEnabled }
|
||||||
|
?.let { existingJavaTarget ->
|
||||||
|
throw InvalidUserCodeException(
|
||||||
|
"Only one of the JVM targets can be configured to work with Java. The target '${existingJavaTarget.name}' is " +
|
||||||
|
"already set up to work with Java; cannot setup another target '$targetName'"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
withJavaEnabled = true
|
||||||
|
|
||||||
|
project.plugins.apply(JavaPlugin::class.java)
|
||||||
|
val javaPluginConvention = project.convention.getPlugin(JavaPluginConvention::class.java)
|
||||||
|
AbstractKotlinPlugin.setUpJavaSourceSets(this, duplicateJavaSourceSetsAsKotlinSourceSets = false)
|
||||||
|
|
||||||
|
// Below, some effort is made to ensure that a user or 3rd-party plugin that inspects or interacts
|
||||||
|
// with the entities created by the Java plugin, not knowing of the existence of the Kotlin plugin,
|
||||||
|
// sees 'the right picture' of the inputs and outputs, for example:
|
||||||
|
// * the relevant dependencies for Java and Kotlin are in sync,
|
||||||
|
// * the Java outputs contain the outputs produced by Kotlin as well
|
||||||
|
|
||||||
|
javaPluginConvention.sourceSets.all { javaSourceSet ->
|
||||||
|
val compilation = compilations.getByName(javaSourceSet.name)
|
||||||
|
val compileJavaTask = project.tasks.getByName(javaSourceSet.compileJavaTaskName) as AbstractCompile
|
||||||
|
configureJavaTask(compilation.compileKotlinTask, compileJavaTask, project.logger)
|
||||||
|
|
||||||
|
setupJavaSourceSetSourcesAndResources(javaSourceSet, compilation)
|
||||||
|
|
||||||
|
val javaClasses = project.files(Callable { compileJavaTask.destinationDir }).builtBy(compileJavaTask)
|
||||||
|
|
||||||
|
compilation.output.classesDirs.from(javaClasses)
|
||||||
|
|
||||||
|
(javaSourceSet.output.classesDirs as? ConfigurableFileCollection)?.from(
|
||||||
|
compilation.output.classesDirs.minus(javaClasses)
|
||||||
|
)
|
||||||
|
|
||||||
|
javaSourceSet.output.setResourcesDir(Callable { compilation.output.resourcesDirProvider })
|
||||||
|
|
||||||
|
setupDependenciesCrossInclusionForJava(compilation, javaSourceSet)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Eliminate the Java output configurations from dependency resolution to avoid ambiguity between them and
|
||||||
|
// the equivalent configurations created for the target:
|
||||||
|
listOf(JavaPlugin.API_ELEMENTS_CONFIGURATION_NAME, JavaPlugin.RUNTIME_ELEMENTS_CONFIGURATION_NAME)
|
||||||
|
.forEach { outputConfigurationName ->
|
||||||
|
project.configurations.findByName(outputConfigurationName)?.isCanBeConsumed = false
|
||||||
|
}
|
||||||
|
|
||||||
|
disableJavaPluginTasks(javaPluginConvention)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupJavaSourceSetSourcesAndResources(
|
||||||
|
javaSourceSet: SourceSet,
|
||||||
|
compilation: KotlinJvmCompilation
|
||||||
|
) {
|
||||||
|
javaSourceSet.java.setSrcDirs(listOf("src/${compilation.defaultSourceSet.name}/java"))
|
||||||
|
compilation.defaultSourceSet.kotlin.srcDirs(javaSourceSet.java.sourceDirectories)
|
||||||
|
|
||||||
|
// To avoid confusion in the sources layout, remove the default Java source directories
|
||||||
|
// (like src/main/java, src/test/java) and instead add sibling directories to those where the Kotlin
|
||||||
|
// sources are placed (i.e. src/jvmMain/java, src/jvmTest/java):
|
||||||
|
javaSourceSet.resources.setSrcDirs(compilation.defaultSourceSet.resources.sourceDirectories)
|
||||||
|
compilation.defaultSourceSet.resources.srcDirs(javaSourceSet.resources.sourceDirectories)
|
||||||
|
|
||||||
|
// Resources processing is done with the Kotlin resource processing task:
|
||||||
|
val processJavaResourcesTask = project.tasks.getByName(javaSourceSet.processResourcesTaskName)
|
||||||
|
processJavaResourcesTask.dependsOn(project.tasks.getByName(compilation.processResourcesTaskName))
|
||||||
|
processJavaResourcesTask.enabled = false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun disableJavaPluginTasks(javaPluginConvention: JavaPluginConvention) {
|
||||||
|
// A 'normal' build should not do redundant job like running the tests twice or building two JARs,
|
||||||
|
// so disable some tasks and just make them depend on the others:
|
||||||
|
val targetJar = project.tasks.getByName(artifactsTaskName) as Jar
|
||||||
|
val javaJar = project.tasks.getByName(javaPluginConvention.sourceSets.getByName("main").jarTaskName) as Jar
|
||||||
|
(javaJar.source as? ConfigurableFileCollection)?.setFrom(targetJar.source)
|
||||||
|
javaJar.conventionMapping("archiveName") { targetJar.archiveName }
|
||||||
|
javaJar.dependsOn(targetJar)
|
||||||
|
javaJar.enabled = false
|
||||||
|
|
||||||
|
val javaTestTask = project.tasks.getByName(JavaPlugin.TEST_TASK_NAME) as Test
|
||||||
|
javaTestTask.dependsOn(project.tasks.getByName(testTaskName) as Test)
|
||||||
|
javaTestTask.enabled = false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupDependenciesCrossInclusionForJava(
|
||||||
|
compilation: KotlinJvmCompilation,
|
||||||
|
javaSourceSet: SourceSet
|
||||||
|
) {
|
||||||
|
// Make sure Kotlin compilation dependencies appear in the Java source set classpaths:
|
||||||
|
|
||||||
|
listOf(
|
||||||
|
compilation.apiConfigurationName,
|
||||||
|
compilation.implementationConfigurationName,
|
||||||
|
compilation.compileOnlyConfigurationName,
|
||||||
|
compilation.deprecatedCompileConfigurationName
|
||||||
|
).forEach { configurationName ->
|
||||||
|
project.addExtendsFromRelation(javaSourceSet.compileClasspathConfigurationName, configurationName)
|
||||||
|
}
|
||||||
|
|
||||||
|
listOf(
|
||||||
|
compilation.apiConfigurationName,
|
||||||
|
compilation.implementationConfigurationName,
|
||||||
|
compilation.runtimeOnlyConfigurationName,
|
||||||
|
compilation.deprecatedRuntimeConfigurationName
|
||||||
|
).forEach { configurationName ->
|
||||||
|
project.addExtendsFromRelation(javaSourceSet.runtimeClasspathConfigurationName, configurationName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the Java source set dependencies to the Kotlin compilation compile & runtime configurations:
|
||||||
|
|
||||||
|
listOfNotNull(
|
||||||
|
javaSourceSet.compileConfigurationName,
|
||||||
|
javaSourceSet.compileOnlyConfigurationName,
|
||||||
|
javaSourceSet.apiConfigurationName.takeIf { project.configurations.findByName(it) != null },
|
||||||
|
javaSourceSet.implementationConfigurationName
|
||||||
|
).forEach { configurationName ->
|
||||||
|
project.addExtendsFromRelation(compilation.compileDependencyConfigurationName, configurationName)
|
||||||
|
}
|
||||||
|
|
||||||
|
listOfNotNull(
|
||||||
|
javaSourceSet.runtimeConfigurationName,
|
||||||
|
javaSourceSet.runtimeOnlyConfigurationName,
|
||||||
|
javaSourceSet.apiConfigurationName.takeIf { project.configurations.findByName(it) != null },
|
||||||
|
javaSourceSet.implementationConfigurationName
|
||||||
|
).forEach { configurationName ->
|
||||||
|
project.addExtendsFromRelation(compilation.runtimeDependencyConfigurationName, configurationName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+4
-5
@@ -7,20 +7,19 @@
|
|||||||
package org.jetbrains.kotlin.gradle.plugin.mpp
|
package org.jetbrains.kotlin.gradle.plugin.mpp
|
||||||
|
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
import org.jetbrains.kotlin.gradle.plugin.Kotlin2JvmSourceSetProcessor
|
|
||||||
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
|
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
|
||||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSetProcessor
|
import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget
|
||||||
import org.jetbrains.kotlin.gradle.plugin.KotlinTargetConfigurator
|
|
||||||
import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTargetConfigurator
|
import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTargetConfigurator
|
||||||
import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider
|
|
||||||
|
|
||||||
class KotlinJvmTargetPreset(
|
class KotlinJvmTargetPreset(
|
||||||
project: Project,
|
project: Project,
|
||||||
kotlinPluginVersion: String
|
kotlinPluginVersion: String
|
||||||
) : KotlinOnlyTargetPreset<KotlinJvmCompilation>(
|
) : KotlinOnlyTargetPreset<KotlinJvmTarget, KotlinJvmCompilation>(
|
||||||
project,
|
project,
|
||||||
kotlinPluginVersion
|
kotlinPluginVersion
|
||||||
) {
|
) {
|
||||||
|
override fun instantiateTarget(): KotlinJvmTarget = KotlinJvmTarget(project)
|
||||||
|
|
||||||
override fun getName(): String = PRESET_NAME
|
override fun getName(): String = PRESET_NAME
|
||||||
|
|
||||||
override fun createCompilationFactory(forTarget: KotlinOnlyTarget<KotlinJvmCompilation>): KotlinCompilationFactory<KotlinJvmCompilation> =
|
override fun createCompilationFactory(forTarget: KotlinOnlyTarget<KotlinJvmCompilation>): KotlinCompilationFactory<KotlinJvmCompilation> =
|
||||||
|
|||||||
+19
@@ -10,7 +10,9 @@ import org.gradle.api.Project
|
|||||||
import org.gradle.api.plugins.JavaPlugin
|
import org.gradle.api.plugins.JavaPlugin
|
||||||
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions
|
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions
|
||||||
import org.jetbrains.kotlin.gradle.plugin.*
|
import org.jetbrains.kotlin.gradle.plugin.*
|
||||||
|
import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget
|
||||||
import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider
|
import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider
|
||||||
|
import org.jetbrains.kotlin.gradle.utils.SingleWarningPerBuild
|
||||||
|
|
||||||
class KotlinJvmWithJavaTargetPreset(
|
class KotlinJvmWithJavaTargetPreset(
|
||||||
private val project: Project,
|
private val project: Project,
|
||||||
@@ -20,6 +22,11 @@ class KotlinJvmWithJavaTargetPreset(
|
|||||||
override fun getName(): String = PRESET_NAME
|
override fun getName(): String = PRESET_NAME
|
||||||
|
|
||||||
override fun createTarget(name: String): KotlinWithJavaTarget<KotlinJvmOptions> {
|
override fun createTarget(name: String): KotlinWithJavaTarget<KotlinJvmOptions> {
|
||||||
|
SingleWarningPerBuild.show(
|
||||||
|
project,
|
||||||
|
DEPRECATION_WARNING
|
||||||
|
)
|
||||||
|
|
||||||
project.plugins.apply(JavaPlugin::class.java)
|
project.plugins.apply(JavaPlugin::class.java)
|
||||||
|
|
||||||
val target = KotlinWithJavaTarget<KotlinJvmOptions>(project, KotlinPlatformType.jvm, name).apply {
|
val target = KotlinWithJavaTarget<KotlinJvmOptions>(project, KotlinPlatformType.jvm, name).apply {
|
||||||
@@ -50,5 +57,17 @@ class KotlinJvmWithJavaTargetPreset(
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val PRESET_NAME = "jvmWithJava"
|
const val PRESET_NAME = "jvmWithJava"
|
||||||
|
|
||||||
|
val DEPRECATION_WARNING = "\nThe 'jvmWithJava' preset is deprecated and will be removed soon. " +
|
||||||
|
"Please use an ordinary JVM target with Java support: \n\n" +
|
||||||
|
" kotlin { \n" +
|
||||||
|
" jvm { \n" +
|
||||||
|
" ${KotlinJvmTarget::withJava.name}() \n" +
|
||||||
|
" } \n" +
|
||||||
|
" }\n\n" +
|
||||||
|
"After this change, please move the Java sources to the Kotlin source set directories. " +
|
||||||
|
"For example, if the JVM target is given the default name 'jvm':\n" +
|
||||||
|
" * instead of 'src/main/java', use 'src/jvmMain/java'\n" +
|
||||||
|
" * instead of 'src/test/java', use 'src/jvmTest/java'\n"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-3
@@ -9,18 +9,22 @@ package org.jetbrains.kotlin.gradle.plugin.mpp
|
|||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
import org.jetbrains.kotlin.gradle.dsl.KotlinCompile
|
import org.jetbrains.kotlin.gradle.dsl.KotlinCompile
|
||||||
import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
|
import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
|
||||||
import org.jetbrains.kotlin.gradle.plugin.*
|
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.KotlinTargetConfigurator
|
||||||
import org.jetbrains.kotlin.gradle.plugin.sources.applyLanguageSettingsToKotlinTask
|
import org.jetbrains.kotlin.gradle.plugin.sources.applyLanguageSettingsToKotlinTask
|
||||||
import org.jetbrains.kotlin.gradle.targets.metadata.KotlinMetadataTargetConfigurator
|
import org.jetbrains.kotlin.gradle.targets.metadata.KotlinMetadataTargetConfigurator
|
||||||
import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider
|
|
||||||
|
|
||||||
class KotlinMetadataTargetPreset(
|
class KotlinMetadataTargetPreset(
|
||||||
project: Project,
|
project: Project,
|
||||||
kotlinPluginVersion: String
|
kotlinPluginVersion: String
|
||||||
) : KotlinOnlyTargetPreset<KotlinCommonCompilation>(
|
) : KotlinOnlyTargetPreset<KotlinOnlyTarget<KotlinCommonCompilation>, KotlinCommonCompilation>(
|
||||||
project,
|
project,
|
||||||
kotlinPluginVersion
|
kotlinPluginVersion
|
||||||
) {
|
) {
|
||||||
|
override fun instantiateTarget() = KotlinOnlyTarget<KotlinCommonCompilation>(project, KotlinPlatformType.common)
|
||||||
|
|
||||||
override fun getName(): String = PRESET_NAME
|
override fun getName(): String = PRESET_NAME
|
||||||
|
|
||||||
override fun createCompilationFactory(
|
override fun createCompilationFactory(
|
||||||
|
|||||||
Reference in New Issue
Block a user