Calling c++ from Ruby

Hi,

I wrote this question on the newsgroup yesterday, but I didn't see it
actually get posted. Here it goes again. I'm trying to call a c++
function from Ruby and I'm getting some errors compiling the c++
part.

Here is my code:
#include "ruby.h"
#include <iostream>
#include <stdarg.h>
VALUE MyTest = Qnil;
extern "C" VALUE create_project(char *c, ...)
{
        va_list args;
        va_start(args, c);
}
extern "C" void Init_mytest()
{
        MyTest = rb_define_module("MyTest");
        rb_define_method(MyTest, "create_project", &create_project,
1);
}

And here is the error:
MyTest.cpp: In function ‘void Init_mytest()’:
MyTest.cpp:16: error: invalid conversion from ‘VALUE (*)(char*, ...)’
to ‘VALUE (*)(...)’
MyTest.cpp:16: error: initializing argument 3 of ‘void
rb_define_method(VALUE, const char*, VALUE (*)(...), int)’

If I don't put "char *c" in the arguments of create_project, it
compiles and works just fine. But if I don't have it, how can I get
the arguments?
I realize this is more of a c++ question, but if anyone has any
simple, fully working example of calling c++ code from Ruby, I would
like to see it.

Thanks,
Tiberiu

I don't know whether it has to do with the error you're getting, but I think
your create_project method is conceptually wrong, because if it should be
called from ruby, all arguments will be passed to it as VALUE s, not as char
or int or any other C type (this is because all ruby objects, on the C side
are of type VALUE).

Also, if you want to create a method which can be called with any number of
arguments from the ruby side, I think you should define it this way:

VALUE create_project(int argc, VALUE * argv, VALUE self)
{
}

extern "C" void Init_mytest(){
  MyTest = rb_define_module("MyTest");
  rb_define_method(MyTest, "create_project", &create_project, -1);
}

The argc parameter is the number of arguments passed to the method (and yes,
it's an exception to the rule I spoke of above about the arguments always
having to be of type VALUE). argv is an array of VALUEs representing the
arguments passed to the method and self is... self. To access the arguments of
the method, you iterate on argv:

for (int i = 0; i < argc; i++){
// do something with argv[i]
}

If some of the parameters of your method are required and some other optional,
you can use the rb_scan_args function, which manages them for you.

For more information, have a look at the chapter about extending ruby in the
pickaxe (for the free online edition, the chapter is at
Programming Ruby: The Pragmatic Programmer's Guide), at the
Doxygen documentation of the ruby C api and, in particular, to the section on
functions starting with the letter R
(http://www.ruby-doc.org/doxygen/current/globals_func.html#index_r\). This part
of the api contains a number of methods starting with rb_, which correspond
(more or less) directly to ruby methods. Unfortunately, there's no description
of the methods, but you can get an idea of what they do looking at their name.
Lastly, you can look at the source code of ruby itself (that's how I found the
information I gave you above). There are C files for the core classes
(array.c, object.c and so on). All the calls to rb_define_method are at the
end of the corresponding files, so you can quickly find out which C function
corresponds to which ruby method. You can download the ruby source code from
http://www.ruby-lang.org or browse the svn repository online at
http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/tags/

I hope this helps

Stefano

···

On Thursday 10 July 2008, Mr_Tibs wrote:

Hi,

I wrote this question on the newsgroup yesterday, but I didn't see it
actually get posted. Here it goes again. I'm trying to call a c++
function from Ruby and I'm getting some errors compiling the c++
part.

Here is my code:
#include "ruby.h"
#include <iostream>
#include <stdarg.h>
VALUE MyTest = Qnil;
extern "C" VALUE create_project(char *c, ...)
{
        va_list args;
        va_start(args, c);
}
extern "C" void Init_mytest()
{
        MyTest = rb_define_module("MyTest");
        rb_define_method(MyTest, "create_project", &create_project,
1);
}

And here is the error:
MyTest.cpp: In function ‘void Init_mytest()’:
MyTest.cpp:16: error: invalid conversion from ‘VALUE (*)(char*, ...)’
to ‘VALUE (*)(...)’
MyTest.cpp:16: error: initializing argument 3 of ‘void
rb_define_method(VALUE, const char*, VALUE (*)(...), int)’

If I don't put "char *c" in the arguments of create_project, it
compiles and works just fine. But if I don't have it, how can I get
the arguments?
I realize this is more of a c++ question, but if anyone has any
simple, fully working example of calling c++ code from Ruby, I would
like to see it.

Thanks,
Tiberiu

Mr_Tibs wrote:

Hi,

I wrote this question on the newsgroup yesterday, but I didn't see it
actually get posted. Here it goes again. I'm trying to call a c++
function from Ruby and I'm getting some errors compiling the c++
part.

Here is my code:
#include "ruby.h"
#include <iostream>
#include <stdarg.h>
VALUE MyTest = Qnil;
extern "C" VALUE create_project(char *c, ...)
{
        va_list args;
        va_start(args, c);
}
extern "C" void Init_mytest()
{
        MyTest = rb_define_module("MyTest");
        rb_define_method(MyTest, "create_project", &create_project,
1);
}

And here is the error:
MyTest.cpp: In function �void Init_mytest()�:
MyTest.cpp:16: error: invalid conversion from �VALUE (*)(char*, ...)�
to �VALUE (*)(...)�
MyTest.cpp:16: error: initializing argument 3 of �void
rb_define_method(VALUE, const char*, VALUE (*)(...), int)�

If I don't put "char *c" in the arguments of create_project, it
compiles and works just fine. But if I don't have it, how can I get
the arguments?
I realize this is more of a c++ question, but if anyone has any
simple, fully working example of calling c++ code from Ruby, I would
like to see it.

Thanks,
Tiberiu

Hi,

I think you meant to use rb_define_singleton_method, instead of
rb_define_method.

Also, the method signature of your C/C++ function is important. If you
want to use variable number of arguments, it needs to look something
like this:

VALUE your_method_name(int argc, VALUE *argv, VALUE klass)

Also, when using C++ you need to cast to correct types... so, in your
case you could fix the compile time error by casting:

rb_define_method(MyTest, "create_project", (VALUE
(*)(...))&create_project, -1);

Also, when using variable arguments you need to pass a -1, since it's an
unknown number of arguments. Ruby also has it's own set of methods to
use to access the arguments.

Have a look at rb_scan_args,

Hope this helps,
-Todd

···

--
Posted via http://www.ruby-forum.com/\.

Dear Tiberiu,

I am not quite sure about your question, but I'd like to suggest this link for Ruby/C++
integration:

http://rice.rubyforge.org/

There is also a gem based on Rice that promises to wrap whole C++ libraries in Ruby,

http://rubyforge.org/projects/rbplusplus .

Best regards,

Axel

···

--
Psssst! Schon vom neuen GMX MultiMessenger gehört?
Der kann`s mit allen: http://www.gmx.net/de/go/multimessenger