c++crubyfftw

Using rb_define_singleton_method in c (or c++)


I am having a lot of trouble figuring out why my rb_define_singleton and rb_define_method calls are breaking when I run the command rake compile.

Firstly, one problem might be that I am actuall not sure what the last integer argument actually represents in order to decide what value to use and I have not been able to find documentation which explains this, yet so I feel like I am just guessing there but the problem seems to be in the 3rd argument anyway so my concern is that

Secondly, my build fails with the following error on calling make:

make compiling ../../../../ext/fftw/fftw.cpp ../../../../ext/fftw/fftw.cpp: In function 'void Init_fftw()': ../../../../ext/fftw/fftw.cpp:64:58: error: invalid conversion from 'VALUE ()(VALUE, VALUE) {aka long unsigned int ()(long unsigned int, long unsigned int)}' to 'VALUE ()(...) {aka long unsigned int ()(...)}' [-fpermissive] rb_define_singleton_method(cNMatrix, "r2c", fftw_r2c, 1); ^ In file included from /Users/private/.rvm/rubies/ruby-2.1.2/include/ruby-2.1.0/ruby/ruby.h:1694:0, from /Users/private/.rvm/rubies/ruby-2.1.2/include/ruby-2.1.0/ruby.h:33, from ../../../../ext/fftw/fftw.cpp:1: /Users/private/.rvm/rubies/ruby-2.1.2/include/ruby-2.1.0/ruby/intern.h:216:6: error: initializing argument 3 of 'void rb_define_singleton_method(VALUE, const char*, VALUE ()(...), int)' [-fpermissive] void rb_define_singleton_method(VALUE, const char, VALUE(*)(ANYARGS), int); ^ make: * [fftw.o] Error 1 rake aborted!

The error means I am not able to test the functions in ruby at all because I need to make this definition successful, first so I have stripped the file to the minimum to try and do that

So far I have tried casting with a variety of types, none of which seemed to work. I am beginning to suspect I am setting things up wrong in extconf with my flags and compiler choice, but I am not sure.

The source code for the failing file is on github

Any advice would be welcome! Thanks


Solution

  • The documentation for the ruby C api is a little lacking. About the only bit of 'official' documentation for this is extension.rdoc

    Your C function can have one of 20 signatures, but since there is no overloading in C and creating 20 versions of all the rb_define_method variants would add a lot of repetition to the interface you use RUBY_METHOD_FUNC(your_function) to typecast your function pointer.

    The integer parameter tells ruby which signature you're using:

    0 upto 17 means that your C function looks like this:

    VALUE some_function(VALUE self, VALUE arg1, VALUE arg2); /* if you had passed 2 */
    

    The integer is simply the number of arguments the function takes, not including self (so this is also the same as the number of arguments passed in ruby land)

    -1 means that your function should have the signature

    VALUE some_function(int argc, VALUE* argv, VALUE self);
    

    i.e. you get passed an array of arguments and the number of arguments. This also means that ruby will let the method be called with any number of arguments (i.e. the arity reported will be -1). rb_scan_args is often useful in this case.

    Finally, -2 means that your function looks like

    VALUE some_function(VALUE self, VALUE args);
    

    and args is a ruby array containing your arguments (again this allows the caller to pass any number of arguments).

    Unfortunately the typecasting means that if you get this wrong your code will just blow up in some undefined way at runtime rather than being a compile time error.