Next: sb-posix, Previous: sb-aclrepl, Up: Contributed Modules
The sb-grovel module helps in generation of foreign function
interfaces. It aids in extracting constants' values from the C
compiler and in generating SB-ALIEN structure and union types,
see Defining Foreign Types.
The ASDF(http://www.cliki.net/ASDF) component type GROVEL-CONSTANTS-FILE has its PERFORM operation defined to write out a C source file, compile it, and run it. The output from this program is Lisp, which is then itself compiled and loaded.
sb-grovel is used in a few contributed modules, and it is currently compatible only to SBCL. However, if you want to use it, here are a few directions.
(eval-when (:compile-toplevel :load-toplevel :execute)
(require :sb-grovel))
(defpackage :example-package.system
(:use :cl :asdf :sb-grovel :sb-alien))
(in-package :example-package.system)
(defsystem example-system
:depends-on (sb-grovel)
:components
((:module "sbcl"
:components
((:file "defpackage")
(grovel-constants-file "example-constants"
:package :example-package)))))
Make sure to specify the package you chose in step 1
The grovel-constants-file, typically named constants.lisp,
comprises lisp expressions describing the foreign things that you want
to grovel for. A constants.lisp file contains two sections:
("sys/types.h" "sys/socket.h" "sys/stat.h" "unistd.h" "sys/un.h"
"netinet/in.h" "netinet/in_systm.h" "netinet/ip.h" "net/if.h"
"netdb.h" "errno.h" "netinet/tcp.h" "fcntl.h" "signal.h" )
((:integer af-local
#+(or sunos solaris) "AF_UNIX"
#-(or sunos solaris) "AF_LOCAL"
"Local to host (pipes and file-domain).")
(:structure stat ("struct stat"
(integer dev "dev_t" "st_dev")
(integer atime "time_t" "st_atime")))
(:function getpid ("getpid" int )))
There are two types of things that sb-grovel can sensibly extract from
the C compiler: constant integers and structure layouts. It is also
possible to define foreign functions in the constants.lisp file, but
these definitions don't use any information from the C program; they
expand directly to sb-alien:define-alien-routine
(see The define-alien-routine Macro) forms.
Here's how to use the grovel clauses:
:integer - constant expressions in C. Used in this form:
(:integer lisp-variable-name "C expression" &optional doc export)
"C expression" will be typically be the name of a constant. But
other forms are possible.
:enum
(:enum lisp-type-name ((lisp-enumerated-name c-enumerated-name) ...)))
An sb-alien:enum type with name lisp-type-name will be defined.
The symbols are the lisp-enumerated-names, and the values
are grovelled from the c-enumerated-names.
:structure - alien structure definitions look like this:
(:structure lisp-struct-name ("struct c_structure"
(type-designator lisp-element-name
"c_element_type" "c_element_name"
:distrust-length nil)
; ...
))
type-designator is a reference to a type whose size (and type
constraints) will be groveled for. sb-grovel accepts a form of type
designator that doesn't quite conform to either lisp nor sb-alien's
type specifiers. Here's a list of type designators that sb-grovel
currently accepts:
integer - a C integral type; sb-grovel will infer the exact
type from size information extracted from the C program. All common C
integer types can be grovelled for with this type designator, but it
is not possible to grovel for bit fields yet.
(unsigned n) - an unsigned integer variable that is n
bytes long. No size information from the C program will be used.
(signed n) - an signed integer variable that is n bytes
long. No size information from the C program will be used.
c-string - an array of char in the structure. sb-grovel
will use the array's length from the C program, unless you pass it the
:distrust-length keyword argument with non-nil value
(this might be required for structures such as solaris's struct
dirent).
c-string-pointer - a pointer to a C string, corresponding to
the sb-alien:c-string type (see Foreign Type Specifiers).
(array alien-type) - An array of the previously-declared alien
type. The array's size will be determined from the output of the C
program and the alien type's size.
(array alien-type n) - An array of the previously-declared alien
type. The array's size will be assumed as being n.
Note that c-string and c-string-pointer do not have the
same meaning. If you declare that an element is of type
c-string, it will be treated as if the string is a part of the
structure, whereas if you declare that the element is of type
c-string-pointer, a pointer to a string will be the
structure member.
:function - alien function definitions are similar to
define-alien-routine definitions, because they expand to such
forms when the lisp program is loaded. See Foreign Function Calls.
(:function lisp-function-name ("alien_function_name" alien-return-type
(argument alien-type)
(argument2 alien-type)))
Let us assume that you have a grovelled structure definition:
(:structure mystruct ("struct my_structure"
(integer myint "int" "st_int")
(c-string mystring "char[]" "st_str")))
What can you do with it? Here's a short interface document:
(allocate-mystruct) - allocates an object of type mystructand
returns a system area pointer to it.
(free-mystruct var) - frees the alien object pointed to by
var.
(with-mystruct var ((member init) [...]) &body body) -
allocates an object of type mystruct that is valid in
body. If body terminates or control unwinds out of
body, the object pointed to by var will be deallocated.
(mystruct-myint var) and (mystruct-mystring var) return
the value of the respective fields in mystruct.
(setf (mystruct-myint var) new-val) and
(setf (mystruct-mystring var) new-val) sets the value of the respective
structure member to the value of new-val. Notice that in
(setf (mystruct-mystring var) new-val)'s case, new-val is a lisp
string.
Basically, you can treat functions and data structure definitions that sb-grovel spits out as if they were alien routines and types. This has a few implications that might not be immediately obvious (especially if you have programmed in a previous version of sb-grovel that didn't use alien types):
with-mystruct macro, be sure that no references
to the variable thus allocated leaks out. It will be deallocated when
the block exits.