11package io.github.kdroidfilter.nucleusnativeaccess.plugin
22
3+ import io.github.kdroidfilter.nucleusnativeaccess.plugin.catalog.kotlinxCoroutineDependency
4+ import io.github.kdroidfilter.nucleusnativeaccess.plugin.catalog.kotlinxCoroutineJvmDependency
5+ import io.github.kdroidfilter.nucleusnativeaccess.plugin.catalog.kotlinxCoroutineTestDependency
36import io.github.kdroidfilter.nucleusnativeaccess.plugin.tasks.GenerateNativeBridgesTask
7+ import org.gradle.api.GradleException
48import org.gradle.api.Plugin
59import org.gradle.api.Project
10+ import org.gradle.api.logging.LogLevel
611import org.gradle.api.tasks.testing.Test
712import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
813import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
914import org.jetbrains.kotlin.gradle.plugin.mpp.NativeBuildType
15+ import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget
1016import java.io.File
1117
1218/* *
@@ -43,27 +49,50 @@ class KotlinNativeExportPlugin : Plugin<Project> {
4349
4450 private fun configureKmp (project : Project , extension : KotlinNativeExportExtension ) {
4551 val kotlin = project.extensions.getByType(KotlinMultiplatformExtension ::class .java)
52+
4653 val libName = extension.nativeLibName.get()
4754 val pkg = extension.nativePackage.get()
4855
56+ // read the jvm target name
57+ // JVM target should exist otherwise the plugin is of no use
58+ val jvmTarget = kotlin.targets.filterIsInstance<KotlinJvmTarget >()
59+ .firstOrNull() ? : throw GradleException (" Sorry this plugin required jvm target to work with" )
60+
61+ val jvmMainSourceSetName = jvmTarget.name + " Main"
62+ val jvmTestSourceSetName = jvmTarget.name + " Test"
63+ val jvmMainTaskName = jvmMainSourceSetName.replaceFirstChar { it.titlecase() }
64+ val jvmTaskName = jvmTarget.name.replaceFirstChar { it.titlecase() }
65+
4966 val nativeBridgesDir = project.layout.buildDirectory.dir(" generated/kne/nativeBridges" )
5067 val jvmProxiesDir = project.layout.buildDirectory.dir(" generated/kne/jvmProxies" )
5168 val jvmResourcesDir = project.layout.buildDirectory.dir(" generated/kne/jvmResources" )
5269
53- // Detect native target and its source sets.
70+ // Detect the first native target and its source sets.
5471 // Convention: use src/nativeMain if it exists (shared native source set),
5572 // otherwise fall back to the first native target's main source set (e.g. linuxX64Main).
5673 val nativeTarget = kotlin.targets
5774 .filterIsInstance<KotlinNativeTarget >()
5875 .firstOrNull()
5976
60- val userNativeSrcDirs = mutableListOf< java.io.File > ()
77+
78+ val nativeTargetTaskName = nativeTarget?.name?.replaceFirstChar { it.titlecase() } ? : " Native"
79+
80+ val userNativeSrcDirs = mutableListOf<File >()
81+
82+ // check if native main dir present
6183 val nativeMainDir = project.projectDir.resolve(" src/nativeMain/kotlin" )
6284 if (nativeMainDir.exists()) userNativeSrcDirs.add(nativeMainDir)
85+
86+ // if native target present use that too
6387 if (nativeTarget != null ) {
88+ project.logger.log(
89+ LogLevel .INFO ,
90+ " NATIVE TARGET FOUND :${nativeTarget.konanTarget.name} ALIAS:${nativeTarget.name} "
91+ )
6492 val targetMainDir = project.projectDir.resolve(" src/${nativeTarget.name} Main/kotlin" )
6593 if (targetMainDir.exists()) userNativeSrcDirs.add(targetMainDir)
6694 }
95+
6796 val userNativeSources = project.files(userNativeSrcDirs)
6897
6998 // Collect commonMain sources for data class discovery
@@ -101,20 +130,20 @@ class KotlinNativeExportPlugin : Plugin<Project> {
101130 project.tasks.register(" generateKneJvmProxies" ) { it.dependsOn(generateBridges) }
102131
103132 // ── Coroutines dependency (required for suspend function support) ──
104- val coroutinesVersion = " 1.10.2"
105133 nativeTarget?.let { target ->
106134 kotlin.sourceSets.findByName(" ${target.name} Main" )?.dependencies {
107- implementation(" org.jetbrains.kotlinx:kotlinx-coroutines-core: $coroutinesVersion " )
135+ implementation(project.kotlinxCoroutineDependency )
108136 }
109137 }
110138 kotlin.sourceSets.findByName(" nativeMain" )?.dependencies {
111- implementation(" org.jetbrains.kotlinx:kotlinx-coroutines-core: $coroutinesVersion " )
139+ implementation(project.kotlinxCoroutineDependency )
112140 }
113- kotlin.sourceSets.findByName(" jvmMain" )?.dependencies {
114- implementation(" org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:$coroutinesVersion " )
141+
142+ kotlin.sourceSets.findByName(jvmMainSourceSetName)?.dependencies {
143+ implementation(project.kotlinxCoroutineJvmDependency)
115144 }
116- kotlin.sourceSets.findByName(" jvmTest " )?.dependencies {
117- implementation(" org.jetbrains.kotlinx:kotlinx-coroutines-test: $coroutinesVersion " )
145+ kotlin.sourceSets.findByName(jvmTestSourceSetName )?.dependencies {
146+ implementation(project.kotlinxCoroutineTestDependency )
118147 }
119148
120149 // Wire generated bridges into the native source set (try nativeMain, fall back to <target>Main)
@@ -123,21 +152,20 @@ class KotlinNativeExportPlugin : Plugin<Project> {
123152 nativeSourceSet?.kotlin?.srcDir(nativeBridgesDir)
124153
125154 // Wire generated JVM proxies into jvmMain
126- kotlin.sourceSets.findByName(" jvmMain " )?.kotlin?.srcDir(jvmProxiesDir)
155+ kotlin.sourceSets.findByName(jvmMainSourceSetName )?.kotlin?.srcDir(jvmProxiesDir)
127156
128157 // Wire generated GraalVM metadata into JVM resources
129- kotlin.sourceSets.findByName(" jvmMain " )?.resources?.srcDir(jvmResourcesDir)
158+ kotlin.sourceSets.findByName(jvmMainSourceSetName )?.resources?.srcDir(jvmResourcesDir)
130159
131160 // Ensure compilation waits for generation
132161 project.tasks.configureEach { task ->
133162 val name = task.name
134163 if (name.startsWith(" compileKotlin" ) &&
135- (name.contains(" Native" , ignoreCase = true ) || name.contains(" LinuxX64" ) ||
136- name.contains(" MacosArm64" ) || name.contains(" MingwX64" ))
164+ (name.contains(" Native" , ignoreCase = true ) || name.contains(nativeTargetTaskName, ignoreCase = true ))
137165 ) {
138166 task.dependsOn(generateBridges)
139167 }
140- if (name == " compileKotlinJvm " || name == " compileKotlinJvmMain " ) {
168+ if (name == " compileKotlin $jvmTaskName " || name == " compileKotlin $jvmMainTaskName " ) {
141169 task.dependsOn(generateBridges)
142170 }
143171 }
@@ -156,10 +184,17 @@ class KotlinNativeExportPlugin : Plugin<Project> {
156184 // ── Bundle native lib into JVM resources (zero-config deployment) ────
157185
158186 if (nativeTarget != null ) {
159- val targetName = nativeTarget.name
160- val targetCap = targetName.replaceFirstChar { it.uppercaseChar() }
187+ // konan target names are the actual target name but we can have an associated alias
188+ val targetAliasName = nativeTarget.name
189+ val targetName = nativeTarget.konanTarget.name
190+
191+ project.logger.log(LogLevel .INFO , " TARGET ALIAS :$targetAliasName , TARGET NAME:$targetName " )
192+
193+ val targetCap = targetAliasName.replaceFirstChar { it.uppercaseChar() }
161194 val libCap = libName.replaceFirstChar { it.uppercaseChar() }
195+
162196 val platform = mapTargetToPlatform(targetName)
197+
163198 val linkTaskName = " link${libCap} ReleaseShared$targetCap "
164199 val nativeLibResourceDir = project.layout.buildDirectory.dir(" generated/kne/nativeLib" )
165200
@@ -170,7 +205,7 @@ class KotlinNativeExportPlugin : Plugin<Project> {
170205 task.dependsOn(linkTaskName)
171206 task.doLast {
172207 val releaseDir = buildDir
173- .dir(" bin/$targetName /${libName} ReleaseShared" ).get().asFile
208+ .dir(" bin/$targetAliasName /${libName} ReleaseShared" ).get().asFile
174209 val nativeFile = releaseDir.listFiles()?.firstOrNull { f ->
175210 f.extension in listOf (" so" , " dylib" , " dll" )
176211 }
@@ -184,11 +219,11 @@ class KotlinNativeExportPlugin : Plugin<Project> {
184219 }
185220
186221 // Wire native lib resource dir into JVM resources
187- kotlin.sourceSets.findByName(" jvmMain " )?.resources?.srcDir(nativeLibResourceDir)
222+ kotlin.sourceSets.findByName(jvmMainSourceSetName )?.resources?.srcDir(nativeLibResourceDir)
188223
189224 // Ensure processResources waits for the native lib copy
190225 project.tasks.configureEach { task ->
191- if (task.name == " jvmProcessResources " || task.name == " processJvmMainResources " ) {
226+ if (task.name == " ${jvmTarget.name} ProcessResources " || task.name == " process ${jvmMainTaskName} Resources " ) {
192227 task.dependsOn(copyNativeLib)
193228 }
194229 }
@@ -200,11 +235,18 @@ class KotlinNativeExportPlugin : Plugin<Project> {
200235 }
201236
202237 /* * Map Kotlin/Native target name to platform directory name. */
203- private fun mapTargetToPlatform (targetName : String ): String = when {
204- targetName.startsWith(" linux" ) -> if (targetName.contains(" Arm" ) || targetName.contains(" aarch" )) " linux-aarch64" else " linux-x64"
205- targetName.startsWith(" macos" ) -> if (targetName.contains(" Arm" ) || targetName.contains(" arm64" ) || targetName.contains(" Arm64" )) " darwin-aarch64" else " darwin-x64"
206- targetName.startsWith(" mingw" ) -> if (targetName.contains(" Arm" )) " win32-arm64" else " win32-x64"
207- else -> " unknown"
238+ private fun mapTargetToPlatform (targetName : String ): String {
239+
240+ val isArm = targetName.contains(" Arm" )
241+ val isArch = targetName.contains(" aarch" )
242+ val isArm64 = targetName.contains(" arm64" ) || targetName.contains(" Arm64" )
243+
244+ return when {
245+ targetName.startsWith(" linux" ) -> if (isArm || isArch) " linux-aarch64" else " linux-x64"
246+ targetName.startsWith(" macos" ) -> if (isArm || isArm64) " darwin-aarch64" else " darwin-x64"
247+ targetName.startsWith(" mingw" ) -> if (isArm) " win32-arm64" else " win32-x64"
248+ else -> " unknown"
249+ }
208250 }
209251
210252 /* *
0 commit comments