Hi, how do I setup multiple module kotlin project ...
# gradle
m
Hi, how do I setup multiple module kotlin project where one of the modules is a multiplatform project but it depends on a non-multiplatform project? I want a setup like this:
Copy code
root/
    my-app/    # multiplatform with jvm/js etc, uses classes in core
    core/      # simple kotlin
    viz/       # tornadofx project for doing visualizations, uses classes in core
At the moment everything is in my-app, but I want to pull some of the core classes that viz needs into a core module, and have the others depend on it. I've given the core build.gradle.kts a plugin of "kotlin("jvm")", and the multiplatform project uses multiplatform plugin, but when I compile I'm getting an error:
The Kotlin Gradle plugin was loaded multiple times in different subprojects
I don't want to make viz and core multiplatform modules, they are simple jvm modules. How do I split my project up so I don't get the error, but the 2 non-multiplatform modules stay simple jvm modules?
m
Load KGP in your root build.gradle[.kts] file with
apply(false)
👆 1
Of course the JS code in
my-app
won't be able to use any of the
core
code unless you make
core
multiplatform as well. But loading KGP in your root build script wil help with the "loaded multiple times" error
m
thanks, I'll try that out. agreed on the JS code but the app has its own commonMain for anything the app needs to share, and I'd map anything in jvmMain to shared types if needbe. I don't think I have anything directly exposed that will move into core.
m
commonMain
won't be able to use
core
either
Usually, you're much better making
core
multiplatform
m
yes, I understand that, what I was trying to say was I'd map anything in jvmMain from core to types in commonMain.
Maybe I have it incorrectly setup, but this is failing: root
Copy code
plugins {
    alias(libs.plugins.kotlin.jvm) apply(false)
}
core
Copy code
plugins {
    alias(libs.plugins.kotlin.jvm)
}
app
Copy code
plugins {
    alias(libs.plugins.kotlin.multiplatform)
    alias(libs.plugins.kotlin.serialization)
}
but the app module is getting the error:
Copy code
Error resolving plugin [id: 'org.jetbrains.kotlin.multiplatform', version: '2.1.0']
> The request for this plugin could not be satisfied because the plugin is already on the classpath with an unknown version, so compatibility cannot be checked.
m
Yea, Gradle plugins are a lie
Do that instead: core
Copy code
plugins {
    id("org.jetbrains.kotlin.jvm")
}
app
Copy code
plugins {
    id("org.jetbrains.kotlin.multiplatform")
    id(/*serialization plugin id here*/)
}
They conflate classloading and APIs, it's a hot mess really
m
hmm, that means adding version strings manually and loses the cleanliness of moving everything into libs.versions.toml if I'm reading it correctly. Might be time to just bite the bullet and make the root project multiplatform and have the modules code sit in jvmMain
v
Instead of the string id, you can also use
kotlin("jvm")
and
kotlin("multiplatform")
and
kotlin("plugin.serialization")
m
Still string based but yea some folks like this better
v
The only thing that needs a version that can come from version catalog is the one you use in the root project
So: root
Copy code
plugins {
    alias(libs.plugins.kotlin.jvm) apply(false)
}
core
Copy code
plugins {
    kotlin("jvm")
}
app
Copy code
plugins {
    kotlin("multiplatform")
    kotlin("plugin.serialization")
}
m
You can maybe try adding both the JVM and multiplatform plugins in your root build.gradle
root
Copy code
plugins {
    alias(libs.plugins.kotlin.jvm) apply(false)
    alias(libs.plugins.kotlin.multiplatform) apply(false)
    alias(libs.plugins.kotlin.serialization) apply(false)
}
core
Copy code
plugins {
    alias(libs.plugins.kotlin.jvm)
}
app
Copy code
plugins {
    alias(libs.plugins.kotlin.multiplatform)
    alias(libs.plugins.kotlin.serialization)
}
v
That should not be necessary, all the plugins are in one code artifact.
Not sure about the serialization plugin
m
Ah yes, serialization needs to be loaded as well
v
Hm, or are jvm and kmp different code artifacts, ...
m
I'm 99% sure they are the same
Serialization is different artifact (I ihave updated the comment above)
v
It might still be best to simply not mix them, but for core and viz also use kmp. You do not need to use a js target there, just only have a jvm target and the result should be the same I think. The separate JVM plugin is just a bit syntax sugar by only having JVM.
At least it was so for K/JS which was discontinued in favor of just using KMP with only a JS target.
m
That has made the gradle clean task stop erroring at least. I'll try moving stuff around.
m
In 2025, I'm starting to add
buildscript {}
blocks 😅
😨 1