Gambit Scheme Foreign function Interface (FFI)
Sun Jul 04 00:00:00 UTC 2021
Calling C functions from Gambit Scheme
lib.c int inc (int x){
return x+1;
}
s.scm
(c-declare "extern int inc ();") ;;c functions must be declared
(define inc (c-lambda (int) int "inc")) ;;function implemented in C code
(pp (map inc '(1 2 3 4)))
Compile as follows
% gsc -c s.scm
% gsc -link s.c
% gsc -obj lib.c s.c s_.c
% gcc lib.o s.o s_.o $GAMBIT/lib/libgambit.a -lm -ldl -lutil -lssl -lcrypto
Calling Gambit Scheme functions from C
slib.scm ;;(##start-repl-server "localhost:44555")
(c-define (inc x) (int) int "inc" "extern"
(+ x 1))
(c-define (fib x) (int) int "fib" "extern"
(if (or (= x 0)
(= x 1))
x
(+ (fib (- x 1))
(fib (- x 2)))))
(c-define (say_hello n) (char-string) char-string "say_hello" "extern"
(string-append "Hello " n "!"))
;;copied from $GAMBIT/test/server.scm
(define (catch-all-errors thunk)
(with-exception-catcher
(lambda (exc)
(write-to-string exc))
thunk))
(define (write-to-string obj)
(with-output-to-string
'()
(lambda () (write obj))))
(define (read-from-string str)
(with-input-from-string str read))
; The following "c-define" form will define the function "eval_string"
; which can be called from C just like an ordinary C function. The
; single argument is a character string (C type "char*") and the
; result is also a character string.
(c-define (eval-string str) (char-string) char-string "eval_string" "extern"
(catch-all-errors
(lambda () (write-to-string (eval (read-from-string str))))))
(c-define (start-repl) () void "start_repl" "extern"
(##start-repl-server "localhost:44555")
(pp "read ")
(read)
(pp "done")
)
slib.h
#include "gambit.h"
typedef ___setup_params_struct GAMBIT;
#define SCHEME_LIBRARY_LINKER ___LNK_slib__ //___LNK_slib__ is defined in slib_.c which is generated with gsc -link slib.c
___BEGIN_C_LINKAGE
extern ___mod_or_lnk SCHEME_LIBRARY_LINKER (___global_state);
___END_C_LINKAGE
GAMBIT* setup_gambit(){
GAMBIT* g = malloc(sizeof(GAMBIT));
___setup_params_reset(g);
g->version = ___VERSION;
g->linker = SCHEME_LIBRARY_LINKER;
___setup(g);
return g;
}
void cleanup_gambit(GAMBIT* g){
___cleanup();
free(g);
}
extern char* say_hello(char* name);
extern int inc(int);
extern int fib(int);
extern char* eval_string(char* s);
extern void start_repl();
main.c
#include
#include
#include "slib.h"
int main(int argc, char** argv) {
printf("Hello World from C\n\n");
GAMBIT* g = setup_gambit();
//printf("From Scheme:\n");
/* char* result = eval_string (argv[1]); */
/* printf("%s = %s\n", argv[1], result); */
/* ___release_string (result); */
start_repl();
cleanup_gambit(g);
return 0;
}
Compile as follows
% gsc -c slib.scm
% gsc -link slib.c #___LNK_slib__ symbol used in main.c generated here
% gcc slib.c slib_.c main.c -D___LIBRARY -I$GAMBIT/include $GAMBIT/lib/libgambit.a -lm -ldl -lutil -lssl -lcrypto
% ./a.out
Hello World from C
From Scheme:
say_hello("Sonny")=Hello Sonny!
inc(2)=3
fib(15)=610
eval_string("(+ 1 1)")=2
#or alternatively build object files with gsc -obj
% gsc -c slib.scm
% gsc -link slib.c #___LNK_slib__ symbol used in main.c generated here
% gsc -obj -cc-options -D___LIBRARY slib.c slib_.c # -cc-options -D___LIBRARY necessary to supress generation of main function
% gsc -obj main.c
% gcc slib.o slib_.o main.o -I$GAMBIT/include $GAMBIT/lib/libgambit.a -lm -ldl -lutil -lssl -lcrypto
% ./a.out
Hello World from C
From Scheme:
say_hello("Sonny")=Hello Sonny!
inc(2)=3
fib(15)=610
eval_string("(+ 1 1)")=2