Interfacing the library and glue code to the interpreter
========================================================

The methods for integrating support for a g-wrapped API into various
target languages vary, so these will have to be dealt with on a case by
case basis.

At the moment only the primitive tool g-wrap-config is documented here.
It can provide the information needed for linking g-wrap into a target
executable for each of the languages g-wrap supports (presuming linking
even makes sense).  Consider this entire area one that's still under
development, so expect the details to change.

Right now code can be statically linked to the interpreters, or loaded
dynamically as shared libraries.  To find out which libraries are
required use the g-wrap-config command.  It may be invoked as follows:

`g-wrap-config --version'
     show version information

`g-wrap-config --help'
     show this message

`g-wrap-config --c-compile-args LANGUAGE'
     C compile args for LANGUAGE

`g-wrap-config --c-link-args LANGUAGE'
     C link args for LANGUAGE

`g-wrap-config --c-static-link-args LANGUAGE'
     C static link args for LANGUAGE

where (at the moment) LANGUAGE may be either rscheme or guile.  Examples
for each of the target languages will be available in the distribution.

This infrastructure is probably not sufficient in the long run if g-wrap
is extended to support many languages, but it's a start, and it handles
the current scope fairly well.

Coping With Old Guile Versions
==============================

The guile interface for dealing with pointers was changed between
version 1.3 and subsequent releases (including 1.3.4), and g-wrap was
changed to use the new interface.  However, as some older distributions
still use guile 1.3 it has been necessary to keep the option of the old
interface available.  If you only use 1.3.4 or later versions of guile,
you can safely ignore this section.

To use the old interface, make sure the C constant GWRAP_OLD_GUILE_SMOB
is defined when compiling the generated C file.

If you are using autoconf, a macro AC_GWRAP_CHECK_GUILE, with no
arguments, is provided in g-wrap.m4.  It checkes which version of guile
is available, and if necessary sets  GWRAP_OLD_STYLE_SMOB.  If you use
it, make sure to include the line

     #undef GWRAP_OLD_STYLE_SMOB

in either acconfig.h, or config.h.in, depending on how you are using
autoconf.  Of course, if you do this, you must ensure config.h is
#included when you compile the generated C file!

For more details on autoconf see its extensive documentation.

NOTE: we can't guarantee that old versions of guile will be supported
forever.  We will try to ensure that most of the versions currently
being distributed work, but we're not in a position to keep multiple
layers of compatability code.

Types available by default
**************************

By default g-wrap supports the following types.  Each may be used as the
TYPE-SYM in calls to `new-function':

Guile Types
===========

`void'
     nothing, on both the C and Scheme sides.

`char'
     a C `char' and a Scheme character.

`int'
     a C `int' and a Scheme number.

`unsigned-int'
     a C `unsigned int' and a Scheme number.

`unsigned-long'
     a C `unsigned long' and a Scheme number.

`unsigned-long-long'
     a C `unsigned long long' and a Scheme number.

`float'
     a C `float' and a Scheme number.

`double'
     a C `double' and a Scheme number.

`bool'
     a C `int' and a Scheme boolean.

`string-as-symbol'
     a C `char *' and a Scheme symbol.  This type lets you pass symbols
     to C as strings and get them back as symbols.  Note that by
     default it is assumed that C returns freshly malloced strings, so
     they'll be deleted immediately.  You can override this on a per
     function basis with the 'no-cleanup option.  For details see the
     description of `make-complex-c-type' in the section on
     Defining basic Scheme/C types.  WARNING, this type is new and
     subject to change.  Don't rely on it unless you're willing to
     possibly have to rewrite your spec file a bit when things stablize.

`const-string'
     a C `char *' and a Scheme string.  This type lets you pass strings
     from Scheme to C and back, but bear in mind that by default, it
     takes the conservative (but leaky) position of assuming that the C
     code might store for later use any strings passed in as arguments,
     and might pass back as return values strings that are shared
     elsewhere, or for some other reason cannot be disposed of.  This
     means that g-wrap will not, by default free the strings it
     allocates to pass to the underlying C function as parameters, and
     it will not free any string that the C function might return.  You
     can override this behavior on a per function basis with the
     'cleanup option; for details see the description of
     `make-complex-c-type' in the section on Defining basic Scheme/C types.
     WARNING, the cleanup functionality is new and
     subject to change.  Don't rely on it unless you're willing to
     possibly have to rewrite your spec file a bit when things stablize.

     FIXME: we need a node covering memory allocation.  Combine it with
     the final node discussing garbage collection.  In the end we need
     a more general approach in g-wrap.

`tSCM'
     This is a "transparent" type that allows you to pass a Scheme
     object directly to a C function, or receive one as a return value
     through the standard Guile SCM type.

The Guile side also supports pointer tokens and pointer arrays.  For
more information, see Pointer Tokens and Pointer Arrays.

Pointer Tokens and Pointer Arrays
---------------------------------

WARNING: Like the "cleanup" functionality, pointer tokens and pointer
arrays should be considered highly experimental and subject to change
up until at least 1.X of g-wrap is released.  Don't use this unless
you're willing to have to re-write everything that depends on it later.
It is currently being tested in GnuCash, but isn't claimed to be ready
for prime-time.  Further, in it's final incarnation, we probably need a
more coherent mechanism.  As it stands this is a first draft, and
things are added as needed.

That said, pointer tokens and pointer arrays provide a method for
handling C pointers as arguments and return values.  Pointer tokens
handle pointers to C structures and pointer arrays handle C arrays of
pointers.

Pointer Tokens
..............

Before deciding to use pointer tokens, please see the warning here
Pointer Tokens and Pointer Arrays.

Pointer tokens provide a method for handling pointers to C structures.
For example, if you had a C function that took as an argument a Lead*
and returned a Gold*, you could tell g-wrap how to handle these pointers
and related functions.

     (make-pointer-token-type 'Lead* "Lead*")
     (make-pointer-token-type 'Gold* "Gold*")
     (new-function
      'frobnicate
      'Gold* "frobnicate" '((Lead* lead))
      "Frobnicate.")

The calls to `make-pointer-token-type' tell g-wrap to create a Scheme
level object for each type that can hold the lower level C pointer at
the Scheme level.  Pointer token objects are represented as opaque
objects (SMOBs actually).  You can pass them around to wrapped C
functions, and there are some support functions for manipulating them
that are detailed below.  You can't directly create pointer tokens at
the Scheme level.  Right now, they're only created as the return values
of C level functions.

Null pointers are just represented by #f.  If a wrapped function tries
to return a null pointer, g-wrap will convert it to #f, and if you pass
in #f to a function that expects a pointer token then g-wrap will
arrange for a null pointer to be passed to the underlying wrapped
function.

The pointer token items themselves are garbage collected, as you would
expect, but the pointers they contain are never touched directly by the
g-wrap subsystems, so it's up to you (or the functions being called) to
handle de-allocation of the associated C-level Foo* pointers.  This will
usually be handled by some sequence like this:

     (define bar (c-func-to-create-foo-pointer))
     (c-func-to-manipulate-foo-pointer bar)
     (c-func-to-destroy-foo-pointer bar)

FIXME: There are also some functions available at the C level for
manuipulating pointer tokens from there, but at the moment those
functions are not documented.

Pointer Arrays
..............

Before deciding to use pointer arrays, please see the warning here
Pointer Tokens and Pointer Arrays.

Pointer arrays provide a method for handling arrays of C pointers to
structures.  At the moment, pointer arrays presume null terminated
arrays of pointers at the C level.  This is a result of the fact that
they were originally implemented to handle an interface that uses null
terminated arrays heavily.  Eventually pointer arrays will be extended
to handle both null terminated and non-null terminated arrays, probably
with two separate types.  This may mean backward-incompatible API
renaming/changes, so be warned.

Null array pointers are just represented by #f.  If a wrapped function
tries to return a null array pointer, g-wrap will convert it to #f, and
if you pass in #f to a function that expects a pointer array then g-wrap
will arrange for a null array pointer to be passed to the underlying
wrapped function.

As an example, pretend you have a C function that takes as an argument
an array of Lead* items (i.e. it has an argument of C type Lead**) and
returns an array of Gold* items, you can tell g-wrap how to handle these
pointers and related functions like this:

     (make-pointer-array-type 'Lead** "Lead**")
     (make-pointer-array-type 'Gold** "Gold**")
     (new-function
      'frobnicate
      'Gold** "frobnicate" '((Lead** lead))
      "Frobnicate.")

The calls to `make-pointer-array-type' tell g-wrap to create a Scheme
level object for each type that can hold the lower level C pointer
array at the Scheme level.  At the Scheme level, pointer array objects
are represented as opaque objects (SMOBs actually).  You can pass them
around to wrapped C functions, and there are some support functions for
manipulating them that are detailed below, but you can't directly
create pointer arrays at the Scheme level.  Right now, they're only
created as the return values of C level functions.

The pointer array items themselves are garbage collected, as you would
expect, but the pointers they contain are never touched directly by the
g-wrap subsystems, so it's up to you (or the functions being called) to
handle de-allocation of the associated C-level Foo** array objects.
This will usually be handled by some sequence like this:

     (define bar (c-func-to-create-foo-array))
     (c-func-to-manipulate-foo-arrays bar)
     (c-func-to-destroy-foo-arrays bar)

G-wrap will handle arranging for the Scheme level pointer wrappers to be
cleaned up by the garbage collector.

In addition to passing pointer arrays as parameters and receiving them
as return values, the following functions are available at the Scheme
level.  Note that right now, as mentioned above, all of the code
presumes that the pointer arrays are null terminated, so if your C
code's not set up to work thi way, then you can't use this functionality
just yet.

 - Function: pointer-array-ref pointer-array index
     Returns a pointer-token representing the C level pointer at the
     given index in the pointer-array (uses zero-indexing).

     Right now there is no range checking on the index, so you can ask
     for a bogus pointer.

 - Function: pointer-array-length pointer-array
     Returns the number of items in the pointer-array.

FIXME: There are also some functions available at the C level for
manuipulating pointer tokens from there, but at the moment those
functions are not documented.

RScheme Types
=============

FIXME: not documented yet...

Extending g-wrap and porting it to other Scheme implementations
***************************************************************

To expand the ability of g-wrap to generate glue code for a given
interpreter, you may want to add support for more Scheme data types.
This is (usually) a simple process if you understand the internal
details of how the interpreter deals with the type in question.

Defining basic Scheme/C types
=============================

For calling C functions from Scheme, a mechanism is needed for checking
the type of Scheme values, converting Scheme values to C values, and
converting C values to Scheme values.  The function `make-c-type' is
used for making a type-description object which represents how to do
this for a given Scheme implementation.

 - Function: make-c-type c-name fn-convert-to-scm fn-convert-from-scm
          fn-scm-is-a
     C-NAME is a string indicating the name of the type in C.
     FN-CONVERT-TO-SCM is a function which generates an expression to
     convert a C value of this type to a Scheme value.
     FN-CONVERT-FROM-SCM is a function which generates an expression
     convert a Scheme value into a C value of this type.   FN-SCM-IS-A
     is a function which generates a check for whether a   Scheme value
     can be converted to this type of C value.  It returns   `0' for
     false and a non-zero value for true.

     The "expressions" generated for output to C code are strings, or
     lists  or trees of strings.

 - Function: add-new-type scheme-sym the-type
     Associates a type-description object, such as that generated by
     `make-c-type', to a symbol so that symbol may be used to refer to
     a type in a parameter of a function such as `(new-function ...)'.

 - Function: add-type scheme-sym c-type-str fn-to-scm fn-from-scm fn-isa
     This both defines the type-description and assigns it to a symbol.

     A simple example of how an integer type corresponding to an
     immediate number in the Guile might be defined:
          (add-type 'int "int"
                      ;fn-convert-to-scm
                      (lambda (x) (list "SCM_MAKINUM(" x ")"))
                      ;fn-convert-from-scm
                      (lambda (x) (list "SCM_INUM(" x ")"))
                      ;fn-scm-is-a
                      (lambda (x) (list "SCM_INUMP(" x ")")))

     An example of how type `void' (used for specifying no return value
     for a function) might be defined for the Guile interpreter.
          (add-type 'void "void"
                      ;fn-convert-to-scm
                      (lambda (x) "SCM_UNSPECIFIED")
                      ;fn-convert-from-scm
                      (lambda (x) "(void)")
                      ;fn-scm-is-a
                      (lambda (x) 1))

 - Function: get-type scheme-sym
     Returns the type-description object associated with a symbol.

 - Function: make-complex-c-type c-name fn-convert-to-scm
          fn-convert-from-scm fn-scm-is-a c-cleanup-arg-default?
          c-cleanup-ret-default? fn-c-cleanup
     WARNING: This function, and the related "cleanup" system should be
     considered highly experimental and subject to change up until at
     least 1.X of g-wrap is released.  Don't use this unless you're
     willing to have to re-write everything that depends on it later.
     It is currently being tested in GnuCash, but isn't claimed to be
     ready for prime-time.  Further, in it's final incarnation, it will
     probably be a more general mechanism...

     This function creates a new g-wrap type corresponding to the C-type
     C-NAME.  Unlike NEW-TYPE, this function does not have any affect
     unless you use ADD-NEW-TYPE to tell g-wrap to add the type to its
     list of known types.

     The parameters have the following purposes:

    C-NAME
          the name of the type as far as C is concerned.

    FN-CONVERT-TO-SCM
          a function returning the C code to be used to convert this
          type from a C representation to a Scheme representation.

    FN-CONVERT-FROM-SCM
          a function returning the C code to be used to convert this
          type from a Scheme representation to a C representation.

    FN-SCM-IS-A
          a function returning the C code to be used to test if a
          Scheme object is of this type.

    C-CLEANUP-ARG-DEFAULT?
          should arguments of this type have their C representations
          (the ones created for the purpose of the C-side function
          call) be cleaned up just after the call by default?

    C-CLEANUP-RET-DEFAULT?
          should return values of this type have their C
          representations (the ones returned by a C-side function call)
          cleaned up just after they are converted to Scheme, but
          before the wrapper code returns to Scheme by default?

    FN-C-CLEANUP
          a function returning the C code to be used to clean up
          (destroy, delete, free, whatever) C representations of this
          type.

     To understand what the cleanup-related arguments do, consider a
     typical wrapper call-sequence.  First the Scheme wrapper function
     is called.  Then all of the Scheme arguments are converted to C
     representations using the convert-to-scm functions, then the C
     function is called with these arguments, and finally, the return
     value, if any is converted from its C representation back to a
     Scheme value and returned from the wrapper.

     The cleanup arguments control the final disposition of the C
     representations of the given type when used as arguments and return
     values.  If an argument is marked as 'cleanup, then just after the
     C function returns, the argument will be cleaned up using the
     c-cleanup function provided by FN-C-CLEANUP.  The same thing
     happens to the C representation of the return value just after it
     has been converted to a Scheme representation, and just before the
     wrapper returns.

     An argument or return value is considered to be "marked as
     'cleanup" if either C-CLEANUP-ARG-DEFAULT? or
     C-CLEANUP-RET-DEFAULT? is not #f respectively, or if the argument
     or return value is marked 'cleanup in the options to NEW-FUNCTION.
     For more details see Defining a new function.

     Deciding when cleanup is appropriate depends on the semantics of
     both the type in question and of a given C function.  What's
     really at issue here is the "ownership" of the C level data
     involved.  For example, imagine you have a C function that takes a
     string pointer as an argument and expects that at the time of the
     call, it becomes the "owner" of that pointer, and perhaps it takes
     that pointer and stores it in a hash table for later use.  If that
     particular argument were marked as 'cleanup in g-wrap, as soon as
     the C function was called, g-wrap would arrange for it to be
     freed, leaving the pointer in the hash table dangling.  So for
     this particular hypothetical function, the argument in question
     needs to be marked as 'no-cleanup, either as the type default
     (probably not a good idea for strings in general), or in the
     NEW-FUNCTION declaration.  For more details see Defining a new function.

     Similar considerations apply to return values.  If you had a C
     function that returned a constant string pointer from some static
     or global table, then it wouldn't be appropriate for the return
     value to be marked 'cleanup.

     Conversely there may also be types for which 'no-cleanup makes the
     most sense as a default, and then 'cleanup would need to be used
     in calls to NEW-FUNCTION occasionally.  For more details see
     Defining a new function.

     Example:

          (add-new-type
           'bar
           (make-complex-c-type
            "bar"
            ;; fn-convert-to-scm
            (lambda (x) (list "bar2scm(" x ")"))
            ;; fn-convert-from-scm
            (lambda (x) (list "scm2bar(" x ")"))
            ;; fn-scm-is-a
            (lambda (x) (list "bar_p(" x ")"))
            ;; c-cleanup-arg-default?
            #t
            ;; c-cleanup-ret-default?
            #t
            ;; fn-c-cleanup
            (lambda (x) (list "free_bar(" x ")"))))

Additional issues
*****************

The most difficult issue with wrapping a C library for use with a Scheme
interpreter seems to be the issue of memory management.  g-wrap does not
try to deal much with this issue because it is a messy one.  One
assumption made by the code generator is that objects are maintained in
the Scheme world--when the interpreter no longer references an object,
it may be garbage-collected and de-allocated.  Another assumption _is
that any object returned by a call to a C function is a new object_
which the interpreter will wrap in a new Scheme object.  If this is not
true, then it is possible for multiple Scheme objects to refer to a
single C object, and serious errors can occur.  I have written code
which uses some fancy tricks to get around this problem for certain
specific cases, but there is no simple way to deal with this problem in
general without the C library to have specific support for helping the
interpreter out.  Future versions of g-wrap may incorporate some support
for helping the C library cooperate with this issue by storing the
Scheme representation of an object inside the object itself.