Open OliverO2 opened 2 years ago
If anyone looking for the same error in android studio, check this once- https://github.com/google/ksp/issues/37#issuecomment-1047366011. I guess the same principle can be extended for KMM.
This issue is still there. Couple of clarifications though:
afterEvaluate
KotlinCompile
task is responsible for compiling JVM only. If you compile iOS as well, consider adding the same 'workaround' with KotlinNativeCompile
class. I bet the same thing can be done for other platforms.kspCommonMainMetadata
means that no code will be generated from shared module source sets except common
. E.g., in KMM project androidMain
and iosMain
won't be able to generate any code.If all you care about is generating code for the commonMain
source set, You can do the following:
plugins {
kotlin("multiplatform")
id("com.google.devtools.ksp")
}
kotlin {
linuxArm64()
linuxX64()
macosArm64()
macosX64()
jvm()
iosX64()
iosArm64()
iosSimulatorArm64()
// ...
sourceSets {
val commonMain by getting {
kotlin.srcDir("build/generated/ksp/metadata/commonMain/kotlin")
// ...
}
val commonTest by getting {
// ...
}
}
// following example here:
// https://github.com/OliverO2/kotlin-multiplatform-ksp/blob/main/base/build.gradle.kts
dependencies {
// Provide symbol processing for each Kotlin '*Main' source set.
kotlin.sourceSets.forEach { sourceSet ->
val kspConfiguration = when {
sourceSet.name == "commonMain" -> "kspCommonMainMetadata"
// but skip configurations for each platform-specific source set
// sourceSet.name.endsWith("Main") -> "ksp${sourceSet.name.substringBefore("Main").replaceFirstChar { it.titlecase() }}"
else -> null
}
if (kspConfiguration != null) add(kspConfiguration, project(":gameplay-protocol-converter-processor"))
}
}
}
// Fix KSP task dependencies (https://github.com/google/ksp/issues/963)
afterEvaluate {
tasks {
val kspCommonMainKotlinMetadata by getting
withType<org.jetbrains.kotlin.gradle.dsl.KotlinCompile<*>> {
if (this !== kspCommonMainKotlinMetadata) {
dependsOn(kspCommonMainKotlinMetadata)
}
}
}
}
This makes all platforms work and IntelliJ recognizes all the generated source files.
This issue is really bizarre... I just updated to Kotlin 1.9.10, and Gradle started saying that the task kspCommonMainKotlinMetadata
didn't exist, but if you println all the tasks names, it obviously exists. I had to change my afterEvaluate
to the below, but I have no idea why it works, nor how safe this is.
afterEvaluate {
val compileTasks = CopyOnWriteArrayList<org.jetbrains.kotlin.gradle.dsl.KotlinCompile<*>>()
tasks {
withType<org.jetbrains.kotlin.gradle.dsl.KotlinCompile<*>> {
if (name != "kspCommonMainKotlinMetadata") {
compileTasks.add(this)
} else {
compileTasks.forEach { t ->
t.dependsOn(this)
}
compileTasks.clear()
}
}
}
}
I also got the same problem after updating to Kotlin 1.9.10. The interesting thing is that while trying to get kspCommonMainKotlinMetadata
in afterEvaluate
is not working, trying to do it after all projects evaluated in gradle.projectsEvaluated
works.
gradle.projectsEvaluated {
tasks {
val kspCommonMainKotlinMetadata by getting
withType<org.jetbrains.kotlin.gradle.dsl.KotlinCompile<*>> {
if (this !== kspCommonMainKotlinMetadata) {
dependsOn(kspCommonMainKotlinMetadata)
}
}
}
}
What I don't quite understand is if there is planned support for commonMain source set in IntelliJ idea out of the box. I mean, in the same way as currently e.g. jvmMain and jsMain source sets are supported.
In this issue, various gradle tricks are described which allow to reference generated code from user's common source sets. Then, there is advice on how to fix things when those tricks no longer work in newer versions.
But is it planned that generated code can be referenced from common source sets out of the box? Maybe it's not in this but in another issue? Thanks!
I haven't tracked KSP for a while, but once upon a time I had collected all sorts of interconnected issues regarding source set support in KSP. It did not go well... Maybe you could start here to get an impression: https://github.com/google/ksp/pull/1021#issuecomment-1212298132
We have found a quite simple solution for all the trouble with KSP and Multiplatform-Projects (including publishing - which started to break the known workarounds with gradle 8.x):
// KSP support for Lens generation - our KSP based Code-Generator, replace with your own!
dependencies.kspCommonMainMetadata(project(":lenses-annotation-processor"))
// solves all implicit dependency trouble and IDEs source code detection
kotlin.sourceSets.commonMain { tasks.withType<KspTaskMetadata> { kotlin.srcDir(destinationDirectory) } }
As mentioned in the gradle docs, which are presented on such missing dependencies, a property
carries dependency information, whereas simple path-Strings do not!
All trouble with build
and publish
(!) tasks simply went away - should be added to the documentation of KSP imho!
I hope this helps someone who also get into such trouble as we did...
I have this issue as well. None of the workarounds in this thread work for me so far
I have this issue as well. None of the workarounds in this thread work for me so far
Which Kotlin and Gradle version do you use?
I have tested my proposal not yet with 2.0! Might be possible some things have changed there...
Yeah this is with kotlin 2.0 and Gradle 8.7
// KSP support for Lens generation - our KSP based Code-Generator, replace with your own! dependencies.kspCommonMainMetadata(project(":lenses-annotation-processor")) // solves all implicit dependency trouble and IDEs source code detection kotlin.sourceSets.commonMain { tasks.withType<KspTaskMetadata> { kotlin.srcDir(destinationDirectory) } }
This is good stuff, @Lysander, thanks for that. I'm posting my version below which is slightly different in terms of positioning the 2 pieces of config, maybe it will help someone.
import com.google.devtools.ksp.gradle.KspTaskMetadata
plugins {
kotlin("multiplatform")
id("multiplatform-module-standard")
id("com.google.devtools.ksp")
}
kotlin {
linuxArm64()
linuxX64()
macosArm64()
macosX64()
sourceSets {
commonMain {
// (2) above
tasks.withType<KspTaskMetadata> { kotlin.srcDir(destinationDirectory) }
dependencies {
api(project(":gameplay-protocol-converter-annotation"))
api(project(":domain"))
api(project(":gameplay-protocol"))
}
}
commonTest {
dependencies {
implementation(kotlin("test"))
}
}
}
}
// (1) above
dependencies {
kspCommonMainMetadata(project(":gameplay-protocol-converter-processor"))
}
@bcmedeiros Thank you for this. I've been struggling to migrate a project to k2 and this helped with figuring out Koin ksp generation. Not sure if their instructions are just out of date but what you provided works perfectly.
I have experimented with KSP's
examples/multiplatform
with IntelliJ IDEA 2022.1, commenting outandroidNative*
andmingwX64
targets inexamples/multiplatform/workload/build.gradle.kts
(sectionskotlin
anddependencies
).Being unaware of generated files, the IDE complains about
examples/multiplatform/workload/src/linuxX64Main/kotlin/Main.kt
:This can be fixed by adding the following to
kotlin.sourceSets
:However, then executing
gradlew :workload:clean :workload:allTests
produces Gradle warnings and compilation errors (excerpt):NOTE: Trying to fix the Gradle warnings with the
idea
plugin'smodule
configuration as suggested in KSP quickstart appears to have no effect with multiplatform.The Gradle warnings can be fixed by adding the required dependencies:
Now, executing
gradlew :workload:clean :workload:allTests
proceeds without the Gradle warnings, but still exhibits compilation errors (excerpt):This can be fixed by making KSP stop generating the same class multiple times (in commonMain as well as per target), reducing the
dependencies
section to:Now
gradlew :workload:clean :workload:allTests
completes successfully. And IntelliJ IDEA is happy as well.Could this be integrated into the example and documentation be added to KSP with Kotlin Multiplatform?