Allegro CL support in SWIG

SWIG is a tool for automatically generating interfaces to C/C++
libraries for use with non-C/C++ programming languages. We have added
a module to SWIG to support generation of interface code suitable for
Allegro Common Lisp. (SWIG stands for Simplified Wrapper and
Interface Generator.)

Why SWIG is useful

Without SWIG, def-foreign-call
is used to create a link between a non-Lisp function residing in a
library and Lisp. But if the library you are interfacing to has many
functions, it can become very tedious to write all the suitable
def-foreign-call forms. The Allegro CL module for SWIG allows
you to automate this process if you have access to the C/C++ header
files for the library.

You will need to be familiar with foreign function calls to properly
use generated interfaces. See foreign-functions.htm.

To use SWIG you need to start with an interface file. Here is an
example. The interface file will be called test.i.

The first thing in the interface file should be a %module
directive. The %module directive is used to define the package
in which the foreign calls and constants will be defined. It is also
used to determine the name of the generated .cl file.

/* Example file: test.i */
%module mypackage

The remainder of the interface file should be populated with the C
function prototypes, typedefs, structure definitions, and preprocessor
directives which define the API.

you will end up with a file called mypackage.cl. Note:
unless told to do otherwise, swig generates the output file in
the same directory as the input file (rather than in the current
working directory if it is different). This can be quite surprising
sometimes.

In mypackage.cl you will find generated code that will not be
pretty to look at. It is not intended for human consumption, but you
will see some constructs that you will recognize: a defpackage
form for :mypackage, defconstants for COMPUTE_STYLE_SQUARE and
COMPUTE_STYLE_SQRT, def-foreign-calls for compute,
open_device, operate_device, and
write_device_number.

You will also notice that SWIG has broken down the typedefs
back into their lowest level types. E.g., the argument type and
return type in the def-foreign-call for compute are
specified as double.

You may notice that all pointers have been translated to
:foreign-address, regardless of what they point to. Make sure you are
just as careful with pointers as you would be in C. Misuse of
pointers can lead to very confusing garbage collection errors.

To use this fictional test API, start up Lisp, load the shared library
object that contains the code that implements the API, and then load
in the generated mypackage.cl file. You could also load the
mypackage.cl file first. The order doesn't matter as long as the
shared library is loaded before you attempt to call one of the API
functions.

Notice in the sample code that we don't just pass the number 100000 to
write_device_number. That is because
write_device_number is expecting a pointer to an integer. If we
just passed 100000, then write_device_number would try to
access address 100000, which would be incorrect. Instead, we create an array
of one element and store the number 100000 there and we pass the array
in. When you pass an array to a foreign function, the address of the
first element is what is really passed.

If you have the C header files for the API that you are interfacing
to, you can save a lot of time by telling SWIG that you want it to
parse the header file to extract the function prototypes, constants,
etc. You do this using the %include directive.

Important note: SWIG does not follow #include directives by
default. This is so that it won't generate a bunch of code for stuff
that really isn't part of the API you're working with. For example,
if testapi.h had "#include <stdio.h>" at the top of it, you
wouldn't want all the stdio.h stuff to be made part of your
mypackage.cl file. This means that if there are relevant
#include files in testapi.h, you will need to add
%include directives to the .i file so SWIG will look at
them. (If you know what you are doing, you can pass the -includeall
command line option to SWIG to make it follow all #include
directives.)

You can also cause your own code to be inserted into the .cl
file. To do so, use the %wrapper %{ %} syntax.