Hello, I have a kotlin multiplatform project that ...
# multiplatform
k
Hello, I have a kotlin multiplatform project that has jvmMain and NativeMain with some
actual
implementation corresponding to some
expect
stubs in common main. I am trying to use my jvmMain
actual
implementations as my androidMain
actual
implementations. I have seen the example of creating a new srcDir in each of the source sets but that does not seem to work as idea wants me to create androidMain
actual
functions. Is it possible to share these implementations between the two targets?
m
Do you really need androidMain for some other things? If not you can stick with jvmMain without android target and use the library in Android as a jvm library and it will work fine
k
The library wraps a Rust library. The jvm portions uses JNI to call into the rust library which has been compiled for both Ios and Android.
p
What does Rust have to do with it?
k
@Kolby Kunz you basically have a Rust lib with JNI bindings around it yeah? And you want to reuse those bindings between
jvmMain
and
androidMain
?
You can create an intermediate JVM source set
commonJvm
used by jvm and android targets.
If you use hierarchical structure, it’s pretty easy to set up using custom group:
Copy code
targetHierarchy.default { // or .custom depending on your setup
  common {
    group("commonJvm") {
      group("jvm") withJvm()
      group("android") withAndroidTarget()
    }
  }
}
If not using hierarchical structure, you will need to create source intermediate source sets manually:
Copy code
val commonJvm by creating {
  dependsOn(commonMain)
} 

jvmMain {
  dependsOn(commonJvm)
}

androidMain {
  dependsOn(commonJvm)
}

// similar with commonJvmTest
k
@Kirill Zhukov Yah that is right with the rust lib with JNI around it. I will give those solutions a try. Thank you!
Now when I run android the
actual
functions say that there is no
expect
declaration for the function. All other sources work though.
These errors only occur at compile time for android.
k
what’s your source set configuration code look like?
k
Copy code
sourceSets {

        all {
          languageSettings.optIn("kotlinx.cinterop.ExperimentalForeignApi")
        }

        val commonMain by getting {
            kotlin.srcDir(askarBindings.resolve("commonMain").resolve("kotlin"))
            dependencies {
                implementation("com.squareup.okio:okio:3.2.0")
                implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.4.0")
                implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1")
                implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.0-RC")
            }
        }
        val commonTest by getting {
            this.dependsOn(commonMain)
            dependencies{
                implementation(kotlin("test"))
            }
        }

        val commonJvmMain by creating {
            kotlin.srcDir(askarBindings.resolve("commonJvmMain").resolve("kotlin"))
            dependencies{
                implementation("net.java.dev.jna:jna:5.13.0")
            }
            dependsOn(commonMain)
        }

        val androidMain by getting {
            kotlin.srcDir(binaries)
            dependencies{
                implementation("net.java.dev.jna:jna:5.13.0@aar")
                implementation("org.jetbrains.kotlinx:atomicfu:0.22.0")
            }
            dependsOn(commonJvmMain)
        }

        val jvmMain by getting {
            kotlin.srcDir(binaries)
            dependencies{
                implementation("net.java.dev.jna:jna:5.13.0")
            }
            dependsOn(commonJvmMain)
        }

        val jvmTest by getting {
            dependsOn(jvmMain)
        }

        val nativeMain by getting {
            kotlin.srcDir(askarBindings.resolve("nativeMain").resolve("kotlin"))
        }

        val nativeTest by getting{
            dependsOn(nativeMain)
        }
    }
j
commonTest shouldn't depend on commonMain. Test source sets have a friend relationship with the main source set already by default. Adding it as a depends on relationship puts it in the main source set tree. (Now commonTest needs to implement `actual`s for *commonMain*'s `expect`s, for example).
What's the reason you're needing to add srcDir manually as well? It's unclear what these manual src directories are. With your source set tree set up with a shared JVM+Android intermediate source set, you should be able to have the common JVM implementations in the default src location for that source set: moduleRoot/src/commonJvmMain/kotlin
I'd also highly recommend using the
targetHierarchy
API @Kirill Zhukov mentioned above. It makes the source set hierarchy code much more concise and readable. It's also less prone to errors with complicated hierarchies.