Passing int* to C from Kotlin/Native
Today, suddenly, a friend of mine gave me an easy question - how can one pass an int pointer to a C function from Kotlin/Native. To my shame, I did not have the answer. Now I do
The Short Answer
memScoped {
val q = alloc<IntVar>()
q.value = 123
function_from_c(q.ptr)
}
The Long Answer
We need several files for the demo project. We will use Gradle Multiplatform Project with Kotlin 1.3.11 and IntelliJ IDEA. Yes, it will be enough to work with (!) Kotlin/Native
C Interop
It’s enough to create only a file.def
file with C code inside (after ---
line):
---
int function_from_c(int* x) {
return *x = *x + 10;
}
The cinterop
tool generates the following Kotlin code interop from it:
fun function_from_c(x: CValuesRef<IntVar>?): Int
Right here we have a question - how to create an object of CValuesRef<IntVar>
type?
The Solution
- Use
CPointer<IntVar>
, which is subtype ofCValuesRef<IntVar>
- Call the
.ptr
extension property on theIntVar
to get aCPointer<IntVar>
instance - Create a
IntVar
instance via thealloc<T>
extension function on aNativePlacement
instance - Get a
NativePlacement
instance from thememScoped { ... }
block receiver - Use the
.value
property onIntVar
to get/setInt
value
Full code of the main.kt
is as follows. Mind the imports from kotlinx.cinterop
:
import file.function_from_c
import kotlinx.cinterop.IntVar
import kotlinx.cinterop.alloc
import kotlinx.cinterop.memScoped
import kotlinx.cinterop.ptr
import kotlinx.cinterop.value
fun main(args: Array<String>) {
println("Hello!")
memScoped {
val q: IntVar = alloc<IntVar>()
q.value = 123
val z = function_from_c(q.ptr)
println(z) // return value, C int
println(q.value) // updated int* from C
}
}
Gradle Project Setup
Let’s create a demo project with Gradle for IntelliJ IDEA. You need an empty Gradle
project to start. I called gradle init
command from console to get it in a new folder
(it was Gradle 5.1 in my case).
As an alternative, you may create a project with File | New | Project...
menu too.
Next, paste the following to the build.gradle
:
plugins {
id 'org.jetbrains.kotlin.multiplatform' version '1.3.11'
}
kotlin {
targets {
/// use presets.mingwX64 for Windows
/// use presets.linuxX64 for Linux
fromPreset(presets.macosX64, 'native') {
compilations.main {
outputKinds 'executable'
cinterops {
myInterop {
defFile project.file("src/native/file.def")
}
}
}
}
}
sourceSets {
nativeMain {
kotlin.srcDir('src/native')
}
}
}
Place the main.kt
and file.def
files into the src/native
folder. Now you may open the project in IntelliJ IDEA
by pointing it to the build.gradle
file (use Java 1.8 in the Gradle Import dialog).
I use Kotlin Multiplatform Project. You may find in the demo sources on my GitHub.
Take a look to the C Interop article for more information on the Kotlin/Native interop with C. An Interop With C tutorials are a good read to see how other types are mapped between C and Kotlin/Native.
Have fun!
comments powered by Disqus