diff --git a/.gitignore b/.gitignore index bc23064..136cac5 100644 --- a/.gitignore +++ b/.gitignore @@ -47,3 +47,6 @@ snow foreign/c/lib !foreign/c/primitives/gauche/*.c !foreign/c/primitives/include/*.h +README.html +*.tgz +*.tar.gz diff --git a/Makefile b/Makefile index b33ab30..df63ae1 100644 --- a/Makefile +++ b/Makefile @@ -2,10 +2,30 @@ CC=gcc DOCKER=docker run -it -v ${PWD}:/workdir DOCKER_INIT=cd /workdir && make clean && -VERSION=$(shell grep "version:" README.md | awk '{split\($0,a\); print a[2];}') +VERSION=$(shell awk '/version:/{ print $$2 }' README.md ) TESTNAME=primitives -all: chibi chicken cyclone gambit gauche gerbil guile kawa larceny mosh racket sagittarius skint stklos tr7 ypsilon +chibi: foreign/c/primitives/chibi/foreign-c.stub + chibi-ffi foreign/c/primitives/chibi/foreign-c.stub + ${CC} \ + -g3 \ + -o foreign/c/primitives/chibi/foreign-c.so \ + foreign/c/primitives/chibi/foreign-c.c \ + -fPIC \ + -lffi \ + -shared + +package: + markdown README.md > README.html + snow-chibi package \ + --version=${VERSION} \ + --authors="Retropikzel" \ + --doc=README.html \ + --description="Portable foreign function interface for R7RS Schemes" \ + foreign/c.sld + +clean-package: + rm -rf *.tgz test-compile-r7rs: tmp/test/libtest.o tmp/test/libtest.so tmp/test/libtest.a make ${COMPILE_R7RS} @@ -46,6 +66,7 @@ tmp/test/libtest.so: tests/c-src/libtest.c tmp/test/libtest.a: tmp/test/libtest.o tests/c-src/libtest.c ar rcs tmp/test/libtest.a tmp/test/libtest.o +documentation/foreign-c.html: # apt-get install pandoc weasyprint docs: @@ -59,54 +80,6 @@ docs: -o documentation/foreign-c.pdf \ README.md -chibi: - make -C foreign/c chibi - -chicken: - make -C foreign/c chicken - -cyclone: - make -C foreign/c cyclone - -gambit: - make -C foreign/c gambit - -gauche: - make -C foreign/c gauche - -gerbil: - make -C foreign/c gerbil - -guile: - make -C foreign/c guile - -kawa: - make -C foreign/c kawa - -larceny: - make -C foreign/c larceny - -mosh: - make -C foreign/c mosh - -racket: - make -C foreign/c racket - -sagittarius: - make -C foreign/c sagittarius - -skint: - make -C foreign/c skint - -stklos: - make -C foreign/c stklos - -tr7: - make -C foreign/c tr7 - -ypsilon: - make -C foreign/c tr7 - clean: find . -name "*.meta" -delete find . -name "*.link" -delete diff --git a/documentation/foreign-c.html b/documentation/foreign-c.html index b37ec65..e69de29 100644 --- a/documentation/foreign-c.html +++ b/documentation/foreign-c.html @@ -1,800 +0,0 @@ - - -
- -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.
- - - -| - | 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:
-(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 ("."))))))
- (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!")
- (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.
-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/foreign/c.sld b/foreign/c.sld index 7fba2be..70941aa 100644 --- a/foreign/c.sld +++ b/foreign/c.sld @@ -10,7 +10,7 @@ (chibi ast) (scheme inexact) (chibi)) - (include-shared "c/lib/chibi")) + (include-shared "c/primitives/chibi/foreign-c")) (chicken (import (scheme base) (scheme write) diff --git a/foreign/c/Makefile b/foreign/c/Makefile index 3837c23..3d4d0e2 100644 --- a/foreign/c/Makefile +++ b/foreign/c/Makefile @@ -1,9 +1,14 @@ CC=gcc -chibi: primitives/chibi/foreign-c.stub - chibi-ffi primitives/chibi/foreign-c.stub - mkdir -p lib - ${CC} -g3 -o lib/chibi.so primitives/chibi/foreign-c.c -fPIC -lffi -shared +chibi: foreign/c/primitives/chibi/foreign-c.stub + chibi-ffi foreign/c/primitives/chibi/foreign-c.stub + ${CC} \ + -g3 \ + -o foreign/c/primitives/chibi/foreign-c.so \ + foreign/c/primitives/chibi/foreign-c.c \ + -fPIC \ + -lffi \ + -shared chicken: @echo "Nothing to build for Chicken" diff --git a/tests/hello.scm b/tests/hello.scm new file mode 100644 index 0000000..02d72be --- /dev/null +++ b/tests/hello.scm @@ -0,0 +1,32 @@ +(import (scheme base) + (scheme write) + (foreign c)) + + +(cond-expand + (windows (define-c-library c-stdlib + '("stdlib.h") + "ucrtbase" + '())) + (else (define-c-library c-stdlib + '("stdlib.h") + "c" + '((additional-versions ("6")))))) + +(define-c-procedure c-system c-stdlib 'system 'int '(pointer)) + +(define (anything->string item) + (parameterize + ((current-output-port (open-output-string))) + (display item) + (get-output-string (current-output-port)))) + +(define (system command) + (c-system (string->c-utf8 + (apply string-append + (map (lambda (item) + (string-append (anything->string item) " ")) + command))))) + +(system '(ls)) +