Substitute stdlib-jdk7{,8} dependencies with stdlib

Only when dependencies contain kotlin-stdlib-1.8+ dependency. Such
substitution could be disabled via 'gradle.properties' by adding 'kotlin
.stdlib.jdk.variants.substitution=false'.

^KT-54136 Fixed
This commit is contained in:
Yahor Berdnikau
2022-10-20 14:38:22 +02:00
committed by Space Team
parent 65c153a722
commit 57578b569e
11 changed files with 237 additions and 1 deletions
@@ -146,6 +146,103 @@ class KotlinSpecificDependenciesIT : KGPBaseTest() {
}
}
@AndroidGradlePluginTests
@DisplayName("stdlib-jdk7, stdlib-jdk8 are substituted with stdlib:1.8+")
@GradleAndroidTest
fun testStdlibSubstitutionAndroid(
gradleVersion: GradleVersion,
agpVersion: String,
jdkVersion: JdkVersions.ProvidedJdk
) {
project(
"AndroidSimpleApp",
gradleVersion,
buildOptions = defaultBuildOptions.copy(
androidVersion = agpVersion
),
buildJdk = jdkVersion.location,
) {
// Adding dependency that pulls transitively older versions
// of stdlib-jdk8
buildGradle.appendText(
"""
|
|dependencies {
| implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2"
|}
""".trimMargin()
)
build("checkDebugDuplicateClasses")
}
}
@AndroidGradlePluginTests
@DisplayName("stdlib-jdk7, stdlib-jdk8 substitution with stdlib:1.8+ is possible to disable")
@GradleAndroidTest
fun testDisableStdlibSubstitutionAndroid(
gradleVersion: GradleVersion,
agpVersion: String,
jdkVersion: JdkVersions.ProvidedJdk
) {
project(
"AndroidSimpleApp",
gradleVersion,
buildOptions = defaultBuildOptions.copy(
androidVersion = agpVersion
),
buildJdk = jdkVersion.location,
) {
// Adding dependency that pulls transitively older versions
// of stdlib-jdk8
buildGradle.appendText(
"""
|
|dependencies {
| implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2"
|}
""".trimMargin()
)
gradleProperties.appendText(
"""
|
|kotlin.stdlib.jdk.variants.substitution=false
""".trimMargin()
)
buildAndFail("checkDebugDuplicateClasses", forceOutput = true) {
assertOutputContains("Duplicate class kotlin.internal.jdk8.JDK8PlatformImplementations")
}
}
}
@JvmGradlePluginTests
@DisplayName("stdlib-jdk7, stdlib-jdk8 substitution with stdlib:1.8+ in Kotlin DSL")
@GradleTest
fun stdlibJdkVariantsSubstitutionKotlinDsl(gradleVersion: GradleVersion) {
project("sourceSetsKotlinDsl", gradleVersion) {
removeDependencies(buildGradleKts)
buildGradleKts.appendText(
"""
|
|dependencies {
| implementation(kotlin("stdlib"))
| implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2")
|}
""".trimMargin()
)
checkTaskCompileClasspath(
"compileKotlin",
listOf("kotlin-stdlib"),
checkModulesNotInClasspath = listOf("kotlin-stdlib-jdk7", "kotlin-stdlib-jdk8"),
isBuildGradleKts = true
)
}
}
@MppGradlePluginTests
@DisplayName("MPP: kotlin-stdlib is added by default")
@GradleTest
@@ -0,0 +1,32 @@
plugins {
id "com.android.application"
id "org.jetbrains.kotlin.android"
}
repositories {
mavenLocal()
mavenCentral()
}
android {
compileSdkVersion 33
defaultConfig {
applicationId "com.example"
minSdkVersion 24
targetSdkVersion 33
versionCode 1
versionName "1.0"
}
// Needed for older AGP. It can be removed when the lowest supported AGP version is 4.2.0 or newer.
compileOptions {
sourceCompatibility 1.8
targetCompatibility 1.8
}
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
testImplementation "junit:junit:4.13.2"
}
@@ -0,0 +1,10 @@
import com.example.AppDummy
/*
* Copyright 2010-2020 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.
*/
fun main(args: Array<String>) {
println(AppDummy())
}
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example" >
<application>
<activity android:name=".KotlinActivity"/>
</application>
</manifest>
@@ -0,0 +1,8 @@
/*
* Copyright 2010-2018 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.
*/
package com.example
class AppDummy
@@ -0,0 +1,10 @@
/*
* Copyright 2010-2018 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.
*/
package com.example
import android.app.Activity
open class KotlinActivity : Activity()
@@ -0,0 +1,10 @@
import com.example.AppDummy
/*
* Copyright 2010-2020 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.
*/
fun main(args: Array<String>) {
println(AppDummy())
}
@@ -0,0 +1,15 @@
package com.example
import org.junit.Test
import org.junit.Assert.*
/*
* 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.
*/
class UnitTest {
@Test
fun isCorrect() {
assertEquals(4, 2 + 2)
}
}
@@ -41,6 +41,10 @@ internal fun customizeKotlinDependencies(project: Project) {
coreLibrariesVersion
)
if (propertiesProvider.stdlibJdkVariantsSubstitution) {
project.configurations.configureStdlibSubstitution(project.dependencies)
}
excludeStdlibAndKotlinTestCommonFromPlatformCompilations(project)
}
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.gradle.internal
import org.gradle.api.Project
import org.gradle.api.artifacts.ConfigurationContainer
import org.gradle.api.artifacts.ExternalDependency
import org.gradle.api.artifacts.dsl.DependencyHandler
import org.gradle.api.provider.Provider
import org.jetbrains.kotlin.gradle.dsl.KotlinJsProjectExtension
@@ -28,6 +29,8 @@ import org.jetbrains.kotlin.gradle.plugin.sources.android.AndroidVariantType
import org.jetbrains.kotlin.gradle.plugin.sources.android.androidSourceSetInfoOrNull
import org.jetbrains.kotlin.gradle.plugin.sources.dependsOnClosure
import org.jetbrains.kotlin.gradle.plugin.sources.sourceSetDependencyConfigurationByScope
import org.jetbrains.kotlin.gradle.targets.js.npm.SemVer
import org.jetbrains.kotlin.gradle.utils.withType
internal fun Project.configureStdlibDefaultDependency(
topLevelExtension: KotlinTopLevelExtension,
@@ -51,6 +54,41 @@ internal fun Project.configureStdlibDefaultDependency(
}
}
/**
* Replacing kotlin-stdlib-jdk8 and kotlin-stdlib-jdk7 artifacts with kotlin-stdlib
* when project stdlib version is >= 1.8.0
*/
internal fun ConfigurationContainer.configureStdlibSubstitution(
dependencies: DependencyHandler
) = all { configuration ->
configuration.withDependencies { dependencySet ->
dependencySet
.withType<ExternalDependency>()
.configureEach { dependency ->
if (dependency.group == KOTLIN_MODULE_GROUP &&
dependency.name == "kotlin-stdlib" &&
dependency.version != null &&
SemVer.from(dependency.version!!) >= kotlin180Version
) {
dependencies.modules { componentModuleMetadataHandler ->
componentModuleMetadataHandler.module("org.jetbrains.kotlin:kotlin-stdlib-jdk7") {
it.replacedBy(
"org.jetbrains.kotlin:kotlin-stdlib",
"kotlin-stdlib-jdk7 is now part of kotlin-stdlib"
)
}
componentModuleMetadataHandler.module("org.jetbrains.kotlin:kotlin-stdlib-jdk8") {
it.replacedBy(
"org.jetbrains.kotlin:kotlin-stdlib",
"kotlin-stdlib-jdk8 is now part of kotlin-stdlib"
)
}
}
}
}
}
}
private fun addStdlibToKpmProject(
project: Project,
coreLibrariesVersion: Provider<String>
@@ -170,6 +208,8 @@ private fun KotlinPlatformType.stdlibPlatformType(
private val androidTestVariants = setOf(AndroidVariantType.UnitTest, AndroidVariantType.InstrumentedTest)
private val kotlin180Version = SemVer(1.toBigInteger(), 8.toBigInteger(), 0.toBigInteger())
private fun KotlinSourceSet.isRelatedToAndroidTestSourceSet(): Boolean {
val androidVariant = androidSourceSetInfoOrNull?.androidVariantType ?: return false
return androidVariant in androidTestVariants
@@ -24,7 +24,7 @@ import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLI
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_MPP_HIERARCHICAL_STRUCTURE_SUPPORT
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_NATIVE_DEPENDENCY_PROPAGATION
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_STDLIB_DEFAULT_DEPENDENCY
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMultiplatformPlugin
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_STDLIB_JDK_VARIANTS_SUBSTITUTION
import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinIrJsGeneratedTSValidationStrategy
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrOutputGranularity
@@ -407,6 +407,9 @@ internal class PropertiesProvider private constructor(private val project: Proje
val stdlibDefaultDependency: Boolean
get() = booleanProperty(KOTLIN_STDLIB_DEFAULT_DEPENDENCY) ?: true
val stdlibJdkVariantsSubstitution: Boolean
get() = booleanProperty(KOTLIN_STDLIB_JDK_VARIANTS_SUBSTITUTION) ?: true
val kotlinTestInferJvmVariant: Boolean
get() = booleanProperty("kotlin.test.infer.jvm.variant") ?: true
@@ -479,6 +482,7 @@ internal class PropertiesProvider private constructor(private val project: Proje
object PropertyNames {
const val KOTLIN_STDLIB_DEFAULT_DEPENDENCY = "kotlin.stdlib.default.dependency"
const val KOTLIN_STDLIB_JDK_VARIANTS_SUBSTITUTION = "kotlin.stdlib.jdk.variants.substitution"
const val KOTLIN_MPP_ENABLE_GRANULAR_SOURCE_SETS_METADATA = "kotlin.mpp.enableGranularSourceSetsMetadata"
const val KOTLIN_MPP_ENABLE_CINTEROP_COMMONIZATION = "kotlin.mpp.enableCInteropCommonization"
const val KOTLIN_MPP_HIERARCHICAL_STRUCTURE_BY_DEFAULT = "kotlin.internal.mpp.hierarchicalStructureByDefault"