Bil Kleb wrote:
We’ve been playing with testing a C-code via Ruby and testunit,
wrapping the C by hand. We’ve just recently tried using SWIG to
automate the wrapping, but so far we haven’t found the right combination
for our situation.
We have C-routines that look a lot like a C++ class, i.e., a struct
definition followed by associated methods where each method takes a
pointer to the associated struct as the first argument.
OK.
The trouble is the C SWIG generator creates a class for the struct
and global module methods for the functions, and we’ve been unable
to figure out how to get the methods mixed into the class created by
the struct.
There’s no automatic way to get SWIG to recognize that your global C
functions should get mapped to instance methods for the Ruby class, but
the work involved is not too bad. For example, suppose your C code
consists of a struct:
struct Foo {
int x, y;
};
and some function(s) that operate on Foo objects:
int sum_xy(struct Foo *foo);
You could write a SWIG interface to this code as follows:
%module bar
%{
#include "foo.h" /* header file with C declarations */
%}
%ignore sum_xy(struct Foo *foo);
%include foo.h
%extend Foo {
int sum_xy() {
return sum_xy(self);
}
}
Some highlights of the SWIG interface file:
-
The %ignore directive tells SWIG to not generate
a wrapper function for the global sum_xy() function
it’s going to see declared in “foo.h”.
-
The %extend directive tells SWIG to add a new
instance method (or methods) to the Ruby class it
is generating. IMO this is one of the most interesting
features of SWIG. Within the body of an %extend-ed
function, the special variable ‘self’ refers to the
current object, much like the ‘this’ pointer in C++
code.
If you were to run the above example through SWIG, e.g.
swig -ruby bar.i
you’d end up with a Bar module that define a Foo class. The Foo class
has an initialize() method, accessors for the x & y members, and a
sum_xy() instance method that takes zero arguments and returns an integer.
For more information about %extend, see section 4.5.6 in the “SWIG
Basics” chapter of the SWIG documentation:
http://www.swig.org/Doc1.3/SWIG.html
Hope this helps,
Lyle