sample/androidNativeActivity with cinterop for a new C lib fails

I have C headers for a C library I have compiled with the NDK for an Android device (androidNativeX64). I have used cinterop to create Kotlin bindings and would like to be able to call them from a Kotlin/Native Android App.

I know I could use JNI, but I want a way to access a C library via unmodified C stubs and I think this should be possible from everything I’ve read about cinterop.

The closest example I could find for this is kotlin-native/samples/androidNativeActivity which I got to run in an emulated Android device after a small fix (Issue #4004).

The current sample code only accesses a structure defined using cinterop, but does not link to a new C library. I added a new .def file in the example to also create a klib for my libbindings.a library which has some new C code, in particular a test function called hello().

The modified src/x86main/main.kt now looks like this:

package sample.androidnative

import kotlinx.cinterop.*
import platform.android.*
import org.rustlightning.bindings.*

fun main() {

val ret = hello(“test”)
… otherwise same as the original main.kt

I also added a new line to kotlin/compilations/cinterops of build.gradle.kts a reference my library called bindings.

compilations["main"].cinterops {
val bindings by creating
val bmpformat by creating
}

The .def file for libbindings looks like the following, where libbindings.a is located at /Users/richard/VSCode/cinterop/bindings.

package = org.rustlightning.bindings
headers = ffi.h
headerFilter = *
staticLibraries = libbindings.a
libraryPaths = /opt/local/lib /usr/local/opt/curl/lib /Users/richard/VSCode/cinterop/bindings
compilerOpts = -Isrc/nativeInterop/cinterop
compilerOpts.linux = -I/usr/include -I/usr/include/x86_64-linux-gnu
linkerOpts.osx = -L/opt/local/lib -Lsrc/nativeInterop/cinterop -l bindings
linkerOpts.linux = -L/usr/lib/x86_64-linux-gnu -l bindings

I copied libbindings.so created with the NDK to ./build/Polyhedron/libs/x86_64 so it will be added to the apk file. It seems like this shouldn’t be necessary if I statically link libbindings.a in the .def file however.

I also added bindings.kt in src/x86main/kotlin that was created by cinterop for my ffi.h header file, where the definition of hello() that was autogenerated looks like this:

@CCall("knifunptr_bindings0_hello")
external fun hello(@CCall.CString to: String?): CPointer<ByteVar>?

As per the README.md I then ran ./gradlew assemble and adb install -r build/outputs/apk/debug/androidNativeActivity-debug.apk to test it out.

The app crashes and I see this error in logcat:

java.lang.UnsatisfiedLinkError: Unable to load native library "/data/app/com.jetbrains.konan_activity2-HOQOXCz3Ejrum1yrc40ZlA==/lib/x86_64/libpoly.so": dlopen failed: cannot locate symbol "hello" referenced by "/data/app/com.jetbrains.konan_activity2-HOQOXCz3Ejrum1yrc40ZlA==/lib/x86_64/libpoly.so"...

Any ideas what I’m doing wrong? I’ve already spent way to much time on this problem now and wish I had some way to better debug what’s going on. I think this could be a really useful way to use Kotlin/native if it works, but I’m afraid I might be trying to do something that is for some reason impossible.

I don’t care about JVM calling right now, but I would expect there could be a way to integrate this with a multiplatform build if it works.

Thanks! Any advice would be greatly appreciated. :pray:

1 Like

Any updates regarding this topic? :slight_smile: