foreign-c/documentation/foreign-c.html

529 lines
21 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>foreign-c a portable foreign function interface for R7RS
Schemes - 0.10.0</title>
<style>
table { width: 250%; }
nav { float: left; width: 20%;}
main { float: right; width: 80%; }
pre { background-color: lightgrey; }
</style>
</head>
<body>
<h1 id="foreign-c">foreign-c</h1>
<p>foreign-c is a C foreign function interface (FFI) library for
R7RS Schemes. It is portable in the sense that it supports
multiple implementations, as opposed to being portable by
conforming to some specification.</p>
<p><a href="https://sr.ht/~retropikzel/foreign-c/trackers">Issue
tracker</a></p>
<p><a href="https://sr.ht/~retropikzel/foreign-c/lists">Maling
lists</a></p>
<ul>
<li><a href="#installation">Installation</a></li>
<li><a href="#documentation">Documentation</a>
<ul>
<li><a href="#types">Types</a></li>
<li><a href="#primitives-1">Primitives 1</a></li>
<li><a href="#primitives-2">Primitives 2</a></li>
<li><a href="#c-bytevector">c-bytevector</a>
<ul>
<li><a href="#creation-and-deletion">Creationg and
deletion</a></li>
<li><a href="#accessors">Accessors</a></li>
</ul></li>
<li><a href="#environment-variables">Environment
variables</a></li>
</ul></li>
</ul>
<h2 id="implementation-support-tables">Implementation support
tables</h2>
<h3 id="primitives-1-table">Primitives 1 table</h3>
<table>
<colgroup>
<col style="width: 13%" />
<col style="width: 10%" />
<col style="width: 16%" />
<col style="width: 15%" />
<col style="width: 16%" />
<col style="width: 11%" />
<col style="width: 16%" />
</colgroup>
<thead>
<tr class="header">
<th></th>
<th style="text-align: center;">c-size-of</th>
<th style="text-align: center;">c-bytevector-u8-set!</th>
<th style="text-align: center;">c-bytevector-u8-ref</th>
<th style="text-align: center;">define-c-library</th>
<th style="text-align: center;">c-bytevector?</th>
<th style="text-align: center;">define-c-procedure</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><strong>Chibi</strong></td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
</tr>
<tr class="even">
<td><strong>Chicken</strong></td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
</tr>
<tr class="odd">
<td><strong>Gauche</strong></td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
</tr>
<tr class="even">
<td><strong>Guile</strong></td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
</tr>
<tr class="odd">
<td><strong>Kawa</strong></td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
</tr>
<tr class="even">
<td><strong>Mosh</strong></td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
</tr>
<tr class="odd">
<td><strong>Racket</strong></td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
</tr>
<tr class="even">
<td><strong>Saggittarius</strong></td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
</tr>
<tr class="odd">
<td><strong>Stklos</strong></td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
</tr>
<tr class="even">
<td><strong>Ypsilon</strong></td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
</tr>
</tbody>
</table>
<h3 id="primitives-2-table">Primitives 2 table</h3>
<table>
<thead>
<tr class="header">
<th></th>
<th style="text-align: center;">define-c-callback</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Chibi</td>
<td style="text-align: center;"></td>
</tr>
<tr class="even">
<td><strong>Chicken</strong></td>
<td style="text-align: center;">X</td>
</tr>
<tr class="odd">
<td>Gauche</td>
<td style="text-align: center;"></td>
</tr>
<tr class="even">
<td><strong>Guile</strong></td>
<td style="text-align: center;">X</td>
</tr>
<tr class="odd">
<td>Kawa</td>
<td style="text-align: center;"></td>
</tr>
<tr class="even">
<td><strong>Mosh</strong></td>
<td style="text-align: center;">X</td>
</tr>
<tr class="odd">
<td><strong>Racket</strong></td>
<td style="text-align: center;">X</td>
</tr>
<tr class="even">
<td><strong>Saggittarius</strong></td>
<td style="text-align: center;">X</td>
</tr>
<tr class="odd">
<td>Stklos</td>
<td style="text-align: center;"></td>
</tr>
<tr class="even">
<td><strong>Ypsilon</strong></td>
<td style="text-align: center;">X</td>
</tr>
</tbody>
</table>
<h3 id="test-files-pass">Test files pass</h3>
<table>
<thead>
<tr class="header">
<th></th>
<th style="text-align: center;">primitives.scm</th>
<th style="text-align: center;">addressof.scm</th>
<th style="text-align: right;">callback.scm</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Chibi</td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
<td style="text-align: right;"></td>
</tr>
<tr class="even">
<td><strong>Chicken</strong></td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
<td style="text-align: right;">X</td>
</tr>
<tr class="odd">
<td>Gauche</td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
<td style="text-align: right;"></td>
</tr>
<tr class="even">
<td><strong>Guile</strong></td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
<td style="text-align: right;">X</td>
</tr>
<tr class="odd">
<td>Kawa</td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
<td style="text-align: right;"></td>
</tr>
<tr class="even">
<td>Mosh</td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
<td style="text-align: right;"></td>
</tr>
<tr class="odd">
<td>Racket</td>
<td style="text-align: center;">X</td>
<td style="text-align: center;"></td>
<td style="text-align: right;"></td>
</tr>
<tr class="even">
<td><strong>Saggittarius</strong></td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
<td style="text-align: right;">X</td>
</tr>
<tr class="odd">
<td>Stklos</td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
<td style="text-align: right;"></td>
</tr>
<tr class="even">
<td>Ypsilon</td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
<td style="text-align: right;"></td>
</tr>
</tbody>
</table>
<h3 id="installation">Installation</h3>
<p>Either download the latest release from <a
href="https://git.sr.ht/~retropikzel/foreign-c/refs">https://git.sr.ht/~retropikzel/foreign-c/refs</a>
or git clone , preferably with a tag, and copy the
<em>foreign</em> directory to your library directory.</p>
<p>Example assuming libraries in directory <em>snow</em>:</p>
<pre><code>git clone https://git.sr.ht/~retropikzel/foreign-c --branch LATEST_VERSION
mkdir -p snow
cp -r foreign-c/foreign snow/
make -C snow/foreign/c SCHEME_IMPLEMENTATION_NAME</code></pre>
<p>With most implementations the make command does not compile
anything. When that is the case it will say “Nothing to build on
SCHEME_IMPLEMENTATION_NAME.”</p>
<h2 id="documentation">Documentation</h2>
<h3 id="types">Types</h3>
<p>Types are given as symbols, for example int8 or
pointer.</p>
<ul>
<li>int8</li>
<li>uint8</li>
<li>int16</li>
<li>uint16</li>
<li>int32</li>
<li>uint32</li>
<li>int64</li>
<li>uint64</li>
<li>char</li>
<li>unsigned-char</li>
<li>short</li>
<li>unsigned-short</li>
<li>int</li>
<li>unsigned-int</li>
<li>long</li>
<li>unsigned-long</li>
<li>float</li>
<li>double</li>
<li>pointer
<ul>
<li>c-bytevector on Scheme side</li>
</ul></li>
<li>callback
<ul>
<li>Callback function</li>
</ul></li>
<li>void
<ul>
<li>Can not be argument type, only return type</li>
</ul></li>
</ul>
<h3 id="primitives-1">Primitives 1</h3>
<p>(<strong>c-type-size</strong> <em>type</em>)</p>
<p>Returns the size of given C type.</p>
<p>(<strong>define-c-library</strong> <em>scheme-name</em>
<em>headers</em> <em>object-name</em> <em>options</em>)</p>
<p>Takes a scheme-name to bind the library to, list of C headers
as strings, shared-object name and options.</p>
<p>The C header strings should not contain “&lt;” or “&gt;”,
they are added automatically.</p>
<p>The name of the shared object should not contain suffix like
.so or .dll. Nor should it contain any prefix like “lib”.</p>
<p>Options:</p>
<ul>
<li>additional-versions
<ul>
<li>Search for additional versions of shared object, given
shared object “c” and additional versions “6” “7” on linux the
files “libc”, “libc.6”, “libc.7” are searched for.</li>
<li>Can be either numbers or strings</li>
</ul></li>
<li>additional-paths
<ul>
<li>Give additional paths to search shared objects from</li>
</ul></li>
</ul>
<p>Example:</p>
<pre><code>(cond-expand
(windows (define-c-library libc-stdlib
&#39;(&quot;stdlib.h&quot;)
&quot;ucrtbase&quot;
&#39;((additional-versions (&quot;0&quot; &quot;6&quot;))
(additiona-paths (&quot;.&quot;)))))
(else (define-c-library libc-stdlib
(list &quot;stdlib.h&quot;)
&quot;c&quot;
&#39;((additional-versions (&quot;0&quot; &quot;6&quot;))
(additiona-paths (&quot;.&quot;))))))</code></pre>
<h4 id="notes">Notes</h4>
<ul>
<li>Do not cond-expand inside the arguments, that might lead to
problems on some implementations.</li>
<li>Do not store options in variables, that might lead to
problems on some implementations.</li>
<li>Pass the headers using quote
<ul>
<li>As (…) and not (list…)</li>
</ul></li>
<li>Pass the options using quote
<ul>
<li>As (…) and not (list…)</li>
</ul></li>
</ul>
<p>(<strong>define-c-procedure</strong> <em>scheme-name</em>
<em>shared-object</em> <em>c-name</em> <em>return-type</em>
<em>argument-type</em>)</p>
<p>Takes a scheme-name to bind the C procedure to, shared-object
where the function is looked from, c-name of the function as
symbol, return-type and argument-types.</p>
<p>Defines a new foreign function to be used from Scheme
code.</p>
<p>Example:</p>
<pre><code>(cond-expand
(windows (define-c-library libc-stdlib &#39;(&quot;stdlib.h&quot;) &quot;ucrtbase&quot; &#39;()))
(else (define-c-library libc-stdlib &#39;(&quot;stdlib.h&quot;) &quot;c&quot; &#39;(&quot;6&quot;))))
(define-c-procedure c-puts libc-stdlib &#39;puts &#39;int &#39;(pointer))
(c-puts &quot;Message brought to you by foreign-c!&quot;)</code></pre>
<h4 id="notes-1">Notes</h4>
<ul>
<li>Pass the return-types using quote
<ul>
<li>As (…) and not (list…)</li>
</ul></li>
</ul>
<p>(<strong>c-bytevector?</strong> <em>obj</em>)</p>
<p>Returns <strong>#t</strong> if <em>obj</em> is c-bytevector,
otherwise returns <strong>#f</strong>.</p>
<p>(<strong>c-bytevector-u8-set!</strong> <em>c-bytevector</em>
<em>k</em> <em>byte</em>)</p>
<p>If K is not a valid index of c-bytevector the behaviour is
undefined.</p>
<p>Stores the byte in element k of c-bytevector.</p>
<p>(<strong>c-bytevector-u8-ref</strong> <em>c-bytevector</em>
<em>k</em>)</p>
<p>If K is not a valid index of c-bytevector the behaviour is
undefined.</p>
<p>Returns the byte at index k of c-bytevector.</p>
<p>(<strong>c-bytevector-pointer-set!</strong>
<em>c-bytevector</em> <em>k</em> <em>pointer</em>)</p>
<p>If K is not a valid index of c-bytevector the behaviour is
undefined.</p>
<p>Stores the pointer(which is also c-bytevector) in element k
of c-bytevector.</p>
<p>(<strong>c-bytevector-pointer-ref</strong>
<em>c-bytevector</em> <em>k</em> <em>pointer</em>)</p>
<p>If K is not a valid index of c-bytevector the behaviour is
undefined.</p>
<p>Returns the pointer(which is also c-bytevector) at index k of
c-bytevector.</p>
<h3 id="primitives-2">Primitives 2</h3>
<p>(<strong>define-c-callback</strong> <em>scheme-name</em>
<em>return-type</em> <em>argument-types</em>
<em>procedure</em>)</p>
<p>Takes scheme-name to bind the Scheme procedure to,
return-type, argument-types and procedure as in place
lambda.</p>
<p>Defines a new Sceme function to be used as callback to C
code.</p>
<p>Example:</p>
<pre><code>; Load the shared library
(cond-expand
(windows (define-c-library libc-stdlib &#39;(&quot;stdlib.h&quot;) &quot;ucrtbase&quot; &#39;()))
(else (define-c-library &#39;(&quot;stdlib.h&quot;) &quot;c&quot; &#39;(&quot;&quot; &quot;6&quot;))))
; Define C function that takes a callback
(define-c-procedure qsort libc-stdlib &#39;qsort &#39;void &#39;(pointer int int callback))
; Define our callback
(pffi-define-callback compare
&#39;int
&#39;(pointer pointer)
(lambda (pointer-a pointer-b)
(let ((a (pffi-pointer-get pointer-a &#39;int 0))
(b (pffi-pointer-get pointer-b &#39;int 0)))
(cond ((&gt; a b) 1)
((= a b) 0)
((&lt; a b) -1)))))
; Create new array of ints to be sorted
(define array (make-c-bytevector (* (c-size-of &#39;int) 3)))
(pffi-pointer-set! array &#39;int (* (c-size-of &#39;int) 0) 3)
(pffi-pointer-set! array &#39;int (* (c-size-of &#39;int) 1) 2)
(pffi-pointer-set! array &#39;int (* (c-size-of &#39;int) 2) 1)
(display array)
(newline)
;&gt; (3 2 1)
; Sort the array
(qsort array 3 (c-size-of &#39;int) compare)
(display array)
(newline)
;&gt; (1 2 3)</code></pre>
<h3 id="c-bytevector">c-bytevector</h3>
<h4 id="creation-and-deletion">Creation and deletion</h4>
<p>(<strong>make-c-null</strong>)</p>
<p>Returns a null C pointer.</p>
<p>(<strong>c-null?</strong> <em>obj</em>)</p>
<p>Returns <strong>#t</strong> if <em>obj</em> is a null C
pointer, otherwise returns <strong>#f</strong>.</p>
<p>(<strong>c-free</strong> <em>c-bytevector</em>)</p>
<p>Frees <em>c-bytevector</em> from memory.</p>
<p>(<strong>make-c-bytevector</strong> <em>k</em>)
(<strong>make-c-bytevector</strong> <em>k</em>
<em>fill</em>)</p>
<p>Returns a newly allocated c-bytevector of <em>k</em>
bytes.</p>
<p>If the <em>fill</em> argument is missing, the initial
contents of the returned c-bytevector are unspecified.</p>
<p>If the <em>fill</em> argument is present, its value must
confine to C uint8_t values , it specifies the initial value for
the bytes of the c-bytevector</p>
<h4 id="accessors">Accessors</h4>
<p>(<strong>native-endianness</strong>)</p>
<p>c-bytevector-s8-set! c-bytevector-s8-ref
c-bytevector-s16-set! c-bytevector-s16-ref
c-bytevector-s16-native-set! c-bytevector-s16-native-ref
c-bytevector-u16-set! c-bytevector-u16-ref
c-bytevector-u16-native-set! c-bytevector-u16-native-ref
c-bytevector-s32-set! c-bytevector-s32-ref
c-bytevector-s32-native-set! c-bytevector-s32-native-ref
c-bytevector-u32-set! c-bytevector-u32-ref
c-bytevector-u32-native-set! c-bytevector-u32-native-ref
c-bytevector-s64-set! c-bytevector-s64-ref
c-bytevector-s64-native-set! c-bytevector-s64-native-ref
c-bytevector-u64-set! c-bytevector-u64-ref
c-bytevector-u64-native-set! c-bytevector-u64-native-ref
c-bytevector-sint-set! c-bytevector-sint-ref
c-bytevector-uint-set! c-bytevector-uint-ref
c-bytevector-ieee-single-set!
c-bytevector-ieee-single-native-set!
c-bytevector-ieee-single-ref c-bytevector-ieee-single-native-ref
c-bytevector-ieee-double-set!
c-bytevector-ieee-double-native-set!
c-bytevector-ieee-double-ref c-bytevector-ieee-double-native-ref
bytevector-&gt;c-bytevector c-bytevector-&gt;bytevector
call-with-address-of</p>
<p>string-&gt;c-utf8 c-utf8-&gt;string</p>
<h3 id="environment-variables">Environment variables</h3>
<p>Setting environment variables like this on Windows works for
this library:</p>
<pre><code>set &quot;PFFI_LOAD_PATH=C:\Program Files (x86)/foo/bar&quot;</code></pre>
<h4 id="pffi_load_path">PFFI_LOAD_PATH</h4>
<p>To add more paths to where pffi looks for libraries set
PFFI_LOAD_PATH to paths separated by ; on windows, and : on
other operating systems.</p>
</body>
</html>