This is ../../src/doc/g-wrap.info, produced by makeinfo version 4.7 from ../../src/doc/g-wrap.texi. INFO-DIR-SECTION Libraries START-INFO-DIR-ENTRY * G-Wrap: (g-wrap). Scheme wrapper for C libraries END-INFO-DIR-ENTRY  File: g-wrap.info, Node: Top, Next: Copying, Prev: (dir), Up: (dir) This is the info manual for G-Wrap, covering versions 1.9.*. * Menu: * Copying:: * Introduction:: * Usage:: --- The Detailed Node Listing --- Introduction * Overview:: * Why Create a Wrapper Generator?:: Usage * A More Detailed Example:: * Creating a Wrapper Module:: * Defining New Wrapped Types::  File: g-wrap.info, Node: Copying, Next: Introduction, Prev: Top, Up: Top 1 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 2 Introduction ************** * Menu: * Overview:: * Why Create a Wrapper Generator?::  File: g-wrap.info, Node: Overview, Next: Why Create a Wrapper Generator?, Up: Introduction 2.1 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 ()) (define-class () #:id 'my-wrapset #:dependencies '(standard)) (define-method (initialize (ws ) 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 - `' derived from `'. 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 () (define-class ( )) (define-method (initialize (ws ) initargs) (next-method ws (append '(#:module (my-module)) initargs))) We derive our Guile-specific wrapset from the generic wrapset `' and the base class for all Guile wrapsets `'. 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.  File: g-wrap.info, Node: Why Create a Wrapper Generator?, Prev: Overview, Up: Introduction 2.2 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/'.  File: g-wrap.info, Node: Usage, Prev: Introduction, Up: Top 3 Usage ******* * Menu: * A More Detailed Example:: * Creating a Wrapper Module:: * Defining New Wrapped Types::  File: g-wrap.info, Node: A More Detailed Example, Next: Creating a Wrapper Module, Prev: Usage, Up: Usage 3.1 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 `' 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.  File: g-wrap.info, Node: Creating a Wrapper Module, Next: Defining New Wrapped Types, Prev: A More Detailed Example, Up: Usage 3.2 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 () #:id 'miscutils) (define-method (initialize (ws ) 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 () #: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 ) 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 '(( 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>  File: g-wrap.info, Node: Defining New Wrapped Types, Prev: Creating a Wrapper Module, Up: Usage 3.3 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.(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 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 `', which can (and should) be used instead of the more generic `' in most cases(2). (define-class ()) 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 #:name ' #: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 ) (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 `', 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 ) (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'. ---------- Footnotes ---------- (1) Though you should probably consider using the time type from SRFI-19 `http://srfi.schemers.org/srfi-19/' instead. (2) When `' 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  Tag Table: Node: Top220 Node: Copying603 Node: Introduction2422 Node: Overview2594 Node: Why Create a Wrapper Generator?8695 Node: Usage10760 Node: A More Detailed Example10942 Node: Creating a Wrapper Module12111 Node: Defining New Wrapped Types16652 Ref: Defining New Wrapped Types-Footnote-121465 Ref: Defining New Wrapped Types-Footnote-221584  End Tag Table