I'm trying to use the PiGPIO library with Kotlin Native as a linked library (not using the deamon).
So I'm using C interop with a .def
file that references the pigpio.h file.
It works (I managed to get a LED blinking) but there is an issue with the typing of integers.
Althoug I didn't enable the experimental unsigned integers feature, the generated stubs are using type UInt
.
For example for the parameters of this function:
@kotlinx.cinterop.internal.CCall public external fun gpioSetMode(gpio: kotlin.UInt, mode: kotlin.UInt): kotlin.Int { /* compiled code */ }
That's OK with me as they are of type unsigned
in C and I want this to be as type-safe as possible:
int gpioSetMode(unsigned gpio, unsigned mode);
Now the problem is that the values to be used as parameters for the functions are defined using macro definitions in the .h
file. For example for the mode
parameter:
#define PI_INPUT 0
#define PI_OUTPUT 1
The generated Kotlin constants corresponding to those values are of type Int
:
public const val PI_INPUT: kotlin.Int /* compiled code */
public const val PI_OUTPUT: kotlin.Int /* compiled code */
However, although calling the function with the constant as a parameter is possible:
gpioSetMode(14, PI_OUTPUT) // compiles fine
I can't create a method that takes the mode as a parameter and use it:
fun main() {
setMode(PI_OUTPUT) // fails to compile (Type Mismatch)
}
fun setMode(mode : UInt) {
gpioSetMode(14, mode)
}
Is there a way to force all constants of positive integers to be of type UInt
?
AFAIK, there is no such option in the cinterop
tool.
In fact, one can say that the problem grows from the library header not using unsigned literals in it's "define" section. But it can be omitted in C, so this header is fine. The tool here is a bit nerdier, so it assumes all integer literals with no additional suffix as the signed typed.
About the way that your generated function works. In Kotlin, there is a smart cast concept(see here), but here it is a problem. In this documentation part, there is a note on smart-casting availability only for checks inside a module. In your case, gpioSetMode(gpio, mode)
and PI_OUTPUT
are located in the same module, while your setMode
is in another one.That's why the first call compiles and the second one does not.
I managed to workaround it in my small sample like that: just added into my code this like, redefining the constant
import my.*
const val PI_OUTPUT = my.PI_OUTPUT
where my
is the library package, most probably pigpio
for you. After that, smart casts will be available for the library functions, and all functions you declare in this module.