-
Notifications
You must be signed in to change notification settings - Fork 4.5k
update: ksp-multiplatform.md #5584
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 5 commits
73396ad
f52b5df
59c5f34
d7da5ca
5eec5fc
ad5727e
9531cae
23c70c4
6e6de18
6f5be47
b5b0edc
bfc2cdb
ac6da33
9c15f72
d2b0548
4dad27e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,56 +1,239 @@ | ||
| [//]: # (title: KSP with Kotlin Multiplatform) | ||
| [//]: # (description: Add KSP to a Kotlin multiplatform project) | ||
|
|
||
| For a quick start, see a [sample Kotlin Multiplatform project](https://github.com/google/ksp/tree/main/examples/multiplatform) | ||
| defining a KSP processor. | ||
| This document explains how to use Kotlin Symbol Processing (KSP) in a Kotlin Multiplatform project. To get started with | ||
| Kotlin Multiplatform, see the [Kotlin Multiplatform overview](https://kotlinlang.org/docs/multiplatform/kmp-overview.html). | ||
|
budindepunk marked this conversation as resolved.
Outdated
|
||
|
|
||
| Starting from KSP 1.0.1, applying KSP on a multiplatform project is similar to that on a single platform, JVM project. | ||
| The main difference is that, instead of writing the `ksp(...)` configuration in dependencies, `add(ksp<Target>)` or `add(ksp<SourceSet>)` | ||
| is used to specify which compilation targets need symbol processing, before compilation. | ||
| To use KSP-based processors in a multiplatform project, assign a processor to each target that needs symbol processing: | ||
|
|
||
| ``` | ||
| add("ksp<Target>", <processor>) | ||
| ``` | ||
|
|
||
| `<processor>` is a Gradle project path. It can be: | ||
|
|
||
| * the specific folder in your project that contains the logic for your symbol processor. | ||
|
budindepunk marked this conversation as resolved.
Outdated
|
||
| * an external processor such as Room or Dagger. | ||
|
budindepunk marked this conversation as resolved.
Outdated
|
||
|
|
||
| > For a full list of targets, see [Multiplatform Gradle DSL reference](https://kotlinlang.org/docs/multiplatform/multiplatform-dsl-reference.html#targets) | ||
| > and [Kotlin/Native supported targets](https://kotlinlang.org/docs/native-target-support.html). | ||
| > | ||
| {style=”tip”} | ||
|
budindepunk marked this conversation as resolved.
Outdated
|
||
|
|
||
| For example: | ||
|
|
||
| <tabs group="build-script"> | ||
| <tab title="Kotlin" group-key="kotlin"> | ||
|
|
||
| ```kotlin | ||
| // build.gradle.kts | ||
|
|
||
| // This example demonstrates various ways to declare KSP dependencies | ||
| // in a Kotlin project, covering multiplatform setups. | ||
|
budindepunk marked this conversation as resolved.
Outdated
|
||
|
|
||
| plugins { | ||
| kotlin("multiplatform") | ||
| id("com.google.devtools.ksp") | ||
| // Apply the KSP plugin | ||
| id("com.google.devtools.ksp") version "%kspVersion%" | ||
| // Apply other plugins as needed (e.g., kotlin("jvm"), | ||
| // kotlin("multiplatform"), etc.) | ||
|
budindepunk marked this conversation as resolved.
Outdated
|
||
| } | ||
|
|
||
| kotlin { | ||
| jvm() | ||
| linuxX64 { | ||
| binaries { | ||
| executable() | ||
| } | ||
| dependencies { | ||
| // =============================================================== | ||
| // 1. MAIN COMPILATIONS (Production Code) | ||
| // =============================================================== | ||
|
|
||
| // In KMP, the global 'ksp' configuration is deprecated to avoid running | ||
| // processors on targets unnecessarily. Use target-specific configurations instead. | ||
|
budindepunk marked this conversation as resolved.
Outdated
|
||
|
|
||
| // Local processor for a specific target (JVM) | ||
| add("kspJvm", project(":test-processor")) | ||
|
|
||
| // External processor for a specific target (Android) | ||
| add("kspAndroid", "androidx.room:room-compiler:2.6.1") | ||
|
zamulla marked this conversation as resolved.
Outdated
|
||
|
|
||
| // Target with multiple processors (JVM) | ||
| add("kspJvm", project(":another-local-processor")) | ||
| add("kspJvm", "com.example:external-processor:1.0") | ||
|
|
||
| // Different processors for different targets | ||
| add("kspJvm", project(":jvm-only-processor")) | ||
| add("kspJs", project(":js-only-processor")) | ||
|
|
||
| // iOS Targets | ||
| // KSP configurations are per-compilation target. Shared intermediate | ||
| // source sets like 'iosMain' do NOT have their own KSP configuration. | ||
| // You must specify them for each iOS target individually. | ||
| add("kspIosX64", project(":test-processor")) | ||
| add("kspIosArm64", project(":test-processor")) | ||
| add("kspIosSimulatorArm64", project(":test-processor")) | ||
|
|
||
| // TIP: If you have many iOS targets, you can avoid repetition by looping: | ||
| kotlin.targets.filter { it.name.startsWith("ios") }.forEach { target -> | ||
| add( | ||
| "ksp${target.name.replaceFirstChar { it.uppercaseChar() }}", | ||
| project(":test-processor") | ||
| ) | ||
| } | ||
|
|
||
| // =============================================================== | ||
| // 2. TEST COMPILATIONS | ||
| // =============================================================== | ||
|
|
||
| // Specify KSP for the test compilation of each target: | ||
| add("kspJvmTest", project(":test-processor")) | ||
| add("kspJsTest", project(":test-processor")) | ||
| add("kspIosX64Test", project(":test-processor")) | ||
|
|
||
|
|
||
| // =============================================================== | ||
| // 3. NEW ANDROID KOTLIN MULTIPLATFORM (Android-KMP) | ||
| // Using id("com.android.kotlin.multiplatform.library") | ||
| // =============================================================== | ||
|
|
||
| // Main Android compilation (Target name is 'android') | ||
| add("kspAndroid", project(":test-processor")) | ||
|
|
||
| // Host Tests / Device Tests: | ||
| // KSP generates these configurations dynamically based on the source set names. | ||
| // The test source sets are named 'androidHostTest', 'androidDeviceTest', etc. | ||
|
|
||
| add("kspAndroidHostTest", project(":test-processor")) | ||
| add("kspAndroidDeviceTest", project(":test-processor")) | ||
| } | ||
| ``` | ||
|
|
||
| </tab> | ||
| <tab title="Groovy" group-key="groovy"> | ||
|
|
||
| ```Groovy | ||
| // build.gradle | ||
|
|
||
| // This example demonstrates various ways to declare KSP dependencies | ||
| // in a Kotlin project, covering multiplatform setups. | ||
|
|
||
| plugins { | ||
| // Apply the KSP plugin | ||
| id 'com.google.devtools.ksp' version '%kspVersion%' | ||
|
|
||
| // Apply other plugins as needed (e.g., kotlin("jvm"), | ||
| // kotlin("multiplatform"), etc.) | ||
| } | ||
|
|
||
| dependencies { | ||
| add("kspCommonMainMetadata", project(":test-processor")) | ||
| add("kspJvm", project(":test-processor")) | ||
| add("kspJvmTest", project(":test-processor")) // Not doing anything because there's no test source set for JVM | ||
| // There is no processing for the Linux x64 main source set, because kspLinuxX64 isn't specified | ||
| // add("kspLinuxX64Test", project(":test-processor")) | ||
| // =============================================================== | ||
| // 1. MAIN COMPILATIONS (Production Code) | ||
| // =============================================================== | ||
|
|
||
| // In KMP, the global 'ksp' configuration is deprecated to avoid running | ||
| // processors on targets unnecessarily. Use target-specific configurations instead. | ||
|
|
||
| // Local processor for a specific target (JVM) | ||
| add('kspJvm', project(':test-processor')) | ||
|
|
||
| // External processor for a specific target (Android) | ||
| add('kspAndroid', 'androidx.room:room-compiler:2.6.1') | ||
|
|
||
| // Target with multiple processors (JVM) | ||
| add('kspJvm', project(':another-local-processor')) | ||
| add('kspJvm', 'com.example:external-processor:1.0') | ||
|
|
||
| // Different processors for different targets | ||
| add('kspJvm', project(':jvm-only-processor')) | ||
| add('kspJs', project(':js-only-processor')) | ||
|
|
||
| // iOS Targets | ||
| // KSP configurations are per-compilation target. Shared intermediate | ||
| // source sets like 'iosMain' do NOT have their own KSP configuration. | ||
| // You must specify them for each iOS target individually. | ||
| add('kspIosX64', project(':test-processor')) | ||
| add('kspIosArm64', project(':test-processor')) | ||
| add('kspIosSimulatorArm64', project(':test-processor')) | ||
|
|
||
| // TIP: If you have many iOS targets, you can avoid repetition by looping: | ||
| kotlin.targets.findAll { it.name.startsWith('ios') }.each { target -> | ||
| add("ksp${target.name.capitalize()}", project(':test-processor')) | ||
| } | ||
|
|
||
| // =============================================================== | ||
| // 2. TEST COMPILATIONS | ||
| // =============================================================== | ||
|
|
||
| // Specify KSP for the test compilation of each target: | ||
| add('kspJvmTest', project(':test-processor')) | ||
| add('kspJsTest', project(':test-processor')) | ||
| add('kspIosX64Test', project(':test-processor')) | ||
|
|
||
| // =============================================================== | ||
| // 3. NEW ANDROID KOTLIN MULTIPLATFORM (Android-KMP) | ||
| // Using id("com.android.kotlin.multiplatform.library") | ||
| // =============================================================== | ||
|
|
||
| // Main Android compilation (Target name is 'android') | ||
| add('kspAndroid', project(':test-processor')) | ||
|
|
||
| // Host Tests / Device Tests: | ||
| // KSP generates these configurations dynamically based on the source set names. | ||
| // The test source sets are named 'androidHostTest', 'androidDeviceTest', etc. | ||
|
|
||
| add('kspAndroidHostTest', project(':test-processor')) | ||
| add('kspAndroidDeviceTest', project(':test-processor')) | ||
| } | ||
| ``` | ||
|
|
||
| </tab> | ||
| </tabs> | ||
|
|
||
| Configuration names for tests in Multiplatform depend on the exact source set names generated by the Kotlin | ||
| plugin. Run the following command in your terminal to see the definitive list of all generated KSP configurations | ||
| for your module: | ||
|
|
||
| ``` | ||
| ./gradlew :<your-module-name>:dependencies | grep ksp | ||
| ``` | ||
|
|
||
| Look for configurations matching your target names to find the right one. | ||
|
|
||
| Since KSP 2 the catch-all `ksp(...)` configuration has been deprecated. Although this may lead to some duplication in | ||
| the build file, specifying each platform individually avoids the cost of applying target-specific processors to targets | ||
| in which they do nothing. | ||
|
|
||
| > To use the deprecated ksp(...) configuration, set the flag `ksp.allow.all.target.configuration=true` | ||
| > in gradle.properties. | ||
|
budindepunk marked this conversation as resolved.
Outdated
|
||
| > | ||
| {style=”tip”} | ||
|
|
||
| To see an example of a multiplatform project with several targets using KSP, | ||
| visit the [source repository](https://github.com/google/ksp/tree/main/examples/multiplatform). | ||
|
|
||
|
|
||
| ## Compilation and processing | ||
|
|
||
| In a multiplatform project, Kotlin compilation may happen multiple times (`main`, `test`, or other build flavors) for each platform. | ||
| So is symbol processing. A symbol processing task is created whenever there is a Kotlin compilation task and a | ||
| corresponding `ksp<Target>` or `ksp<SourceSet>` configuration is specified. | ||
| In a multiplatform project, Kotlin creates a separate compilation for each target and source set, such as `main` and | ||
|
budindepunk marked this conversation as resolved.
Outdated
|
||
| `test`. For every eligible Kotlin compilation task, KSP creates a corresponding symbol processing task. | ||
|
|
||
| The [example project](https://github.com/google/ksp/tree/main/examples/multiplatform) defines six targets: | ||
|
|
||
| * JVM | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What do you think to move the info about main and test before this list, maybe rephrase, and in the list mention it in the way:
|
||
| * JS | ||
| * Linux X64 | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't we write the target names as one word? |
||
| * Android Native X64 | ||
| * Android Native Arm64 | ||
| * Mingw X64 | ||
|
budindepunk marked this conversation as resolved.
|
||
|
|
||
| For example, in the above `build.gradle.kts`, there are 4 compilation tasks: common/metadata, JVM main, Linux x64 main, Linux x64 test, | ||
| and 3 symbol processing tasks: common/metadata, JVM main, Linux x64 test. | ||
| Each of these targets includes a `main` and a `test` compilation. As a result, the project creates at least 12 Kotlin | ||
| compilation tasks. | ||
|
|
||
| ## Avoid the ksp(...) configuration on KSP 1.0.1+ | ||
| In the example's `workload/build.gradle.kts`, KSP dependencies are declared for the following configurations: | ||
|
budindepunk marked this conversation as resolved.
Outdated
|
||
|
|
||
| Before KSP 1.0.1, there is only one, unified `ksp(...)` configuration available. Therefore, processors either applies to all | ||
| compilation targets, or nothing at all. Note that the `ksp(...)` configuration not only applies to the main source set, but also | ||
| the test source set if it exists, even on traditional, non-multiplatform projects. This brought unnecessary overheads to build time. | ||
| * `kspJvm` and `kspJvmTest` | ||
| * `kspJs` and `kspJsTest` | ||
| * `kspAndroidNativeX64` and `kspAndroidNativeX64Test` | ||
| * `kspAndroidNativeArm64` and `kspAndroidNativeArm64Test` | ||
| * `kspLinuxX64` (test is omitted/commented out) | ||
| * `kspMingwX64` (test is omitted/commented out) | ||
|
budindepunk marked this conversation as resolved.
Outdated
|
||
|
|
||
| Starting from KSP 1.0.1, per-target configurations are provided as shown in the above example. In the future: | ||
| 1. For multiplatform projects, the `ksp(...)` configuration will be deprecated and removed. | ||
| 2. For single platform projects, the `ksp(...)` configuration will only apply to the main, default compilation. | ||
| Other targets like `test` will need to specify `kspTest(...)` in order to apply processors. | ||
| KSP creates one symbol processing task for each configuration where a KSP dependency is declared. In this example, the | ||
|
budindepunk marked this conversation as resolved.
Outdated
|
||
| project creates at least 12 Kotlin compilation tasks and 10 symbol processing tasks. The remaining compilations don't | ||
| have corresponding KSP tasks because KSP isn't configured for them. | ||
|
|
||
| Starting from KSP 1.0.1, there is an early access flag `-DallowAllTargetConfiguration=false` to switch to the more efficient behavior. | ||
| If the current behavior is causing performance issues, please give it a try. | ||
| The default value of the flag will be flipped from `true` to `false` on KSP 2.0. | ||
Uh oh!
There was an error while loading. Please reload this page.