Repository navigation
Calling_C_Functions
Kno has a simple foreign function interface to access C functions from either Kno itself or external libraries. The current implementation only handles scalar types, including integers (various sizes), floating point numbers (ditto), strings, KNO's native lisp pointers, and opaque pointer values.
The procedure FFI/PROC creates an FFI procedure and has the form:
`(ffi/proc *external_name* *library file (or #f)* *return_type* *arg1type* *arg2type* ...)`For example, we can do:
(define strlen (ffi/proc "strlen" #f 'size_t 'string))
#|kno>|# (strlen "foo")
3
(define unixtime (ffi/proc "time" #f time_t #[basetype ptr nullable #t]))
#|kno>|# (strlen "foo")
#T2019-06-12T15:41:56Z
(define unix-getenv (ffi/proc "getenv" #f 'strcpy 'string))
#|kno>|# (unix-getenv "USER")
"haase"KNO's foreign function interface does not provide destructuring of structured objects or pointers to structured objects, but it does functions can return raw pointer values which are wrapped by KNO and can be passed to other foreign functions.
The base type codes are symbols, including:
-
voidis a 'non value'; this only makes sense for return types -
floatis a low precision floating point number -
doubleis a higher precision float point number -
uintis an unsigned integer -
intis an integer -
ushortis an unsigned short integer -
shortis a short integer -
ulongis an unsigned long integer -
longis a long integer -
ucharis an unsigned byte -
byteis an unsigned byte -
ssize_tis an integer ssize_t value -
charis a signed byte -
stringis a utf8-string -
packetis a null terminated set of bytes -
ptris some kind of pointer value -
consis a raw KNO cons pointer -
lispis a KNO lisp pointer, which has already been incref'd -
lisprefis a KNO lisp pointer, which needs to be incref'd -
time_tis a unix time value -
nullis any object but is always passed as a NULL pointer value
KNO's FFI interface allows the annotation of values, including pointer values, with **typetag*s. This can be used to have the foreign function interface do type checking on arguments. For example,a simple wrapper of the UNIX filename access could be:
(define fopen
(ffi/proc "fopen" #f #[basetype ptr typetag file] 'string 'string))
(define fclose
(ffi/proc "fclose" #f 'int #[basetype ptr typetag file]))
(define fgetc
(ffi/proc "fgetc" #f 'int #[basetype ptr typetag file]))
(define fputc
(ffi/proc "fgetc" #f 'int 'int #[basetype ptr typetag file]))
In this example, fopen returns a raw pointer tagged with file
and the other functions will automatically check for this tagged value
when they are invoked.
For more complicated libraries, one approach for connecting with them is to define a lightweight C wrapper which provides the basic API in terms of the core FFI types and then linking to that wrapper using the FFI interface.