source: project/wiki/eggref/4/lazy-ffi @ 13306

Last change on this file since 13306 was 13306, checked in by felix winkelmann, 12 years ago

added xlib page and removed download links

File size: 8.7 KB
Line 
1[[tags: egg]]
2
3== lazy-ffi
4
5[[toc:]]
6
7=== Description
8
9Another foreign function interface, based on libffi.
10
11=== Author
12
13[[felix winkelmann]]
14
15=== Requirements
16
17* [[silex]]
18* [[easyffi]]
19
20=== Usage
21
22{{(require-extension lazy-ffi)}}
23
24This extension defines the module {{lazy-ffi}}.
25
26=== Documentation
27
28A very easy to use foreign function interface, which provides a
29special read-syntax to call arbitrary functions in shared
30libraries. This facility uses
31[[http://sources.redhat.com/libffi|libffi]] and dynamic loading (via
32{{dlopen(3)}}) to load shared libraries and construct foreign calls at
33runtime and in interpreted code.
34
35To use this extension in compiled code, invoke the compiler with
36{{-extension lazy-ffi}}.  This is necessary because the extension
37defines a special read-syntax which has to be registered before the
38source code is read in. This is not required for interpreted code.
39
40Note: the libffi package is actively under development, but the
41website doesn't reflect the current work in progress. A snapshot of
42the current development version is available at
43[[http://www.call-with-current-continuation.org/libffi-2.tgz]]. The
44latter is more portable and robust than the version currently
45advertised at the libffi website.
46
47==== Read syntax
48
49The following read syntax is provided:
50
51<read>#~STRING</read>
52
53Registers the shared library named STRING. Subsequent access to
54foreign symbols will try to find the required symbol in all libraries
55registered so far. The library name may also be {{#f}}, which allows
56looking up symbols in the current executable (this may require special
57linker options, depending on platform).
58
59<read>#~SYMBOL</read>
60
61Identifies a foreign symbol, which will be looked up in the currently
62registered shared libraries.  Returns a procedure that can be called
63like a normal Scheme procedure.
64
65A special case is the syntax {{#~~}}. When used, an expression is
66expected preceding any further arguments that should evaluate to a
67foreign pointer object identifying the address of a C function.
68
69<read>#~(ITEM ...)</read>
70
71Equivalent to {{(list #~ITEM ...)}}. This can be used to register
72several shared libraries at once or pre-resolve foreign symbols.
73
74A foreign procedure is called like a normal procedure, with argument
75values automatically converted to the appropriate foreign
76representation, using the following mapping of Scheme types to C
77types:
78
79<table>
80<tr><th>Scheme type</th><th>C type</th></tr>
81<tr><td>boolean</td><td>{{int}} (1 or 0)</td></tr>
82<tr><td>exact</td><td>{{int}}</td></tr>
83<tr><td>inexact</td><td>{{double}}</td></tr>
84<tr><td>char</td><td>{{char}}</td></tr>
85<tr><td>pointer or locative</td><td>{{void *}}</td></tr>
86<tr><td>string</td><td>{{char *}}</td></tr>
87<tr><td>symbol</td><td>{{char *}}</td></tr>
88</table>
89
90Arguments of any other type will signal an error (see below for
91specifying specific argument conversions).
92
93Additionally, the procedure can be called with a number of special
94keyword arguments:
95
96; {{return}} : {{TYPE}}
97
98Specifies the result type. If not given, the result will be ignored. TYPE should be one of the following:
99
100<table>
101<tr><td>{{int:}}</td></tr>
102<tr><td>{{char:}}</td></tr>
103<tr><td>{{float:}}</td></tr>
104<tr><td>{{double:}}</td></tr>
105<tr><td>{{pointer:}}</td></tr>
106<tr><td>{{string:}}</td></tr>
107<tr><td>{{symbol:}}</td></tr>
108<tr><td>{{bool:}}</td></tr>
109<tr><td>{{void:}}</td></tr>
110<tr><td>{{scheme-object:}}</td></tr>
111</table>
112
113; {{safe}} : {{BOOLEAN}}
114
115If given, then the call may call back into Scheme (for example by
116passing a pointer to a callback function).  If not given, then call
117may '''not''' invoke any Scheme callbacks, or bad things will happen.
118
119{{TYPE VALUE}}
120
121To force a specific argument type conversion (and to allow slightly
122better argument type checking), a type specifier may also be provided
123as a keyword, followed by the actual argument. Valid type specifiers
124are:
125
126<table>
127<tr><td>{{int:}}</td><td>exact number</td></tr>
128<tr><td>{{float: double:}}</td><td>inexact number</td></tr>
129<tr><td>{{pointer:}}</td><td>pointer object</td></tr>
130<tr><td>{{bool:}}</td><td>boolean (actually any Scheme object), will be passed as 1 or 0</td></tr>
131<tr><td>{{char:}}</td><td>char</td></tr>
132<tr><td>{{string:}}</td><td>string</td></tr>
133<tr><td>{{symbol:}}</td><td>string (the name of the symbol)</td></tr>
134<tr><td>{{scheme-object:}}</td><td>any Scheme value</td></tr>
135<tr><td>{{scheme-pointer:}}</td><td>any non-immediate Scheme value (a pointer to the data-section will be passed)</td></tr>
136</table>
137
138(The type specifiers {{scheme-pointer:}} and {{scheme-object:}} are
139mainly intended for advanced uses of this extension)
140
141=== Examples
142
143<examples><example>
144<expr>
145#~"libc.so.6"
146(#~printf "%d -> %g, ok: %s\n" 123 45.67 "hello")
147(#~sleep 1)
148
149#~"libm.so.6"
150
151(#~sin 33.4 return: double:)    ==> 0.915809602890819
152(#~tolower #\A return: char:)   ==> #\a
153
154(let* ([box (f64vector 0)]
155       [r (#~modf 123.456 box return: double:)] )
156  (list r box) )   ==> (0.456 #f64(123.0))
157</expr>
158</example></examples>
159
160Here the "Hello, world" example from the GTK 2.0 tutorial:
161
162<examples><example>
163<expr>
164;; Compile like this:
165;
166; $ csc -X lazy-ffi.scm gtkhello.scm
167
168(use lazy-ffi)
169
170#~"libgtk-x11-2.0.so"
171#~"libglib-2.0.so"
172#~"libgobject-2.0.so"
173
174(define GTK_WINDOW_TOPLEVEL 0)
175
176(define-external (hello (c-pointer widget) (c-pointer data)) void
177  (print "Hello, world") )
178
179(define-external (delete_event (c-pointer widget)
180                               (c-pointer event)
181                               (c-pointer data) )
182  bool
183  (print "delete event occurred")
184  #t)
185
186(define-external (destroy (c-pointer widget) (c-pointer data)) void
187  (#~gtk_main_quit) )
188
189(define (g_signal_connect a b c d)
190  (#~g_signal_connect_data a b c pointer: d pointer: #f 0) )
191
192(#~gtk_init (foreign-value "&C_main_argc" c-pointer) (foreign-value "&C_main_argv" c-pointer))
193
194(define window (#~gtk_window_new GTK_WINDOW_TOPLEVEL return: pointer:))
195   
196(g_signal_connect window "delete_event" #$delete_event #f) 
197(g_signal_connect window "destroy" #$destroy #f)
198
199(#~gtk_container_set_border_width window 10)
200   
201(define button (#~gtk_button_new_with_label "Hello World" return: pointer:))
202   
203(g_signal_connect button "clicked" #$hello #f)
204
205(define-external (close_all (c-pointer widget)) void
206  (#~gtk_widget_destroy window) )
207
208(g_signal_connect button "clicked" #$close_all #f)
209(#~gtk_container_add window button)
210(#~gtk_widget_show button) 
211(#~gtk_widget_show window)
212(#~gtk_main safe: #t)
213</expr>
214</example></examples>
215
216Calling a pointer directly:
217
218<examples><example>
219<expr>
220#~"libdl.so.2"
221
222(define atof (#~dlsym pointer: #f "atof" return: pointer:)) ; lookup in current module
223
224(print atof)    ; ==> "#&lt;pointer 1077736272.0&gt;"
225
226(#~~ atof "99" return: double:)    ; ==> 99.0
227
228; Taking it to the extreme...
229
230(use lolevel)
231
232(#~~ (address->pointer 1077736272) "42.1" return: double:)    ; ==> 42.1
233</expr>
234</example></examples>
235
236=== Changelog
237
238* 1.8.2 Ported to chicken4
239* 1.8 Removed use of {{___callback}}
240* 1.7 Uses externalized easyffi extension, uses more modern CHICKEN features
241* 1.6 Fixed silly bug in f32vector handling
242* 1.5 Added basic argument and result handling for unsigned ints; allows {{#f}} as module name
243* 1.4 Changed read-syntax to {{#~}} and removed SRFI-4 type-specifiers (transformed automatically)
244* 1.3 Fixed bug (hash-table related, of course)
245* 1.2 Adapted to SRFI-69-compatible hash-tables
246* 1.1 Added {{~~}}
247* 1.0 Initial release
248
249=== License
250
251  Copyright (c) 2005, Felix L. Winkelmann
252  All rights reserved.
253 
254  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following
255  conditions are met:
256 
257    Redistributions of source code must retain the above copyright notice, this list of conditions and the following
258      disclaimer.
259    Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
260      disclaimer in the documentation and/or other materials provided with the distribution.
261    Neither the name of the author nor the names of its contributors may be used to endorse or promote
262      products derived from this software without specific prior written permission.
263 
264  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
265  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
266  AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
267  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
268  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
269  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
270  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
271  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
272  POSSIBILITY OF SUCH DAMAGE.
Note: See TracBrowser for help on using the repository browser.