1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
|
<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" /><title>Step-By-Step Example of the Foreign Function Interface</title><meta name="generator" content="DocBook XSL Stylesheets V1.62.4" /><link rel="home" href="index.html" title="SBCL User Manual" /><link rel="up" href="ffi.html" title="Chapter5.The Foreign Function Interface" /><link rel="previous" href="foreign-function-calls.html" title="Foreign Function Calls" /><link rel="next" href="colophon.html" title="Colophon" /></head><body><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Step-By-Step Example of the Foreign Function Interface</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="foreign-function-calls.html">Prev</a></td><th width="60%" align="center">Chapter5.The Foreign Function Interface</th><td width="20%" align="right"><a accesskey="n" href="colophon.html">Next</a></td></tr></table><hr /></div><div class="sect1" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="ffi-example"></a>Step-By-Step Example of the Foreign Function Interface</h2></div></div><div></div></div><p>
This section presents a complete example of an interface to a somewhat
complicated C function.
</p><p>
Suppose you have the following C function which you want to be able to
call from Lisp in the file <tt class="filename">test.c</tt>
</p><pre class="programlisting">
struct c_struct
{
int x;
char *s;
};
struct c_struct *c_function (i, s, r, a)
int i;
char *s;
struct c_struct *r;
int a[10];
{
int j;
struct c_struct *r2;
printf("i = %d\n", i);
printf("s = %s\n", s);
printf("r->x = %d\n", r->x);
printf("r->s = %s\n", r->s);
for (j = 0; j < 10; j++) printf("a[%d] = %d.\n", j, a[j]);
r2 = (struct c_struct *) malloc (sizeof(struct c_struct));
r2->x = i + 5;
r2->s = "a C string";
return(r2);
};</pre><p>
</p><p>
It is possible to call this C function from Lisp using the file
<tt class="filename">test.lisp</tt> containing
</p><pre class="programlisting">
(cl:defpackage "TEST-C-CALL" (:use "CL" "SB-ALIEN" "SB-C-CALL"))
(cl:in-package "TEST-C-CALL")
;;; Define the record C-STRUCT in Lisp.
(define-alien-type nil
(struct c-struct
(x int)
(s c-string)))
;;; Define the Lisp function interface to the C routine. It returns a
;;; pointer to a record of type C-STRUCT. It accepts four parameters:
;;; I, an int; S, a pointer to a string; R, a pointer to a C-STRUCT
;;; record; and A, a pointer to the array of 10 ints.
;;;
;;; The INLINE declaration eliminates some efficiency notes about heap
;;; allocation of alien values.
(declaim (inline c-function))
(define-alien-routine c-function
(* (struct c-struct))
(i int)
(s c-string)
(r (* (struct c-struct)))
(a (array int 10)))
;;; a function which sets up the parameters to the C function and
;;; actually calls it
(defun call-cfun ()
(with-alien ((ar (array int 10))
(c-struct (struct c-struct)))
(dotimes (i 10) ; Fill array.
(setf (deref ar i) i))
(setf (slot c-struct 'x) 20)
(setf (slot c-struct 's) "a Lisp string")
(with-alien ((res (* (struct c-struct))
(c-function 5 "another Lisp string" (addr c-struct) ar)))
(format t "~&back from C function~%")
(multiple-value-prog1
(values (slot res 'x)
(slot res 's))
;; Deallocate result. (after we are done referring to it:
;; "Pillage, *then* burn.")
(free-alien res)))))</pre><p>
</p><p>
To execute the above example, it is necessary to compile the C routine,
e.g.:
<b class="userinput"><tt>cc -c test.c</tt></b>
(In order to enable incremental loading with some linkers, you may need
to say
<b class="userinput"><tt>cc -G 0 -c test.c</tt></b>)
</p><p>
Once the C code has been compiled, you can start up Lisp and load it in:
<b class="userinput"><tt>sbcl</tt></b>.
Lisp should start up with its normal prompt.</p><p>
Within Lisp,
compile the Lisp file. (This step can be done separately. You don't
have to recompile every time.)
<b class="userinput"><tt>(compile-file "test.lisp")</tt></b>
</p><p>
Within Lisp, load the foreign object file to define the necessary
symbols:
<b class="userinput"><tt>(load-foreign "test.o")</tt></b>.
This must be done before loading any code that refers
to these symbols.
</p><p>
Now you can load the compiled Lisp ("fasl") file into Lisp:
<b class="userinput"><tt>(load "test.fasl")</tt></b>
And once the Lisp file is loaded, you can call the
Lisp routine that sets up the parameters and calls the C
function:
<b class="userinput"><tt>(test-c-call::call-cfun)</tt></b>
</p><p>
The C routine should print the following information to standard output:
</p><pre class="programlisting">i = 5
s = another Lisp string
r->x = 20
r->s = a Lisp string
a[0] = 0.
a[1] = 1.
a[2] = 2.
a[3] = 3.
a[4] = 4.
a[5] = 5.
a[6] = 6.
a[7] = 7.
a[8] = 8.
a[9] = 9.</pre><p>
After return from the C function,
the Lisp wrapper function should print the following output:
</p><pre class="programlisting">back from C function</pre><p>
And upon return from the Lisp wrapper function,
before the next prompt is printed, the
Lisp read-eval-print loop should print the following return values:
</p><pre class="programlisting">
10
"a C string"
</pre><p>
</p></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="foreign-function-calls.html">Prev</a></td><td width="20%" align="center"><a accesskey="u" href="ffi.html">Up</a></td><td width="40%" align="right"><a accesskey="n" href="colophon.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Foreign Function Calls</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">Colophon</td></tr></table></div></body></html>
|