351 lines
12 KiB
Markdown
351 lines
12 KiB
Markdown
---
|
|
title: foreign-c a portable foreign function interface for R7RS Schemes
|
|
version: 0.10.0
|
|
---
|
|
|
|
# foreign-c
|
|
|
|
foreign-c is a C foreign function interface (FFI) library for R7RS Schemes. It
|
|
is portable in the sense that it supports multiple implementations, as opposed
|
|
to being portable by conforming to some specification.
|
|
|
|
[Issue tracker](https://sr.ht/~retropikzel/foreign-c/trackers)
|
|
|
|
[Maling lists](https://sr.ht/~retropikzel/foreign-c/lists)
|
|
|
|
- [Installation](#installation)
|
|
- [Documentation](#documentation)
|
|
- [Types](#types)
|
|
- [Primitives 1](#primitives-1)
|
|
- [Primitives 2](#primitives-2)
|
|
- [c-bytevector](#c-bytevector)
|
|
- [Environment variables](#environment-variables)
|
|
|
|
|
|
## Implementation support tables
|
|
|
|
### Primitives 1 table
|
|
|
|
| | c-size-of | c-bytevector-u8-set! |c-bytevector-u8-ref | define-c-library | c-bytevector? | define-c-procedure |
|
|
|------------------|:------------:|:--------------------:|:------------------:|:-------------------:|:-------------:|:-------------------:|
|
|
| **Chibi** | X | X |X | X | X | X |
|
|
| **Chicken** | X | X |X | X | X | X |
|
|
| **Gauche** | X | X |X | X | X | X |
|
|
| **Guile** | X | X |X | X | X | X |
|
|
| **Kawa** | X | X |X | X | X | X |
|
|
| **Mosh** | X | X |X | X | X | X |
|
|
| **Racket** | X | X |X | X | X | X |
|
|
| **Saggittarius** | X | X |X | X | X | X |
|
|
| **Stklos** | X | X |X | X | X | X |
|
|
| **Ypsilon** | X | X |X | X | X | X |
|
|
|
|
### Primitives 2 table
|
|
|
|
| | define-c-callback |
|
|
|------------------|:-----------------:|
|
|
| Chibi | |
|
|
| **Chicken** | X |
|
|
| Gauche | |
|
|
| **Guile** | X |
|
|
| Kawa | |
|
|
| **Mosh** | X |
|
|
| **Racket** | X |
|
|
| **Saggittarius** | X |
|
|
| Stklos | |
|
|
| **Ypsilon** | X |
|
|
|
|
### Test files pass
|
|
|
|
| | primitives.scm | addressof.scm | callback.scm |
|
|
|------------------|:--------------:|:-------------:|-------------:|
|
|
| Chibi | X | X | |
|
|
| **Chicken** | X | X | X |
|
|
| Gauche | X | X | |
|
|
| **Guile** | X | X | X |
|
|
| Kawa | X | X | |
|
|
| Mosh | X | X | |
|
|
| Racket | X | | |
|
|
| **Saggittarius** | X | X | X |
|
|
| Stklos | X | X | |
|
|
| Ypsilon | X | X | |
|
|
|
|
### Installation
|
|
|
|
Either download the latest release from
|
|
[https://git.sr.ht/~retropikzel/foreign-c/refs](https://git.sr.ht/~retropikzel/foreign-c/refs) or git clone
|
|
, preferably with a tag, and copy the _foreign_ directory to your library
|
|
directory.
|
|
|
|
As an example assuming you have a project and your libraries live in directory
|
|
called snow in it:
|
|
|
|
git clone https://git.sr.ht/~retropikzel/foreign-c --branch LATEST_VERSION
|
|
mkdir -p snow
|
|
cp -r foreign-c/foreign snow/
|
|
make -C snow/foreign/c <SCHEME_IMPLEMENTATION_NAME>
|
|
|
|
With most implementations the make command does not compile anything. When that
|
|
is the case it will say "Nothing to build on SCHEME\_IMPLEMENTATION\_NAME."
|
|
|
|
## Documentation
|
|
|
|
### Types
|
|
|
|
Types are given as symbols, for example 'int8 or 'pointer.
|
|
|
|
- int8
|
|
- uint8
|
|
- int16
|
|
- uint16
|
|
- int32
|
|
- uint32
|
|
- int64
|
|
- uint64
|
|
- char
|
|
- unsigned-char
|
|
- short
|
|
- unsigned-short
|
|
- int
|
|
- unsigned-int
|
|
- long
|
|
- unsigned-long
|
|
- float
|
|
- double
|
|
- pointer
|
|
- c-bytevector on Scheme side
|
|
- callback
|
|
- Callback function
|
|
- void
|
|
- Can not be argument type, only return type
|
|
|
|
### Primitives 1
|
|
|
|
(**c-type-size** _type_)
|
|
|
|
Returns the size of given C type.
|
|
|
|
(**define-c-library** _scheme-name_ _headers_ _object-name_ _options_)
|
|
|
|
Takes a scheme-name to bind the library to, list of C headers as
|
|
strings, shared-object name and options.
|
|
|
|
The C header strings should not contain "<" or ">", they are added
|
|
automatically.
|
|
|
|
The name of the shared object should not contain suffix like .so or .dll.
|
|
Nor should it contain any prefix like "lib".
|
|
|
|
The options are:
|
|
|
|
- additional-versions
|
|
- Search for additional versions of shared object, given shared object "c"
|
|
and additional versions "6" "7" on linux the files "libc", "libc.6",
|
|
"libc.7" are searched for.
|
|
- Can be either numbers or strings
|
|
- additional-paths
|
|
- Give additional paths to search shared objects from
|
|
|
|
Example:
|
|
|
|
(cond-expand
|
|
(windows (define-c-library libc-stdlib
|
|
'("stdlib.h")
|
|
"ucrtbase"
|
|
'((additional-versions ("0" "6"))
|
|
(additiona-paths (".")))))
|
|
(else (define-c-library libc-stdlib
|
|
(list "stdlib.h")
|
|
"c"
|
|
'((additional-versions ("0" "6"))
|
|
(additiona-paths ("."))))))
|
|
|
|
#### Notes
|
|
|
|
- Do not cond-expand inside the arguments, that might lead to problems on some
|
|
implementations.
|
|
- Do not store options in variables, that might lead to problems on some
|
|
implementations.
|
|
- Pass the headers using quote
|
|
- As '(...) and not (list...)
|
|
- Pass the options using quote
|
|
- As '(...) and not (list...)
|
|
|
|
(**define-c-procedure** _scheme-name_ _shared-object_ _c-name_ _return-type_
|
|
_argument-type_)
|
|
|
|
Takes a scheme-name to bind the C procedure to, shared-object where the function
|
|
is looked from, c-name of the function as symbol, return-type and argument-types.
|
|
|
|
Defines a new foreign function to be used from Scheme code.
|
|
|
|
|
|
Example:
|
|
|
|
(cond-expand
|
|
(windows (define-c-library libc-stdlib '("stdlib.h") "ucrtbase" '()))
|
|
(else (define-c-library libc-stdlib '("stdlib.h") "c" '("6"))))
|
|
(define-c-procedure c-puts libc-stdlib 'puts 'int '(pointer))
|
|
(c-puts "Message brought to you by foreign-c!")
|
|
|
|
#### Notes
|
|
|
|
- Pass the return-types using quote
|
|
- As '(...) and not (list...)
|
|
|
|
(**c-bytevector?** _obj_)
|
|
|
|
Returns **#t** if _obj_ is c-bytevector, otherwise returns **#f**.
|
|
|
|
(**c-bytevector-u8-set!** _c-bytevector_ _k_ _byte_)
|
|
|
|
If K is not a valid index of c-bytevector the behaviour is undefined.
|
|
|
|
Stores the byte in element k of c-bytevector.
|
|
|
|
(**c-bytevector-u8-ref** _c-bytevector_ _k_)
|
|
|
|
If K is not a valid index of c-bytevector the behaviour is undefined.
|
|
|
|
Returns the byte at index k of c-bytevector.
|
|
|
|
(**c-bytevector-pointer-set!** _c-bytevector_ _k_ _pointer_)
|
|
|
|
If K is not a valid index of c-bytevector the behaviour is undefined.
|
|
|
|
Stores the pointer(which is also c-bytevector) in element k of c-bytevector.
|
|
|
|
(**c-bytevector-pointer-ref** _c-bytevector_ _k_ _pointer_)
|
|
|
|
If K is not a valid index of c-bytevector the behaviour is undefined.
|
|
|
|
Returns the pointer(which is also c-bytevector) at index k of c-bytevector.
|
|
|
|
### Primitives 2
|
|
(**define-c-callback** _scheme-name_ _return-type_ _argument-types_ _procedure_)
|
|
|
|
Takes scheme-name to bind the Scheme procedure to, return-type, argument-types
|
|
and procedure as in place lambda.
|
|
|
|
Defines a new Sceme function to be used as callback to C code.
|
|
|
|
Example:
|
|
|
|
; Load the shared library
|
|
(cond-expand
|
|
(windows (define-c-library libc-stdlib '("stdlib.h") "ucrtbase" '()))
|
|
(else (define-c-library '("stdlib.h") "c" '("" "6"))))
|
|
|
|
; Define C function that takes a callback
|
|
(define-c-procedure qsort libc-stdlib 'qsort 'void '(pointer int int callback))
|
|
|
|
; Define our callback
|
|
(pffi-define-callback compare
|
|
'int
|
|
'(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 (make-c-bytevector (* (c-size-of 'int) 3)))
|
|
(pffi-pointer-set! array 'int (* (c-size-of 'int) 0) 3)
|
|
(pffi-pointer-set! array 'int (* (c-size-of 'int) 1) 2)
|
|
(pffi-pointer-set! array 'int (* (c-size-of 'int) 2) 1)
|
|
|
|
(display array)
|
|
(newline)
|
|
;> (3 2 1)
|
|
|
|
; Sort the array
|
|
(qsort array 3 (c-size-of 'int) compare)
|
|
|
|
(display array)
|
|
(newline)
|
|
;> (1 2 3)
|
|
|
|
### c-bytevector
|
|
|
|
(**make-c-bytevector** _k_)
|
|
(**make-c-bytevector** _k_ _fill_)
|
|
|
|
Returns a newly allocated c-bytevector of _k_ bytes.
|
|
|
|
If the _fill_ argument is missing, the initial contents of the
|
|
returned c-bytevector are unspecified.
|
|
|
|
If the _fill_ argument is present, it's value must confine to C uint8_t values
|
|
, it specifies the initial value for the bytes of the c-bytevector
|
|
|
|
(**make-c-null**)
|
|
|
|
Returns a null C pointer.
|
|
|
|
(**c-null?** _obj_)
|
|
|
|
Returns **#t** if _obj_ is a null C pointer, otherwise returns **#f**.
|
|
|
|
(**c-free** _c-bytevector_)
|
|
|
|
Frees _c-bytevector_ from memory.
|
|
|
|
native-endianness
|
|
c-bytevector-s8-set!
|
|
c-bytevector-s8-ref
|
|
c-bytevector-s16-set!
|
|
c-bytevector-s16-ref
|
|
c-bytevector-s16-native-set!
|
|
c-bytevector-s16-native-ref
|
|
c-bytevector-u16-set!
|
|
c-bytevector-u16-ref
|
|
c-bytevector-u16-native-set!
|
|
c-bytevector-u16-native-ref
|
|
c-bytevector-s32-set!
|
|
c-bytevector-s32-ref
|
|
c-bytevector-s32-native-set!
|
|
c-bytevector-s32-native-ref
|
|
c-bytevector-u32-set!
|
|
c-bytevector-u32-ref
|
|
c-bytevector-u32-native-set!
|
|
c-bytevector-u32-native-ref
|
|
c-bytevector-s64-set!
|
|
c-bytevector-s64-ref
|
|
c-bytevector-s64-native-set!
|
|
c-bytevector-s64-native-ref
|
|
c-bytevector-u64-set!
|
|
c-bytevector-u64-ref
|
|
c-bytevector-u64-native-set!
|
|
c-bytevector-u64-native-ref
|
|
c-bytevector-sint-set!
|
|
c-bytevector-sint-ref
|
|
c-bytevector-uint-set!
|
|
c-bytevector-uint-ref
|
|
c-bytevector-ieee-single-set!
|
|
c-bytevector-ieee-single-native-set!
|
|
c-bytevector-ieee-single-ref
|
|
c-bytevector-ieee-single-native-ref
|
|
c-bytevector-ieee-double-set!
|
|
c-bytevector-ieee-double-native-set!
|
|
c-bytevector-ieee-double-ref
|
|
c-bytevector-ieee-double-native-ref
|
|
bytevector->c-bytevector
|
|
c-bytevector->bytevector
|
|
call-with-address-of
|
|
|
|
string->c-utf8
|
|
c-utf8->string
|
|
|
|
### Environment variables
|
|
|
|
Setting environment variables like this on Windows works for this library:
|
|
|
|
set "PFFI_LOAD_PATH=C:\Program Files (x86)/foo/bar"
|
|
|
|
#### PFFI\_LOAD\_PATH
|
|
|
|
To add more paths to where pffi looks for libraries set PFFI\_LOAD\_PATH to
|
|
paths separated by ; on windows, and : on other operating systems.
|
|
|