compose-multiplatform
compose-multiplatform copied to clipboard
Adding any compose dependency breaks resolving the Gradle configuration
When I am adding the compose dependency to a (resolvable) Gradle configuration (includeImplementation
is my custom configuration) as follows:
includeImplementation(compose.desktop.currentOs) // same with common
and then trying to resolve the dependencies of this configuration
includeImplementation.resolvedConfiguration.firstLevelModuleDependencies
I am getting the following error
Caused by: org.gradle.internal.component.AmbiguousConfigurationSelectionException: Cannot choose between the following variants of org.jetbrains.compose.foundation:foundation:1.0.0-beta5:
- debugRuntimeElements-published
- desktopRuntimeElements-published
- releaseRuntimeElements-published
My custom configuration above is one example, but there are other scenarios where you have to use custom configurations from third-party Gradle plugins, and therefore using this together with Compose does not work.
Do you use Kotlin multiplatform gradle plugin? Since Compose is published like a multiplatform solution, this plugin is required for dependency resolution
I am not using the multiplatform plugin, because I am having trouble to use the custom configuration from the third party plugin in the scope of KotlinDependencyHandler
, as this scope only has some predefined standard configurations available for use.
plugins {
kotlin("jvm") version "1.5.31"
id("fabric-loom") version "0.10-SNAPSHOT"
kotlin("plugin.serialization") version "1.5.31"
id("org.jetbrains.compose") version "1.0.0-beta5"
}
repositories {
mavenCentral()
google()
maven("https://maven.fabricmc.net/")
mavenLocal()
maven("https://oss.sonatype.org/content/repositories/snapshots")
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
}
val includeImplementation by configurations.creating {
configurations.implementation.configure { extendsFrom(this@creating) }
}
dependencies {
minecraft("com.mojang:minecraft:$minecraftVersion")
mappings("net.fabricmc:yarn:$yarnMappingsVersion")
modImplementation("net.fabricmc:fabric-loader:$fabricLoaderVersion")
modImplementation("net.fabricmc.fabric-api:fabric-api:$fabricApiVersion")
modImplementation("net.fabricmc:fabric-language-kotlin:$fabricLanguageKotlinVersion")
includeImplementation(compose.desktop.currentOs)
includeImplementation("org.litote.kmongo:kmongo-coroutine-core:4.3.0")
includeImplementation("org.litote.kmongo:kmongo-serialization-mapping:4.3.0")
includeImplementation("org.slf4j:slf4j-simple:1.7.32")
includeImplementation("org.apache.commons:commons-text:1.9")
// example usage which triggers the error
includeImplementation.resolvedConfiguration.firstLevelModuleDependencies
}
Or is there any way I could convert this project using Compose to a project using the multiplatform plugin?
Or is there any way I could convert this project using Compose to a project using the multiplatform plugin?
Yes, it is quite easy.
Replace kotlin("jvm") version "1.5.31" with kotlin("multiplatform") version "1.5.31"
add the code below and move dependencies there. It should work.
kotlin {
jvm {
withJava()
}
sourceSets {
named("jvmMain") {
dependencies {
>>put dependencies here
}
}
}
}
Yes I already tried that, but the custom configurations such as modImplementation etc are not available there.
What are these custom functions for?
As an option, you could split code in two modules. Use Compose+mpp plugin in one module and custom imports in another.
What are these custom functions for?
They are Gradle configurations, minecraft
specified the Minecraft dependency, mappings
specifies the mappings for Minecraft and modImplementation
adds Minecraft mods.
As an option, you could split code in two modules. Use Compose+mpp plugin in one module and custom imports in another.
I could do that, but I would still have to execute includeImplementation.resolvedConfiguration.firstLevelModuleDependencies
in the other module dependening on the compose module, which would lead to the same error.
I could do that, but I would still have to execute includeImplementation.resolvedConfiguration.firstLevelModuleDependencies in the other module dependening on the compose module, which would lead to the same error
Could you share you build scripts? I struggle to understand that is the issue
The simplest example would be just to try and shade the compose dependency using the Gradle shadow plugin in a JVM context. Not that I'd recommend this, but this will trigger the problem I mean, as it tried to resolve the compose dependency as well.
To trigger the problem:
plugins {
kotlin("jvm") version "1.6.10"
id("org.jetbrains.compose") version "1.0.1-rc2"
id("com.github.johnrengelman.shadow") version "7.1.1"
}
repositories {
mavenCentral()
google()
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
}
val embed: Configuration by configurations.creating
dependencies {
embed(implementation(compose.desktop.currentOs)!!)
}
tasks {
shadowJar {
configurations = listOf(embed)
}
}
Now you might suggest that I can just use the multiplatform plugin instead, but that is not an option as it does provide all the functionality that I need. edit: it does not provide
I guess you meant don not provide. What exactly is missing?
I guess you meant don not provide.
correct
What exactly is missing?
The custom Gradle configurations (minecraft
, modImplementation
) and compatiblity with other Gradle plugins as shown in my previous comment.
With release 1.0.1
the issue was resolved for the Compose dependencies themselves, but with 1.1.0
it was reintroduced, this time caused by the skiko dependency:
> Cannot choose between the following variants of org.jetbrains.skiko:skiko:0.7.12:
- androidRuntimeElements-published
- awtRuntimeElements-published
All of them match the consumer attributes:
- Variant 'androidRuntimeElements-published' capability org.jetbrains.skiko:skiko:0.7.12:
- Unmatched attributes:
- Provides org.gradle.category 'library' but the consumer didn't ask for it
- Provides org.gradle.libraryelements 'jar' but the consumer didn't ask for it
- Provides org.gradle.status 'release' but the consumer didn't ask for it
- Provides org.gradle.usage 'java-runtime' but the consumer didn't ask for it
- Provides org.jetbrains.kotlin.platform.type 'jvm' but the consumer didn't ask for it
- Provides ui 'android' but the consumer didn't ask for it
- Variant 'awtRuntimeElements-published' capability org.jetbrains.skiko:skiko:0.7.12:
- Unmatched attributes:
- Provides org.gradle.category 'library' but the consumer didn't ask for it
- Provides org.gradle.libraryelements 'jar' but the consumer didn't ask for it
- Provides org.gradle.status 'release' but the consumer didn't ask for it
- Provides org.gradle.usage 'java-runtime' but the consumer didn't ask for it
- Provides org.jetbrains.kotlin.platform.type 'jvm' but the consumer didn't ask for it
I know that technically I should use the multiplatform plugin (but it is not possible right now), but I am curious why release 1.0.1
fixed all the issues - and now they are back because of the skiko publication.
Have the same issues building fatjar with compose dependencies
I tried to use a separate project with the Kotlin Multiplatform Gradle plugin, but the same issue comes up there as well.
Asking more generally:
How can I get a list of all transitive dependencies of compose.desktop.common
, using either the JVM or the Multiplatform Plugin. With all the methods I tried, I always get the "Cannot choose between the following variants" error.
Related issue: https://github.com/JetBrains/skiko/issues/547
Generally speaking, the issue here is not if one uses the Kotlin Multiplatform plugin or not, but that Gradle does not have enough information about which artifact it should use.
To fix this, the Compose Gradle plugin should ask for the correct UI attribute. For this to work correctly, I think skiko has to provide the correct attributes with each artifact first. Also, skiko should add a namespace to the ui attribute - I also added that to the skiko issue.
Temporary fix
I found out that you can apparently "fix" this by using some weird Gradle behaviour, and ask for an ui attribute that does not even exist. Let's use awt
, just because it makes sense in this case.
To apply this fix, do this, either using configurations.all
or just for your configuration which you use to shade or include dependencies:
configurations.all {
attributes {
attribute(Attribute.of("ui", String::class.java), "awt")
}
}
Some time ago I was running into Cannot choose between the following variants
and came up with this snippet:
tasks.register("printRuntimeDependencies") {
println("Project runtime dependencies:")
allprojects {
println()
println("-------- ${project.name} --------")
project.configurations.matching { it.name == "desktopRuntimeClasspath" }
.matching { !it.allDependencies.isEmpty() }
.forEach {
it.allDependencies.forEach { dep ->
if (dep.group != null) {
println("${dep.group}:${dep.name}:${dep.version}")
}
}
}
}
}
@jakobkmar Thank you for your workaround!