[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

calling c++ from Ruby

Mr_Tibs

7/10/2008 4:23:00 PM

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
3 Answers

Stefano Crocco

7/10/2008 5:04:00 PM

0

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 =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[i]
}

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...), 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.ht...). 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.rub... or browse the svn repository online at=20
http://svn.ruby-lang.org/cgi-bin/viewvc...

I hope this helps

Stefano



Axel Etzold

7/10/2008 6:04:00 PM

0

Dear Tiberiu,

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

http://rice.ruby...

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

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

Best regards,

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

Todd Fisher

7/24/2008 2:25:00 AM

0

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

Hope this helps,
-Todd
--
Posted via http://www.ruby-....