This doc describes how KSP is implemented and how to test and debug it, as well as processors. Unless otherwised noted, it assumes running in Gradle.
The Kotlin compiler has two main parts: Kotlin Gradle Plugin (KGP) and the compiler itself.
KSP 1.x is also comprised of 2 parts similarly:
- KSP Gradle plugin (KSPGP), which works with Kotlin Gradle Plugin, KGP, to get compilation information and create KSP tasks (e.g.,
kspKotlin
,kspTestKotlin
,kspDebugKotlin
, etc.). These tasks invoke Kotlin compiler with the following KSP compiler plugin specified in the compiler plugin classpath. - KSP Compiler plugin (KSPCP) is a plugin to the Kotlin compiler. When the compiler runs, it loads KSP compiler plugin which in turn runs processors.
By default, KGP and KSPGP are invoked by Gradle and run in Gradle daemon. They create compileKotlin
and kspKotlin
tasks that send requests to KotlinCompileDaemon
which runs in a separate JVM instance in another process.
Because processors, KSP and Kotlin Compiler run in KotlinCompileDaemon
, not Gradle daemon, the debug button in IDE, which usually debugs the Gradle process, doesn't work. The process to debug is KotlinCompileDaemon
:
- Make sure
KotlinCompileDaemon
is attachable / debuggable by specifying deubg options inkotlin.daemon.jvm.options
. For example, when invoking Gradle build from command line:
$ ./gradlew :app:kspDebugKotlin --rerun-tasks -Dkotlin.daemon.jvm.options="-Xdebug,-Xrunjdwp:transport=dt_socket\,address=8765\,server=y\,suspend=n"
- Find the
KotlinCompileDaemon
. There can be multiple instances in the system, especially when IDE is being used or there are other Gradle Kotlin projects that are being built. Look for the PID using this command:
$ ps ax | grep 8765 | grep KotlinCompileDaemon
- Then, attach the debugger to the process with the PID we just found.
- Because of the
suspend=n
in the above example, the compilation will just keep running without waiting for the debugger. On the other hand, because the daemon will be alive for a while (3 hours by default), the process is now attached and we can set break points. - Run the above gradle build command again. The daemon should now stop at some break point, if they are hit.
If you can't find or attach to the KotlinCompileDaemon
, try killing it first. Stopping Gradle daemon sometimes helps, too. For example
$ ./gradlew --stop; pkill -f KotlinCompileDaemon
Same to debugging, the target process is KotlinCompileDaemon
, rather than the Gradle daemon.
When developing a processor, Kotlin Compile Testing can be very useful. It calls into the compiler directly from test code or main function instead of through Gradle and KotlinCompileDaemon
, so IDE's debugger usually works out of box.
Another major advantage is testing. It's much simpler and faster to write, run and debug tests than the full-fledged Gradle TestKit.
See their documentation for more details.
If you're running the compiler from command line, there will be no KotlinCompileDaemon
. The debug options should be passed directly to the java
command, instead of through -Dkotlin.daemon.jvm.options
.
Instead of the dedicated KotlinCompileDaemon
, the Kotlin compiler can also run in Gradle daemon directly with the Gradle property kotlin.compiler.execution.strategy=in-process
. You should be able to debug the Gradle build directly from the IDE.
Note that running compiler in this way suffers from several performance and correctness issues. It should only be used when necessary, at your own discretion.
For debugging, please check this issue first and comment if the question isn't already known.