-
Notifications
You must be signed in to change notification settings - Fork 0
/
Module (chicken foreign)
376 lines (263 loc) · 12.8 KB
/
Module (chicken foreign)
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
[[tags: manual]]
[[toc:]]
== Module (chicken foreign)
This module provides a ''foreign function interface'' to access externally
defined functions and variables in C-compatible languages, as well as
operating-system specific functionality.
Note that this interface is source-based, since CHICKEN translates
Scheme code to C. It is not binary, as in many other Scheme implementations.
Several special forms of this interface refer to ''foreign type specifiers'',
consult the [[Foreign type specifiers|relevant chapter]] of this manual for
more information.
== Accessing external objects
=== foreign-code
<macro>(foreign-code STRING ...)</macro>
Executes the embedded C/C++ code {{STRING ...}}, which should
be a sequence of C statements, which are executed and return an unspecified result.
<enscript highlight=scheme>
(foreign-code "doSomeInitStuff();") => #<unspecified>
</enscript>
Code wrapped inside {{foreign-code}} may not invoke callbacks into Scheme.
=== foreign-value
<macro>(foreign-value CODE TYPE)</macro>
Evaluates the embedded C/C++ expression {{CODE}} (which may be a string or symbol), returning a value of type given
in the foreign-type specifier {{TYPE}}.
<enscript highlight=scheme>
(print (foreign-value "my_version_string" c-string))
</enscript>
=== foreign-declare
<macro>(foreign-declare STRING ...)</macro>
Include given strings verbatim into header of generated file.
=== define-foreign-type
<macro>(define-foreign-type NAME TYPE [ARGCONVERT [RETCONVERT]])</macro>
Defines an alias for {{TYPE}} with the name {{NAME}} (a symbol).
{{TYPE}} may be a type-specifier or a string naming a C type. The
namespace of foreign type specifiers is separate from the normal
Scheme namespace. The optional arguments {{ARGCONVERT}} and
{{RETCONVERT}} should evaluate to procedures that map argument- and
result-values to a value that can be transformed to {{TYPE}}:
<enscript highlight=scheme>
(define-foreign-type char-vector
nonnull-c-string
(compose list->string vector->list)
(compose list->vector string->list) )
(define strlen
(foreign-lambda int "strlen" char-vector) )
(strlen '#(#\a #\b #\c)) ==> 3
(define memset
(foreign-lambda char-vector "memset" char-vector char int) )
(memset '#(#_ #_ #_) #\X 3) ==> #(#\X #\X #\X)
</enscript>
Foreign type-definitions are only visible in the compilation-unit in which
they are defined, so use {{include}} to use the same definitions
in multiple files.
=== foreign-type-size
<macro>(foreign-type-size TYPE)</macro>
Returns the size of the storage required to hold values of the
given foreign type {{TYPE}}. This is basically equivalent to
<enscript highlight=scheme>
(foreign-value "sizeof(TYPE)" size_t)
</enscript>
but also handles user-defined types and allows "TYPE" to be a string,
which will be given literally to the {{sizeof}} operator.
=== define-foreign-variable
<macro>(define-foreign-variable NAME TYPE [STRING])</macro>
Defines a foreign variable of name {{NAME}} (a symbol). {{STRING}}
should be the real name of a foreign variable or parameterless
macro. If {{STRING}} is not given, then the variable name {{NAME}}
will be converted to a string and used instead. All references and
assignments (via {{set!}}) are modified to correctly convert values
between Scheme and C representation. This foreign variable can only be
accessed in the current compilation unit, but the name can be
lexically shadowed. Note that {{STRING}} can name an arbitrary C
expression. If no assignments are performed, then {{STRING}} doesn't
even have to specify an lvalue.
See that {{define-foreign-variable}} will not generate C declarations
or memory allocation code; use it to include references to variables
in external C code. To actually create Scheme variables visible from C,
use {{define-external}} (see the Manual section on
[[Callbacks]]).
For example, the following code:
<enscript lang="scheme">
(import foreign)
(define-foreign-variable x double "var_x")
(print x)
</enscript>
will not work, because a reference to {{var_x}} will be inserted in the C code,
but no declaration will be included (this can be easily verified by translating
the program into C with {{csc -t program.scm}}). Changing the second line to
{{(define-external x double 0.5)}} will work (and the value 0.5 will be printed).
=== foreign-lambda
<macro>(foreign-lambda RETURNTYPE NAME ARGTYPE ...)</macro>
Represents a
binding to an external routine. This form can be used in the position
of an ordinary {{lambda}} expression. {{NAME}} specifies the
name of the external procedure and should be a string or a symbol.
=== foreign-lambda*
<macro>(foreign-lambda* RETURNTYPE ((ARGTYPE VARIABLE) ...) STRING ...)</macro>
Similar to {{foreign-lambda}}, but instead of generating code to
call an external function, the body of the C procedure is directly given
in {{STRING ...}}:
<enscript highlight=scheme>
(define my-strlen
(foreign-lambda* int ((c-string str))
"int n = 0;
while(*(str++)) ++n;
C_return(n);") )
(my-strlen "one two three") ==> 13
</enscript>
For obscure technical reasons you should use the {{C_return}} macro instead of the normal {{return}} statement
to return a result from the foreign lambda body as some cleanup code has to be run before execution
commences in the calling code.
=== foreign-safe-lambda
<macro>(foreign-safe-lambda RETURNTYPE NAME ARGTYPE ...)</macro>
This is similar to {{foreign-lambda}}, but also allows the called
function to call Scheme functions. See [[Callbacks]].
=== foreign-safe-lambda*
<macro>(foreign-safe-lambda* RETURNTYPE ((ARGTYPE VARIABLE)...) STRING ...)</macro>
This is similar to {{foreign-lambda*}}, but also allows the called
function to call Scheme functions and allocate Scheme data-objects. See [[Callbacks]].
=== foreign-primitive
<macro>(foreign-primitive [RETURNTYPE] ((ARGTYPE VARIABLE) ...) STRING ...)</macro>
This is also similar to {{foreign-lambda*}} but the code will be
executed in a ''primitive'' CPS context, which means it will not
actually return, but call its continuation on exit. This means that code
inside this form may allocate Scheme data on the C stack (the
''nursery'') with {{C_alloc}} (see below). You can return multiple
values inside the body of the {{foreign-primitive}} form by using
the following C code:
<enscript highlight=scheme>
C_word av[N + 2] = { C_SCHEME_UNDEFINED, C_k, X1, ... };
C_values(N + 2, av);
</enscript>
where {{N}} is the number of values to be returned, and {{X1, ...}}
are the results, which should be Scheme data objects. When returning
multiple values, the return-type should be omitted. Of course, if you
have to dynamically compute the values, you do not have to use C's
array initialization syntax, but you can just assign them one by one.
Returning just a single value can still be done via the {{C_return(...)}} macro.
== Callbacks
To enable an external C function to call back to Scheme, the form
{{foreign-safe-lambda}} (or {{foreign-safe-lambda*}})
has to be used. This generates special code to save and restore important
state information during execution of C code. There are two ways of
calling Scheme procedures from C: the first is to invoke the runtime
function {{C_callback}} with the closure to be called and the number
of arguments. The second is to define an externally visible wrapper
function around a Scheme procedure with the {{define-external}}
form.
Note: the names of all functions, variables and macros exported by the
CHICKEN runtime system start with {{C_}}. It is advisable to
use a different naming scheme for your own code to avoid name clashes.
Callbacks (defined by {{define-external}})
do not capture the lexical environment.
Non-local exits leaving the scope of the invocation of a callback from Scheme into C
will not remove the C call-frame from the stack (and will result in a memory
leak). '''Note:''' The same applies to
SRFI-18 threading, which is implemented with {{call/cc}};
additionally, if you enter one callback, switch threads and then exit
a different callback, your program is likely to crash.
=== define-external
<macro>(define-external [QUALIFIERS] (NAME (ARGUMENTTYPE1 VARIABLE1) ...) RETURNTYPE BODY ...)</macro><br>
<macro>(define-external NAME TYPE [INIT])</macro>
The first form defines an externally callable Scheme
procedure. {{NAME}} should be a symbol, which, when converted to a
string, represents a legal C identifier. {{ARGUMENTTYPE1 ...}} and
{{RETURNTYPE}} are foreign type specifiers for the argument variables
{{VAR1 ...}} and the result, respectively. {{QUALIFIERS}}
is an optional qualifier for the foreign procedure definition, like
{{__stdcall}}.
<enscript highlight=scheme>
(define-external (foo (c-string x)) int (string-length x))
</enscript>
The second form of {{define-external}} can be used to define
variables that are accessible from foreign code. It declares
a global variable named by the symbol {{NAME}} that
has the type {{TYPE}}. {{INIT}} can be an arbitrary
expression that is used to initialize the variable. {{NAME}} is
accessible from Scheme just like any other foreign variable defined by
{{define-foreign-variable}}.
<enscript highlight=scheme>
(define-external foo int 42)
((foreign-lambda* int ()
"C_return(foo);")) ==> 42
</enscript>
'''Note:''' don't be tempted to
assign strings or bytevectors to external variables. Garbage collection
moves those objects around, so it is a very bad idea to assign pointers
to heap-data. If you have to do so, then copy the data object into
statically allocated memory (for example by using {{object-evict}}).
Results of type {{scheme-object}} returned by {{define-external}}
are always allocated in the secondary heap, that is, not in the stack.
=== C_callback
[C function] C_word C_callback (C_word closure, int argc)
This function can be used to invoke the Scheme procedure {{closure}}.
{{argc}} should contain the number of arguments that are passed to
the procedure on the temporary stack. Values are put onto the temporary
stack with the {{C_save}} macro.
=== C_callback_adjust_stack
[C function] void C_callback_adjust_stack (C_word *ptr, int size)
The runtime-system uses the stack as a special allocation area and
internally holds pointers to estimated limits to distinguish between
Scheme data objects inside the stack from objects outside of it. If
you invoke callbacks at wildly differing stack-levels, these limits
may shift from invocation to invocation. Callbacks defined with
{{define-external}} will perform appropriate adjustments
automatically, but if you invoke {{C_callback}} manually, you should
perform a {{C_callback_adjust_stack}} to make sure the internal limits
are set properly. {{ptr}} should point to some data object on the
stack and {{size}} is the number of words contained in the data object
(or some estimate). The call will make sure the limits are adjusted so
that the value pointed to by {{ptr}} is located in the stack.
== Locations
It is also possible to define variables containing unboxed C data,
so called ''locations''. It should be noted that locations may
only contain simple data, that is: everything that fits into a
machine word, and double-precision floating point values.
=== define-location
<macro>(define-location NAME TYPE [INIT])</macro>
Identical to {{(define-external NAME TYPE [INIT])}}, but the variable
is not accessible from outside of the current compilation unit (it is
declared {{static}}).
=== let-location
<macro>(let-location ((NAME TYPE [INIT]) ...) BODY ...)</macro>
Defines a lexically bound location.
=== location
<macro>(location NAME)</macro><br>
<macro>(location X)</macro>
<read>#$</read>
This form returns a pointer object
that contains the address of the variable {{NAME}}.
If the argument to {{location}} is not a location defined by {{define-location}},
{{define-external}} or {{let-location}}, then
(location X)
is essentially equivalent to
(make-locative X)
(See the [[Module (chicken locative)|manual section on locatives]] for more
information about locatives)
Note that {{(location X)}} may be abbreviated as {{#$X}}.
<enscript highlight=scheme>
(define-external foo int)
((foreign-lambda* void (((c-pointer int) ip)) "*ip = 123;")
(location foo))
foo ==> 123
</enscript>
This facility is especially useful in situations, where a C function
returns more than one result value:
<enscript highlight=scheme>
#>
#include <math.h>
<#
(define modf
(foreign-lambda double "modf" double (c-pointer double)) )
(let-location ([i double])
(let ([f (modf 1.99 (location i))])
(print "i=" i ", f=" f) ) )
</enscript>
See [[/location-and-c-string-star|location and c-string*]]
for a tip on returning a {{c-string*}} type.
{{location}} returns a value of type {{c-pointer}}, when given
the name of a callback-procedure defined with {{define-external}}.
---
Previous: [[Module (chicken flonum)]]
Next: [[Module (chicken format)]]