File: ffi-example.html

package info (click to toggle)
sbcl 1%3A0.8.16-1
  • links: PTS
  • area: main
  • in suites: sarge
  • size: 15,028 kB
  • ctags: 14,790
  • sloc: lisp: 194,656; ansic: 16,544; asm: 2,060; sh: 1,674; makefile: 199
file content (139 lines) | stat: -rw-r--r-- 6,454 bytes parent folder | download
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(&quot;i = %d\n&quot;, i);
  printf(&quot;s = %s\n&quot;, s);
  printf(&quot;r-&gt;x = %d\n&quot;, r-&gt;x);
  printf(&quot;r-&gt;s = %s\n&quot;, r-&gt;s);
  for (j = 0; j &lt; 10; j++) printf(&quot;a[%d] = %d.\n&quot;, j, a[j]);
  r2 = (struct c_struct *) malloc (sizeof(struct c_struct));
  r2-&gt;x = i + 5;
  r2-&gt;s = &quot;a C string&quot;;
  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 &quot;TEST-C-CALL&quot; (:use &quot;CL&quot; &quot;SB-ALIEN&quot; &quot;SB-C-CALL&quot;))
(cl:in-package &quot;TEST-C-CALL&quot;)

;;; 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) &quot;a Lisp string&quot;)

    (with-alien ((res (* (struct c-struct))
                      (c-function 5 &quot;another Lisp string&quot; (addr c-struct) ar)))
      (format t &quot;~&amp;back from C function~%&quot;)
      (multiple-value-prog1
          (values (slot res 'x)
                  (slot res 's))

        ;; Deallocate result. (after we are done referring to it:
        ;; &quot;Pillage, *then* burn.&quot;)
        (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 &quot;test.lisp&quot;)</tt></b>
</p><p>
Within Lisp, load the foreign object file to define the necessary
symbols:
<b class="userinput"><tt>(load-foreign &quot;test.o&quot;)</tt></b>.
This must be done before loading any code that refers
to these symbols.
</p><p>
Now you can load the compiled Lisp (&quot;fasl&quot;) file into Lisp:
<b class="userinput"><tt>(load &quot;test.fasl&quot;)</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-&gt;x = 20
r-&gt;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
&quot;a C string&quot;
</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>