Вопрос

I want to generate a common lisp cffi wrapper for a C library (SOIL) and while I'm confident in cl & cffi I am not sure what libraries to use or how to get started with them. Basically I would ask a more detailed question but don't know what I don't know.

Это было полезно?

Решение

[UPDATE] This is rather out of date. These days I'd recommend looking into cl-autowrap or cffi/c2ffi


There are a few wrapper generators out there but there are two names that stand out from the group, SWIG and Verrazano.


Verrazano is unmaintained now and so really shouldn't be relied upon, however for your use with the SOIL library it worked...kind of! The steps that follow have been taken straight from the examples on using the kinect with common lisp.

First, make sure you have gcxml installed. For me this was done as follows:

sudo apt-get install gccxml

And now in your repl (you may have to edit the path based on your system):

(ql:quickload :cffi)
(ql:quickload :verrazano)
(verrazano:generate-binding (list :cffi :package-name :soil :input-files (list "SOIL/SOIL.h")))

You now have a wrapper in the soil.lisp file. Straight away I found problems, the enums were named very strangely (.-1 .-2 etc) and these same odd names were being exported. I removed these and renamed the enums. You then find that the enums are not used in the function calls so you will want to modify the 'defcfun' calls to make use of them.

I would recommend finding a library that has already done this to use as a guide if you are not used to doing this. I found lispbuilder to have some extensive examples in this area.


SWIG is definitely the better option and will serve you well even with complicated libraries. The general practice is that you write a SWIG interface file which tells swig where to find the library and then which features to wrap. SWIG's documentation is extensive and very good:

http://www.swig.org/Doc2.0/Contents.html#Contents

Also check out their page on Swig and Common Lisp http://www.swig.org/Doc2.0/Lisp.html

Now it is a good idea to use the separate interface files for the following reasons (taken from the swig documentation)

  • It is rarely necessary to access every single function in a large package. Many C functions might have little or no use in a scripted environment. Therefore, why wrap them?
  • Separate interface files provide an opportunity to provide more precise rules about how an interface is to be constructed.
  • Interface files can provide more structure and organization.
  • SWIG can't parse certain definitions that appear in header files. Having a separate file allows you to eliminate or work around these problems.
  • Interface files provide a more precise definition of what the interface is. Users wanting to extend the system can go to the interface file and immediately see what is available without having to dig it out of header files.

...HOWEVER, you can often get away without writing one and let SWIG work it out. For soil this involves the following:

Write a file called soil.i and put the following inside it (you may need to change the paths).

%module soil
%{
/* Includes the header in the wrapper code */
#include "/usr/include/SOIL/SOIL.h"
%}

/* Parse the header file to generate wrappers */
%include "/usr/include/SOIL/SOIL.h"

Next run the following at the terminal swig -cffi -module soil soil.i

And you will have a new soil.lisp file. As with verrazano go have a look a the function calls to see how the enums are being used (or more likely not being used).


Now with both of these you will almost certainly want to make things more 'lispy'. Often there are pointers passed in to functions to be populated by the C function which you will want to hide from your users.

That is a place to start, hopefully you can work from here. Ciao

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top