Cleanup configuration to fix corner cases in HMPP dependency resolution

* Set the local-to-project attribute on the compatibility metadata
  variant's "elements" configuration; not setting this attribute could
  lead to ambiguity because of diverging sets of non-matched attributes

* Don't create the `runtimeOnly` configuration for the Kotlin/Native
  targets (or potentially other targets with no runtime dependencies),
  as the K/N target configurator is not aware of the configuration and
  would not set the configuration up properly

* Don't create the legacy `*Default` configurations, as they basically
  duplicate the `*ApiElements` / `*RuntimeElements` configurations but
  don't have all the right attributes, so they are reckoned compatible
  with some consumers unnecessarily and pollute the dependency
  resolution error reports.

Issue #KT-47506
This commit is contained in:
Sergey Igushkin
2021-08-03 03:30:53 +04:00
committed by Space
parent 126f6eff28
commit e691de6e4c
3 changed files with 51 additions and 15 deletions
@@ -346,6 +346,40 @@ class VariantAwareDependenciesIT : BaseGradleIT() {
}
}
@Test
fun testResolveCompatibilityMetadataVariantWithNative() = with(Project("native-libraries")) {
setupWorkingDir()
val nestedProjectName = "nested"
embedProject(Project("native-libraries"), nestedProjectName)
projectDir.resolve("gradle.properties").appendText(
"\n" + """
kotlin.mpp.enableGranularSourceSetsMetadata=true
kotlin.mpp.enableCompatibilityMetadataVariant=true
"""
)
val resolveConfigurationTaskName = "resolveConfiguration"
val marker = "###=>"
gradleBuildScript().appendText(
"\n" + """
dependencies { "commonMainImplementation"(project(":$nestedProjectName")) }
tasks.create("$resolveConfigurationTaskName") {
doFirst {
println("$marker" + configurations.getByName("metadataCompileClasspath").toList())
}
}
"""
)
build(resolveConfigurationTaskName) {
assertSuccessful()
val output = output.lines().single { marker in it }.substringAfter(marker).removeSurrounding("[", "]").split(",")
assertTrue { output.any { "$nestedProjectName-1.0.jar" in it } }
}
}
}
internal fun BaseGradleIT.Project.embedProject(other: BaseGradleIT.Project, renameTo: String? = null) {
@@ -165,23 +165,22 @@ abstract class AbstractKotlinTargetConfigurator<KotlinTargetType : KotlinTarget>
val configurations = project.configurations
val defaultConfiguration = configurations.maybeCreate(target.defaultConfigurationName).apply {
setupAsLocalTargetSpecificConfigurationIfSupported(target)
}
val mainCompilation = target.compilations.maybeCreate(KotlinCompilation.MAIN_COMPILATION_NAME)
val compileConfiguration = configurations.findByName(mainCompilation.deprecatedCompileConfigurationName)
val implementationConfiguration = configurations.maybeCreate(mainCompilation.implementationConfigurationName)
val runtimeOnlyConfiguration = configurations.maybeCreate(mainCompilation.runtimeOnlyConfigurationName)
val runtimeOnlyConfiguration = when (mainCompilation) {
is KotlinCompilationToRunnableFiles<*> -> configurations.maybeCreate(mainCompilation.runtimeOnlyConfigurationName)
else -> null
}
val apiElementsConfiguration = configurations.maybeCreate(target.apiElementsConfigurationName).apply {
configurations.maybeCreate(target.apiElementsConfigurationName).apply {
description = "API elements for main."
isVisible = false
isCanBeResolved = false
isCanBeConsumed = true
attributes.attribute<Usage>(USAGE_ATTRIBUTE, KotlinUsages.producerApiUsage(target))
attributes.attribute(USAGE_ATTRIBUTE, KotlinUsages.producerApiUsage(target))
extendsFrom(configurations.maybeCreate(mainCompilation.apiConfigurationName))
if (mainCompilation is KotlinCompilationToRunnableFiles) {
val runtimeConfiguration = configurations.findByName(mainCompilation.deprecatedRuntimeConfigurationName)
@@ -192,32 +191,34 @@ abstract class AbstractKotlinTargetConfigurator<KotlinTargetType : KotlinTarget>
}
if (mainCompilation is KotlinCompilationToRunnableFiles<*>) {
val runtimeElementsConfiguration = configurations.maybeCreate(target.runtimeElementsConfigurationName).apply {
configurations.maybeCreate(target.runtimeElementsConfigurationName).apply {
description = "Elements of runtime for main."
isVisible = false
isCanBeConsumed = true
isCanBeResolved = false
attributes.attribute<Usage>(USAGE_ATTRIBUTE, KotlinUsages.producerRuntimeUsage(target))
attributes.attribute(USAGE_ATTRIBUTE, KotlinUsages.producerRuntimeUsage(target))
val runtimeConfiguration = configurations.findByName(mainCompilation.deprecatedRuntimeConfigurationName)
extendsFrom(implementationConfiguration, runtimeOnlyConfiguration)
extendsFrom(implementationConfiguration)
if (runtimeOnlyConfiguration != null)
extendsFrom(runtimeOnlyConfiguration)
runtimeConfiguration?.let { extendsFrom(it) }
usesPlatformOf(target)
setupAsPublicConfigurationIfSupported(target)
}
defaultConfiguration.extendsFrom(runtimeElementsConfiguration)
} else {
defaultConfiguration.extendsFrom(apiElementsConfiguration)
}
if (createTestCompilation) {
val testCompilation = target.compilations.getByName(KotlinCompilation.TEST_COMPILATION_NAME)
val compileTestsConfiguration = configurations.findByName(testCompilation.deprecatedCompileConfigurationName)
val testImplementationConfiguration = configurations.maybeCreate(testCompilation.implementationConfigurationName)
val testRuntimeOnlyConfiguration = configurations.maybeCreate(testCompilation.runtimeOnlyConfigurationName)
val testRuntimeOnlyConfiguration = when (testCompilation) {
is KotlinCompilationToRunnableFiles<*> -> configurations.maybeCreate(testCompilation.runtimeOnlyConfigurationName)
else -> null
}
compileConfiguration?.let { compileTestsConfiguration?.extendsFrom(it) }
testImplementationConfiguration.extendsFrom(implementationConfiguration)
testRuntimeOnlyConfiguration.extendsFrom(runtimeOnlyConfiguration)
testRuntimeOnlyConfiguration?.extendsFrom(runtimeOnlyConfiguration)
if (mainCompilation is KotlinCompilationToRunnableFiles && testCompilation is KotlinCompilationToRunnableFiles) {
val runtimeConfiguration = configurations.findByName(mainCompilation.deprecatedRuntimeConfigurationName)
@@ -448,6 +448,7 @@ class KotlinMetadataTargetConfigurator :
project.configurations.create(COMMON_MAIN_ELEMENTS_CONFIGURATION_NAME).apply {
isCanBeConsumed = true
isCanBeResolved = false
setupAsPublicConfigurationIfSupported(target)
usesPlatformOf(target)
attributes.attribute(