search


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