STklos Reference Manual
12. Foreign Function Interface


The STklos Foreign Function Interface (FFI for short) has been defined to allow an easy access to functions written in C without needing to build C-wrappers and, consequently, without any need to write C code. Note that the FFI is very machine dependent and that it works only on a limited set of architectures/systems 1. Moreover, since FFI allows very low level access, it is easy to crash the STklos VM when using an external C function.

Note that the support for FFI is still minimal and that it will evolve in future versions.

The definition of an external function is done with the define-external special form. This form takes as arguments a typed list of parameters and accepts several options to define the name of the function in the C world, the library which defines this function, ... The type of the function result and the type of its arguments are defined in Figure 2. This table lists the various keywords reserved for denoting types and their equivalence between the C and the Scheme worlds.

NameCorresponding C typeCorresponding Scheme Type
:charcharScheme character
:shortshortScheme integer
:ushortunsigned shortScheme integer
:intintScheme integer
:uintunsined intScheme integer
:longlong intScheme integer
:ulongunsigned long intScheme integer
:floatfloatScheme real number
:doubledoubleScheme real number
:pointervoid *Scheme pointer object or Scheme string
:stringchar *Scheme string
:objvoid *Any Scheme object passed as is
Fig. 2: FFI types

(define-external name parameters option)STklos syntax

The form define-external binds a new procedure to name. The arity of this new procedure is defined by the typed list of parameters given by parameters. This parameters list is a list of keywords (as defined in the previous table) or couples whose first element is the name of the parameter, and the second one is a type keyword. All the types defined in the above table, except :void, are allowed for the parameters of a foreign function.
Define-external accepts several options:
  • :return-type is used to define the type of the value returned by the foreign function. The type returned must be chosen in the types specified in the table. For instance:
    (define-external maximum(:int :int)
       :return-type :int)
    defines the foreign function maximum which takes two C integers and returns an integer result. Omitting this option default to a result type equal to :void (i.e. the returned value is undefined).
  • :entry-name is used to specify the name of the foreign function in the C world. If this option is omitted, the entry-name is supposed to be name. For instance:
    (define-external minimum((a :int) (b :int))
       :return-type :int
       :entry-name  "min")
    defines the Scheme function minimum whose application executes the C function called min.
  • :library-name is used to specify the library which contains the foreign-function. If necessary, the library is loaded before calling the C function. So,
    (define-external minimum((a :int) (b :int))
       :return-type  :int
       :entry-name   "min"
        :library-name "libminmax")
    defines a function which will execute the function min located in the library libminmax.xx (where xx is the suffix used for shared libraries on the running system (generally so))

Hereafter, there are some commented definitions of external functions:

 (define-external isatty ((fd :int))
     :return-type :boolean)

  (define-external system ((cmd :string))
    :return-type :int)

  (define-external ttyname (:int)
    :return-type :string)

All these functions are defined in the C standard library, hence it is not necessary to specify the :library-name option.

  • istty is declared here as a function which takes an integer and returns a boolean (in fact, the value returned by the C function isatty is an int, but we ask here to the FFI system to translate this result as a boolean value in the Scheme world).
  • system is a function which takes a string as parameter and returns an int.
  • ttyname is a function whih takes an int and returns a string. Note that in this function the name of the parameter has been omitted as within C prototypes.

If an external function receives an :int argument and is passed a Scheme bignum, which then doesn't fit a long int in C, the external function will signal an error. When a :float or :double argument is declared and is passed a Scheme real that requires so many bits so as to not be representable in that type, that argument will be silently taken as infinity.

 (define-external c-abs ((fd :int))
     :entry-name "abs"
     :return-type :int)

 (define-external c-fabs ((fd :double))
     :entry-name "fabs"
     :return-type :double)

 (define-external c-fabsf ((fd :float))
     :entry-name "fabsf"
     :return-type :float)
(c-abs (- (expt 2 70)))    ⇒ Error
(c-fabs -1.0e+250)         ⇒ 1e+250
(c-fabsf -1.0e+250)        ⇒ +inf.0
(c-fabs (- (expt 10 300))) ⇒ 1e+300
(c-fabs (- (expt 10 600))) ⇒ +inf.0
TODO: describe malloc and malloc_atomic and their interaction with the GC

1: FFI system should works on the following architectures/systems: gcc_ppc_osx, gcc_sparc_unix, gcc_x64_unix, gcc_x86_unix.

This Html page has been produced by Skribe.
Last update Wed Nov 24 17:57:14 2021