diff --git a/Makefile b/Makefile index 57eebd1..1801621 100644 --- a/Makefile +++ b/Makefile @@ -5,18 +5,15 @@ DOCKER_INIT=cd /workdir && make clean && VERSION=$(shell awk '/version:/{ print $$2 }' README.md ) TESTNAME=primitives -package: README.html +package: docs snow-chibi package \ --version=${VERSION} \ --authors="Retropikzel" \ - --doc=README.html \ + --doc=documentation/foreign-c.html \ --foreign-depends=ffi \ --description="Portable foreign function interface for R7RS Schemes" \ foreign/c.sld -README.html: - markdown README.md > README.html - clean-package: rm -rf *.tgz diff --git a/dockerfiles/Dockerfile.snow-chibi-install-test b/dockerfiles/Dockerfile.snow-chibi-install-test index 2c88e11..e7d38af 100644 --- a/dockerfiles/Dockerfile.snow-chibi-install-test +++ b/dockerfiles/Dockerfile.snow-chibi-install-test @@ -11,7 +11,9 @@ RUN apt-get update && apt-get install -y \ build-essential \ libffi-dev \ libmbedtls-dev \ - markdown + markdown \ + pandoc \ + weasyprint RUN git clone https://github.com/Retropikzel/chibi-scheme.git --branch=snow-chibi-foreign-depends RUN cd chibi-scheme && make && make install RUN chicken-install r7rs diff --git a/documentation/foreign-c.html b/documentation/foreign-c.html index e69de29..5a94dc3 100644 --- a/documentation/foreign-c.html +++ b/documentation/foreign-c.html @@ -0,0 +1,814 @@ + + +
+ +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.
+ + + +Required versions:
+| + | c-type-size | +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 | +
| + | define-c-callback | +
|---|---|
| Chibi | ++ |
| Chicken | +X | +
| Gauche | ++ |
| Guile | +X | +
| Kawa | ++ |
| Mosh | +X | +
| Racket | +X | +
| Saggittarius | +X | +
| STklos | ++ |
| Ypsilon | +X | +
| + | 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 | ++ |
Eithe download the latest release from https://git.sr.ht/~retropikzel/foreign-c/refs + or git clone, preferably with a tag, and copy the + foreign directory to your library directory.
+Example assuming libraries in directory snow:
+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.”
+Types are given as symbols, for example ’int8 or + ’pointer.
+(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”.
+Options:
+Example:
+(define-c-library libc
+ (list "stdlib.h")
+ "c"
+ '((additional-versions ("" "0" "6"))
+ (additional-paths ("."))))
+ Note that libc is exported by this library so you might not + need to load it.
+(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.h") "ucrtbase" '()))
+ (else (define-c-library libc '("stdlib.h") "c" '("6"))))
+(define-c-procedure c-puts libc 'puts 'int '(pointer))
+(c-puts "Message brought to you by foreign-c!")
+ (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.
+(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
+(define-c-callback compare
+ 'int
+ '(pointer pointer)
+ (lambda (pointer-a pointer-b)
+ (let ((a (c-bytevector-sint-get pointer-a (native-endianness) 0))
+ (b (c-bytevector-sint-get pointer-b (native-endianness) 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-type-size 'int) 3)))
+(c-bytevector-s32-native-set! array (* (c-type-size 'int) 0) 3)
+(c-bytevector-s32-native-set! array (* (c-type-size 'int) 1) 2)
+(c-bytevector-s32-native-set! array (* (c-type-size 'int) 2) 1)
+
+(display array)
+(newline)
+;> (3 2 1)
+
+; Sort the array
+(qsort array 3 (c-type-size 'int) compare)
+
+(display array)
+(newline)
+;> (1 2 3)
+ Foreign-c c-bytevector interface is copied from R6RS + bytevectors, with some added functionality for C null pointers + and manual memory management.
+(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.
+(call-with-address-of c-bytevector + thunk)
+Calls thunk with address pointer of + c-bytevector.
+Since the support for calling C functions taking pointer + address arguments, ones prefixrd 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.
+(bytevector->c-bytevector + bytevector)
+Returns a newly allocated c-bytevector of the bytes of + bytevector.
+(c-bytevector->bytevector)
+Returns a newly allocated bytevector of the bytes of + c-bytevector.
+(native-endianness)
+Returns the endianness symbol associated implementation’s + preferred endianness (usually that of the underlying machine + architecture). This may be any <endianness symbol>, + including a symbol other than big and little.
+(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
+(c-bytevector-s8-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-s8-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-char-set! + c-bytevector k char)
+If k is not a valid index of c-bytevector the + behaviour is undefined.
+Stores the char in element k of + c-bytevector.
+(c-bytevector-char-ref c-bytevector + k)
+If k is not a valid index of c-bytevector the + behaviour is undefined.
+Returns the char at index k of + c-bytevector.
+(c-bytevector-uchar-set! + c-bytevector k char)
+If k is not a valid index of c-bytevector the + behaviour is undefined.
+Stores the unsigned char in element k of + c-bytevector.
+(c-bytevector-uchar-ref + c-bytevector k)
+If k is not a valid index of c-bytevector the + behaviour is undefined.
+Returns the unsigned char at index k of + c-bytevector.
+(c-bytevector-uint-ref c-bytevector + k endianness size) + (c-bytevector-sint-ref c-bytevector + k endianness size) + (c-bytevector-uint-set! c-bytevector + k n endianness size) + (c-bytevector-sint-set! c-bytevector + k n endianness size)
+Size must be a positive exact integer object. If + k,…,k + size − 1 is not valid indices + of c-bytevector the behavior is unspecified.
+The c-bytevector-uint-ref procedure retrieves the exact + integer object corresponding to the unsigned representation of + size size and specified by endianness at + indices k,…,k + size − 1.
+The c-bytevector-sint-ref procedure retrieves the exact + integer object corresponding to the two’s-complement + representation of size size and specified by + endianness at indices k,…,k + + size − 1. For c-bytevector-uint-set!, n must + be an exact integer object in the interval + {0,…,256^size − 1}.
+The c-bytevector-uint-set! procedure stores the unsigned + representation of size size and specified by + endianness into c-bytevector at indices + k,…,k + size − 1.
+The . . . -set! procedures return unspecified values.
+Examples:
+(define cbv (make-c-bytevector (c-type-size 'int)))
+(c-bytevector-sint-set! cbv 0 100 (native-endianness) (c-type-size 'int))
+(c-bytevector-sint-ref cbv 0 (native-endianness) (c-type-size 'int))
+> 100
+ (c-bytevector-u16-ref c-bytevector + k endianness) + (c-bytevector-s16-ref c-bytevector + k endianness) + (c-bytevector-u16-native-ref + c-bytevector k) + (c-bytevector-s16-native-ref + c-bytevector k) + (c-bytevector-u16-set! c-bytevector + k n endianness) + (c-bytevector-s16-set! c-bytevector + k n endianness) + (c-bytevector-u16-native-set! + c-bytevector k n) + (c-bytevector-s16-native-set! + c-bytevector k n)
+K must be a valid index of c-bytevector ; + so must k + 1. For c-bytevector-u16-set! and + c-bytevector-u16-native-set!, n must be an exact + integer object in the interval {0,…,216 − 1}. For + c-bytevector-s16-set! and c-bytevector-s16-native-set!, + n must be an exact integer object in the interval + {−215,…,215 − 1}.
+These retrieve and set two-byte representations of numbers at + indices k and k + 1, according to the + endianness specified by endianness. The procedures with + u16 in their names deal with the unsigned representation; those + with s16 in their names deal with the two’s-complement + representation.
+The procedures with native in their names employ the native + endianness, and work only at aligned indices: k must be + a multiple of 2.
+The …-set! procedures return unspecified values.
+(c-bytevector-u32-ref c-bytevector + k endianness) + (c-bytevector-s32-ref c-bytevector + k endianness) + (c-bytevector-u32-native-ref + c-bytevector k) + (c-bytevector-s32-native-ref + c-bytevector k) + (c-bytevector-u32-set! c-bytevector + k n endianness) + (c-bytevector-s32-set! c-bytevector + k n endianness) + (c-bytevector-u32-native-set! + c-bytevector k n) + (c-bytevector-s32-native-set! + c-bytevector k n)
+K,…,k + 3 must be valid indices of + bytevector. For c-bytevector-u32-set! and + bytevector-u32-native-set!, n must be an exact integer + object in the interval {0,…,232 − 1}. For bytevector-s32-set! + and bytevector-s32-native-set!, n must be an exact + integer object in the interval {−231,…,232 − 1}.
+These retrieve and set four-byte representations of numbers + at indices k,…,k + 3, according to the + endianness specified by endianness. The procedures with + u32 in their names deal with the unsigned representation; those + with s32 with the two’s-complement representation.
+The procedures with native in their names employ the native + endianness, and work only at aligned indices: k must be + a multiple of 4.
+The …-set! procedures return unspecified values.
+(c-bytevector-u64-ref c-bytevector + k endianness) + (c-bytevector-s64-ref c-bytevector + k endianness) + (c-bytevector-u64-native-ref + c-bytevector k) + (c-bytevector-s64-native-ref + c-bytevector k) + (c-bytevector-u64-set! c-bytevector + k n endianness) + (c-bytevector-s64-set! c-bytevector + k n endianness) + (c-bytevector-u64-native-set! + c-bytevector k n) + (c-bytevector-s64-native-set! + c-bytevector k n)
+K,…,k + 7 must be valid indices of + c-bytevector. For c-bytevector-u64-set! and + c-bytevector-u64-native-set!, n must be an exact + integer object in the interval {0,…,264 − 1}. For + c-bytevector-s64-set! and c-bytevector-s64-native-set!, + n must be an exact integer object in the interval + {−263,…,264 − 1}.
+These retrieve and set eight-byte representations of numbers + at indices k,…,k + 7, according to the + endianness specified by endianness. The procedures with + u64 in their names deal with the unsigned representation; those + with s64 with the two’s-complement representation.
+The procedures with native in their names employ the native + endianness, and work only at aligned indices: k must be + a multiple of 8.
+The …-set! procedures return unspecified values.
+(c-bytevector-ieee-single-native-ref) + (c-bytevector-ieee-single-ref)
+K,…,k + 3 must be valid indices of + c-bytevector. For c-bytevector-ieee-single-native-ref, + k must be a multiple of 4.
+These procedures return the inexact real number object that + best represents the IEEE-754 single-precision number represented + by the four bytes beginning at index k.
+(c-bytevector-ieee-double-native-ref) + (c-bytevector-ieee-double-ref)
+K,…,k + 7 must be valid indices of + c-bytevector. For c-bytevector-ieee-double-native-ref, + k must be a multiple of 8.
+These procedures return the inexact real number object that + best represents the IEEE-754 double-precision number represented + by the eight bytes beginning at index k.
+(c-bytevector-ieee-single-native-set!) + (c-bytevector-ieee-single-set!)
+K,…,k + 3 must be valid indices of + c-bytevector. For c-bytevector-ieee-single-native-set!, + k must be a multiple of 4.
+These procedures store an IEEE-754 single-precision + representation of x into elements k through k + + 3 of bytevector, and return unspecified values.
+(c-bytevector-ieee-double-native-set!) + (c-bytevector-ieee-double-set!)
+K,…,k + 7 must be valid indices of + bytevector. For c-bytevector-ieee-double-native-set!, k + must be a multiple of 8.
+These procedures store an IEEE-754 double-precision + representation of x into elements k through k + + 7 of bytevector, andreturn unspecified values.
+(string->c-utf8 string)
+Returns a newly allocated (unless empty) c-bytevector that + contains the UTF-8 encoding of the given string.
+(c-utf8->string + c-bytevector)
+Returns a newly allocated (unless empty) string whose + character sequence is encoded by the given c-bytevector.
+libc
+Since the library uses C standard internally, and that is + most likely library to have different name on different + operating systems. For example libc.so on Linux, ucrtbase.dll on + windows and libroot.so on Haiku. It makes sense to export it, + saving the users the trouble of figuring out which named shared + library they should load.
+See foreign/c/libc.scm to see which headers are included and + what shared libraries are loaded.
+Example:
+(define-c-procedure c-puts libc 'puts 'int '(pointer))
+(c-puts "Message brought to you by foreign-c!")
+ Setting environment variables like this on Windows works for + this library:
+set "FOREIGN_C_LOAD_PATH=C:\Program Files (x86)/foo/bar"
+ 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.
+ + diff --git a/documentation/foreign-c.pdf b/documentation/foreign-c.pdf index f73fb68..ace1c8b 100644 Binary files a/documentation/foreign-c.pdf and b/documentation/foreign-c.pdf differ diff --git a/foreign/c/primitives/chibi/foreign-c.stub b/foreign/c/primitives/chibi/foreign-c.stub index 1579a81..bde411e 100644 --- a/foreign/c/primitives/chibi/foreign-c.stub +++ b/foreign/c/primitives/chibi/foreign-c.stub @@ -1,5 +1,7 @@ ; vim: ft=scheme +(c-link "ffi") + (c-system-include "stdint.h") (c-system-include "dlfcn.h") (c-system-include "stdio.h")