This is the info manual for G-Wrap, covering versions 1.9.*.

Copying
*******

Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995
Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA

Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation.

NO WARRANTY

BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

Introduction
************

Overview
========

Given a definition of the types and prototypes for a given C interface, G-Wrap will automatically generate the C code that provides access to that interface and its types from the Scheme level.

To use G-Wrap, you must make sure it knows how to handle all of the C types that the functions you will be calling take as arguments and return as values, and you must also tell G-Wrap about the C prototypes of these functions.  Since G-Wrap already knows about quite a few of the common C types, for many simple C APIs, you may not need to add any custom type specifications.

G-Wrap is implemented as a Guile module, and so its interface is a programmatic one.  You tell G-Wrap about your functions and types, and ask it to generate wrappers for you by calling the functions exported from the (g-wrap) module.

As a simple example, if you wanted to wrap a C API that contained only one function with a prototype like this

       int frob(int x, double y);

a complete G-Wrap specification would look like this:

       (define-module (my-wrapset)
         #:use-modules (oop goops))
         #:use-modules (g-wrap))

         #:export (<my-wrapset>))

       (define-class <my-wrapset> (<gw-guile-wrapset>)
         #:id 'my-wrapset
         #:dependencies '(standard))

       (define-method (initialize (ws <my-wrapset>) initargs)
         (next-method)

         (wrap-function! ws
                         #:name 'frob
                         #:returns 'int
                         #:arguments '((int x) (double y))
                         #:c-name "frob"
                         #:description "Return the result of frobbing x and y."))

You can see that the specification is encapsulated in a Guile module that exports a class - <my-wrapset> derived from <gw-wrapset>. A wrapset is the G-Wrap counterpart to some API; it describes how the API looks in C and provides additional information for the target language. The wrapset above doesn't yet provide any such information; it is abstract and can be refined for every target language.

In the define-class statement, the wrapset defines its ID, a globally unique identifier, and declares a dependency on the standard wrapset, which provides the basic C types. In the initialize method, the frob function is wrapped, providing all relevant data such as return and argument types.

To refine the above wrapset for Guile, you derive from it and add the necessary information:

     (define-module (my-guile-wrapset)
       #:use-module (oop goops)
       #:use-module (g-wrap)
       #:use-module (g-wrap guile)
       #:use-module (g-wrap guile ws standard)

       #:export (<my-guile-wrapset>)

     (define-class <my-guile-wrapset> (<my-wrapset> <gw-guile-wrapset>))

     (define-method (initialize (ws <my-guile-wrapset>) initargs)
       (next-method ws (append '(#:module (my-module)) initargs)))

We derive our Guile-specific wrapset from the generic wrapset <my-wrapset> and the base class for all Guile wrapsets <gw-guile-wrapset>. In initialize, we tell G-Wrap that the wrapset should eventually reside in the Guile module my-module.

Once G-Wrap has seen this specification, the code for the wrappers can be generated with this code:

       (use-modules (g-wrap) (g-wrap guile) (my-guile-wrapset))
       (generate-wrapset 'guile 'my-wrapset "my-wrapset")

This will produce the C file my-wrapset.c, that can be compiled into a shared library which will, when loaded by Guile, define a Scheme function named frob which you can call as expected:

       (frob 4 2.3)

When it comes to defining how C types should be handled, G-Wrap is very flexible.  G-Wrap provides a fairly generic underlying infrastructure which can then be customized for particular purposes by teaching it how to generate code for a given type or wrapset.  You can take explicit control over what code is generated in the wrapper module to handle arguments and return values of a given type (both for their initialization and cleanup), what code is generated to handle the wrapper module's global initialization, and what code is generated to provide global declarations.

At the lowest level, there is a "wrapping protocol" for types, which you can plug into to describe how a type is converted from and to the target language as well as other aspects of the type. G-Wrap comes with a few of these more types pre-defined.  This set should cover most of the common cases, but you can extend this set if needed.  The wrapper types currently available by default include:

basic
     wrapper types to handle C types which can be represented most appropriately on the Scheme side by a conversion directly to a native Scheme type, e.g. double and char.

non-native
     a wrapper type to handle "non-native" objects, that is, C types which can not, or should not be represented on the Scheme side by a conversion to a native Scheme representation, or types for which preserving the C-side pointer equivalency is important.  Instances of this wrapper type are represented at runtime by a Guile SMOB containing the actual C pointer.

enumeration
     a wrapper type to handle C enumerations which automatically grabs the right C-side values at runtime.

Furthermore, G-Wrap allows you to define types in one wrapper module that can then be used by other wrapper modules.  So as an example, you should be able to define a GLib wrapper module that provides wrapper specifications for GList*'s that other wrapper modules can then import and use in their own wrapper function prototypes for argument and result types.  The goal is for this to allow different wrapper modules to be able to safely exchange data among their wrapped functions when they share common wrapped types.

As mentioned, G-Wrap itself is implemented as purely Scheme-code Guile modules.  This means that you you can wrap functions for multiple modules on the fly from any invocation of Guile.

Why Create a Wrapper Generator?
===============================

When accessing a given foreign API from a variety of target languages, the description of the foreign API is a common bit of information that will be needed by the infrastructure supporting each of the target languages.  Further, since the internal mechanisms by which a given target language can access a foreign API are often in flux, it makes sense to consider automatically generating the "glue code" that binds the library API and the target language together.  This means that whenever the foreign function access mechanisms in a target language change, only G-Wrap (or some similar tool) will need to be updated. Then all of the relevant glue code can be trivially re-generated.  This is the job that G-Wrap was designed to handle.

In truth, one of the primary goals of G-Wrap is also to acumulate as many language independent definitions of various APIs as possible, so that interfaces for other languages may be generated automatically, whether by G-Wrap, or some other program.

The original motivation for G-Wrap came from Aubrey Jaffer's suggestion to Christopher Lee that using Scheme to parse a language neutral API specification and generate glue code would be a good way to address this problem for Scheme interpreters.  G-Wrap may well evolve beyond that to support other languages, but for now, it only handles access to C APIs from Guile.

In fact, the original implementation of G-Wrap was much more declarative than programmatic.  The API specification files were not executable Scheme code, but rather declarative Scheme forms.  In the long run, this might be preferable, if G-Wrap decides to move in the direction of language independence, or an alternate possibility is to design a language neutral API spec file (as gnome-guile is trying to do) and then just have a translator from that to native G-Wrap calls.

G-Wrap can be found at http://www.nongnu.org/g-wrap/.

Usage
*****

A More Detailed Example
=======================

In this chapter we'll walk through the process of wrapping an increasingly complex C API.  In the process, we'll try to hit all the important G-Wrap features.

You'll see how to define a wrapset, add new types to it (when the default set of types isn't sufficient), wrap the C-side functions, and then generate the Guile wrapper code from the wrapset definition.

To start, let's presume you want to wrap a C interface that initially looks like this:

       char*  join_strings(char *a, char *b);
       double seconds_since_dow(unsigned int day_of_the_week);

and you want to call your wrapset ``miscutils''.

To define your module, you need to create a wrapper specification, which normally consists of deriving from the <gw-wrapset> class and providing an initialize method that adds the to-be-wrapped functions and types.  Conventionally, if you're creating a wrapper module named "foo", the wrapset specification file would be named foo-spec.scm, or placed in separate ws/ subdirectory.

Creating a Wrapset
==================

Inside the wrapset specification file, the first thing you have to do is create the wrapset class.  But before that, you have to tell Guile that you'll use the GOOPS and G-Wrap modules. So the most trivial wrapper module possible would look something like this:

       (use-modules (oop goops) (g-wrap) (g-wrap guile))

       (define-class <miscutils-wrapset> (<gw-guile-wrapset>)
         #:id 'miscutils)

       (define-method (initialize (ws <miscutils-wrapset>) initargs)
         (next-method ws (append '(#:module (miscutils)) initargs)))

Note how the Guile module that the wrapset should reside in is passed to the next-method of initialize as a keyword argument.

However, this wrapset won't let you do much.  In particular, a newly created wrapset doesn't know about any wrapped types.  In general you'll probably want to be able to use the standard set of G-Wrap wrapped types which include support for int, double, strings, etc.  If so, then you need to add a #:dependencies keyword argument to the class definition:

       (define-class <miscutils-wrapset> (<gw-guile-wrapset>)
         #:id 'miscutils
         #:dependencies '(standard))

Now you can start wrapping functions using the default set of wrapped types with calls to wrap-function!.  To wrap join_strings and seconds_since, you would want to say something like this:

       (define-method (initialize (ws <miscutils-wrapset>) initargs)
         (next-method ws (append '(#:module (miscutils)) initargs))

         (wrap-function!
           ws
           #:name 'join_strings
           #:returns 'mchars
           #:c-name "join_strings"
           #:arguments '((mchars a) (mchars b))
           #:description "Return a string consisting of a followed by b.")

         (wrap-function!
          ws
          #:name 'seconds-since-dow
          #:returns 'double
          #:c-name "seconds_since_dow"
          #:arguments '((<gw:unsigned-int> day-of-week))
          #:description "Given day-of-week (ranging 1-7), return elapsed time since then."))

wrap-function!'s arguments should be quite obvious:

ws
     the module to which the function wrapper should be added.

#:name
     the symbol which should be bound to the wrapped function in Scheme at runtime.

#:returns
     the symbol naming the G-Wrap wrapped type of the C function result.

#:c-name
     a string giving the C function's name.

#:arguments
     a list of the C function's arguments where each element is of the form (g-wrapped-type arg-name-symbol).

#:description
     a string describing the function.

Actually, the example given above won't work because specifying mchars (roughly G-Wrap's type for char*) alone doesn't provide enough information about the allocation semantics of the argument or return value.  G-Wrap needs to know whether a char* argument that's passed in to a function should be considered to be "owned" by the function after the C function returns, or should be considered caller owned, and hence safe for deletion if appropriate. So G-Wrap requires you to be explicit, and provides two type options for string type arguments and return values: caller-owned and callee-owned.  The "m" in mchars stands for malloc, since it's conceivable that for some C functions, the argument or result might need to be allocated/freed via some other mechanism.

So, for our example API, let's presume that join_strings takes two strings that are owned by the caller and returns a newly allocated string that will also be owned by the caller.  Given that, the correct way to wrap this function would be:

         (wrap-function!
           ws
           #:name 'join_strings
           #:returns '(mchars caller-owned)
           #:c-name "join_strings"
           #:arguments '(((mchars caller-owned) a) ((mchars caller-owned) b))
           #:description "Return a string consisting of a followed by b.")

At this point, we have a wrapset named "miscutils" that wraps our two C functions so that when the wrapper module's C code is generated, compiled, and then loaded back into Guile, we should be able to call these C functions normally.  You could use it like this:

       guile> (use-modules (miscutils))
       guile> (join-strings "out" "let")
       "outlet"
       guile> (seconds-since-dow 1)
       3099.232
       guile>

Defining New Wrapped Types
==========================

Though G-Wrap already provides a number of wrapped types in the standard wrapset, there will be many cases where you will need to define your own wrapped types.

As an example, let's presume someone has added a fine-grained, wide ranging, time type to miscutils along with a function that uses that type like this:

FIXME: Add an overview of how G-Wrap thinks about types -- i.e. using a template-like process with ccodegens inserting content in important places.

       typedef Timespec64 {
         long long seconds;
         long int nanoseconds;
       } timespec_64;

       Timespec64 elapsed_time(Timespec64 start, Timespec64 finish);

and let's further presume that we've decided that you want to represent Timespec64 values on the scheme side using a cons pair where the car will be the seconds and the cdr will be the nanoseconds. (Though you should probably consider using the time type from SRFI-19 http://srfi.schemers.org/srfi-19/ instead.)

Since you've decided to use a native Scheme representation for the type, you'll want to define it as an instance of the G-Wrap "normal" or "native" wrapper type.  This primarily involves telling G-Wrap how to translate from the C representation of the type to the Scheme representation and vice-versa.

The way you do this, is by declaring your new wrapped type and specifying a set of C-code generator functions (or "codegens") that will handle producing the C code inside your function wrappers that will handle the translations.

The first thing you need for your new type is a G-Wrap name.  For this example, we'll use timespec64.

To begin, you have to define a new class for your type. We derive it from <gw-rti-type>, which can (and should) be used instead of the more generic <gw-type> in most cases (When <gw-rti-type> is used, G-Wrap is able to use shared conversion functions and not emit code for each wrapper function, in most cases, which can considerably reduce the emitted code size).

       (define-class <timespec64-type> (<gw-rti-type>))

Then you can add your new type to your wrapset.  Presume that the following code is inside the body of the initialize method of our previous examples;  i.e. ws is bound to the miscutils wrapset you're creating.

         (add-type! ws (make <timespec64-type>
                             #:name '<miscutils:timespec-64>
                             #:c-type-name "Timespec64"
                             #:c-const-type-name "const Timespec64"))

In order to make this type useful, you have to define some relevant codegen methods.  Let's start with one that will tell G-Wrap how to ``unwrap'' instances of this type that are passed in as arguments from the Scheme side.

       (define-method (unwrap-value-cg (type <gw-ctype-void>)
                                       (value <gw-value>) error-var)
         (list
           "if (!msu_scm_timespec_64_p(" (scm-var value) "))"
           `(gw:error ,error-var type ,(wrapped-var value))
           "else\n"
           "  " (var value) " = msu_timespec64_to_c(" (scm-var value) ");\n"))

A codegen returns a list where each element in the list may either be a sub-list or a string, basically a tree of strings.  In the end, this list will be flattened into one long string and inserted into the C code being generated for the wrapper module.

The unwrap-value-cg is called with the type that should be ``unwrapped'', the actual value, which consists of a Scheme and a C variable. As you can see this codegen grabs the Scheme name and the C names of the value and then assignes the C value to be the result of converting the scheme value with the hypothetical msu_timespec64_to_scm function.

The list produced by unwrap-value-cg contains a special sublist, starting with gw:error. This indicates a failure condition, which is checked in the generated code and acted upon properly (i.e. raising an ``argument type'' error).

The above codegen presumes that the C function msu_scm_timespec_64_p has been defined and returns non-zero if the given SCM is a pair and both elements are integers.

At this point G-Wrap knows how to convert and incoming Scheme arguments, but it doesn't know how to convert from C values to Scheme, which is needed if you return a Timespec64. To teach it, you need to define the wrap-value-cg for <timespec64-type>, which has the duty to ``wrap'' the C value for Scheme.

So in our Timespec64 example, we might define our unwrap codegen like this:

       (define-method (wrap-value-cg (type <gw-ctype-void>)
                                     (value <gw-value>) error-var)
         (list
           (scm-var value) " = "msu_timespec64_to_scm(" (scm-var value) ");\n"))

There are a bunch of codegens you can define for a type but if you do nothing overly fancy, you can get away with just wrap-value-cg, unwrap-value-cg. For C values that need deconstruction, there is also destruct-value-cg.