[Gradle] Deprecate multiple same targets
Having multiple jvm, js and other targets in the same project is now deprecated and will be forbidden in the future. Users should migrate away from that by using custom compilations or different projects. ^KT-59316 Verification Pending
This commit is contained in:
committed by
Space Team
parent
044c0adae7
commit
0e34d0b01a
+30
-3
@@ -5,14 +5,20 @@
|
||||
|
||||
package org.jetbrains.kotlin.gradle.dsl
|
||||
|
||||
import org.gradle.api.*
|
||||
import org.gradle.api.Action
|
||||
import org.gradle.api.InvalidUserCodeException
|
||||
import org.gradle.api.NamedDomainObjectCollection
|
||||
import org.gradle.api.Project
|
||||
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
|
||||
import org.jetbrains.kotlin.gradle.InternalKotlinGradlePluginApi
|
||||
import org.jetbrains.kotlin.gradle.plugin.*
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinPluginLifecycle.Stage.AfterFinaliseDsl
|
||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.Companion.kotlinPropertiesProvider
|
||||
import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinToolingDiagnostics.KotlinTargetAlreadyDeclared
|
||||
import org.jetbrains.kotlin.gradle.plugin.diagnostics.kotlinToolingDiagnosticsCollector
|
||||
import org.jetbrains.kotlin.gradle.plugin.hierarchy.KotlinHierarchyDslImpl
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.*
|
||||
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrTargetPreset
|
||||
import javax.inject.Inject
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
@@ -194,7 +200,7 @@ internal abstract class DefaultTargetsFromPresetExtension @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
internal fun KotlinTarget.isProducedFromPreset(kotlinTargetPreset: KotlinTargetPreset<*>): Boolean =
|
||||
private fun KotlinTarget.isProducedFromPreset(kotlinTargetPreset: KotlinTargetPreset<*>): Boolean =
|
||||
preset == kotlinTargetPreset
|
||||
|
||||
internal fun <T : KotlinTarget> KotlinTargetsContainerWithPresets.configureOrCreate(
|
||||
@@ -211,6 +217,9 @@ internal fun <T : KotlinTarget> KotlinTargetsContainerWithPresets.configureOrCre
|
||||
}
|
||||
|
||||
existingTarget == null -> {
|
||||
if (this is KotlinMultiplatformExtension) {
|
||||
project.reportIfTargetOfTheSameTypeAlreadyCreated(targets, targetPreset, targetName)
|
||||
}
|
||||
val newTarget = targetPreset.createTarget(targetName)
|
||||
targets.add(newTarget)
|
||||
configure(newTarget)
|
||||
@@ -226,4 +235,22 @@ internal fun <T : KotlinTarget> KotlinTargetsContainerWithPresets.configureOrCre
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Project.reportIfTargetOfTheSameTypeAlreadyCreated(
|
||||
targets: NamedDomainObjectCollection<KotlinTarget>,
|
||||
preset: KotlinTargetPreset<*>,
|
||||
targetName: String,
|
||||
) {
|
||||
val existingTargets = targets.matching { it.preset?.name == preset.name }
|
||||
val targetDslFunctionName = when(preset) {
|
||||
is KotlinJsIrTargetPreset -> "js"
|
||||
is KotlinJsTargetPreset -> "js"
|
||||
is KotlinAndroidTargetPreset -> "androidTarget"
|
||||
else -> preset.name
|
||||
}
|
||||
if (existingTargets.isNotEmpty()) {
|
||||
kotlinToolingDiagnosticsCollector.report(this, KotlinTargetAlreadyDeclared(targetDslFunctionName, targetName, Throwable()))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+25
@@ -546,6 +546,31 @@ object KotlinToolingDiagnostics {
|
||||
throwable = trace
|
||||
)
|
||||
}
|
||||
|
||||
object KotlinTargetAlreadyDeclared : ToolingDiagnosticFactory(WARNING) {
|
||||
operator fun invoke(targetDslFunctionName: String, targetName: String, trace: Throwable?) = build(
|
||||
"""
|
||||
Kotlin Target '$targetDslFunctionName()' is already declared.
|
||||
Declaring multiple Kotlin Targets of the same type is deprecated.
|
||||
|
||||
i.e.
|
||||
kotlin {
|
||||
$targetDslFunctionName()
|
||||
$targetDslFunctionName("$targetName") /* <- second '$targetDslFunctionName' target in the project is deprecated */
|
||||
}
|
||||
|
||||
Please use different Gradle Projects or create Kotlin Compilations.
|
||||
For example:
|
||||
|
||||
kotlin {
|
||||
$targetDslFunctionName() {
|
||||
val $targetName by compilations.creating
|
||||
}
|
||||
}
|
||||
""".trimIndent(),
|
||||
throwable = trace
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun String.indentLines(nSpaces: Int = 4, skipFirstLine: Boolean = true): String {
|
||||
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright 2010-2023 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.unitTests.diagnosticsTests
|
||||
|
||||
import com.android.build.gradle.LibraryPlugin
|
||||
import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinToolingDiagnostics.KotlinTargetAlreadyDeclared
|
||||
import org.jetbrains.kotlin.gradle.util.*
|
||||
import kotlin.test.Test
|
||||
|
||||
class KotlinTargetAlreadyDeclaredTest {
|
||||
|
||||
@Test
|
||||
fun `no diagnostic reported when only single targets declared`() {
|
||||
val project = buildProjectWithMPP {
|
||||
plugins.apply(LibraryPlugin::class.java)
|
||||
androidLibrary { compileSdk = 33 }
|
||||
kotlin {
|
||||
jvm()
|
||||
js()
|
||||
androidTarget()
|
||||
linuxX64()
|
||||
linuxArm64()
|
||||
}
|
||||
}
|
||||
|
||||
project.evaluate()
|
||||
project.assertNoDiagnostics(KotlinTargetAlreadyDeclared)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `no diagnostic reported when custom name is used`() {
|
||||
val project = buildProjectWithMPP {
|
||||
kotlin {
|
||||
jvm("jvm2")
|
||||
linuxX64("linux")
|
||||
}
|
||||
}
|
||||
|
||||
project.evaluate()
|
||||
project.assertNoDiagnostics(KotlinTargetAlreadyDeclared)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `no diagnostic reported when target declaration dsl is used to get existing target`() {
|
||||
val project = buildProjectWithMPP {
|
||||
kotlin {
|
||||
jvm() // declare
|
||||
jvm() // get target declared above
|
||||
}
|
||||
}
|
||||
|
||||
project.evaluate()
|
||||
project.assertNoDiagnostics(KotlinTargetAlreadyDeclared)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `diagnostic reported when jvm target declared twice with different names`() {
|
||||
val project = buildProjectWithMPP {
|
||||
kotlin {
|
||||
jvm()
|
||||
jvm("jvm2")
|
||||
}
|
||||
}
|
||||
|
||||
project.evaluate()
|
||||
project.assertContainsDiagnostic(
|
||||
KotlinTargetAlreadyDeclared("jvm", "jvm2", null),
|
||||
ignoreThrowable = true
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `diagnostic reported when native target declared twice with different names`() {
|
||||
val project = buildProjectWithMPP {
|
||||
kotlin {
|
||||
linuxArm64()
|
||||
linuxArm64("linux")
|
||||
}
|
||||
}
|
||||
|
||||
project.evaluate()
|
||||
project.assertContainsDiagnostic(
|
||||
KotlinTargetAlreadyDeclared("linuxArm64", "linux", null),
|
||||
ignoreThrowable = true
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `diagnostic reported when android target declared twice with different names`() {
|
||||
val project = buildProjectWithMPP {
|
||||
plugins.apply(LibraryPlugin::class.java)
|
||||
androidLibrary { compileSdk = 33 }
|
||||
kotlin {
|
||||
androidTarget()
|
||||
androidTarget("android2")
|
||||
}
|
||||
}
|
||||
|
||||
project.evaluate()
|
||||
project.assertContainsDiagnostic(
|
||||
KotlinTargetAlreadyDeclared("androidTarget", "android2", null),
|
||||
ignoreThrowable = true
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `diagnostic reported when js target declared twice with different names`() {
|
||||
val project = buildProjectWithMPP {
|
||||
kotlin {
|
||||
js("browser")
|
||||
js("nodejs")
|
||||
}
|
||||
}
|
||||
|
||||
project.evaluate()
|
||||
project.assertContainsDiagnostic(
|
||||
KotlinTargetAlreadyDeclared("js", "nodejs", null),
|
||||
ignoreThrowable = true
|
||||
)
|
||||
}
|
||||
}
|
||||
+10
-4
@@ -23,6 +23,11 @@ internal fun checkDiagnosticsWithMppProject(projectName: String, projectConfigur
|
||||
project.checkDiagnostics(projectName)
|
||||
}
|
||||
|
||||
internal fun ToolingDiagnostic.equals(that: ToolingDiagnostic, ignoreThrowable: Boolean) = if (ignoreThrowable) {
|
||||
this.id == that.id && this.message == that.message && this.severity == that.severity
|
||||
} else {
|
||||
this == that
|
||||
}
|
||||
|
||||
/**
|
||||
* [compactRendering] == true will omit projects with no diagnostics from the report, as well as
|
||||
@@ -76,8 +81,9 @@ internal fun Project.assertContainsDiagnostic(factory: ToolingDiagnosticFactory)
|
||||
kotlinToolingDiagnosticsCollector.getDiagnosticsForProject(this).assertContainsDiagnostic(factory)
|
||||
}
|
||||
|
||||
internal fun Project.assertContainsDiagnostic(diagnostic: ToolingDiagnostic) {
|
||||
kotlinToolingDiagnosticsCollector.getDiagnosticsForProject(this).assertContainsDiagnostic(diagnostic)
|
||||
internal fun Project.assertContainsDiagnostic(diagnostic: ToolingDiagnostic, ignoreThrowable: Boolean = false) {
|
||||
kotlinToolingDiagnosticsCollector.getDiagnosticsForProject(this)
|
||||
.assertContainsDiagnostic(diagnostic, ignoreThrowable)
|
||||
}
|
||||
|
||||
private fun Any.withIndent() = this.toString().prependIndent(" ")
|
||||
@@ -86,8 +92,8 @@ internal fun Collection<ToolingDiagnostic>.assertContainsDiagnostic(factory: Too
|
||||
if (!any { it.id == factory.id }) failDiagnosticNotFound("diagnostic with id ${factory.id} ", this)
|
||||
}
|
||||
|
||||
internal fun Collection<ToolingDiagnostic>.assertContainsDiagnostic(diagnostic: ToolingDiagnostic) {
|
||||
if (diagnostic !in this) failDiagnosticNotFound("diagnostic $diagnostic\n", this)
|
||||
internal fun Collection<ToolingDiagnostic>.assertContainsDiagnostic(diagnostic: ToolingDiagnostic, ignoreThrowable: Boolean = false) {
|
||||
if (none { it.equals(diagnostic, ignoreThrowable) }) failDiagnosticNotFound("diagnostic $diagnostic\n", this)
|
||||
}
|
||||
|
||||
private fun failDiagnosticNotFound(diagnosticDescription: String, notFoundInCollection: Collection<ToolingDiagnostic>) {
|
||||
|
||||
+91
-1
@@ -1,6 +1,96 @@
|
||||
[KotlinTargetAlreadyDeclared | WARNING] Kotlin Target 'linuxArm64()' is already declared.
|
||||
Declaring multiple Kotlin Targets of the same type is deprecated.
|
||||
|
||||
i.e.
|
||||
kotlin {
|
||||
linuxArm64()
|
||||
linuxArm64("linuxArm_B") /* <- second 'linuxArm64' target in the project is deprecated */
|
||||
}
|
||||
|
||||
Please use different Gradle Projects or create Kotlin Compilations.
|
||||
For example:
|
||||
|
||||
kotlin {
|
||||
linuxArm64() {
|
||||
val linuxArm_B by compilations.creating
|
||||
}
|
||||
}
|
||||
----
|
||||
[KotlinTargetAlreadyDeclared | WARNING] Kotlin Target 'jvm()' is already declared.
|
||||
Declaring multiple Kotlin Targets of the same type is deprecated.
|
||||
|
||||
i.e.
|
||||
kotlin {
|
||||
jvm()
|
||||
jvm("jvm_B") /* <- second 'jvm' target in the project is deprecated */
|
||||
}
|
||||
|
||||
Please use different Gradle Projects or create Kotlin Compilations.
|
||||
For example:
|
||||
|
||||
kotlin {
|
||||
jvm() {
|
||||
val jvm_B by compilations.creating
|
||||
}
|
||||
}
|
||||
----
|
||||
[KotlinTargetAlreadyDeclared | WARNING] Kotlin Target 'jvm()' is already declared.
|
||||
Declaring multiple Kotlin Targets of the same type is deprecated.
|
||||
|
||||
i.e.
|
||||
kotlin {
|
||||
jvm()
|
||||
jvm("jvm_C") /* <- second 'jvm' target in the project is deprecated */
|
||||
}
|
||||
|
||||
Please use different Gradle Projects or create Kotlin Compilations.
|
||||
For example:
|
||||
|
||||
kotlin {
|
||||
jvm() {
|
||||
val jvm_C by compilations.creating
|
||||
}
|
||||
}
|
||||
----
|
||||
[KotlinTargetAlreadyDeclared | WARNING] Kotlin Target 'jvm()' is already declared.
|
||||
Declaring multiple Kotlin Targets of the same type is deprecated.
|
||||
|
||||
i.e.
|
||||
kotlin {
|
||||
jvm()
|
||||
jvm("jvm_D") /* <- second 'jvm' target in the project is deprecated */
|
||||
}
|
||||
|
||||
Please use different Gradle Projects or create Kotlin Compilations.
|
||||
For example:
|
||||
|
||||
kotlin {
|
||||
jvm() {
|
||||
val jvm_D by compilations.creating
|
||||
}
|
||||
}
|
||||
----
|
||||
[KotlinTargetAlreadyDeclared | WARNING] Kotlin Target 'js()' is already declared.
|
||||
Declaring multiple Kotlin Targets of the same type is deprecated.
|
||||
|
||||
i.e.
|
||||
kotlin {
|
||||
js()
|
||||
js("js_B") /* <- second 'js' target in the project is deprecated */
|
||||
}
|
||||
|
||||
Please use different Gradle Projects or create Kotlin Compilations.
|
||||
For example:
|
||||
|
||||
kotlin {
|
||||
js() {
|
||||
val js_B by compilations.creating
|
||||
}
|
||||
}
|
||||
----
|
||||
[TargetsNeedDisambiguation | WARNING] The following targets are not distinguishable:
|
||||
* 'js_A', 'js_B'
|
||||
* 'jvm_C', 'jvm_D'
|
||||
* 'linuxArm_A', 'linuxArm_B'
|
||||
Use an additional attribute to disambiguate them
|
||||
See https://kotlinlang.org/docs/multiplatform-set-up-targets.html#distinguish-several-targets-for-one-platform for more details
|
||||
See https://kotlinlang.org/docs/multiplatform-set-up-targets.html#distinguish-several-targets-for-one-platform for more details
|
||||
Reference in New Issue
Block a user