This is g-wrap.info, produced by makeinfo version 4.0b from g-wrap.texi.


File: g-wrap.info,  Node: Top,  Next: Copying,  Prev: (dir),  Up: (dir)

This is the info manual for g-wrap, covering versions 1.1.*.

                  **********************************
                  NOTE: THESE DOCS ARE NOT FINISHED.
                  **********************************

I'm including them in the hope that they're at least somewhat useful,
but they have only been partially converted to reflect the major changes
that have happened recently.  There may be very misleading or just rough
bits as you get further in, and the part still documents the old
version.  Caveat emptor.  I hope to finish revising them soon.

* Menu:

* Copying::
* Introduction::
* Usage::
* Extending G-wrap::
* Reference::
* Functions for describing C code to import to the interpreter::
* C code needed for adding new types::
* Generating and using the glue code::
* Types available by default::
* Extending g-wrap and porting it to other Scheme implementations::
* Portable "Fancy tricks"::

 --- The Detailed Node Listing ---

Introduction

* Caveats::
* Overview::
* Why Create a Wrapper Generator?::

Usage

* A More Detailed Example.::
* Creating a Wrapper Module::
* Defining New Wrapped Types::
* Wrapping C Functions::
* Generating the Wrapper Code::
* Using the Wrapped Interface::

Extending G-wrap

* Other Internal Details::
* Adding New Wrapper Types::

Reference

* Wrapper Module Operations::
* Defining Wrapped Types::
* Defining New Wrapper Types::
* Wrapping Functions::
* Wrapper Types Available by Default::
* Wrapped Types Available by Default::

Functions for describing C code to import to the interpreter

* Defining a new function::
* Adding a new type::
* Defining a new constant::
* Other functions needed for describing the library glue code::
* Example of a library description::

Defining a new function

* Manually defining functions::
* Scanning source code for functions to export::

Manually defining functions

* Scanning source code for functions to export::

C code needed for adding new types

* Utility functions::
* Printing object representations::
* Function for deallocating an object::
* Function for object comparisons::

Generating and using the glue code

* Generating the glue code::
* Accessing the wrapped API from the target language::
* Coping With Old Guile Versions::

Types available by default

* Guile Types::
* RScheme Types::

Guile Types

* Pointer Tokens and Pointer Arrays::

Pointer Tokens and Pointer Arrays

* Pointer Tokens::
* Pointer Arrays::

Extending g-wrap and porting it to other Scheme implementations

* Defining basic Scheme/C types::


File: g-wrap.info,  Node: Copying,  Next: Introduction,  Prev: Top,  Up: Top

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.


File: g-wrap.info,  Node: Introduction,  Next: Usage,  Prev: Copying,  Up: Top

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

* Menu:

* Caveats::
* Overview::
* Why Create a Wrapper Generator?::


File: g-wrap.info,  Node: Caveats,  Next: Overview,  Prev: Introduction,  Up: Introduction

Caveats
=======

  1. I'd like to state right up front that g-wrap is to some extent an
     experimental work.  It seems useful, but it is certainly not
     elegant, at least not yet, and maybe not ever, and it's somehat
     hard for me to say whether that's a statement about the problem,
     or the current solution.

  2. The current implementation of the wrapper types (normal,
     non-native, and enumerations), and the whole "hash-table" oriented
     infrastructure behind them should almost certainly be re-written
     reasonably soon to use goops instead of the ad-hock mess that's
     there right now which somewhat fakes a mini-inheritance structure.
     None of this has any effect on wrapper run-time, but it's ugly.

  3. G-wrap should be made smarter about guile modules.  In particular
     it needs to be migrated away from the old (and deprecated) way of
     implementing use-modules completely in one .so file.  Making this
     change will involve switching g-wrap to generate a .scm file *and*
     a .so.  Once that's done, perhaps we should allow for the
     specification of scheme code that should be inserted into places
     in the parent .scm file (This might eliminate the need for many
     uses of the gw:inline-scheme function, or perhaps better yet, we
     should figure out a way to orient g-wrap much more closely toward
     generating *just* the C wrappers and let the user create the
     top-level .scm file themselves.  I'm not sure that would retain
     all the flexibility, but it would simplify things, and I already
     worry that g-wrap is suffering from mission-creep.

  4. All of these things are my (rlb's) fault, not Christopher's :>



File: g-wrap.info,  Node: Overview,  Next: Why Create a Wrapper Generator?,  Prev: Caveats,  Up: 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 you may not need to add any type specifications for many
straightforward interfaces.

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:

       (let ((mod (gw:new-module "my-g-wrap-module")))
         (gw:module-depends-on mod "gw-runtime")
         (gw:wrap-function
          mod
          'frob
          '<gw:int> "frob" '((<gw:int> x) (<gw:double> y))
          "Return the result of frobbing x and y.")

Once g-wrap has seen this specification, the code for the wrappers can
be generated with this call:

       (gw:generate-module "my-g-wrap-module")

This will produce C code that when either compiled into a static Guile
executable, or built as a shared library and dynamically loaded from
Guile will 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 wrapper module.  You can take
explicit control over what code is generated in the wrapper module(1)
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.  G-wrap can also spit out a fully
functional, dynamically-loadable Guile module if you like (so
technically, (use-modules (g-wrapped ncurses)) is now possible, and
(with a minor tweak to re-enable some code) g-wrap can generate html
docs for the wrapper interface.

At the lowest level, there is a "most generic wrapper type" from which
all other wrapper types are derived, and g-wrap comes with a few of
these more specialized wrapper 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:

`normal (native)'
     a wrapper type to handle C types which can be represented most
     appropriately on the Scheme side by a conversion directly to a
     native Scheme type.

`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.

Further, g-wrap now has a first pass at an implementation that should
allow 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 now implemented as a purely Scheme-code
Guile module, and no longer uses globals.  This means that you you can
now wrap functions for multiple modules on the fly from any invocation
of guile.

---------- Footnotes ----------

(1) The term "wrapper module" will always be used to indicate the
collection of C code that is generated as the wrapper for a given C
API.  It may or may not have any correlation to a Guile module.  When a
Guile module is meant, the term Guile module will be used explicitly.


File: g-wrap.info,  Node: Why Create a Wrapper Generator?,  Prev: Overview,  Up: Introduction

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 <ftp://ftp.gnucash.org/pub/g-wrap/>.


File: g-wrap.info,  Node: Usage,  Next: Extending G-wrap,  Prev: Introduction,  Up: Top

Usage
*****

* Menu:

* A More Detailed Example.::
* Creating a Wrapper Module::
* Defining New Wrapped Types::
* Wrapping C Functions::
* Generating the Wrapper Code::
* Using the Wrapped Interface::


File: g-wrap.info,  Node: A More Detailed Example.,  Next: Creating a Wrapper Module,  Prev: Usage,  Up: Usage

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

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

You'll see how to define a wrapper module, 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 wrapper module 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 wrapper module "miscutils".

To define your module, you need to create a wrapper specification, which
is just a file (or files) of scheme code that calls g-wrap functions to
create the wrapper module.  Conventionally, if you're creating a wrapper
module named "foo", the wrapper-module specification file would be named
foo-spec.scm.


File: g-wrap.info,  Node: Creating a Wrapper Module,  Next: Defining New Wrapped Types,  Prev: A More Detailed Example.,  Up: Usage

Creating a Wrapper Module
=========================

Inside the wrapper module specification file, the first thing you have
to do is create the wrapper module.  This is handled with a call to the
function `gw:new-module', but before that, you have to tell Guile that
you want to use g-wrap functions with a call to `(use-modules
(g-wrap))'.  So the most trivial wrapper module possible would look
something like this:

       (let ((mod (gw:new-module "miscutils")))
         #t)

However, this module won't let you do much.  In particular, a newly
created wrapper module 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 call to `gw:module-depends-on' like so:

       (let ((mod (gw:new-module "miscutils")))
         (gw:module-depends-on mod "gw-runtime")
         #t)

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

       (let ((mod (gw:new-module "miscutils")))
     
         (gw:module-depends-on mod "gw-runtime")
     
         (gw:wrap-function
          mod
          'join_strings
          '<gw:char*> "join_strings" '((<gw:char*> a) (<gw:char*> b))
          "Return a string consisting of a followed by b.")
     
         (gw:wrap-function
          mod
          'seconds-since-dow
          '<gw:double> "seconds_since_dow" '((<gw:unsigned-int> day-of-week))
          "Given day-of-week (ranging 1-7), return elapsed time since then."))

`gw:wrap-function''s arguments in order are

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

  2. the symbol which should be bound to the wrapped function in Scheme
     at runtime.

  3. the symbol naming the g-wrap wrapped type of the C function result.

  4. a string giving the C function's name.

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

  6. a string describing the function.


Actually, the example given above won't work because g-wrap has no
definition for char*'s.  There is no <gw:char*> wrapped type.  The
reason is that specifying 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 different types for string type arguments and return
values: `<gw:m-chars-caller-owned>' and `<gw:m-chars-callee-owned>'.
The "m" 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 our example API would be:

       (let ((mod (gw:new-module "miscutils")))
     
         (gw:module-depends-on mod "gw-runtime")
     
         (gw:wrap-function
          mod
          'join-strings
          '<gw:m-chars-caller-owned> "join_strings"
          '((<gw:m-chars-caller-owned> a) (<gw:m-chars-caller-owned> b))
          "Return a string consisting of a followed by b.")
     
         (gw:wrap-function
          mod
          'seconds-since-dow
          '<gw:double> "seconds_since_dow" '((<gw:unsigned-int> day-of-week))
          "Given day-of-week (ranging 1-7), return elapsed time since then."))

At this point, we have a wrapper module 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.  Presuming you set miscutils up as a g-wrap
module of that name, you could use it like this:


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


File: g-wrap.info,  Node: Defining New Wrapped Types,  Next: Wrapping C Functions,  Prev: Creating a Wrapper Module,  Up: Usage

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

Though g-wrap already provides a number of wrapped types in the
gw-runtime library, 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.(1)

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 C 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 "ccodegens") 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 `<miscutils:timespec-64>'.  Note that whatever name
you pick here will actually be bound to a value at runtime.  The reason
for this will become clear later.

To begin, you have to add your new type to your module.  Presume that
the following code is inside the body of the "let" defined in our
previous examples.  i.e. `mod' is bound to the miscutils g-wrap module
you're creating.


       (let ((wt (gw:wrap-type mod
                               '<miscutils:timespec-64>
                               "Timespec64"
                               "const Timespec64")))
         #t)

The above bit of code does nothing more than create a new (empty)
wrapped type.  In order to make this type useful, you have to define
some relevant ccodegens.  Let's start with one that will tell g-wrap how
to check instances of this type that are passed in as arguments from the
Scheme side.  Presume this code is placed where the `#t' is in the
"let" above.


         (gw:type-set-scm-arg-type-test-ccodegen!
          wt
          (lambda (param)
            (list
             "msu_scm_timespec_64_p(" (gw:param-get-scm-name param) ")")))

A ccodegen is just a lambda that generates 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 scm-arg-type-test-ccodegen is always called with just one argument,
a representation of the function parameter whose type should be checked.
`gw:param-get-scm-name' is an accessor for these parameter
representations that will return the name of the C variable that will be
holding the Scheme value passed as an argument to any function with a
parameter of this wrapped type.  The C code returned by your
scm-arg-type-test-ccodegen should check this Scheme value, and return a
non-zero value if the argument is of the correct type.  The above
ccodegen presumes that the C function `msu_scm_timesepec_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 check the type of incoming SCM
arguments, but it doesn't know how to convert between the C and Scheme
representations of your Timespec64 values.  To teach it, you need to
define a `pre-call-arg-ccodegen'.  This ccodegen is used to generate C
code in the wrapper functions that will be executed after all of the
Scheme values passed as arguments to the wrapped function have been
checked by their respective test code (generated by their respective
`scm-arg-type-test-ccodegen' functions), but before the call to the C
function being wrapped.

When you specify a `pre-call-arg-ccodegen', it will be called with one
argument.  As with your `scm-arg-type-test-ccodegen', this argument
will be a representation of the function parameter that's being
processed, and the code you generate with this ccodegen will, in most
cases, just be responsible for converting from the Scheme representation
for the argument into a C representation that can be passed to the C
function that's being wrapped.  In addition to the function used above,
`gw:param-get-scm-name', you can also ask the param for the name of the
C variable that will be used in the call to the C function that's being
wrapped by calling `gw:param-get-c-name'.

So in our Timespec64 example, we might defined our pre-call ccodegen
like this:


         (gw:type-set-pre-call-arg-ccodegen!
          wt
          (lambda (param)
            (let* ((scm-name (gw:param-get-scm-name param))
                   (c-name (gw:param-get-c-name param)))
              (list
               c-name
               " = msu_scm_timespec64_to_c_timespec64(" scm-name ");\n"))))

As you can see this ccodegen grabs the Scheme name and the C names of
the param and then assignes the C value to be the result of converting
the scheme value with the hypothetical
`msu_scm_timespec64_to_c_timespec64' function.  You can do other things
in your pre-call ccodegen, but making sure that a C representation of
the Scheme value ends up in the variable named "c-name" is usually the
critical thing.

Note too that if you don't like the "tree of strings" approach to
generating the C code, you can always rewrite the code like this:(2)


         (gw:type-set-pre-call-arg-ccodegen!
          wt
          (lambda (param)
            (simple-format #f
                           "~A = ~A;\n"
                           (gw:param-get-scm-name param)
                           (gw:param-get-c-name param))))

STOPPED HERE BELOW UNFINISHED...


         (gw:type-set-call-ccodegen!
          wt
          (lambda (standard-c-call-gen result func-call-code)
            (list (gw:result-get-c-name result) " = " func-call-code ";\n")))
     
       (define (add-standard-result-handlers! type c->scm-converter)
         (define (standard-pre-handler result)
           (let* ((ret-type-name (gw:result-get-proper-c-type-name result))
                  (ret-var-name (gw:result-get-c-name result)))
             (list "{\n"
                   "    " ret-type-name " " ret-var-name ";\n")))
     
         (gw:type-set-pre-call-result-ccodegen! type standard-pre-handler)
     
         (gw:type-set-post-call-result-ccodegen!
          type
          (lambda (result)
            (let* ((scm-name (gw:result-get-scm-name result))
                   (c-name (gw:result-get-c-name result)))
              (list
               (c->scm-converter scm-name c-name)
               "  }\n")))))
     
         (add-standard-result-handlers!
          wt
          (lambda (scm-name c-name)
            (let ((old-func
                   (lambda (x)
                     (list "gnc_timespec2timepair(" x ")"))))
              (list scm-name
                    " = "
                    (old-func c-name)
                    ";\n")))))

Also, note that although there are a bunch of ccodegens you can define
for a type, many are optional.

Note that though the code here is C-code, you can also in-line scheme
code in many cases with a special construct...

---------- Footnotes ----------

(1) Though you should probably consider using the time type from
SRFI-19 <http://srfi.schemers.org/srfi-19/> instead.

(2) This could result in a loss in portability across Scheme
implementations, though right now g-wrap only works with Guile, and may
never be ported anywhere else.


File: g-wrap.info,  Node: Wrapping C Functions,  Next: Generating the Wrapper Code,  Prev: Defining New Wrapped Types,  Up: Usage

Wrapping C Functions
====================


File: g-wrap.info,  Node: Generating the Wrapper Code,  Next: Using the Wrapped Interface,  Prev: Wrapping C Functions,  Up: Usage

Generating the Wrapper Code
===========================


File: g-wrap.info,  Node: Using the Wrapped Interface,  Prev: Generating the Wrapper Code,  Up: Usage

Using the Wrapped Interface
===========================


File: g-wrap.info,  Node: Extending G-wrap,  Next: Reference,  Prev: Usage,  Up: Top

Extending G-wrap
****************

* Menu:

* Other Internal Details::
* Adding New Wrapper Types::


File: g-wrap.info,  Node: Other Internal Details,  Next: Adding New Wrapper Types,  Prev: Extending G-wrap,  Up: Extending G-wrap

Other Internal Details
======================


File: g-wrap.info,  Node: Adding New Wrapper Types,  Prev: Other Internal Details,  Up: Extending G-wrap

Adding New Wrapper Types
========================


File: g-wrap.info,  Node: Reference,  Next: Functions for describing C code to import to the interpreter,  Prev: Extending G-wrap,  Up: Top

Reference
*********

* Menu:

* Wrapper Module Operations::
* Defining Wrapped Types::
* Defining New Wrapper Types::
* Wrapping Functions::
* Wrapper Types Available by Default::
* Wrapped Types Available by Default::


File: g-wrap.info,  Node: Wrapper Module Operations,  Next: Defining Wrapped Types,  Prev: Reference,  Up: Reference

Wrapper Module Operations
=========================


File: g-wrap.info,  Node: Defining Wrapped Types,  Next: Defining New Wrapper Types,  Prev: Wrapper Module Operations,  Up: Reference

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


File: g-wrap.info,  Node: Defining New Wrapper Types,  Next: Wrapping Functions,  Prev: Defining Wrapped Types,  Up: Reference

Defining New Wrapper Types
==========================


File: g-wrap.info,  Node: Wrapping Functions,  Next: Wrapper Types Available by Default,  Prev: Defining New Wrapper Types,  Up: Reference

Wrapping Functions
==================


File: g-wrap.info,  Node: Wrapper Types Available by Default,  Next: Wrapped Types Available by Default,  Prev: Wrapping Functions,  Up: Reference

Wrapper Types Available by Default
==================================


File: g-wrap.info,  Node: Wrapped Types Available by Default,  Prev: Wrapper Types Available by Default,  Up: Reference

Wrapped Types Available by Default
==================================


File: g-wrap.info,  Node: Functions for describing C code to import to the interpreter,  Next: C code needed for adding new types,  Prev: Reference,  Up: Top

Functions for describing C code to import to the interpreter
************************************************************

These Scheme functions are used to describe the library to be interfaced
to the interpreter.  Use of these functions should allow the library to
be described in a manner which is independent from the details of any
particular Scheme interpreter's implementation.  An example of the use
of these functions is given in *Note Example of a library description::.

* Menu:

* Defining a new function::
* Adding a new type::
* Defining a new constant::
* Other functions needed for describing the library glue code::
* Example of a library description::


File: g-wrap.info,  Node: Defining a new function,  Next: Adding a new type,  Prev: Functions for describing C code to import to the interpreter,  Up: Functions for describing C code to import to the interpreter

Defining a new function
=======================

* Menu:

* Manually defining functions::
* Scanning source code for functions to export::


File: g-wrap.info,  Node: Manually defining functions,  Next: Scanning source code for functions to export,  Prev: Defining a new function,  Up: Defining a new function

Manually defining functions
---------------------------

 - Function: new-function scheme-name ret-type c-name param-list
          description
     Exports a C-function to the Scheme interpreter.  C-NAME must be a
     string naming the function to be exported.  SCHEME-NAME must be a
     symbol naming the corresponding function to be provided at the
     Scheme level.  RET-TYPE must be a symbol or a list of the form
     (TYPE-SYM . OPTIONS) which describes the function's return type,
     and PARAM-LIST describes the function's parameters.  PARAM-LIST
     must be a list where each element is also a list of the form
     (TYPE-SYM ARG-NAME . OPTIONS).  For both the return value and the
     arguments, TYPE-SYM is a symbol of a type assigned using NEW-TYPE,
     ADD-TYPE or GWRAP-C-ASSUME-TYPES-WRAPPED, and OPTIONS must be
     symbols.  Currently 'cleanup and 'no-cleanup are the only
     available options and they are used to override the default
     cleanup behaviors on a per-argument/return-value basis.  See the
     discussion of 'cleanup in the `make-complex-c-type' documentation
     for details.

     DESCRIPTION must be a string, and will be added to the
     automatically generated documentation file.

     Examples:

          (new-function
           'eig-dsyev
           'void "eig_dsyev" '((MAT A) (MAT Z) (VEC w))
           "calculates eigenvectors Z and eigenvalues w
          of real symmetric matrix A")

     This writes a wrapper function which accepts three arguments,
     checks them to make sure they are of types `MAT', `MAT', and
     `VEC', converts the parameters to the corresponding C-types, then
     calls the C function `eig_dsyev' on the converted arguments.  The
     wrapper function returns an "unspecified" value because the return
     type is void--otherwise the return value of the C function would be
     converted to a Scheme value and returned.  The wrapper-function is
     bound to the Scheme symbol `eig-dsyev'.

     *For Guile*
     This command also adds a pair of the form `(SCHEME-SYM .
     DESCRIPTION)' to a list exported to the Guile interpreter as
     `*gw:descriptions*' which describes the function.

     In the example above, the following pair is then added to
     `*gw:descriptions*' when the interpreter is initialized (or when
     the module is dynamically linked to the interpreter):

          (eig-dsyev .
          "(eig-dsyev A Z w)
            A is a MAT, Z is a MAT, w is a VEC.
            no return value.
          calculates eigenvectors Z and eigenvalues w
          of real symmetric matrix A")

     The following example depicts the use of the cleanup options:

          (new-function
           'some-function
           '(some-type no-cleanup)
           "some_function"
           '((some-other-type x cleanup) (yet-another-type y 'no-cleanup))
           "Do something to x and y to produce an answer of type some-type.")


* Menu:

* Scanning source code for functions to export::


File: g-wrap.info,  Node: Scanning source code for functions to export,  Prev: Manually defining functions,  Up: Defining a new function

Scanning source code for functions to export
--------------------------------------------

 - Function: gwrap-scan-source-file filename
     This command looks through FILENAME for ANSI function declarations
     that are preceded by a special comment, and does some simplistic
     parsing to find out enough about each function to write a wrapper
     function for it.  To export a function, simply add the following
     comment before an ANSI function declaration (note, the `/*[' must
     be the first characters on the line, no indenting):
          /*[EXPORT FLAGS]
           DESCRIPTION
           */
     where DESCRIPTION is a short description of what the function does,
     and FLAGS (usually left empty) can indicate that g-wrap should
     override its default assumptions about return type, parameter
     types, or function name.

     If FLAGS contains:
        * `(name NEW-NAME)'   the function is exported as NEW-NAME.

        * `(types ((N NEW-TYPE) ...))'   the type of the N-th parameter
          (the first parameter is 0) is   assumed to be NEW-TYPE.

        * `(ret-type NEW-TYPE)'   the return type of the function is
          assumed to be NEW-TYPE.

     Up to three characters of each line of DESCRIPTION are ignored if
     they are space or '*' characters.

     For example, if this function definition is in `lmatrix.c',
          /*[EXPORT (ret-type RETVEC0)]
           * out := A.x
           */
          VEC *mv_mlt(VEC *v_out, MAT *A, VEC *x) {
            ....
          }
     then these lines in the library description file
          (set! type-translations
                (append '((VEC* VEC) (MAT* MAT)) type-translations))
          (gwrap-scan-source-file "lmatrix.c")
     will be equivalent to
          (new-function
           'mv-mlt
           'VEC "mv_mlt" '((VEC v-out) (MAT A) (VEC x))
           "out := A.x")



File: g-wrap.info,  Node: Adding a new type,  Next: Defining a new constant,  Prev: Defining a new function,  Up: Functions for describing C code to import to the interpreter

Adding a new type
=================

 - Function: add-type scheme-sym c-name fn-to-scm fn-from-scm fn-isa
     Defines a new Scheme type corresponding to C-type C-NAME, and
     associates it with symbol SCHEME-SYM.   Objects of this type are
     printed with C-function C-PRINT-NAME,  deallocated by C-function
     C-DIE-NAME, and checked for equality with  C-function C-EQ-NAME.

     Scheme-sym should be a symbol, and the other arguments should be
     strings.

 - Function: new-type scheme-sym c-name c-print-fn c-die-fn c-eq-fn
          [options ...]
     As does `add-type', this command defines a new Scheme type
     corresponding to C-type C-NAME, and associates it with symbol
     SCHEME-SYM. SCHEME-SYM can then be used as a type parameter  in
     functions `new-constant' and `new-function'.   In addition, a
     function called C-NAME? is generated to test if  any Scheme object
     is an object of this type.

     `new-type' also documents the type in documentation file.  If
     `(doc DESCRIPTION)' is passed as an option,  DESCRIPTION is used
     to document the type.

     Example:
          (new-type 'MAT  "MAT"  "MAT_print"  "m_free"  "MAT_eq")

        *  A Scheme function `MAT?' is defined to test to see if a
          Scheme  value has this type.

        *  C functions must be provided for performing the tasks of
          performing the  basic jobs which the interpreter needs to
          perform for Scheme objects.   In this example,  `MAT_print'
          writes the representation of the matrix to a port,  `MAT_die'
          deallocates the matrix,  `MAT_eq' checks for equality of
          matrices.   See *Note C code needed for adding new types:: to
          see how to  write these functions.

        *  This allows `MAT's to be used as function parameters and  as
          return values.

        *  For Guile, this creates a new smob type for holding (`MAT*')
          pointers, and for RScheme it creates a new object-class for
          the type.


File: g-wrap.info,  Node: Defining a new constant,  Next: Other functions needed for describing the library glue code,  Prev: Adding a new type,  Up: Functions for describing C code to import to the interpreter

Defining a new constant
=======================

 - Function: new-constant sym-name type varb
     Defines a constant with C value VARB and C-type TYPE, and
     export it into the interpreter with Scheme-name SYM-NAME.
     SYM-NAME and VARB must be strings.

     If `(doc DESCRIPTION)' is passed as an option,    DESCRIPTION is
     used to document the constant in the    documentation file.

     Example:
          (new-constant 'MNULL  'MAT  "NULL" '(doc "null matrix"))
     This adds a value to the interpreter which is the `NULL' pointers,
     wrapped as a `MAT' value, and bound to symbol `MNULL'.


File: g-wrap.info,  Node: Other functions needed for describing the library glue code,  Next: Example of a library description,  Prev: Defining a new constant,  Up: Functions for describing C code to import to the interpreter

Other functions needed for describing the library glue code
===========================================================

 - Function: gwrap-open-module fname [options ...]
     *For Guile*
     Opens a text file with name FNAME.c, and a Guile initialization
     function       void init_FNAME(void).     FNAME must be a string.
       Also generates a text file with name FNAME.h which contains
     declarations of functions and variables which may be needed by
     other    code, and a file FNAME.html which contains documentation
     about    the exported functions, types, and constants.

     If `(c++? #t)' is passed as an option, a `C++' file    (FNAME.cc)
     is generated instead of a C file (FNAME.c).

     If `(guile-module LST)' is passed as an option, then    g-wrap
     generates code for a (dynamically linkable) module, where the
     module-path is LST.  If this option is #f, no module is
     generated.

     If `(guile-prefix NAME)' is passed as an option NAME indicates a
     prefix that will be appended to the guile-side names.  This may be
     useful if you don't want to create a module.

     If `(call-on-init FN-NAME)' is passed as an option    (FN-NAME
     should be the name of a function of type    `void FN-NAME(void)'),
       FN-NAME is called when the Scheme interpreter initializes the
     library wrapper.

     *For RScheme*
     Creates code for generating an RScheme module named `fname'.
     This includes a file FNAME.scm of glue-code, and an RScheme
     module control file FNAME.mcf which tells the RScheme module
     compiler how to build/compile the module.

     Option `(c-files ("FILE1.C" ...))' puts code in the module
     control file which tells the RScheme module compiler to compile the
       specified C files into the module.

     Option `(h-files ("FILE1.H" ...))' puts code in the module
     control file which tells the RScheme module compiler to use the
     header    files when compiling code into the module.

     Option `(rs-scm-files ("FILE1" ...))' puts code in the    module
     control file which tells the RScheme module compiler to    compile
     compile the specified Scheme files into the module.

     Option `(rs-mods ("MOD1" ...))' indicates that the module    will
     use types, functions, or constants from the specified RScheme
     modules.

     For example,
           (gwrap-open-module "cmat"
                              ; name of Guile module
                              '(guile-module (math matrix cmat))
                              ; extra C files to compile into RS module
                              '(c-files ("cmat_gw_fns.c"))
                              ; extra RScheme modules to include
                              '(rs-mods ("mathlib"))
                              ; extra Scheme files to compile into RS mod
                              '(rs-scm-files ("matrix.scm")))


 - Function: gwrap-include-local-header x
     The C version of the glue code needs to include local header file
      "X".

 - Function: gwrap-include-global-header x
     The C version of the glue code needs to include global header file
       "X".

 - Function: gwrap-generate-wrapped-header x
     Generate a C header file for all of the wrapped functions and
     store it in the file named "X".  This can be useful if you want
     the g-wrap file to be the ultmate authority about the API.  G-wrap
     will include documentation in the header file derived from the
     `new-function' documentation strings.

 - Function: gwrap-assume-types-wrapped lst [options ...]
     Assume that types have been defined in another G-wrap file, so
     that they may be used as parameters in the current G-wrap file.
     LST is a list of pairs of the form (SCHEME-SYM    C-NAME) where
     SCHEME-SYM is a symbol for the type which    will be used to for
     defining parameter types in calls to 'new-function', and    C-NAME
     is a string indicating the name of the object type in C.


 - Function: gwrap-close-module
     Specify end of module description, causing the glue-code and
     related  files to be generated.


File: g-wrap.info,  Node: Example of a library description,  Prev: Other functions needed for describing the library glue code,  Up: Functions for describing C code to import to the interpreter

Example of a library description
================================

     ;;; -*- scheme -*-
     ;;; This file generates the glue code for interfacing the the cmatrix
     ;;;  library to Guile (I've shortened it for the sake of example)
     (set! type-translations
           (append '((VEC* VEC) (MAT* MAT)) type-translations))
     
     (gwrap-open-module "cmat"
                        ; name of Guile module
                        '(guile-module (math matrix cmat))
                        ; extra C files to compile into the RScheme module
                        '(c-files ("cmat_gw_fns.c"))
                        ; extra RScheme modules to include
                        '(rs-mods ("mathlib"))
                        ; extra Scheme files to compile into RScheme module
                        '(rs-scm-files ("matrix.scm")))
     (gwrap-include-global-header "cmat.h")
     
     ;; New types to wrap with smobs
     (new-type
      'MAT  "MAT"  "MAT_print"  "m_free"  "MAT_eq"
      '(doc
        "2D matrix of double precision floats"))
     
     ;; Some constants:
     (new-constant 'MNULL  'MAT  "NULL" '(doc "null matrix"))
     
     ;; Functions to export to Scheme
     (new-function
      'm-rows
      'int "M_ROWS_CHECKED" '((MAT m))
      "returns number of rows in m")
     (new-function
      'm-cols
      'int "M_COLS_CHECKED" '((MAT m))
      "returns number of columns in m")
     
     ;; Scan some files to automatically export some functions
     (let ((scan-in-cmatrix-dir
            (lambda (x)
             (gwrap-scan-source-file
              (string-append "../../chrlib/cmatrix/" x)))))
       (for-each scan-in-cmatrix-dir '("cmat_basefns" "cmat_stats.c")))
     
     (gwrap-close-module)


File: g-wrap.info,  Node: C code needed for adding new types,  Next: Generating and using the glue code,  Prev: Functions for describing C code to import to the interpreter,  Up: Top

C code needed for adding new types
**********************************

When you add a new type to the interpreter, you will need to supply the
names of three functions.  One function prints a representation of an
object of that type, another is called to deallocate the object when it
is garbage-collected, and the third is called to compare two objects of
that type for equality.

* Menu:

* Utility functions::
* Printing object representations::
* Function for deallocating an object::
* Function for object comparisons::


File: g-wrap.info,  Node: Utility functions,  Next: Printing object representations,  Prev: C code needed for adding new types,  Up: C code needed for adding new types

Utility functions
=================

These functions, prototyped in `g-wrap.h' and implemented for each
interpreter which g-wrap supports, can be used in the glue functions
for writing strings to Scheme ports and raising Scheme errors.

 - Function: void gw_puts (char* STR, GWSCM PORT)
     Writes string STR to Scheme port PORT.

 - Function: void gw_error (char* MESSAGE)
     Raises a Scheme error with string MESSAGE.


File: g-wrap.info,  Node: Printing object representations,  Next: Function for deallocating an object,  Prev: Utility functions,  Up: C code needed for adding new types

Printing object representations
===============================

The function for printing a representation of the object should have a
declaration similar to this:
     void PRINT_FN_NAME (TYPE* obj, GWSCM port, int writingp);
The first parameter accepts a pointer to the object to be printed, the
second parameter accepts a Scheme value representing the Scheme port to
write to, and the final argument indicates whether the object is being
printed with `display' (`writingp==0') or `write' (`writingp!=0').  The
function `gw_puts(char*,GWSCM)' can be used to write a string to the
port.

Here is an example of a function used for printing a matrix type:
     void MAT_print(MAT *m, GWSCM scmport, int writingp) {
       int i, j;
       char buff[80];
     
       if ( !m ) {  gw_puts("MNULL",scmport); return; }
       if ( writingp ) {
         sprintf(buff,"(MAT %d %d (", m->m, m->n);
         gw_puts(buff, scmport);
       } else {
         gw_puts("\n", scmport);
       }
       for ( i = 0; i < m->m; i++ ) {
         if ( !writingp ) { gw_puts("[ ", scmport); }
         for ( j = 0; j < m->n; j++ ) {
           sprintf(buff,"%lf ", m->me[i][j]);
           gw_puts(buff, scmport);
         }
         if ( !writingp ) { gw_puts("]\n", scmport); }
       }
       if ( writingp ) { gw_puts(")) ", scmport); }
     }


File: g-wrap.info,  Node: Function for deallocating an object,  Next: Function for object comparisons,  Prev: Printing object representations,  Up: C code needed for adding new types

Function for deallocating an object
===================================

The function for deallocating a pointer to an object on garbage
collection should have a single argument--a pointer to the object to be
deallocated.

An example of such a function declaration:
     void m_free(MAT *);


File: g-wrap.info,  Node: Function for object comparisons,  Prev: Function for deallocating an object,  Up: C code needed for adding new types

Function for object comparisons
===============================

The function for checking the equality of two objects should have a
declaration like
     int EQUAL_FN_NAME(TYPE* OBJ1, TYPE* OBJ2);
It should return 0 for false (not equal), and 1 for true (equal).

Here is an example from the matrix object type:
     int MAT_equal(MAT *m1, MAT *m2) {
       int i, j;
     
       if ( !m1 || !m2 )                           { return ( m1 == m2 ); }
       if ( ! (m1->m == m2->m && m1->n == m2->n) ) { return 0; }
       for ( i = 0; i < m1->m; i++ ) {
         for ( j = 0; j < m1->n; j++ ) {
           if ( m1->me[i][j] != m2->me[i][j] ) { return 0; }
         }
       }
       return 1;
     }


File: g-wrap.info,  Node: Generating and using the glue code,  Next: Types available by default,  Prev: C code needed for adding new types,  Up: Top

Generating and using the glue code
**********************************

* Menu:

* Generating the glue code::
* Accessing the wrapped API from the target language::
* Coping With Old Guile Versions::

