Next: , Previous: 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 (for a detailed explanation, refer to see Wrapsets). 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))
           #:name 'join_strings
           #:returns 'mchars
           #:c-name "join_strings"
           #:arguments '((mchars a) (mchars b))
           #:description "Return a string consisting of a followed by b.")
          #:name 'seconds-since-dow
          #:returns 'double
          #:c-name "seconds_since_dow"
          #:arguments '((uint day-of-week))
          #:description "Given day-of-week (ranging 1-7), return elapsed time since then."))

wrap-function!'s arguments should be quite obvious. They are detailed in See Wrapping a C Function.

Actually, the example given above won't work because specifying mchars (roughly G-Wrap's type for char*, see C Types Provided in the Standard Wrapset) 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 is:

           #: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")
       guile> (seconds-since-dow 1)