Hello everyone! I wanted to ask for an advice: ...
# kotlin-native
t
Hello everyone! I wanted to ask for an advice: There is a C library that I want to create multiplatform library wrapper for and use it in a multiplatform project (say, targeting jvm, android and iOS). I foresee 2 paths for implementation: 1. For jvm and android create jni interface and call the C lib through it. For native it would use just cinterop. Expect/actual mechanism for the common code. 2. Create a Kotlin/Native wrapper for C with cinterop, provide jni through @CName annotations and use the wrapper itself for jvm targets (completely hiding original c lib from platform code). Expect/actual as in variant 1. What would be a better way? Any details I should be aware of? Any advice about such a project, links or references highly appreciated, thanks!
f
I would go with 1. Kotlin is garbage collected on all platforms so when you interop with non-garbage collected code you have two ways: manually clean up the reference to the c objects (cleaning up the memory) when you use your Kotlin objects (this makes your Kotlin code cluttered and mon-idiomatic though), or you can register the cleaning action on the garbage collector to happen automatically when the Kotlin objected Is gced. You have to do either of these things on both native and JVM. If you go with option one, you can have some common abstractions (e.g. registingering cleanup actions on the gced) and produce a single wrapper that behaves similar. If you go with option 2 (JVM is a wrapper of the native wrapper), then potentially you have to manage the memory twice (once to clear reference from JVM to Kotlin native (gced) and once from Kotlin native to the c library. Also, the behavior of the wrapper of the wrapper (JVM) may be different from the native one, which is generally undesirable for multiplatform stuff that could instead share code and behavior. Try to take a look at the code of Skiko (KMP wrapper around skia) for example.
t
Thanks! That makes sense
j
Zipline builds like 1 if you want another real world example. We use cmake for Android and JNI on JVM and then have a cinterop-based native implementation for Linux, iOS, macOS, etc.
👍 1
t
And how’s the api designed? Like JNI and cinterop-based lib exposes the same methods and then it is used in common code as is?
j
Yes, the API is common across all targets with expect/actual and the implementation varies based on whether it's JNI-based or cinterop-based
t
Thanks, that helps
One more question, maybe you faced something similar. Working with forward declarations kinda sucks. Do you just redefine structs in .def file or maybe there another way? Or just use definitions from cnames package?
t
Yep!
Thanks
j
Thankfully it's not too many. In other projects I work on it's a lot more.