Dynamic FFI
Written by jjgarcia on 2005-10
ECL's unstable version (in CVS) now contains means both to call C functions and to export functions to the C world (callbacks). Furthermore, this project, initiated by M. Goffioul, has led to an implementation that, at least on the Intel platform, does not rely on the C compiler, but on assembler code generated run time. We hope to port this to the remaining architectures: PPC, Sparc, x86_64
If you want to test it, save the code below in a file called "example.lsp" and load it in the interpreter (if on x86/Windows,Linux,FreeBSD) or compile it and load it (if on other platforms).
The output should look as follows: the first column is the input value, the second and fourth column are the output of either a callback or a C function (in this case "sin"). Other columns are provided to compare accuracy of the result.
Value 1+ (cback) lisp sin(cfun) lisp
0 1.0 1.0 0.0 0.0
1 2.0 2.0 .841470985 0.84147096
2 3.0 3.0 .909297427 0.9092974
3 4.0 4.0 .141120008 0.14112
4 5.0 5.0 -0.7568025 -0.7568025
5 6.0 6.0 -.95892427 -0.9589243
6 7.0 7.0 -0.2794155 -0.2794155
7 8.0 8.0 .656986599 0.6569866
8 9.0 9.0 .989358247 0.98935825
9 10.0 10.0 .412118485 0.4121185
;; Notice that the following example will work on all platforms if compiled ;; as in ;; (COMPILE-FILE "example.lisp") ;; (LOAD-FILE "example") ;; ;; However, on the x86 platform (i.e. Intel running Linux, FreeBSD, Windows, ;; etc on 32 bit modes), this example also works when loaded from the ;; interpreter. In this case, assembly code is built at run-time and there ;; is no need to have a C compiler around. Ports to other architectures are ;; being developed and any kind of help is welcome. ;;
;; ;; This is a "callback", i.e. a function that can be called from the C world. ;; We can retreive a UFFI pointer to this function using #'FFI:CALLBACK, as ;; shown below. ;; (ffi:defcallback increment :double ((x :double)) (1+ x) )
;; ;; This is a foreign function, i.e. a C function that can be called from the ;; lisp world. Here we do not need to handle pointers: a lisp function called ;; C-SIN is created that does the job of translating arguments for us. The ;; syntax here is pure UFFI. ;; (ffi:def-function ("sin" C-sin) ((x :double)) :returning :double :module :default)
(format t "Value 1+ (cback) lisp sin(cfun) lisp ~%") (format t "=====================================================~%")
(dotimes (i 10) (format t "~10D ~10f ~10f ~10f ~10f~%" i (si::call-cfun (ffi:callback 'increment) :double '(:double) (list i)) (1+ i) (C-sin i) (sin i)))