OpenMCL uses an interface translation system based on the FFIGEN system (described here and here) to make the constant, type, structure, and function definitions in a set of .h files available to lisp code.
The basic idea of the FFIGEN scheme is to use the C compiler's frontend and parser to translate .h files into semantically equivalent .ffi files, which use an S-expression - based syntax to represent the definitions contained in those headers. Lisp code can then concentrate on the .ffi representation, without having to concern itself with the semantics of header file inclusion or the arcana of C parsing.
The original FFIGEN system used a modified version of the LCC C compiler to produce .ffi files. Since many LinuxPPC header files contain GCC-specific constructs, OpenMCL's translation system uses a modified version of GCC (called, somewhat confusingly,ffigen
.) A LinuxPPC binary
is available at:
and source differences are at:
The FFIGEN package for Darwin will be made available soon. It works much the same way as the LinuxPPC version does, but I need to package source differences relative to a reference release of Apple's modified GCC.
A shell script (distributed with the source and binary packages) called
h-to-ffi.sh
reads a specified .h file (and optional
preprocessor arguments) and writes a (hopefully) equivalent .ffi file
to standard output, calling the installed C preprocessor and the
ffigen
program with appropriate arguments.
For each interface
directory subdir distributed with OpenMCL, a shell
script (distributed with OpenMCL as
"ccl:headers;subdir;C;populate.sh"
calls
h-to-ffi.sh
on a large number of the header files
in /usr/include and creates a parallel directory tree in
"ccl:headers;subdir;C;usr;include;"
,
populating that directory with .ffi files.
A lisp function defined in
"ccl:library;parse-ffi.lisp"
reads the .ffi files
in a specified interface directory subdir and generates
new versions of the Berkeley DB 1.x
databases
("ccl:headers;subdir;constants.db"
,
"ccl:headers;subdir;functions.db"
,
"ccl:headers;subdir;records.db"
, and
"ccl:headers;subdir;types.db"
); it can
optionally produce a parallel direcory of .lisp files (in
"ccl:headers;subdir;usr;include;
). Such
.lisp files aren't used directly by OpenMCL, but may be
interesting as reference material: the information in the .db
files is an encoded version of the union of the information in
the .lisp files.
Most of the entities in the .db files are named (this is true of all types, constants, and functions and of most record types.) These names (and gensyms used to uniquely identify anonymous records) are mapped to upper case and the resulting strings are used as database keys. (The case of external function names is preserved, and this information is stored - along with parameter type information - in the "value" associated with that key.)
This means that if two distinct foreign entities - the hypothetical
functions Open
and oPeN
, for instance -
differ only in case, one of these (arbitrarily) will be accessible
in the database under the key OPEN
. It's assumed that
there are some cases where this occurs, but it's not known how
often conflicts happen. At this point, the convenience of being
able to ignore case issues from Lisp seems to be more important
in practice.
The DB databases are used by the #$ and #_ reader macros and are used in the expansion of RREF, RLET, and related macros. Note that version 1.x of Berkeley DB is released under a license which does not impose terms on how applications which use that library are distributed.
"ccl:headers;subdir;C;populate.sh"
shell
script. When you're confident that the files and preprocessor
options match your environment, cd to the
"ccl:headers;subdir;C;"
directory and
invoke ./populate.sh
. Repeat this step until
you're able to cleanly translate all files refrenced in the
shell script.
? (require "PARSE-FFI") PARSE-FFI ? (parse-standard-ffi-files :SUBDIR) ;;; lots of output ... after a while, shiny new .db files should ;;; appear in "ccl:headers;subdir;"
PARSE-STANDARD-FFI-FILES
accepts a
:PREPEND-UNDERSCORES
keyword argument. Darwin
(and some other platforms) use a convention wherein the
symbols associated with C-visible external function and
variables have underscore characters prepended to their names.
When this argument is true,
PARSE-STANDARD-FFI-FILES
will prepend underscores
to all foreign function names written to the database, so that
(#_foo ...) expands into an EXTERNAL-CALL
to
"_foo".