Hello! After upgrade from Kotlin 1.9.10 to 1.9.20-...
# gradle
p
Hello! After upgrade from Kotlin 1.9.10 to 1.9.20-RC2 warning appears during Gradle build (w: Kotlin Target 'jvm()' is already declared.) I indeed have two jvm targets in one Gradle module but with different names jvm("server") and jvm("client"). Does this warning mean that this case is not allowed now? How should i organize my Gradle module to produce two jars in one module? Now I'm doing like written here: https://kotlinlang.org/docs/multiplatform-set-up-targets.html#distinguish-several-targets-for-one-platform
👀 1
Matching documentation PR is here
I think the general idea is to use different Gradle projects or KGP compilations but I'm not 100% this covers all the use cases yet
Being able to use
expect
/
actual
was convenient and I have yet to find an equivalent
p
Yes expect/actual is one of the cases. Other is to apply plugin on single module and have several outputs.
j
and I have yet to find an equivalent
Is it even possible? 👀
m
My hunch right now is "no" but that stuff is hard so maybe there is a way?
j
I am not sure if Gradle variants + interface + default implementation could help here
If Gradle variants work like Android ones, it should be possible. Maybe Gradle, Android and JetBrains could agree about getting an API for that in Gradle, it would help a lot AGP or KMP world
🚫 1
m
Ahah oh no, please no Android Variants 😅
j
Well, Android variants are expect/actual
m
Yea but without IDE support, right?
The fact that you have to "choose" your android variant in a dialog is a pita
j
Yea but without IDE support, right?
That is more related to Android Studio plugin
m
All I know is I have missed refactoring variant code multiple times because the IDE only knows of a given variant at a time
j
Probably to reduce the load on low end computers, as there is no IDE support for unselected variants, but it should be possible to get it working in all variants at the same time
m
My understanding is that
expect
/`actual` is the best way to make it work all variants at the same time
But 🤷
j
Personally, I still prefer the explicit
expect
one, as it is missing on Android variants, it can be hard to reason about what you are doing on
main
without checking the debug/release (or whatever) source sets
💯 1
☝️ 1
m
Exactly! Also
expect
/`actual` paves the way for
commonMain
artifacts, if we can ever have such a thing
j
Is there any open issue about this on the Gradle repo?
m
I think it's more a Kotlin/KGP thing, not Gradle?
j
I haven’t played a lot with Gradle variants, I am not sure if there is any limitation
m
Gradle variants will not help you with IDE support
j
I think Gradle variants work on the IDE, only the expect part is missing, but that would be a KGP issue
m
What do you mean? Gradle variants expose different artifacts. so you kind of have to "select" one
j
KGP was exposing different artifacts too, right?
m
Depends what you call artifacts I guess. I have
commonTests
that have
expect fun HttpEngine(): HttpEngine
. I can't really model that with Gradle variants
Or I guess I could produce
engine-ktor.jar
and
engine-okhttp.jar
j
I am not sure, but I think that common just doesn’t exist. There is an artifact for each variant created in KMP, they are like little modules. Common just contributed to those “variant” artifacts
m
Or I guess I could produce
engine-ktor.jar
and
engine-okhttp.jar
That "could" work. But then I need 2 different KGP compilations: "okhttpTest" and "ktorTest". Both of them having their own
SourceSet
("okHttpTest" and "ktorTest")
j
I don't know what Gradle variant produces, but I guess it is producing that
and both have their source sets
m
Which leaves me with 2 choices: • Either I duplicate all my tests (not cool) • Or I source (
srcDir()
) a common
jvmCommon
directory into both
okHttpTest
and
ktorTest
(breaks IDE. When I'm in
"jvmCommon"
, how do I know what ``HttpEngine`` I'm using)
j
Said differently, this allows you to declare the dependencies specific to a feature in their own dependency scope, but everything is still compiled as a single source set. There will also be a single artifact (the component Jar) including support for all features.
Looks like variants are merged into one jar
And probably Gradle variants only work with Java too
m
Is that the thing for supporting multiple Gradle versions?
This is wildly different, requires reflection/ServiceLoader and what not
j
No, this is Gradle feature variants
👀 1
Copy code
sourceSets {
    create("mongodbSupport") {
        java {
            srcDir("src/mongodb/java")
        }
    }
}

java {
    registerFeature("mongodbSupport") {
        usingSourceSet(sourceSets["mongodbSupport"])
    }
}
m
Right. I still fail to see how this helps the IDE
Unless the .jar could have some "information" about the different variants of a symbol and where they're located
Which duplicates the
expect
/`actual` functionality I guess?
j
Unless the .jar could have some "information" about the different variants of a symbol and where they're located (edited)
Yeah...
Maybe Gradle, Android and JetBrains could agree
nod 1
I think there are a lot of "duplicated" behaviors which could be provided by an abstract API from Gradle, with custom(and easy) implementation on plugins
variants is only one more
m
Also this all should work with Maven 👀 😛
Ideally this is a Kotlin feature that works with multiple build systems
j
For example, KGP has its own source sets as the Gradle ones are too Java
nod 1
I hope they can improve all of this after the cleanup of APIs in Gradle 9.0
🤞 1
m
Back to OP's question, @PHondogo if you don't have
expect
/`actual` , you can split your project in several projects (
:common
,
:server
,
:client
). If you're using convention plugins it shouldn't complicate your build a lot more. If you don't then there'll be an initial cost but this will make your build more maintainable if it grows bigger.
You have instruction how to do this here
p
In my case i have a lot of modules with such plugin. With splitting each module to several projects there will be multiplication of them by number of variants. I'm trying to avoid this.