Add kotlin-stdlib dependency in a lazy way
^KT-41642 In Progress
This commit is contained in:
+49
-32
@@ -30,7 +30,7 @@ class KotlinSpecificDependenciesIT : KGPBaseTest() {
|
||||
fun testStdlibByDefaultJvm(gradleVersion: GradleVersion) {
|
||||
project("simpleProject", gradleVersion) {
|
||||
removeDependencies(buildGradle)
|
||||
checkTaskCompileClasspath("compileKotlin", listOf("kotlin-stdlib" /*any of them*/))
|
||||
checkTaskCompileClasspath("compileKotlin", listOf("kotlin-stdlib"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ class KotlinSpecificDependenciesIT : KGPBaseTest() {
|
||||
|
||||
checkTaskCompileClasspath(
|
||||
"compileKotlinJs",
|
||||
listOf("kotlin-stdlib"),
|
||||
listOf("kotlin-stdlib-js"),
|
||||
isBuildGradleKts = true
|
||||
)
|
||||
}
|
||||
@@ -115,7 +115,7 @@ class KotlinSpecificDependenciesIT : KGPBaseTest() {
|
||||
buildJdk = jdkVersion.location
|
||||
) {
|
||||
removeDependencies(buildGradle)
|
||||
checkTaskCompileClasspath("compileDebugKotlin", listOf("kotlin-stdlib" /*any of them*/))
|
||||
checkTaskCompileClasspath("compileDebugKotlin", listOf("kotlin-stdlib"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,28 +192,6 @@ class KotlinSpecificDependenciesIT : KGPBaseTest() {
|
||||
}
|
||||
}
|
||||
|
||||
@DisplayName("Adds kotlin-stdlib variant based on jvmTarget value")
|
||||
@JvmGradlePluginTests
|
||||
@GradleTest
|
||||
fun testStdlibBasedOnJdk(gradleVersion: GradleVersion) {
|
||||
project("simpleProject", gradleVersion) {
|
||||
removeDependencies(buildGradle)
|
||||
buildGradle.modify { "$it\nkotlin.target.compilations[\"main\"].kotlinOptions { jvmTarget = \"1.6\" }" }
|
||||
val version = defaultBuildOptions.kotlinVersion
|
||||
checkTaskCompileClasspath(
|
||||
"compileKotlin",
|
||||
listOf("kotlin-stdlib-$version"),
|
||||
listOf("kotlin-stdlib-jdk7", "kotlin-stdlib-jdk8")
|
||||
)
|
||||
|
||||
buildGradle.modify { "$it\nkotlin.target.compilations[\"main\"].kotlinOptions { jvmTarget = \"11\" }" }
|
||||
checkTaskCompileClasspath(
|
||||
"compileKotlin",
|
||||
listOf("kotlin-stdlib", "kotlin-stdlib-jdk7", "kotlin-stdlib-jdk8"),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmGradlePluginTests
|
||||
@DisplayName("Explicit kotlin-stdlib version overrides default one")
|
||||
@GradleTest
|
||||
@@ -224,19 +202,54 @@ class KotlinSpecificDependenciesIT : KGPBaseTest() {
|
||||
"""
|
||||
|
||||
kotlin.target.compilations["main"].kotlinOptions.jvmTarget = "1.8"
|
||||
dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib") }
|
||||
dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") }
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
// Check that the explicit stdlib overrides the plugin's choice of stdlib-jdk8
|
||||
checkTaskCompileClasspath(
|
||||
"compileKotlin",
|
||||
listOf("kotlin-stdlib-${defaultBuildOptions.kotlinVersion}"),
|
||||
listOf("kotlin-stdlib-jdk8")
|
||||
listOf("kotlin-stdlib-jdk8-${defaultBuildOptions.kotlinVersion}")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmGradlePluginTests
|
||||
@DisplayName("KT-41642: adding stdlib should not resolve dependencies eagerly")
|
||||
@GradleTest
|
||||
fun testStdlibEagerDependencies(gradleVersion: GradleVersion) {
|
||||
project("simpleProject", gradleVersion) {
|
||||
|
||||
// Disabling auto-adding kotlin.test dependencies
|
||||
gradleProperties.appendText(
|
||||
"""
|
||||
|
||||
kotlin.test.infer.jvm.variant=false
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
buildGradle.appendText(
|
||||
//language=Groovy
|
||||
"""
|
||||
|
||||
configurations.each { config ->
|
||||
config.dependencies.addAllLater(
|
||||
project.objects.listProperty(Dependency.class).value(
|
||||
project.provider {
|
||||
throw new Throwable("Dependency resolved in ${'$'}{config.name}!")
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
build("help") {
|
||||
assertOutputDoesNotContain("Dependency resolved in")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AndroidGradlePluginTests
|
||||
@DisplayName("Android: Kotlin test single dependency in unit tests")
|
||||
@GradleAndroidTest
|
||||
@@ -497,7 +510,7 @@ class KotlinSpecificDependenciesIT : KGPBaseTest() {
|
||||
|
||||
checkTaskCompileClasspath(
|
||||
"compileTestKotlin",
|
||||
listOf("kotlin-stdlib-", "kotlin-reflect-", "kotlin-test-").map { it + customVersion }
|
||||
listOf("kotlin-stdlib-jdk8-", "kotlin-reflect-", "kotlin-test-").map { it + customVersion }
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -620,11 +633,15 @@ class KotlinSpecificDependenciesIT : KGPBaseTest() {
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
build("${subproject?.prependIndent(":").orEmpty()}:$printingTaskName") {
|
||||
build("${subproject?.prependIndent(":").orEmpty()}:$printingTaskName", forceOutput = true) {
|
||||
val itemsLine = output.lines().single { "###$printingTaskName" in it }.substringAfter(printingTaskName)
|
||||
val items = itemsLine.removeSurrounding("[", "]").split(", ").toSet()
|
||||
checkAnyItemsContains.forEach { pattern -> assertTrue { items.any { pattern in it } } }
|
||||
checkNoItemContains.forEach { pattern -> assertFalse { items.any { pattern in it } } }
|
||||
checkAnyItemsContains.forEach { pattern ->
|
||||
assertTrue("Dependencies does not contain $pattern") { items.any { pattern in it } }
|
||||
}
|
||||
checkNoItemContains.forEach { pattern ->
|
||||
assertFalse("Dependencies contain $pattern") { items.any { pattern in it } }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -106,7 +106,7 @@ class PublishingIT : KGPBaseTest() {
|
||||
) {
|
||||
assertTasksExecuted(":compileKotlin", ":compileTestKotlin")
|
||||
val pomLines = projectPath.resolve("build/publications/myLibrary/pom-default.xml").readLines()
|
||||
val stdlibVersionLineNumber = pomLines.indexOfFirst { "<artifactId>kotlin-stdlib-jdk8</artifactId>" in it } + 1
|
||||
val stdlibVersionLineNumber = pomLines.indexOfFirst { "<artifactId>kotlin-stdlib</artifactId>" in it } + 1
|
||||
val versionLine = pomLines[stdlibVersionLineNumber]
|
||||
assertTrue { "<version>${buildOptions.kotlinVersion}</version>" in versionLine }
|
||||
}
|
||||
|
||||
@@ -96,6 +96,9 @@ dependencies {
|
||||
functionalTestImplementation(project(":kotlin-gradle-plugin-kpm-android"))
|
||||
functionalTestImplementation(project(":kotlin-tooling-metadata"))
|
||||
functionalTestImplementation(testFixtures(project(":kotlin-gradle-plugin-idea")))
|
||||
functionalTestImplementation("com.github.gundy:semver4j:0.16.4:nodeps") {
|
||||
exclude(group = "*")
|
||||
}
|
||||
}
|
||||
|
||||
testCompileOnly(project(":compiler"))
|
||||
|
||||
+161
-111
@@ -11,6 +11,8 @@ import org.gradle.api.InvalidUserDataException
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.artifacts.*
|
||||
import org.gradle.api.artifacts.dsl.DependencyHandler
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.api.tasks.testing.AbstractTestTask
|
||||
import org.gradle.api.tasks.testing.Test
|
||||
import org.gradle.api.tasks.testing.junit.JUnitOptions
|
||||
@@ -32,40 +34,60 @@ import org.jetbrains.kotlin.gradle.plugin.sources.android.androidSourceSetInfoOr
|
||||
import org.jetbrains.kotlin.gradle.plugin.sources.dependsOnClosure
|
||||
import org.jetbrains.kotlin.gradle.plugin.sources.sourceSetDependencyConfigurationByScope
|
||||
import org.jetbrains.kotlin.gradle.plugin.sources.withDependsOnClosure
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.SemVer
|
||||
import org.jetbrains.kotlin.gradle.targets.jvm.JvmCompilationsTestRunSource
|
||||
import org.jetbrains.kotlin.gradle.tasks.locateTask
|
||||
import org.jetbrains.kotlin.gradle.testing.KotlinTaskTestRun
|
||||
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
|
||||
import org.jetbrains.kotlin.gradle.utils.providerWithLazyConvention
|
||||
import org.jetbrains.kotlin.gradle.utils.withType
|
||||
|
||||
internal const val KOTLIN_MODULE_GROUP = "org.jetbrains.kotlin"
|
||||
internal const val KOTLIN_COMPILER_EMBEDDABLE = "kotlin-compiler-embeddable"
|
||||
internal const val PLATFORM_INTEGERS_SUPPORT_LIBRARY = "platform-integers"
|
||||
|
||||
internal fun customizeKotlinDependencies(project: Project) {
|
||||
configureStdlibDefaultDependency(project)
|
||||
if (project.topLevelExtension is KotlinProjectExtension) { // TODO: extend this logic to PM20
|
||||
val topLevelExtension = project.topLevelExtension
|
||||
val coreLibrariesVersion = project.objects.providerWithLazyConvention {
|
||||
topLevelExtension.coreLibrariesVersion
|
||||
}
|
||||
|
||||
if (PropertiesProvider(project).stdlibDefaultDependency)
|
||||
project.configureStdlibDefaultDependency(topLevelExtension, coreLibrariesVersion)
|
||||
|
||||
if (topLevelExtension is KotlinProjectExtension) { // TODO: extend this logic to PM20
|
||||
configureKotlinTestDependency(project)
|
||||
}
|
||||
configureDefaultVersionsResolutionStrategy(project)
|
||||
|
||||
project.configurations.configureDefaultVersionsResolutionStrategy(
|
||||
coreLibrariesVersion
|
||||
)
|
||||
|
||||
excludeStdlibAndKotlinTestCommonFromPlatformCompilations(project)
|
||||
}
|
||||
|
||||
private fun configureDefaultVersionsResolutionStrategy(project: Project) {
|
||||
project.configurations.all { configuration ->
|
||||
// Use the API introduced in Gradle 4.4 to modify the dependencies directly before they are resolved:
|
||||
configuration.withDependencies { dependencySet ->
|
||||
val coreLibrariesVersion = project.topLevelExtension.coreLibrariesVersion
|
||||
dependencySet.filterIsInstance<ExternalDependency>()
|
||||
.filter { it.group == KOTLIN_MODULE_GROUP && it.version.isNullOrEmpty() }
|
||||
.forEach { it.version { constraint -> constraint.require(coreLibrariesVersion) } }
|
||||
}
|
||||
private fun ConfigurationContainer.configureDefaultVersionsResolutionStrategy(
|
||||
coreLibrariesVersion: Provider<String>
|
||||
) = all { configuration ->
|
||||
configuration.withDependencies { dependencySet ->
|
||||
dependencySet
|
||||
.withType<ExternalDependency>()
|
||||
.configureEach { dependency ->
|
||||
if (dependency.group == KOTLIN_MODULE_GROUP &&
|
||||
dependency.version.isNullOrEmpty()
|
||||
) {
|
||||
dependency.version {
|
||||
it.require(coreLibrariesVersion.get())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun excludeStdlibAndKotlinTestCommonFromPlatformCompilations(project: Project) {
|
||||
val multiplatformExtension = project.multiplatformExtensionOrNull ?: return
|
||||
|
||||
multiplatformExtension.targets.matching { it !is KotlinMetadataTarget }.all {
|
||||
multiplatformExtension.targets.matching { it !is KotlinMetadataTarget }.configureEach {
|
||||
it.excludeStdlibAndKotlinTestCommonFromPlatformCompilations()
|
||||
}
|
||||
}
|
||||
@@ -97,134 +119,162 @@ private fun KotlinTarget.excludeStdlibAndKotlinTestCommonFromPlatformCompilation
|
||||
}
|
||||
|
||||
//region stdlib
|
||||
internal fun configureStdlibDefaultDependency(project: Project) = with(project) {
|
||||
if (!PropertiesProvider(project).stdlibDefaultDependency)
|
||||
return
|
||||
private fun Project.configureStdlibDefaultDependency(
|
||||
topLevelExtension: KotlinTopLevelExtension,
|
||||
coreLibrariesVersion: Provider<String>
|
||||
) {
|
||||
|
||||
val scopesToHandleConfigurations = listOf(KotlinDependencyScope.API_SCOPE, KotlinDependencyScope.IMPLEMENTATION_SCOPE)
|
||||
|
||||
val extension = topLevelExtension
|
||||
when {
|
||||
project.hasKpmModel -> addStdlibToKpmProject(project)
|
||||
extension is KotlinProjectExtension -> {
|
||||
extension.sourceSets.all { kotlinSourceSet ->
|
||||
scopesToHandleConfigurations.forEach { scope ->
|
||||
val scopeConfiguration = project.sourceSetDependencyConfigurationByScope(kotlinSourceSet, scope)
|
||||
|
||||
project.tryWithDependenciesIfUnresolved(scopeConfiguration) { dependencies ->
|
||||
val scopeToAddStdlibDependency =
|
||||
if (isRelatedToAndroidTestSourceSet(kotlinSourceSet)
|
||||
) // AGP deprecates API configurations in test source sets
|
||||
KotlinDependencyScope.IMPLEMENTATION_SCOPE
|
||||
else KotlinDependencyScope.API_SCOPE
|
||||
|
||||
if (scope != scopeToAddStdlibDependency)
|
||||
return@tryWithDependenciesIfUnresolved
|
||||
|
||||
chooseAndAddStdlibDependency(project, kotlinSourceSet, dependencies)
|
||||
}
|
||||
}
|
||||
project.hasKpmModel -> addStdlibToKpmProject(project, coreLibrariesVersion)
|
||||
topLevelExtension is KotlinSingleTargetExtension<*> -> topLevelExtension
|
||||
.target
|
||||
.addStdlibDependency(configurations, dependencies, coreLibrariesVersion)
|
||||
topLevelExtension is KotlinMultiplatformExtension -> topLevelExtension
|
||||
.targets
|
||||
.configureEach { target ->
|
||||
target.addStdlibDependency(configurations, dependencies, coreLibrariesVersion)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun addStdlibToKpmProject(
|
||||
project: Project
|
||||
project: Project,
|
||||
coreLibrariesVersion: Provider<String>
|
||||
) {
|
||||
project.kpmModules.matching { it.name == GradleKpmModule.MAIN_MODULE_NAME }.configureEach { main ->
|
||||
main.fragments.matching { it.name == GradleKpmFragment.COMMON_FRAGMENT_NAME }.configureEach { common ->
|
||||
project.kpmModules.named(GradleKpmModule.MAIN_MODULE_NAME) { main ->
|
||||
main.fragments.named(GradleKpmFragment.COMMON_FRAGMENT_NAME) { common ->
|
||||
common.dependencies {
|
||||
api(project.kotlinDependency("kotlin-stdlib-common", project.topLevelExtension.coreLibrariesVersion))
|
||||
api(project.dependencies.kotlinDependency("kotlin-stdlib-common", coreLibrariesVersion.get()))
|
||||
}
|
||||
}
|
||||
main.variants.configureEach { variant ->
|
||||
val dependency = when (variant.platformType) {
|
||||
val dependencyHandler = project.dependencies
|
||||
val stdlibModule = when (variant.platformType) {
|
||||
KotlinPlatformType.common -> error("variants are not expected to be common")
|
||||
KotlinPlatformType.jvm -> "kotlin-stdlib" // TODO get JDK from JVM variants
|
||||
KotlinPlatformType.jvm -> chooseStdlibJvmDependency(coreLibrariesVersion)
|
||||
KotlinPlatformType.js -> "kotlin-stdlib-js"
|
||||
KotlinPlatformType.wasm -> "kotlin-stdlib-wasm"
|
||||
KotlinPlatformType.androidJvm -> null // TODO: expect support on the AGP side?
|
||||
KotlinPlatformType.native -> null
|
||||
}
|
||||
if (dependency != null) {
|
||||
if (stdlibModule != null) {
|
||||
variant.dependencies {
|
||||
api(project.kotlinDependency(dependency, project.topLevelExtension.coreLibrariesVersion))
|
||||
api(dependencyHandler.kotlinDependency(stdlibModule, coreLibrariesVersion.get()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun chooseAndAddStdlibDependency(
|
||||
project: Project,
|
||||
kotlinSourceSet: KotlinSourceSet,
|
||||
dependencies: DependencySet
|
||||
private fun KotlinTarget.addStdlibDependency(
|
||||
configurations: ConfigurationContainer,
|
||||
dependencies: DependencyHandler,
|
||||
coreLibrariesVersion: Provider<String>
|
||||
) {
|
||||
val sourceSetDependencyConfigurations =
|
||||
KotlinDependencyScope.values().map { project.sourceSetDependencyConfigurationByScope(kotlinSourceSet, it) }
|
||||
compilations.configureEach { compilation ->
|
||||
compilation.allKotlinSourceSets.forEach { kotlinSourceSet ->
|
||||
val scope = if (compilation.isTest() ||
|
||||
(this is KotlinAndroidTarget &&
|
||||
kotlinSourceSet.isRelatedToAndroidTestSourceSet()
|
||||
)
|
||||
) {
|
||||
KotlinDependencyScope.IMPLEMENTATION_SCOPE
|
||||
} else {
|
||||
KotlinDependencyScope.API_SCOPE
|
||||
}
|
||||
val scopeConfiguration = configurations
|
||||
.sourceSetDependencyConfigurationByScope(kotlinSourceSet, scope)
|
||||
|
||||
val hierarchySourceSetsDependencyConfigurations = kotlinSourceSet.dependsOnClosure.flatMap { hierarchySourceSet ->
|
||||
KotlinDependencyScope.values().map { scope ->
|
||||
project.sourceSetDependencyConfigurationByScope(hierarchySourceSet, scope)
|
||||
scopeConfiguration.withDependencies { dependencySet ->
|
||||
// Check if stdlib is directly added to SourceSet
|
||||
if (isStdlibAddedByUser(configurations, stdlibModules, kotlinSourceSet)) return@withDependencies
|
||||
|
||||
val stdlibModule = compilation
|
||||
.platformType
|
||||
.stdlibPlatformType(coreLibrariesVersion, this, kotlinSourceSet)
|
||||
?: return@withDependencies
|
||||
|
||||
// Check if stdlib module is added to SourceSets hierarchy
|
||||
if (
|
||||
isStdlibAddedByUser(
|
||||
configurations,
|
||||
setOf(stdlibModule),
|
||||
*kotlinSourceSet.dependsOnClosure.toTypedArray()
|
||||
)
|
||||
) return@withDependencies
|
||||
|
||||
dependencySet.addLater(
|
||||
coreLibrariesVersion.map {
|
||||
dependencies.kotlinDependency(stdlibModule, it)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val compilations = CompilationSourceSetUtil.compilationsBySourceSets(project).getValue(kotlinSourceSet)
|
||||
.filter { it.target !is KotlinMetadataTarget }
|
||||
|
||||
if (compilations.isEmpty())
|
||||
// source set doesn't take part in any compilation; prohibit this in the future; also, this caused KT-40559 in Android libraries
|
||||
return
|
||||
|
||||
val platformTypes = compilations.mapTo(mutableSetOf()) { it.platformType }
|
||||
|
||||
val sourceSetStdlibPlatformType = when {
|
||||
platformTypes.size == 1 -> platformTypes.single()
|
||||
setOf(KotlinPlatformType.jvm, KotlinPlatformType.androidJvm).containsAll(platformTypes) -> KotlinPlatformType.jvm
|
||||
else -> KotlinPlatformType.common
|
||||
}
|
||||
|
||||
val isStdlibAddedByUser = sourceSetDependencyConfigurations
|
||||
.flatMap { it.allNonProjectDependencies() }
|
||||
.any { dependency -> dependency.group == KOTLIN_MODULE_GROUP && dependency.name in stdlibModules }
|
||||
|
||||
if (!isStdlibAddedByUser) {
|
||||
val stdlibModuleName = when (sourceSetStdlibPlatformType) {
|
||||
KotlinPlatformType.jvm -> stdlibModuleForJvmCompilations(compilations)
|
||||
KotlinPlatformType.androidJvm ->
|
||||
if (kotlinSourceSet.androidSourceSetInfoOrNull?.androidSourceSetName == AndroidBaseSourceSetName.Main.name)
|
||||
stdlibModuleForJvmCompilations(compilations) else null
|
||||
|
||||
KotlinPlatformType.js -> "kotlin-stdlib-js"
|
||||
KotlinPlatformType.wasm -> "kotlin-stdlib-wasm"
|
||||
KotlinPlatformType.native -> null
|
||||
KotlinPlatformType.common -> // there's no platform compilation that the source set is default for
|
||||
"kotlin-stdlib-common"
|
||||
}
|
||||
|
||||
// If the exact same module is added in the source sets hierarchy, possibly even with a different scope, we don't add it
|
||||
val moduleAddedInHierarchy = hierarchySourceSetsDependencyConfigurations.any {
|
||||
it.allNonProjectDependencies()
|
||||
.any { dependency -> dependency.group == KOTLIN_MODULE_GROUP && dependency.name == stdlibModuleName }
|
||||
}
|
||||
|
||||
if (stdlibModuleName != null && !moduleAddedInHierarchy)
|
||||
dependencies.add(project.kotlinDependency(stdlibModuleName, project.kotlinExtension.coreLibrariesVersion))
|
||||
}
|
||||
}
|
||||
|
||||
private fun isRelatedToAndroidTestSourceSet(kotlinSourceSet: KotlinSourceSet): Boolean {
|
||||
val androidVariantType = kotlinSourceSet.androidSourceSetInfoOrNull?.androidVariantType ?: return false
|
||||
return androidVariantType in setOf(AndroidVariantType.UnitTest, AndroidVariantType.InstrumentedTest)
|
||||
private fun isStdlibAddedByUser(
|
||||
configurations: ConfigurationContainer,
|
||||
stdlibModules: Set<String>,
|
||||
vararg sourceSets: KotlinSourceSet
|
||||
): Boolean {
|
||||
return sourceSets
|
||||
.asSequence()
|
||||
.flatMap { sourceSet ->
|
||||
KotlinDependencyScope.values().map { scope ->
|
||||
configurations.sourceSetDependencyConfigurationByScope(sourceSet, scope)
|
||||
}.asSequence()
|
||||
}
|
||||
.flatMap { it.allNonProjectDependencies().asSequence() }
|
||||
.any { dependency ->
|
||||
dependency.group == KOTLIN_MODULE_GROUP && dependency.name in stdlibModules
|
||||
}
|
||||
}
|
||||
|
||||
private fun KotlinPlatformType.stdlibPlatformType(
|
||||
coreLibrariesVersion: Provider<String>,
|
||||
kotlinTarget: KotlinTarget,
|
||||
kotlinSourceSet: KotlinSourceSet
|
||||
): String? = when (this) {
|
||||
KotlinPlatformType.jvm -> chooseStdlibJvmDependency(coreLibrariesVersion)
|
||||
KotlinPlatformType.androidJvm -> {
|
||||
if (kotlinTarget is KotlinAndroidTarget &&
|
||||
kotlinSourceSet.androidSourceSetInfoOrNull?.androidSourceSetName == AndroidBaseSourceSetName.Main.name
|
||||
) {
|
||||
chooseStdlibJvmDependency(coreLibrariesVersion)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
KotlinPlatformType.js -> "kotlin-stdlib-js"
|
||||
KotlinPlatformType.wasm -> "kotlin-stdlib-wasm"
|
||||
KotlinPlatformType.native -> null
|
||||
KotlinPlatformType.common -> // there's no platform compilation that the source set is default for
|
||||
"kotlin-stdlib-common"
|
||||
}
|
||||
|
||||
private val kotlin180Version = SemVer(1.toBigInteger(), 8.toBigInteger(), 0.toBigInteger())
|
||||
|
||||
private fun chooseStdlibJvmDependency(
|
||||
coreLibrariesVersion: Provider<String>
|
||||
): String {
|
||||
// Current 'SemVer.satisfies' release always returns `false` for any "-SNAPSHOT" version.
|
||||
return if (SemVer.from(coreLibrariesVersion.get()) < kotlin180Version) {
|
||||
"kotlin-stdlib-jdk8"
|
||||
} else {
|
||||
"kotlin-stdlib"
|
||||
}
|
||||
}
|
||||
|
||||
private val androidTestVariants = setOf(AndroidVariantType.UnitTest, AndroidVariantType.InstrumentedTest)
|
||||
|
||||
private fun KotlinSourceSet.isRelatedToAndroidTestSourceSet(): Boolean {
|
||||
val androidVariant = androidSourceSetInfoOrNull?.androidVariantType ?: return false
|
||||
return androidVariant in androidTestVariants
|
||||
}
|
||||
|
||||
private val stdlibModules = setOf("kotlin-stdlib-common", "kotlin-stdlib", "kotlin-stdlib-jdk7", "kotlin-stdlib-jdk8", "kotlin-stdlib-js")
|
||||
|
||||
private fun stdlibModuleForJvmCompilations(compilations: Iterable<KotlinCompilation<*>>): String {
|
||||
val jvmTargets = compilations.map { (it.kotlinOptions as KotlinJvmOptions).jvmTarget }
|
||||
return if ("1.6" in jvmTargets) "kotlin-stdlib" else "kotlin-stdlib-jdk8"
|
||||
}
|
||||
//endregion
|
||||
|
||||
//region kotlin-test
|
||||
@@ -246,7 +296,7 @@ internal fun configureKotlinTestDependency(project: Project) {
|
||||
val versionOrNullBySourceSet = mutableMapOf<KotlinSourceSet, String?>()
|
||||
|
||||
project.kotlinExtension.sourceSets.all { kotlinSourceSet ->
|
||||
val configuration = project.sourceSetDependencyConfigurationByScope(kotlinSourceSet, scope)
|
||||
val configuration = project.configurations.sourceSetDependencyConfigurationByScope(kotlinSourceSet, scope)
|
||||
var finalizingDependencies = false
|
||||
|
||||
configuration.nonProjectDependencies().matching(::isKotlinTestRootDependency).apply {
|
||||
@@ -272,7 +322,7 @@ internal fun configureKotlinTestDependency(project: Project) {
|
||||
if (!isAtLeast1_5(effectiveVersion)) continue
|
||||
val clarifyCapability = kotlinTestCapabilityForJvmSourceSet(project, kotlinSourceSet) ?: continue
|
||||
val clarifiedDependency =
|
||||
(project.kotlinDependency(KOTLIN_TEST_ROOT_MODULE_NAME, version) as ExternalDependency).apply {
|
||||
(project.dependencies.kotlinDependency(KOTLIN_TEST_ROOT_MODULE_NAME, version) as ExternalDependency).apply {
|
||||
if (version == null) {
|
||||
version { constraint -> constraint.require(project.kotlinExtension.coreLibrariesVersion) }
|
||||
}
|
||||
@@ -356,8 +406,8 @@ private fun KotlinTargetWithTests<*, *>.findTestRunsByCompilation(byCompilation:
|
||||
}
|
||||
//endregion
|
||||
|
||||
internal fun Project.kotlinDependency(moduleName: String, versionOrNull: String?) =
|
||||
project.dependencies.create("$KOTLIN_MODULE_GROUP:$moduleName${versionOrNull?.prependIndent(":").orEmpty()}")
|
||||
internal fun DependencyHandler.kotlinDependency(moduleName: String, versionOrNull: String?) =
|
||||
create("$KOTLIN_MODULE_GROUP:$moduleName${versionOrNull?.prependIndent(":").orEmpty()}")
|
||||
|
||||
private fun Project.tryWithDependenciesIfUnresolved(configuration: Configuration, action: (DependencySet) -> Unit) {
|
||||
fun reportAlreadyResolved() {
|
||||
|
||||
+1
-1
@@ -365,7 +365,7 @@ internal fun requestedDependencies(
|
||||
): Iterable<Dependency> {
|
||||
fun collectScopedDependenciesFromSourceSet(sourceSet: KotlinSourceSet): Set<Dependency> =
|
||||
requestedScopes.flatMapTo(mutableSetOf()) { scope ->
|
||||
project.sourceSetDependencyConfigurationByScope(sourceSet, scope).incoming.dependencies
|
||||
project.configurations.sourceSetDependencyConfigurationByScope(sourceSet, scope).incoming.dependencies
|
||||
}
|
||||
|
||||
val otherContributingSourceSets = dependsOnClosureWithInterCompilationDependencies(project, sourceSet)
|
||||
|
||||
+1
-1
@@ -179,7 +179,7 @@ private fun buildKotlinProjectStructureMetadata(extension: KotlinMultiplatformEx
|
||||
else listOf(sourceSet)
|
||||
val sourceSetExportedDependencies = scopes.flatMap { scope ->
|
||||
sourceSetsToIncludeDependencies.flatMap { hierarchySourceSet ->
|
||||
project.sourceSetDependencyConfigurationByScope(hierarchySourceSet, scope).allDependencies.toList()
|
||||
project.configurations.sourceSetDependencyConfigurationByScope(hierarchySourceSet, scope).allDependencies.toList()
|
||||
}
|
||||
}
|
||||
sourceSet.name to sourceSetExportedDependencies.map { ModuleIds.fromDependency(it) }.toSet()
|
||||
|
||||
+4
-1
@@ -136,7 +136,10 @@ private fun dependenciesForPomRewriting(target: AbstractKotlinTarget): Provider<
|
||||
val project = target.project
|
||||
|
||||
// Only the commonMain API dependencies can be published for consumers who can't read Gradle project metadata
|
||||
val commonMainApi = project.sourceSetDependencyConfigurationByScope(commonMain, KotlinDependencyScope.API_SCOPE)
|
||||
val commonMainApi = project.configurations.sourceSetDependencyConfigurationByScope(
|
||||
commonMain,
|
||||
KotlinDependencyScope.API_SCOPE
|
||||
)
|
||||
val commonMainDependencies = commonMainApi.allDependencies
|
||||
commonMainDependencies.map { ModuleCoordinates(it.group, it.name, it.version) }.toSet()
|
||||
}
|
||||
|
||||
+13
-10
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.gradle.plugin.sources
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.artifacts.Configuration
|
||||
import org.gradle.api.artifacts.ConfigurationContainer
|
||||
import org.jetbrains.kotlin.gradle.plugin.HasKotlinDependencies
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||
@@ -23,19 +24,21 @@ internal enum class KotlinDependencyScope(val scopeName: String) {
|
||||
RUNTIME_ONLY_SCOPE(RUNTIME_ONLY);
|
||||
|
||||
companion object {
|
||||
val compileScopes = listOf(KotlinDependencyScope.API_SCOPE, KotlinDependencyScope.IMPLEMENTATION_SCOPE, KotlinDependencyScope.COMPILE_ONLY_SCOPE)
|
||||
val compileScopes = listOf(API_SCOPE, IMPLEMENTATION_SCOPE, COMPILE_ONLY_SCOPE)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun Project.sourceSetDependencyConfigurationByScope(sourceSet: HasKotlinDependencies, scope: KotlinDependencyScope): Configuration =
|
||||
project.configurations.getByName(
|
||||
when (scope) {
|
||||
API_SCOPE -> sourceSet.apiConfigurationName
|
||||
IMPLEMENTATION_SCOPE -> sourceSet.implementationConfigurationName
|
||||
COMPILE_ONLY_SCOPE -> sourceSet.compileOnlyConfigurationName
|
||||
RUNTIME_ONLY_SCOPE -> sourceSet.runtimeOnlyConfigurationName
|
||||
}
|
||||
)
|
||||
internal fun ConfigurationContainer.sourceSetDependencyConfigurationByScope(
|
||||
kotlinDependenciesContainer: HasKotlinDependencies,
|
||||
scope: KotlinDependencyScope
|
||||
): Configuration = getByName(
|
||||
when (scope) {
|
||||
API_SCOPE -> kotlinDependenciesContainer.apiConfigurationName
|
||||
IMPLEMENTATION_SCOPE -> kotlinDependenciesContainer.implementationConfigurationName
|
||||
COMPILE_ONLY_SCOPE -> kotlinDependenciesContainer.compileOnlyConfigurationName
|
||||
RUNTIME_ONLY_SCOPE -> kotlinDependenciesContainer.runtimeOnlyConfigurationName
|
||||
}
|
||||
)
|
||||
|
||||
internal fun Project.compilationDependencyConfigurationByScope(
|
||||
compilation: KotlinCompilation<*>,
|
||||
|
||||
+1
-1
@@ -182,7 +182,7 @@ internal class KotlinCompilationNpmResolver(
|
||||
)
|
||||
all.extendsFrom(compilationConfiguration)
|
||||
compilation.allKotlinSourceSets.forEach { sourceSet ->
|
||||
val sourceSetConfiguration = project.sourceSetDependencyConfigurationByScope(sourceSet, scope)
|
||||
val sourceSetConfiguration = project.configurations.sourceSetDependencyConfigurationByScope(sourceSet, scope)
|
||||
all.extendsFrom(sourceSetConfiguration)
|
||||
}
|
||||
}
|
||||
|
||||
+12
-4
@@ -248,7 +248,12 @@ class KotlinMetadataTargetConfigurator :
|
||||
val apiElementsConfiguration = configurations.getByName(target.apiElementsConfigurationName)
|
||||
|
||||
// With the metadata target, we publish all API dependencies of all the published source sets together:
|
||||
apiElementsConfiguration.extendsFrom(sourceSetDependencyConfigurationByScope(sourceSet, KotlinDependencyScope.API_SCOPE))
|
||||
apiElementsConfiguration.extendsFrom(
|
||||
configurations.sourceSetDependencyConfigurationByScope(
|
||||
sourceSet,
|
||||
KotlinDependencyScope.API_SCOPE
|
||||
)
|
||||
)
|
||||
|
||||
/** For Kotlin/Native-shared source sets, we also add the implementation dependencies to apiElements, because Kotlin/Native
|
||||
* can't have any implementation dependencies, all dependencies used for compilation must be shipped along with the klib.
|
||||
@@ -260,7 +265,10 @@ class KotlinMetadataTargetConfigurator :
|
||||
if (isSharedNativeCompilation) {
|
||||
sourceSet.withDependsOnClosure.forEach { hierarchySourceSet ->
|
||||
apiElementsConfiguration.extendsFrom(
|
||||
sourceSetDependencyConfigurationByScope(hierarchySourceSet, KotlinDependencyScope.IMPLEMENTATION_SCOPE)
|
||||
configurations.sourceSetDependencyConfigurationByScope(
|
||||
hierarchySourceSet,
|
||||
KotlinDependencyScope.IMPLEMENTATION_SCOPE
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -368,7 +376,7 @@ class KotlinMetadataTargetConfigurator :
|
||||
if (sourceSet is DefaultKotlinSourceSet)
|
||||
sourceSet.dependencyTransformations[scope] = granularMetadataTransformation
|
||||
|
||||
val sourceSetDependencyConfigurationByScope = project.sourceSetDependencyConfigurationByScope(sourceSet, scope)
|
||||
val sourceSetDependencyConfigurationByScope = project.configurations.sourceSetDependencyConfigurationByScope(sourceSet, scope)
|
||||
|
||||
if (isSourceSetPublished) {
|
||||
if (scope != KotlinDependencyScope.COMPILE_ONLY_SCOPE) {
|
||||
@@ -470,7 +478,7 @@ class KotlinMetadataTargetConfigurator :
|
||||
attributes.attribute(USAGE_ATTRIBUTE, KotlinUsages.producerApiUsage(target))
|
||||
attributes.attribute(CATEGORY_ATTRIBUTE, project.categoryByName(Category.LIBRARY))
|
||||
|
||||
val commonMainApiConfiguration = project.sourceSetDependencyConfigurationByScope(
|
||||
val commonMainApiConfiguration = project.configurations.sourceSetDependencyConfigurationByScope(
|
||||
project.kotlinExtension.sourceSets.getByName(KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME),
|
||||
KotlinDependencyScope.API_SCOPE
|
||||
)
|
||||
|
||||
+1
-1
@@ -199,7 +199,7 @@ internal class KaptWithoutKotlincConfig : KaptConfig<KaptWithoutKotlincTask> {
|
||||
val kaptDependency = "org.jetbrains.kotlin:kotlin-annotation-processing-gradle:${project.getKotlinPluginVersion()}"
|
||||
listOf(
|
||||
project.dependencies.create(kaptDependency),
|
||||
project.kotlinDependency(
|
||||
project.dependencies.kotlinDependency(
|
||||
"kotlin-stdlib",
|
||||
project.topLevelExtension.coreLibrariesVersion
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user