Portable Foreign Function Interface for R7RS

Portable foreign function interface for R7RS. It is portable in the sense that it supports multiple implementations, as opposed to being portable by conforming to some specification.

Project

Issue trackers

Maling lists

Jenkins

Table of contents

Goals

Non goals

Status

Currently the interface of the library is in okay shape. It propably will not change much but no guarantees are being made just yet.

Due to supporting many different Scheme implementations, different parts of this software are in different stage. As a whole it is still in alpha stage. That said the interface should not be changing anymore and some implementations are in beta.

Current caveats

Implementation table

Beta

pffi-init pffi-size-of pffi-shared-object-auto-load pffi-shared-object-load pffi-pointer-null pffi-pointer-null? pffi-pointer-allocate pffi-pointer-address pffi-pointer? pffi-pointer-free pffi-pointer-set! pffi-pointer-get pffi-string->pointer pffi-pointer->string pffi-struct-make pffi-struct-pointer pffi-struct-offset-get pffi-struct-get pffi-struct-set! pffi-define pffi-define-callback
Chibi X X X X X X X X X X X X X X X X X X X X
Gauche X X X X X X X X X X X X X X X X X X X
Guile X X X X X X X X X X X X X X X X X X X X
Kawa X X X X X X X X X X X X X X X X X X X X
Racket X X X X X X X X X X X X X X X X X X X X
Saggittarius X X X X X X X X X X X X X X X X X X X X

Alpha

pffi-init pffi-size-of pffi-shared-object-auto-load pffi-shared-object-load pffi-pointer-null pffi-pointer-null? pffi-pointer-allocate pffi-pointer-address pffi-pointer? pffi-pointer-free pffi-pointer-set! pffi-pointer-get pffi-string->pointer pffi-pointer->string pffi-struct-make pffi-struct-pointer pffi-struct-offset-get pffi-struct-get pffi-struct-set! pffi-define pffi-define-callback
Chicken-5 X X X X X X X X X X X X X X X X X X X X
Cyclone X X X X X X X X X X X X X X X X X X X
Gambit X X X X X X X X
Gerbil X X X X X X
Larceny X X X X X X
Mosh X X X X X X X X X X X X X X X X X X X X
Skint X X X X X X
Stklos X X X X X X X X X X X X X X
tr7 X X X X X
Ypsilon X X X X X

Not started

Other

Documentation

Usage

Chibi

Needs libffi-dev, on Debina/Ubuntu/Mint install with:

apt install libffi-dev

Build with:

make chibi

Chicken

Needs r7rs egg, install with:

chicken-install r7rs

Racket

Needs racket-r7rs, install with:

raco pkg install --auto r7rs

Kawa

Kawa Needs at least Java version 22

Needs jvm flags:

Reference

Types

Types are given as symbols, for example ’int8 or ’pointer.

Procedures and macros

Some of these are procedures and some macros, it might also change implementation to implementation.

pffi-init

pffi-init

Always call this first, on most implementation it does nothing but some implementations might need initialisation run.

pffi-size-of

pffi-size-of object -> number

Returns the size of the pffi-struct, pffi-enum or pffi-type.

pffi-align-of

pffi-align-of type -> number

Returns the align of the type.

pffi-shared-object-auto-load

pffi-shared-object-auto-load headers shared-object-name [options] -> object

Load given shared object automatically searching many predefined paths.

Takes as argument a list of C headers, these are for the compiler ones. And an shared-object name, used by the dynamic FFI’s. The name of the shared object should not contain suffix like .so or .dll. Nor should it contain any prefix like “lib”.

Additional options argument can be provided, theys should be a pair with a keyword. The options are:

Example:

(define libc-stdlib
  (cond-expand
    (windows (pffi-shared-object-auto-load (list "stdlib.h") "ucrtbase"))
    (else (pffi-shared-object-auto-load (list "stdlib.h")
                                        "c"
                                        '(additional-versions . ("6"))
                                        '(additional-search-paths . ("."))))))

pffi-shared-object-load

pffi-shared-object-load headers path [options]

It is recommended to use the pffi-shared-object-auto-load instead of this directly.

Headers is a list of strings needed to be included, for example

(list "curl/curl.h")

Path is the full path of the shared object without any “lib” prefix or “.so/.dll” suffix. For example:

"curl"

Options:

pffi-pointer-null

pffi-pointer-null -> pointer

Returns a new NULL pointer.

pffi-pointer-null?

pffi-pointer-null? pointer -> boolean

Returns #t if given pointer is null pointer, #f otherwise.

pffi-pointer-allocate

pffi-pointer-allocate size -> pointer

Returns newly allocated pointer of given size.

pffi-pointer-address

pffi-pointer-address pointer -> number

Returns the address of given pointer as number.

pffi-pointer?

pffi-pointer? object -> boolean

Returns #t if given object is pointer, #f otherwise.

pffi-pointer-free

pffi-pointer-free pointer

Frees given pointer.

pffi-pointer-set!

pffi-pointer-set! pointer type offset value

Sets the value on a pointer on given offset. For example:

(define p (pffi-pointer-allocate 128))
(pffi-pointer-set! p 'int 64 100)

Would set the offset of 64, on pointer p to value 100.

pffi-pointer-get

pffi-pointer-get pointer type offset -> object

Gets the value from a pointer on given offset. For example:

(define p (pffi-pointer-allocate 128))
(pffi-pointer-set! p 'int 64 100)
(pffi-pointer-get p 'int 64)
> 100

pffi-string->pointer

pffi-string->pointer string -> pointer

Makes pointer out of a given string.

pffi-pointer->string

pffi-pointer->string pointer -> string

Makes string out of a given pointer.

pffi-struct-make

pffi-struct-make c-type members . pointer -> pffi-struct

Creates a new pffi-struct and allocates pointer for it. The members argument is a list of member names and types. For example:

(define color (pffi-struct-make 'color '((int8 . r) (int8 . g) (int8 . b) (int8 .a ))))
(define test (pffi-struct-make "struct test" '((int8 . r) (int8 . g) (int8 . b) (int8 .a ))))

C-type argument can be symbol or a string.

pffi-struct-pointer

pffi-struct-pointer pffi-struct -> pointer

Returns the pointer that holds the struct content. You need to use this when passing a struct as a pointer to foreign functions.

(define s (pffi-struct-make 'test '((int . r) (int . g) (int . b))))
(pffi-struct-pointer s)

pffi-struct-offset-get

pffi-struct-offset-get member-name -> number

Returns the offset of a struct member with given name.

pffi-struct-get

pffi-struct-get pffi-struct member-name -> object

Returns the value of the givens struct member.

pffi-struct-set!

pffi-struct-set! pffi-struct member-name value

Sets the value of the givens struct member. It is up to you to make sure that the type of value is correct.

pffi-define

pffi-define scheme-name shared-object c-name return-type argument-types

Defines a new foreign function to be used from Scheme code. For example:

(define libc-stdlib
    (cond-expand
        (windows (pffi-shared-object-auto-load (list "stdlib.h") (list) "ucrtbase" (list "")))
        (else (pffi-shared-object-auto-load (list "stdlib.h") (list) "c" (list "" "6")))))
(pffi-define c-puts libc-stdlib 'puts 'int (list 'pointer))
(c-puts "Message brought to you by FFI!")

pffi-define-callback

pffi-define-callback scheme-name return-type argument-types procedure

Defines a new Sceme function to be used as callback to C code. For example:

; Load the shared library
(define libc-stdlib
    (cond-expand
        (windows (pffi-shared-object-auto-load (list "stdlib.h") (list) "ucrtbase" (list "")))
        (else (pffi-shared-object-auto-load (list "stdlib.h") (list) "c" (list "" "6")))))

; Define C function that takes a callback
(pffi-define qsort libc-stdlib 'qsort 'void (list 'pointer 'int 'int 'callback))

; Define our callback
(pffi-define-callback compare
                      'int
                      (list 'pointer 'pointer)
                      (lambda (pointer-a pointer-b)
                        (let ((a (pffi-pointer-get pointer-a 'int 0))
                              (b (pffi-pointer-get pointer-b 'int 0)))
                          (cond ((> a b) 1)
                                ((= a b) 0)
                                ((< a b) -1)))))

; Create new array of ints to be sorted
(define array (pffi-pointer-allocate (* (pffi-size-of 'int) 3)))
(pffi-pointer-set! array 'int (* (pffi-size-of 'int) 0) 3)
(pffi-pointer-set! array 'int (* (pffi-size-of 'int) 1) 2)
(pffi-pointer-set! array 'int (* (pffi-size-of 'int) 2) 1)

(display array)
(newline)
;> (3 2 1)

; Sort the array
(qsort array 3 (pffi-size-of 'int) compare)

(display array)
(newline)
;> (1 2 3)