From: Joel VanderWerf Date: 2005-12-14T02:58:59+09:00 Subject: Re: Accessing C structures in Ruby Martin DeMello wrote: > Eero Saynatkari wrote: > >>Yep, that looks fine to me. There are certainly other ways but aside >>from some repetitiveness, this is easy and versatile (particularly if >>you need to pass data to C libraries as well). If you have lots and >>lots of functions like that, you could even do with a little #define. > > > http://redshift.sourceforge.net/cgen/ might be helpful (not used it > myself, but this seems like a prime use case) > > martin I would have mentioned it but the OP wanted to do things the hard way :) Cgen takes care of accessors (including type checking/conversion, marshalling, mark/free when accessors are typed to refer to objects), and also manages inheritance of structure members in parallel with the ruby inheritance hierarchy. It's got a nice wrapper around rb_parse_args. It's also good if you want to dynamically generate the extension in response to loaded code, user input, etc. I've been using it for over 4 years now. The docs need work, though... An example (simplified from http://redshift.sourceforge.net/cgen/examples/complex.rb.html): require 'cgen/cshadow' class MyComplex < Numeric include CShadow shadow_attr_accessor :re => "double re", :im => "double im" end MyComplex.commit z = MyComplex.new z.re = 5 z.im = 1.3 p z __END__ Output: # The full example also shows how to add methods written in C (but embedded in your ruby source) to do abs() and in-place multiplication. Running this example generates a directory with the following contents, which is used to build the extension (all of this happens during the commit call): C:\ruby\prj\cgen\examples>ls -l MyComplex total 220 -rw-rw-rw- 1 vjoel 0 45 2005-12-13 09:42 extconf.rb -rw-rw-rw- 1 vjoel 0 150 2005-12-13 09:42 make.log -rw-rw-rw- 1 vjoel 0 3619 2005-12-13 09:42 Makefile -rw-rw-rw- 1 vjoel 0 25 2005-12-13 09:39 MyComplex-i386-mswin32.def -rwxrwxrwx 1 vjoel 0 3589 2005-12-13 09:39 MyComplex.c -rw-rw-rw- 1 vjoel 0 589 2005-12-13 09:40 MyComplex.exp -rw-rw-rw- 1 vjoel 0 762 2005-12-13 09:39 MyComplex.h -rw-rw-rw- 1 vjoel 0 1976 2005-12-13 09:40 MyComplex.lib -rw-rw-rw- 1 vjoel 0 17259 2005-12-13 09:39 MyComplex.obj -rw-rw-rw- 1 vjoel 0 91136 2005-12-13 09:40 MyComplex.pdb -rw-rw-rw- 1 vjoel 0 20546 2005-12-13 09:40 MyComplex.so -rw-rw-rw- 1 vjoel 0 53248 2005-12-13 09:39 vc60.pdb Cgen is careful not to repeat all this work the second time you run the same program--it writes files only if they have changed. And just to give an idea of what functions it handles: C:\ruby\prj\cgen\examples\MyComplex>grep "^\w" MyComplex.c static void mark_MyComplex_Shadow(MyComplex_Shadow *shadow); static void free_MyComplex_Shadow(MyComplex_Shadow *shadow); VALUE module_MyComplex; void Init_MyComplex(void) static void mark_MyComplex_Shadow(MyComplex_Shadow *shadow) static void free_MyComplex_Shadow(MyComplex_Shadow *shadow) VALUE __dump__data_module_MyComplex_method(VALUE self) VALUE __load__data_module_MyComplex_method(VALUE self, VALUE from_array) VALUE im_module_MyComplex_method(VALUE self) VALUE im_equals_module_MyComplex_method(int argc, VALUE *argv, VALUE self) VALUE re_module_MyComplex_method(VALUE self) VALUE re_equals_module_MyComplex_method(int argc, VALUE *argv, VALUE self) VALUE new_module_MyComplex_singleton_method(int argc, VALUE *argv, VALUE self) VALUE alloc_func_module_MyComplex(VALUE klass) Here's an example (sample.rb) showing the argument parsing wrapper: lib2.define_c_singleton_method(Point, :test).instance_eval { c_array_args { required :arg0, :arg1 optional :arg2, :arg3, :arg4 typecheck :arg2 => Numeric, :arg3 => Numeric default :arg3 => "INT2NUM(7)", :arg4 => "INT2NUM(NUM2INT(arg2) + NUM2INT(arg3))" rest :rest block :block } body %{\ rb_funcall(block, #{declare_symbol :call}, 6, arg0, arg1, arg2, arg3, arg4, rest); } } -- vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407