calling c++ from Ruby

M

Mr_Tibs

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
 
S

Stefano Crocco

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 =3D Qnil;
extern "C" VALUE create_project(char *c, ...)
{
va_list args;
va_start(args, c);
}
extern "C" void Init_mytest()
{
MyTest =3D rb_define_module("MyTest");
rb_define_method(MyTest, "create_project", &create_project,
1);
}

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

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 thin=
k=20
your create_project method is conceptually wrong, because if it should be=20
called from ruby, all arguments will be passed to it as VALUE s, not as cha=
r=20
or int or any other C type (this is because all ruby objects, on the C side=
=20
are of type VALUE).

Also, if you want to create a method which can be called with any number of=
=20
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 =3D 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=
,=20
it's an exception to the rule I spoke of above about the arguments always=20
having to be of type VALUE). argv is an array of VALUEs representing the=20
arguments passed to the method and self is... self. To access the arguments=
of=20
the method, you iterate on argv:

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

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

=46or more information, have a look at the chapter about extending ruby in =
the=20
pickaxe (for the free online edition, the chapter is at
http://www.ruby-doc.org/docs/ProgrammingRuby/html/ext_ruby.html), at the=20
Doxygen documentation of the ruby C api and, in particular, to the section =
on=20
functions starting with the letter R
(http://www.ruby-doc.org/doxygen/current/globals_func.html#index_r). This p=
art=20
of the api contains a number of methods starting with rb_, which correspond=
=20
(more or less) directly to ruby methods. Unfortunately, there's no descript=
ion=20
of the methods, but you can get an idea of what they do looking at their na=
me.=20
Lastly, you can look at the source code of ruby itself (that's how I found =
the=20
information I gave you above). There are C files for the core classes=20
(array.c, object.c and so on). All the calls to rb_define_method are at the=
=20
end of the corresponding files, so you can quickly find out which C functio=
n=20
corresponds to which ruby method. You can download the ruby source code fro=
m=20
http://www.ruby-lang.org or browse the svn repository online at=20
http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/tags/

I hope this helps

Stefano
 
T

Todd Fisher

Mr_Tibs said:
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,
http://www.oreillynet.com/ruby/blog/2007/04/c_extension_authors_use_rb_sca_1.html

Hope this helps,
-Todd
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,968
Messages
2,570,154
Members
46,701
Latest member
XavierQ83

Latest Threads

Top