Skip to content

Commit 952f388

Browse files
committed
docs: Recommend separate Gradle module for Compose + native interop
When using Nucleus Native Access with Compose Desktop, the Compose compiler plugin conflicts with arbitrary Kotlin/Native targets used for FFM bridges. This update documents the recommended approach: separate the native bridge code into its own Gradle module without the Compose compiler plugin, and have the Compose Desktop app depend on it. This avoids configuration conflicts and allows both plugins to work correctly.
1 parent 331882c commit 952f388

1 file changed

Lines changed: 47 additions & 7 deletions

File tree

README.md

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -491,29 +491,69 @@ For GraalVM native-image builds, the native `.so`/`.dylib` must be placed next t
491491

492492
### Using with Compose Desktop / Nucleus
493493

494+
The Compose compiler plugin and Nucleus Native Access both add Kotlin/Native targets, but Compose doesn't support arbitrary native compilations (e.g. `linuxX64`, `mingwX64` for FFM bridges). **The recommended approach is to put your native code in a separate Gradle module** without the Compose compiler plugin:
495+
496+
```
497+
my-app/
498+
├── native/ ← Kotlin/Native + nucleusnativeaccess (no Compose)
499+
│ └── build.gradle.kts
500+
├── app/ ← Compose Desktop + depends on :native
501+
│ └── build.gradle.kts
502+
└── settings.gradle.kts
503+
```
504+
505+
**`:native/build.gradle.kts`** — native bridge module:
506+
507+
```kotlin
508+
plugins {
509+
kotlin("multiplatform") version "2.3.20"
510+
id("io.github.kdroidfilter.nucleusnativeaccess")
511+
}
512+
513+
kotlin {
514+
jvmToolchain(25)
515+
linuxX64() // or macosArm64(), mingwX64()
516+
jvm()
517+
}
518+
519+
kotlinNativeExport {
520+
nativeLibName = "mylib"
521+
nativePackage = "com.example.mylib"
522+
}
523+
```
524+
525+
**`:app/build.gradle.kts`** — Compose Desktop module:
526+
494527
```kotlin
495528
plugins {
496529
kotlin("multiplatform") version "2.3.20"
497530
id("org.jetbrains.compose") version "1.10.2"
498531
id("org.jetbrains.kotlin.plugin.compose") version "2.3.20"
499532
id("io.github.kdroidfilter.nucleus") version "1.7.2"
500-
id("io.github.kdroidfilter.nucleusnativeaccess")
501533
}
502534

503-
// Compose compiler only targets JVM (native sources have no @Composable)
504-
composeCompiler {
505-
targetKotlinPlatforms.set(
506-
setOf(org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType.jvm)
507-
)
535+
kotlin {
536+
jvmToolchain(25)
537+
jvm()
538+
539+
sourceSets {
540+
val jvmMain by getting {
541+
dependencies {
542+
implementation(compose.desktop.currentOs)
543+
implementation(project(":native"))
544+
}
545+
}
546+
}
508547
}
509548

510-
// No java.library.path needed — native lib is auto-extracted from JAR
511549
nucleus.application {
512550
mainClass = "com.example.MainKt"
513551
jvmArgs += listOf("--enable-native-access=ALL-UNNAMED")
514552
}
515553
```
516554

555+
This avoids any conflict between the Compose compiler and Kotlin/Native targets used for FFM bridges.
556+
517557
### Using with C interop (e.g. libnotify)
518558

519559
You can combine the plugin with Kotlin/Native cinterop to wrap native C libraries and expose them to JVM:

0 commit comments

Comments
 (0)