To compile and load BINGE an ASDF file is provided.  Just install it
in your system directory and do

  (asdf:oos 'asdf:load-op :binge)

BINGE depends on NPG (the Naive Parser Generator) and a few system
dependent extensions (found in src/lib/sysdep).  NPG can be found in
the same place you found BINGE.


The compilation of a FFI goes through three steps: the parsing (or
extraction), the creation of the C namespace, and the generation of
the FFI itself.

For example, to generate a FFI for all the functions, types, and
global variables of the a header file foo.h (and its included
headers), you can do:

  (binge:make-ffi #P"foo-ffi.lisp"
		    (binge:extract-from-headers '("foo.h"))))

This won't extract any symbolic constant unless you explicitly specify
them with the :constants argument of extract-from-headers.

BINGE should be able to parse C source files as well, but this is
currently untested.

Both make-ffi and extract-from-headers have keyword arguments you may
want to look at, they let you specify what to extract and what type of
backend to use (in case you want to cross-generate).  In particular
the :defines and :preamble keywords of extract-from-headers come handy
to cope with weird extensions of certain compilers; for instance on
gcc-based systems you may want to use something like:

  :defines '(("__attribute__(x)" "")
  	     ("__extension__(x)" "0")
	     ("__inline" "")
	     ("__asm(x)" ""))

There is a global variable binge:*gcc-null-defines* just for this
purpose, so on FreeBSD and Linux you just need to write

  (binge:extract-from-headers '("ncurses.h")
    :defines binge:*gcc-null-defines*)

Actually gcc has many more nasty extensions and some cannot be tamed
with just few defines; the __builtin_va_list, for example.  This
needs to be manually added to the namespace as a separate declaration.

The special variable *compress-types* is an experimental feature made
to reduce the number of type declarations in the generated FFI.  It
can be set to three values:

    - NIL, don't compress, keep all the necessary declarations
    - :TYPEDEFS, remove the superfluous typedefs
    - :ALL, remove all the non strictly necessary types, converting
      the pointers to them into void pointers

A real life version of the example above would be something like:

  (setf constants-list '(...))

  (setf namespace
      (binge:extract-from-headers '("ncurses.h")
        :defines binge:*gcc-null-defines*
	:constants constants-list)))

     (make-instance 'binge-decl:c-typedef-declaration
		    :name "__builtin_va_list"
		    :type :vararg) namespace)

  (binge:make-ffi #P"ncurses-ffi.lisp" namespace
		  :functions t	; all functions
		  :constants t	; all constants
		  :backend (make-instance 'binge-backend:sbcl-backend
		  	   		  :package "NCURSES"
		  	   		  :prefix "%"))

Where you specify a list of symbolic constants to extract (:constants
some-var), tell BINGE to get all the functions, and prepend all the
exported symbols with an percentage sign (:prefix "%").

So if everything works as expected, you should be able to simply

  (sb-alien:load-1-foreign "/usr/lib/libncurses.so") ; if running SBCL
  (load "ncurses-ffi.lisp")

and use the new curses library.

In reality, this won't be enough; things must be adjusted and many
macros need to be written from scratch (the C macros).  For instance,
in this particular case, ncurses.h declares several functions which
aren't actually in the library (libncurses.so), so either you specify
a limited set of functions you want to extract, with the :functions
keyword argument of make-ffi, or you manually remove from the output
file those missing in the library.  As the former solution may be a
daunting task, given the size of the ncurses library, you'll probably
settle for the latter.

More examples can be found in the example directory.  They are
normally compiled and loaded together with the rest of BINGE and
they'll be available in the binge-examples package (see
example/package.lisp).  For instance, to generate the FFI for the
Berkeley DB library simply type


If you want to try a different backend than your default one, try for

  (let ((binge:*backend* (make-instance 'binge-backend:uffi-backend)))

The UFFI backend is unconditionally loaded first, so, if your platform
has its own specific backend, UFFI's won't be the default one.  If,
for whatever reason, you need to cross-generate a FFI for another Lisp
system you have to load the appropriate backend manually:

  (load "binge:backends;your-backend.lisp")


You might want to temper with binge:*c-preprocessor* if, to invoke the
C preprocessor, you don't use "cc -E".

If the general mechanism provided by extract-from-headers doesn't suit
your needs, you could try using binge:extract, which is a generic
function specialised on pathnames and streams.  You have to provide
your own preprocessed file or stream as the sole argument.

If you want to spare a couple of hours to write your own backend, have
a look in src/backend/sbcl.lisp for an example.  That's at the moment
the backend which is likely to be most up to date.

Although BINGE is known to compile on LispWorks 4.2 you may want to
check out this page if you run into stack limit problems:


The parsing of constant expression is still somehow limited and may
result in parser errors in some particularly complex cases; please let
me know.

Some regression tests are provided in the directory test.  You can run
them with

  (asdf:oos 'asdf:load-op :binge-tests)

or simply

  (asdf:oos 'asdf:test-op :binge)


BINGE is copyright Walter C. Pelissero (walter@pelissero.de) and under
GPL, though the files it produces are not.  See the file COPYING for
further details.