21 SWIG and Common Lisp

Common Lisp is a high-level, all-purpose, object-oriented, dynamic, functional programming language with long history. Common Lisp is used in many fields, ranging from web development to finance, and also common in computer science education. There are more than 9 different implementations of common lisp which are available, all have different foreign function interfaces. SWIG currently supports only the Allegro Common Lisp, Common Foreign Function Interface(CFFI), CLisp and UFFI foreign function interfaces.

21.1 Allegro Common Lisp

Allegro Common Lisp support in SWIG has been updated to include support for both C and C++. You can read about the interface here

21.2 Common Foreign Function Interface(CFFI)

CFFI, the Common Foreign Function Interface, is a portable foreign function interface for ANSI Common Lisp systems, similar in spirit to UFFI. Unlike UFFI, CFFI requires only a small set of low-level functionality from the Lisp implementation, such as calling a foreign function by name, allocating foreign memory, and dereferencing pointers.

To run the cffi module of SWIG requires very little effort, you just need to run:

swig -cffi -module module-name   file-name 

But a better was of using all the power of SWIG is to write SWIG interface files. Below we will explain how to write interface files and the various things which you can do with them.

21.2.1 Additional Commandline Options

The following table list the additional commandline options available for the CLISP module. They can also be seen by using:

swig -cffi -help 

CFFI specific options
-generate-typedef If this option is given then defctype will be used to generate shortcuts according to the typedefs in the input.
-[no]cwrap Turn on or turn off generation of an intermediate C file when creating a C interface. By default this is only done for C++ code.
-[no]swig-lisp Turns on or off generation of code for helper lisp macro, functions, etc. which SWIG uses while generating wrappers. These macros, functions may still be used by generated wrapper code.

21.2.2 Generating CFFI bindings

As we mentioned earlier the ideal way to use SWIG is to use interface files. To illustrate the use of it, lets assume that we have a file named test.h with the following C code:
#define y 5
#define x (y >>  1)

typedef int days;

struct bar {
  short p, q;
    char a, b;
    int *z[1000];
    struct bar * n;
};
  
struct   bar * my_struct;

struct foo {
    int a;
    struct foo * b[100];
  
};

int pointer_func(void (*ClosureFun)( void* _fun, void* _data, void* _evt ), int p);

int func123(div_t * p,int **q[100],int r[][1000][10]);

void lispsort_double (int n, double * array);

enum color { RED, BLUE, GREEN};
Corresponding to this we will write a simple interface file:
%module test

%include "test.h"

The generated SWIG Code will be:
;;;SWIG wrapper code starts here

(cl:defmacro defanonenum (&body enums)
   "Converts anonymous enums to defconstants."
  `(cl:progn ,@(cl:loop for value in enums
                        for index = 0 then (cl:1+ index)
                        when (cl:listp value) do (cl:setf index (cl:second value)
                                                          value (cl:first value))
                        collect `(cl:defconstant ,value ,index))))

(cl:eval-when (:compile-toplevel :load-toplevel)
  (cl:unless (cl:fboundp 'swig-lispify)
    (cl:defun swig-lispify (name flag cl:&optional (package cl:*package*))
      (cl:labels ((helper (lst last rest cl:&aux (c (cl:car lst)))
                    (cl:cond
                      ((cl:null lst)
                       rest)
                      ((cl:upper-case-p c)
                       (helper (cl:cdr lst) 'upper
                               (cl:case last
                                 ((lower digit) (cl:list* c #\- rest))
                                 (cl:t (cl:cons c rest)))))
                      ((cl:lower-case-p c)
                       (helper (cl:cdr lst) 'lower (cl:cons (cl:char-upcase c) rest)))
                      ((cl:digit-char-p c)
                       (helper (cl:cdr lst) 'digit 
                               (cl:case last
                                 ((upper lower) (cl:list* c #\- rest))
                                 (cl:t (cl:cons c rest)))))
                      ((cl:char-equal c #\_)
                       (helper (cl:cdr lst) '_ (cl:cons #\- rest)))
                      (cl:t
                       (cl:error "Invalid character: ~A" c)))))
        (cl:let ((fix (cl:case flag
                        ((constant enumvalue) "+")
                        (variable "*")
                        (cl:t ""))))
          (cl:intern
           (cl:concatenate
            'cl:string
            fix
            (cl:nreverse (helper (cl:concatenate 'cl:list name) cl:nil cl:nil))
            fix)
           package))))))

;;;SWIG wrapper code ends here


(cl:defconstant y 5)

(cl:defconstant x (cl:ash 5 -1))

(cffi:defcstruct bar
	(p :short)
	(q :short)
	(a :char)
	(b :char)
	(z :pointer)
	(n :pointer))

(cffi:defcvar ("my_struct" my_struct)
 :pointer)

(cffi:defcstruct foo
	(a :int)
	(b :pointer))

(cffi:defcfun ("pointer_func" pointer_func) :int
  (ClosureFun :pointer)
  (p :int))

(cffi:defcfun ("func123" func123) :int
  (p :pointer)
  (q :pointer)
  (r :pointer))

(cffi:defcfun ("lispsort_double" lispsort_double) :void
  (n :int)
  (array :pointer))

(cffi:defcenum color
	:RED
	:BLUE
	:GREEN)

The SWIG wrapper code refers to the special code which SWIG may need to use while wrapping C code. You can turn on/off the generation of this code by using the -[no]swig-lisp option. You must have noticed that SWIG goes one extra step to ensure that CFFI does not do automatic lispification of the C function names. The reason SWIG does this is because quite often developers want to build a nice CLOS based lispy API, and this one to one correspondence between C function names and lisp function name helps.

Maybe you want to have your own convention for generating lisp function names for corresponding C function names, or you just want to lispify the names, also, before we forget you want to export the generated lisp names. To do this, we will use the SWIG feature directive. Let's edit the interface file such that the C type "div_t*" is changed to Lisp type ":my-pointer", we lispify all names, export everything, and do some more stuff.

%module test

%typemap(cin) div_t* ":my-pointer";

%feature("intern_function","1");
%feature("export");

%feature("inline") lispsort_double;

%feature("intern_function", "my-lispify") lispsort_double;
%rename func123 renamed_cool_func;
%ignore "pointer_func";

%include "test.h"

The typemap(cin) ensures that for all arguments which are input to C with the type "div_t*", the ":my-pointer" type be used. Similarly typemap(cout) are used for all types which are returned from C.

The feature intern_function ensures that all C names are interned using the swig-lispify function. The "1" given to the feature is optional. The use of feature like %feature("intern_function","1"); globally enables interning for everything. If you want to target a single function, or declaration then use the targeted version of feature, %feature("intern_function", "my-lispify") lispsort_double;, here we are using an additional feature which allows us to use our lispify function.

The export feature allows us to export the symbols. The inline feature declaims the declared function as inline. The rename directive allows us to change the name(it is useful when generating C wrapper code for handling overloaded functions). The ignore directive ignores a certain declaration.

There are several other things which are possible, to see some example of usage of SWIG look at the Lispbuilder and wxCL projects. The generated code with 'noswig-lisp' option is:

(cl:defconstant #.(swig-lispify "y" 'constant) 5)

(cl:export '#.(swig-lispify "y" 'constant))

(cl:defconstant #.(swig-lispify "x" 'constant) (cl:ash 5 -1))

(cl:export '#.(swig-lispify "x" 'constant))

(cffi:defcstruct #.(swig-lispify "bar" 'classname)
	(#.(swig-lispify "p" 'slotname) :short)
	(#.(swig-lispify "q" 'slotname) :short)
	(#.(swig-lispify "a" 'slotname) :char)
	(#.(swig-lispify "b" 'slotname) :char)
	(#.(swig-lispify "z" 'slotname) :pointer)
	(#.(swig-lispify "n" 'slotname) :pointer))

(cl:export '#.(swig-lispify "bar" 'classname))

(cl:export '#.(swig-lispify "p" 'slotname))

(cl:export '#.(swig-lispify "q" 'slotname))

(cl:export '#.(swig-lispify "a" 'slotname))

(cl:export '#.(swig-lispify "b" 'slotname))

(cl:export '#.(swig-lispify "z" 'slotname))

(cl:export '#.(swig-lispify "n" 'slotname))

(cffi:defcvar ("my_struct" #.(swig-lispify "my_struct" 'variable))
 :pointer)

(cl:export '#.(swig-lispify "my_struct" 'variable))

(cffi:defcstruct #.(swig-lispify "foo" 'classname)
	(#.(swig-lispify "a" 'slotname) :int)
	(#.(swig-lispify "b" 'slotname) :pointer))

(cl:export '#.(swig-lispify "foo" 'classname))

(cl:export '#.(swig-lispify "a" 'slotname))

(cl:export '#.(swig-lispify "b" 'slotname))

(cffi:defcfun ("renamed_cool_func" #.(swig-lispify "renamed_cool_func" 'function)) :int
  (p :my-pointer)
  (q :pointer)
  (r :pointer))

(cl:export '#.(swig-lispify "renamed_cool_func" 'function))

(cl:declaim (cl:inline #.(my-lispify "lispsort_double" 'function)))

(cffi:defcfun ("lispsort_double" #.(my-lispify "lispsort_double" 'function)) :void
  (n :int)
  (array :pointer))

(cl:export '#.(my-lispify "lispsort_double" 'function))

(cffi:defcenum #.(swig-lispify "color" 'enumname)
	#.(swig-lispify "RED" 'enumvalue :keyword)
	#.(swig-lispify "BLUE" 'enumvalue :keyword)
	#.(swig-lispify "GREEN" 'enumvalue :keyword))

(cl:export '#.(swig-lispify "color" 'enumname))

21.2.3 Generating CFFI bindings for C++ code

This feature to SWIG (for CFFI) is very new and still far from complete. Pitch in with your patches, bug reports and feature requests to improve it.

Generating bindings for C++ code, requires -c++ option to be present and it first generates C binding which will wrap the C++ code, and then generates the corresponding CFFI wrapper code. In the generated C wrapper code, you will often want to put your own C code, such as the code to include various files. This can be done by making use of "%{" and "%}" as shown below.

%{
 #include "Test/test.h"
%}

Also, while parsing the C++ file and generating C wrapper code SWIG may need to be able to understand various symbols used in other header files. To help SWIG in doing this while ensuring that wrapper code is g the %varargs directive is probably the easiest way to tackle the problem. However, using typemaps, it is possible to do some very advanced kinds of wrapping.

One point of discussion concerns the structure of the libffi examples in the previous section. Looking at that code, it is not at all clear that this is the easiest way to solve the problem. However, there are a number of subtle aspects of the solution to consider--mostly concerning the way in which the problem has been decomposed. First, the example is structured in a way that tries to maintain separation between wrapper-specific information and the declaration of the function itself. The idea here is that you might structure your interface like this:

%typemap(const char *fmt, ...) {
   ...
}
%feature("action") traceprintf {
   ...
}

/* Include some header file with traceprintf in it */
%include "someheader.h"

Second, careful scrutiny will reveal that the typemaps involving (...) have nothing whatsoever to do with the libffi library. In fact, they are generic with respect to the way in which the function is actually called. This decoupling means that it will be much easier to consider other library alternatives for making the function call. For instance, if libffi wasn't supported on a certain platform, you might be able to use something else instead. You could use conditional compilation to control this:

#ifdef USE_LIBFFI
%feature("action") printf {
   ...
}
#endif
#ifdef USE_OTHERFFI
%feature("action") printf {
...
}
#endif

Finally, even though you might be inclined to just write a hand-written wrapper for varargs functions, the techniques used in the previous section have the advantage of being compatible with all other features of SWIG such as exception handling.

As a final word, some C programmers seem to have the assumption that the wrapping of variable length argument functions is an easily solved problem. However, this section has hopefully dispelled some of these myths. All things being equal, you are better off avoiding variable length arguments if you can. If you can't avoid them, please consider some of the simple solutions first. If you can't live with a simple solution, proceed with caution. At the very least, make sure you carefully read the section "A7.3.2 Function Calls" in Kernighan and Ritchie and make sure you fully understand the parameter passing conventions used for varargs. Also, be aware of the platform dependencies and reliability issues that this will introduce. Good luck.

./usr/share/doc/swig-doc/Manual/Lisp.html0000644000000000000000000005610711034014446017125 0ustar rootroot SWIG and Common Lisp

21 SWIG and Common Lisp

Common Lisp is a high-level, all-purpose, object-oriented, dynamic, functional programming language with long history. Common Lisp is used in many fields, ranging from web development to finance, and also common in computer science education. There are more than 9 different implementations of common lisp which are available, all have different foreign function interfaces. SWIG currently supports only the Allegro Common Lisp, Common Foreign Function Interface(CFFI), CLisp and UFFI foreign function interfaces.

21.1 Allegro Common Lisp

Allegro Common Lisp support in SWIG has been updated to include support for both C and C++. You can read about the interface here

21.2 Common Foreign Function Interface(CFFI)

CFFI, the Common Foreign Function Interface, is a portable foreign function interface for ANSI Common Lisp systems, similar in spirit to UFFI. Unlike UFFI, CFFI requires only a small set of low-level functionality from the Lisp implementation, such as calling a foreign function by name, allocating foreign memory, and dereferencing pointers.

To run the cffi module of SWIG requires very little effort, you just need to run:

swig -cffi -module module-name   file-name 

But a better was of using all the power of SWIG is to write SWIG interface files. Below we will explain how to write interface files and the various things which you can do with them.

21.2.1 Additional Commandline Options

The following table list the additional commandline options available for the CLISP module. They can also be seen by using:

swig -cffi -help 

CFFI specific options
-generate-typedef If this option is given then defctype will be used to generate shortcuts according to the typedefs in the input.
-[no]cwrap Turn on or turn off generation of an intermediate C file when creating a C interface. By default this is only done for C++ code.
-[no]swig-lisp Turns on or off generation of code for helper lisp macro, functions, etc. which SWIG uses while generating wrappers. These macros, functions may still be used by generated wrapper code.

21.2.2 Generating CFFI bindings

As we mentioned earlier the ideal way to use SWIG is to use interface files. To illustrate the use of it, lets assume that we have a file named test.h with the following C code:
#define y 5
#define x (y >>  1)

typedef int days;

struct bar {
  short p, q;
    char a, b;
    int *z[1000];
    struct bar * n;
};
  
struct   bar * my_struct;

struct foo {
    int a;
    struct foo * b[100];
  
};

int pointer_func(void (*ClosureFun)( void* _fun, void* _data, void* _evt ), int p);

int func123(div_t * p,int **q[100],int r[][1000][10]);

void lispsort_double (int n, double * array);

enum color { RED, BLUE, GREEN};
Corresponding to this we will write a simple interface file:
%module test

%include "test.h"

The generated SWIG Code will be:
;;;SWIG wrapper code starts here

(cl:defmacro defanonenum (&body enums)
   "Converts anonymous enums to defconstants."
  `(cl:progn ,@(cl:loop for value in enums
                        for index = 0 then (cl:1+ index)
                        when (cl:listp value) do (cl:setf index (cl:second value)
                                                          value (cl:first value))
                        collect `(cl:defconstant ,value ,index))))

(cl:eval-when (:compile-toplevel :load-toplevel)
  (cl:unless (cl:fboundp 'swig-lispify)
    (cl:defun swig-lispify (name flag cl:&optional (package cl:*package*))
      (cl:labels ((helper (lst last rest cl:&aux (c (cl:car lst)))
                    (cl:cond
                      ((cl:null lst)
                       rest)
                      ((cl:upper-case-p c)
                       (helper (cl:cdr lst) 'upper
                               (cl:case last
                                 ((lower digit) (cl:list* c #\- rest))
                                 (cl:t (cl:cons c rest)))))
                      ((cl:lower-case-p c)
                       (helper (cl:cdr lst) 'lower (cl:cons (cl:char-upcase c) rest)))
                      ((cl:digit-char-p c)
                       (helper (cl:cdr lst) 'digit 
                               (cl:case last
                                 ((upper lower) (cl:list* c #\- rest))
                                 (cl:t (cl:cons c rest)))))
                      ((cl:char-equal c #\_)
                       (helper (cl:cdr lst) '_ (cl:cons #\- rest)))
                      (cl:t
                       (cl:error "Invalid character: ~A" c)))))
        (cl:let ((fix (cl:case flag
                        ((constant enumvalue) "+")
                        (variable "*")
                        (cl:t ""))))
          (cl:intern
           (cl:concatenate
            'cl:string
            fix
            (cl:nreverse (helper (cl:concatenate 'cl:list name) cl:nil cl:nil))
            fix)
           package))))))

;;;SWIG wrapper code ends here


(cl:defconstant y 5)

(cl:defconstant x (cl:ash 5 -1))

(cffi:defcstruct bar
	(p :short)
	(q :short)
	(a :char)
	(b :char)
	(z :pointer)
	(n :pointer))

(cffi:defcvar ("my_struct" my_struct)
 :pointer)

(cffi:defcstruct foo
	(a :int)
	(b :pointer))

(cffi:defcfun ("pointer_func" pointer_func) :int
  (ClosureFun :pointer)
  (p :int))

(cffi:defcfun ("func123" func123) :int
  (p :pointer)
  (q :pointer)
  (r :pointer))

(cffi:defcfun ("lispsort_double" lispsort_double) :void
  (n :int)
  (array :pointer))

(cffi:defcenum color
	:RED
	:BLUE
	:GREEN)

The SWIG wrapper code refers to the special code which SWIG m