diff --git a/Makefile b/Makefile index 0cacdd7..1c2a799 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,23 @@ -.PHONY=libtest.o libtest.so libtest.a +.PHONY=libtest.o libtest.so libtest.a documentation CC=gcc DOCKER=docker run -it -v ${PWD}:/workdir DOCKER_INIT=cd /workdir && make clean && all: chibi gauche libtest.so libtest.o libtest.a +# apt-get install pandoc weasyprint +docs: + mkdir -p documentation + pandoc --standalone \ + --template templates/documentation.html README.md \ + > documentation/R7RS-PFFI.html + #pandoc -s --pdf-engine=weasyprint -o documentation/R7RS-PFFI.pdf README.md + pandoc -t html5 \ + --pdf-engine=weasyprint \ + --css templates/css/pdf-documentation.css \ + -o documentation/R7RS-PFFI.pdf \ + README.md + chibi: chibi-ffi src/chibi/pffi.stub ${CC} -g3 -o retropikzel/pffi/chibi-pffi.so \ @@ -46,7 +59,8 @@ test-compile-library: libtest.so libtest.a libtest.o SCHEME=${SCHEME} compile-r7rs-library retropikzel/pffi.sld test-compile: test-compile-library - SCHEME=${SCHEME} CFLAGS="-I./include" LDFLAGS="-ltest" compile-r7rs -I . test.scm && ./test + SCHEME=${SCHEME} CFLAGS="-I./include -L." LDFLAGS="-ltest libtest.o" compile-r7rs -I . test.scm + ./test test-compile-docker: libtest.so libtest.a docker build -f dockerfiles/test . --build-arg SCHEME=${SCHEME} --tag=pffi-${SCHEME} diff --git a/README.md b/README.md index 9b1cc65..9dc52c1 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,12 @@ -# Portable Foreign Function Interface for R7RS schemes +--- +title: Portable Foreign Function Interface for R7RS Documentation +--- -Foreign function interface that is supported on multiple R7RS Sceheme implementations. +# Portable Foreign Function Interface for R7RS -Any help in form of constructive advice and bug reports are appreciated. +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](https://todo.sr.ht/~retropikzel/r7rs-pffi) @@ -14,44 +18,55 @@ Any help in form of constructive advice and bug reports are appreciated. ## Table of contents + + +
## Goals + - Support only R7RS implementations - Same interface on all implementations @@ -60,6 +75,7 @@ Any help in form of constructive advice and bug reports are appreciated. - Stability and being boring after 1.0.0 is reached ## Non goals + - To have every possible FFI feature - Compiling of used library C code at any point @@ -67,6 +83,7 @@ Any help in form of constructive advice and bug reports are appreciated. - The pffi library itself may require compilation on installation ## 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. @@ -76,16 +93,20 @@ different stage. As a whole it is still in **alpha** stage. That said the interf changing anymore and some implementations are in **beta**. ### Current caveats + - No way to pass structs by value - Most implementations are missing callback support ## 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 | @@ -93,10 +114,12 @@ changing anymore and some implementations are in **beta**. | 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 | | | @@ -109,6 +132,7 @@ changing anymore and some implementations are in **beta**. | Ypsilon | | | | | | | | | | | | | | | X | X | X | X | X | | | ### Not started + - [LIPS](https://lips.js.org/) - Will work on nodejs by using some C FFI library from npm @@ -130,6 +154,7 @@ changing anymore and some implementations are in **beta**. - Need to study the implementation more ### Other + - [s7](https://scheme.fail://ccrma.stanford.edu/software/snd/snd/s7.html) - Propably does not need FFI as it is embeddable only @@ -137,10 +162,13 @@ changing anymore and some implementations are in **beta**. - Desires no C interop, I can respect that ## Documentation + -### Usage +### Usage + -#### Chibi +#### Chibi + Needs libffi-dev, on Debina/Ubuntu/Mint install with: @@ -151,19 +179,22 @@ Build with: chibi-ffi retropikzel/r7rs-pffi/r7rs-pffi-chibi.stub gcc -o retropikzel/r7rs-pffi/r7rs-pffi-chibi.so -fPIC -shared retropikzel/r7rs-pffi/r7rs-pffi-chibi.c -lchibi-scheme -lffi -#### Chicken +#### Chicken + Needs [r7rs egg](https://wiki.call-cc.org/eggref/5/r7rs), install with: chicken-install r7rs -#### Racket +#### Racket + Needs [racket-r7rs](https://github.com/lexi-lambda/racket-r7rs), install with: raco pkg install --auto r7rs -#### Kawa +#### Kawa + Kawa Needs at least Java version 22 @@ -175,8 +206,10 @@ Needs jvm flags: - --enable-native-access=ALL-UNNAMED ### Reference + #### Types + Types are given as symbols, for example 'int8 or 'pointer. @@ -203,23 +236,28 @@ Types are given as symbols, for example 'int8 or 'pointer. - Callback function #### Procedures and macros + Some of these are procedures and some macros, it might also change implementation to implementation. ##### **pffi-init** + Always call this first, on most implementation it does nothing but some implementations might need initialisation run. ##### **pffi-size-of** object -> number + Returns the size of the pffi-struct, pffi-enum or pffi-type. ##### **pffi-align-of** type -> number + Returns the align of the type. ##### **pffi-shared-object-auto-load** headers shared-object-name [options] -> object + Load given shared object automatically searching many predefined paths. @@ -249,6 +287,7 @@ Example: ##### **pffi-shared-object-load** headers path [options] + It is recommended to use the pffi-shared-object-auto-load instead of this directly. @@ -268,26 +307,37 @@ Options: - List of different versions of library to try, for example (list ".0" ".1") ##### **pffi-pointer-null** -> pointer + Returns a new NULL pointer. ##### **pffi-pointer-null?** pointer -> boolean + Returns #t if given pointer is null pointer, #f otherwise. ##### **pffi-pointer-allocate** size -> pointer + Returns newly allocated pointer of given size. +##### **pffi-pointer-address** pointer -> number + + +Returns the address of given pointer as number. + ##### **pffi-pointer?** object -> boolean + Returns #t if given object is pointer, #f otherwise. ##### **pffi-pointer-free** pointer + Frees given pointer. ##### **pffi-pointer-set!** pointer type offset value + Sets the value on a pointer on given offset. For example: @@ -297,6 +347,7 @@ Sets the value on a pointer on given offset. For example: Would set the offset of 64, on pointer p to value 100. ##### **pffi-pointer-get** pointer type offset -> object + Gets the value from a pointer on given offset. For example: @@ -306,14 +357,17 @@ Gets the value from a pointer on given offset. For example: > 100 ##### **pffi-string->pointer** string -> pointer + Makes pointer out of a given string. ##### **pffi-pointer->string** pointer -> string + Makes string out of a given pointer. ##### **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: @@ -324,6 +378,7 @@ names and types. For example: C-type argument can be symbol or a string. ##### **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. @@ -332,19 +387,23 @@ a pointer to foreign functions. (pffi-struct-pointer s) ##### **pffi-struct-offset-get** member-name -> number + Returns the offset of a struct member with given name. ##### **pffi-struct-get** pffi-struct member-name -> object + Returns the value of the givens struct member. ##### **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** scheme-name shared-object c-name return-type argument-types + Defines a new foreign function to be used from Scheme code. For example: @@ -356,6 +415,7 @@ Defines a new foreign function to be used from Scheme code. For example: (c-puts "Message brought to you by FFI!") ##### **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: @@ -395,3 +455,5 @@ Defines a new Sceme function to be used as callback to C code. For example: (display array) (newline) ;> (1 2 3) + +
diff --git a/documentation/R7RS-PFFI.html b/documentation/R7RS-PFFI.html new file mode 100644 index 0000000..b8a7187 --- /dev/null +++ b/documentation/R7RS-PFFI.html @@ -0,0 +1,980 @@ + + + + + + Portable Foreign Function Interface for R7RS +Documentation + + + +

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-initpffi-size-ofpffi-shared-object-auto-loadpffi-shared-object-loadpffi-pointer-nullpffi-pointer-null?pffi-pointer-allocatepffi-pointer-addresspffi-pointer?pffi-pointer-freepffi-pointer-set!pffi-pointer-getpffi-string->pointerpffi-pointer->stringpffi-struct-makepffi-struct-pointerpffi-struct-offset-getpffi-struct-getpffi-struct-set!pffi-definepffi-define-callback
ChibiXXXXXXXXXXXXXXXXXXXX
GaucheXXXXXXXXXXXXXXXXXXX
GuileXXXXXXXXXXXXXXXXXXXX
KawaXXXXXXXXXXXXXXXXXXXX
RacketXXXXXXXXXXXXXXXXXXXX
SaggittariusXXXXXXXXXXXXXXXXXXXX
+

Alpha

+

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
pffi-initpffi-size-ofpffi-shared-object-auto-loadpffi-shared-object-loadpffi-pointer-nullpffi-pointer-null?pffi-pointer-allocatepffi-pointer-addresspffi-pointer?pffi-pointer-freepffi-pointer-set!pffi-pointer-getpffi-string->pointerpffi-pointer->stringpffi-struct-makepffi-struct-pointerpffi-struct-offset-getpffi-struct-getpffi-struct-set!pffi-definepffi-define-callback
Chicken-5XXXXXXXXXXXXXXXXXXXX
CycloneXXXXXXXXXXXXXXXXXXX
GambitXXXXXXXX
GerbilXXXXXX
LarcenyXXXXXX
MoshXXXXXXXXXXXXXXXXXXXX
SkintXXXXXX
StklosXXXXXXXXXXXXXX
tr7XXXXX
YpsilonXXXXX
+

Not started

+

+ +

Other

+

+ +

Documentation

+

+

Usage

+

+

Chibi

+

+

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

+
apt install libffi-dev
+

Build with:

+
chibi-ffi retropikzel/r7rs-pffi/r7rs-pffi-chibi.stub
+gcc -o retropikzel/r7rs-pffi/r7rs-pffi-chibi.so -fPIC -shared retropikzel/r7rs-pffi/r7rs-pffi-chibi.c -lchibi-scheme -lffi
+

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
+

+

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

+
pffi-size-of + object -> number
+

+

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

+
pffi-align-of + type -> number
+

+

Returns the align of the type.

+
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 + 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 + -> pointer
+

+

Returns a new NULL pointer.

+
pffi-pointer-null? + pointer -> boolean
+

+

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

+
pffi-pointer-allocate + size -> pointer
+

+

Returns newly allocated pointer of given size.

+
pffi-pointer-address + pointer -> number
+

+

Returns the address of given pointer as number.

+
pffi-pointer? + object -> boolean
+

+

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

+
pffi-pointer-free + pointer
+

+

Frees given pointer.

+
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 + 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 + string -> pointer
+

+

Makes pointer out of a given string.

+
pffi-pointer->string + pointer -> string
+

+

Makes string out of a given pointer.

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

+

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 + member-name -> number
+

+

Returns the offset of a struct member with given name.

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

+

Returns the value of the givens struct member.

+
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 + 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 + 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)
+
+ + diff --git a/documentation/R7RS-PFFI.pdf b/documentation/R7RS-PFFI.pdf new file mode 100644 index 0000000..0e0b6e0 Binary files /dev/null and b/documentation/R7RS-PFFI.pdf differ diff --git a/templates/css/pdf-documentation.css b/templates/css/pdf-documentation.css new file mode 100644 index 0000000..4ffab09 --- /dev/null +++ b/templates/css/pdf-documentation.css @@ -0,0 +1,2 @@ +h5 { font-weight: normal; } +pre { background-color: lightgrey; } diff --git a/templates/documentation.html b/templates/documentation.html new file mode 100644 index 0000000..1ba4835 --- /dev/null +++ b/templates/documentation.html @@ -0,0 +1,18 @@ + + + + + + $title$ + + + + $body$ + +