(foreign c)

About

(foreign c) is a C foreign function interface (FFI) library for R6RS and R7RS Schemes

Repository

Supported implementations

R6RS is supported trough akku.

- Chez => 10.0.0
    - R6RS
- Chibi > 0.11
    - R7RS
    - Depends on libffi
- Chicken >= 6.0.0
    - R7RS
- Ikarus >= 0.0.4-rc1+
    - R6RS
- Ironscheme
    - R6RS
- Kawa >= 3.11 and Java >= 24
    - R7RS
    - Needs arguments to enable FFI
        - -J--add-exports=java.base/jdk.internal.foreign.abi=ALL-UNNAMED
        - -J--add-exports=java.base/jdk.internal.foreign.layout=ALL-UNNAMED
        - -J--add-exports=java.base/jdk.internal.foreign=ALL-UNNAMED
        - -J--enable-native-access=ALL-UNNAMED
    - All needed arguments on one line for copy pasting
        - -J--add-exports=java.base/jdk.internal.foreign.abi=ALL-UNNAMED -J--add-exports=java.base/jdk.internal.foreign.layout=ALL-UNNAMED -J--add-exports=java.base/jdk.internal.foreign=ALL-UNNAMED -J--enable-native-access=ALL-UNNAMED
    - So that snow-chibi installed library is found
        - -Dkawa.import.path=/usr/local/share/kawa/lib/*.sld
- Mosh
    - R7RS
- Racket >= 8.16 [cs]
    - R7RS
- Sagittarius >= 0.9.13
    - R6RS
    - R7RS
- STklos >= 26.0
    - R7RS
- Ypsilon >= 2.08
    - R7RS

Notes

- Do not cond-expand inside the arguments, that might lead to problems on some
  implementations.
- Do not store member names or types in variables, that might lead to problems
  on some implementations.
- Pass the members using quote
  - As '(...) and not (list ...)

C Libraries

(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 or #f and options. If shared-object name
is given as #f then platforms C library is used.

The C header strings should not contain "<" or ">", they are added
automatically. Pass them using ' and not (list ...).

The name of the shared object should not contain suffix like .so or .dll.
Nor should it contain any prefix like "lib".

Options:

- 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:

    (define-c-library libc '("stdio.h") #f '())

    (define-c-library libcurl
                      '("curl/curl.h")
                      "curl"
                      '((additional-versions ("" "0" "6"))
                        (additional-paths ("."))))

C Functions

(define-c-procedure scheme-name shared-object c-name return-type argument-types)

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:

    (define-c-library libc '("stdlib.h") #f '())
    (define-c-procedure c-puts libc 'puts 'int '(pointer))
    (c-puts "Message brought to you by foreign-c!")

Internal

(foreign-c-internal-make-c-bytevector pointer)

Internal procedure, do not use.

Environment variables

Setting environment variables like this on Windows works for this library:

    set "FOREIGN_C_LOAD_PATH=C:Program Files (x86)/foo/bar"

FOREIGN_C_LOAD_PATH

To add more paths to where foreign c looks for libraries set
FOREIGN_C_LOAD_PATH to paths separated by ; on windows, and : on other
operating systems.

C Callbacks

(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.

Callback utilities

pointer->c-bytevector

This procedure can be used inside the callback to make c-bytevector out of
C pointer.

Call with address of (C &)

(call-with-address-of cbv thunk)

Calls thunk with address c-bytevector of c-bytevector.

Since the support for calling C functions taking pointer address arguments,
ones prefixed with & in C, varies, some additional ceremony is needed on
the Scheme side.

Example:

Calling from C:

    //void func(int** i);
    func(&i);

Calling from Scheme:

    (define cbv (make-bytevector (c-type-size 'int)))
    (call-with-address-of
     cbv
     (lambda (address)
      (func address)))
    ; Use cbv here
The passed c-bytevector, in example named cbv, should only be used **after**
call to call-with-addres-of ends.

C pointers

c-bytevectors

(make-c-bytevector size . byte)

Returns a newly allocated c-bytevector of size 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 u8 values,
it specifies the initial value for the bytes of the c-bytevector.

If allocation fails, error is signaled.

Example:

(make-c-bytevector 128)

(make-c-bytevector 128 0)
Returns a newly allocated c-bytevector containing its arguments.

Example:

(c-bytevector 0 0 0 0)

(c-bytevector? obj)

Returns #t if obj is c-bytevector, otherwise returns #f.

(c-bytevector-free cbv ...)

Frees given c-bytevectors from memory.

(c-bytevector-null)

Returns a null c-bytevector.

(c-bytevector-null? cbv)

Returns #t if obj is a null c-bytevector, otherwise returns #f.

(c-bytevector-set! cbv type offset/member value)

Set value of given type on offset on bytevector bv. Offset is counted as
bytes for regular types.

When type is c-array-type offset is multiplied by the size of arrays type.

When type is c-struct-type type instead of offset give member name.

(c-bytevector-ref cbv type offset/member)

Get value of given type on offset on bytevector bv. Offset is counted as
bytes for regular types.

When type is c-array-type offset is multiplied by the size of arrays type.

When type is c-struct-type type instead of offset give member name.

(bytevector->c-bytevector bv)

Returns a newly allocated c-bytevector of the bytes of bytevector.

(c-bytevector->bytevector cbv size)

Returns a newly allocated bytevector of the bytes of c-bytevector.

Strings

(c-bytevector->string cbv)

Returns a newly allocated string whose character sequence is
encoded by the given c-bytevector. If c-bytevector is null empty string is
returned.

(string->c-bytevector str)

Returns a newly allocated (unless empty) c-bytevector that contains the
UTF-8 encoding of the given string.

(with-string->c-bytevector str thunk)

Calls thunk with newly allocated c-bytevector that contains the UTF-8 encoding
of the given string and frees it after thunk finishes.

(c-bytevector->integer cbv . offset)

Returns the address of the bytevector as integer. If offset is given it is
added to the the returned integer. Offset must be an integer.

(integer->c-bytevector address)

Returns the bytevector in the integer address.

null-byte

Null byte (0) you can use in strings.

C Types

(c-integer-type? type)

Returns #t if given type is C integer type, otherwise returns #f

Example:

(c-integer-type? 'i8)
> #t

(c-char-type? type)

Returns #t if given type is C char type, otherwise returns #f

Example:

(c-char-type? 'char)
> #t

(c-float-type? type)

Returns #t if given type is C float type, otherwise returns #f

Example:

(c-float-type? 'float)
> #t

(c-double-type? type)

Returns #t if given type is C double type, otherwise returns #f

Example:

(c-double-type? 'double)
> #t

(c-signed-type? type)

Returns #t if given type is C signed type, otherwise returns #f

Example:

(c-signed-type? 'i8)
> #t
(c-signed-type? 'u8)
> #f

(c-pointer-type? type)

Returns #t if given type is C pointer type, otherwise returns #f

Example:

(c-pointer-type? 'pointer)
> #t

Size

(c-type-size type)

Returns the size of given type.

Example:

(c-type-size 'i8)
> 1
(define-c-array-type items 'i8)
(c-type-size items)
> 1
(define-c-array-type color '((r u8) (g u8) (b u8)))
(c-type-size color)
> 3

(c-type-size+ . types)

Adds given types together and returns the result.

Example:

(c-type-size+ 'u8 'u8)
> 2

(c-type-size- . types)

Subtracts given types and returns the result.

Example:

(c-type-size- 'int 'u8)
> 3

(c-type-size/ type n)

Divides given type with n and retursn the result.

Example:

(c-type-size/ 'int 2)
> 2

(c-type-size* type n)

Multiplies given type with n and returns the result.

Example:

(c-type-size* 'int 10)
> 40

Alignment

(c-type-align type)

Returns the align of given type.

Example:

(c-type-align 'int)
> 4

(c-type-align+ . types)

Adds given aligns together and returns the result.

Example:

(c-type-align+ 'u8 'u8)
> 2

(c-type-align- . types)

Subtracts given aligns and returns the result.

Example:

(c-type-align- 'int 'u8)
> 3

(c-type-align* type n)

Multiples given align with n and returns the result.

Example:

(c-type-align* 'int 100)
> 400

(c-type-align/ type n)

Divides given align with n and retursn the result.

Example:

(c-type-align/ 'int 2)
> 2

Arrays

(c-array-type? type)

Returns #t if given type is C array type, otherwise returns #f Example:
(define-c-array-type items 'i8)
(c-integer-type? items)
> #t

(define-c-array-type name type)

Creates a new C array type that can be used when accessing c-bytevectors.
name is the name of the type and type is the type of items.

Example:

    (define-c-array-type i8-array 'i8)
    (define ar1 (make-c-bytevector (* (c-type-size i8-array) 10)))
    (c-bytevector-set! ar1 i8-array 5 25) ; Set the 5th item of array to 25
    (write (c-bytevector-ref ar1 i8-array 5))
    > 25

Structs

(c-struct-type? type)

Returns #t if given type is C array type, otherwise returns #f
Example:

(define-c-struct-type color '((r u8) (g u8) (b u8)))
(c-struct-type? color)
> #t

(define-c-struct-type name members)

Creates a new C struct type that can be used when accessing c-bytevectors.
name is the name of the type and members is a list of member names and types.

Example:

    (define-c-struct-type color '((r i8) (g i8) (b i8) (a i8)))

    (define green (make-c-bytevector (c-type-size color)))
    (c-bytevector-set! green color 'r 1)
    (c-bytevector-set! green color 'g 2)
    (c-bytevector-set! green color 'b 3)
    (c-bytevector-set! green color 'a 4)

    (display (c-bytevector-ref green color 'g))
    > 2

(struct->list cbv type)

Creates an association list from given struct type and c-bytevector.