[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.ruby

ebedded: calling a C function from script.

Shea Martin

1/22/2007 3:31:00 PM

I have my embedded interpreter running my scipt. Now I would like my
script to call function in my C++ program.

i.e.,

int getSomeValue()
{
return 5;
}

void setSomeValue( int value )
{
_value = value;
}

How would I call these functions from my ruby script?

~S
11 Answers

Stefano Crocco

1/22/2007 4:19:00 PM

0

Alle 16:35, lunedì 22 gennaio 2007, Shea Martin ha scritto:
> I have my embedded interpreter running my scipt. Now I would like my
> script to call function in my C++ program.
>
> i.e.,
>
> int getSomeValue()
> {
> return 5;
> }
>
> void setSomeValue( int value )
> {
> _value = value;
> }
>
> How would I call these functions from my ruby script?
>
> ~S

If I understand correctly what you mean, I think you need to create a ruby
method wrapping that function. If you want to do that at kernel-level, that
is not inside a class, you should do the following (in your C code) (NOTE:
all this is untested. I've tried a little project which mixed ruby and C some
time ago, but soon abandoned it. What I'm telling comes from my memory of
that attempt and its source code):

1: define a static C function which wraps your own. It must accept at least
one argument of type VALUE (the first one is self) and return a VALUE (return
Qnil if you don't need the return value). For instance, a wrapper around your
getSomeValue() could be something like

static VALUE _getSomeValue(VALUE self){
//INT2NUM converts from a C int to a ruby number (FixNum or BigNum)
return INT2NUM(getSomeValue());
}

2: Create a ruby method which calls _getSomeValue. To do this, use the
rb_define_global_function function:

rb_define_global_function("get_some_value", _getSomeValue, 1);

Here the first argument is the name of the ruby method, _getSomeValue is a
pointer to the C function which implements the method and 1 is the number of
arguments of the C function.

After calling rb_define_global_function, you'll be able to
call "get_some_value" from your script:

puts get_some_value
=> 5

If you need more information on this topic, you can refer to the Pickaxe book,
in the chapter called (at least in the online edition) "Extending ruby".
Besides, you may find useful the ruby C api
(http://www.ruby-doc.org/doxyge...) and, of course, ruby source code.
Moreover, today on the mailing list was announced a tutorial on writing ruby
extensions. It's at http://nanoblog.ath.cx/index.rb?module=readmor... I
haven't read it, so I don't know if it can be useful to you (there are
differences between writing an extension and embedding the interpreter)

I hope this helps

Stefano


Shea Martin

1/24/2007 2:33:00 PM

0

Thanks, that worked great. How do I do I define a class method?
Doesn't seem to be in ruby book.
~S

Shea Martin

1/24/2007 3:24:00 PM

0

Shea Martin wrote:
> Thanks, that worked great. How do I do I define a class method? Doesn't
> seem to be in ruby book.
> ~S

Also, I can't seem to figure out how to pass ARGV to my script. I tried
setting the global AGV before running, but it gets reset when I start.

~S

Shea Martin

1/24/2007 3:59:00 PM

0

Here is another one i can't find in the book or online:

How do I call a global function (which resides in a script) from C.

<script>
def script_main( args )
puts "something"
end
</script>

<cpp>
ruby_init();
ruby_script("embedded");

init_my_ruby_stuff();

rb_load_file( "test.rb" )
ID id = rb_intern( "script_main" );
rb_funcall( rb_cObject, id, 0 );

ruby_finalize();

return 0;
<cpp/>

But this crashes with an access violation when I run it... am I doing
something wrong?

~S

Stefano Crocco

1/24/2007 4:01:00 PM

0

Alle 16:25, mercoledì 24 gennaio 2007, Shea Martin ha scritto:
> Shea Martin wrote:
> > Thanks, that worked great. How do I do I define a class method? Doesn't
> > seem to be in ruby book.
> > ~S
>
> Also, I can't seem to figure out how to pass ARGV to my script. I tried
> setting the global AGV before running, but it gets reset when I start.
>
> ~S

You should use the ruby_options C function.

To define a class method, you should first define a class. This is done using
the rb_define_class function. It takes two parameters, the name of the class
(as a char*) and the superclass (as a VALUE, not its name). For instance, if
you want to define the class MyClass, as a subclass of Object, you'd do:

rb_define_class("MyClass", rb_cObject);

rb_cObject is a C global variable of type VALUE which corresponds to the ruby
Object class. rb_define_class returns a VALUE corresponding to the new class.
With it, you can define both instance methods and class methods.

To define a class method you should use rb_define_module_function, while to
define an instance method, you'd use the rb_define_method function. They both
takes four arguments: the class or module (the value returned by
rb_define_class, for instance), the name of the method, a pointer to the C
function which implements the method and the number of arguments this C
function takes (including the self argument).

A complete example (again, untested):

static VALUE _class_method(VALUE self, VALUE arg){
//Do something here and return a VALUE or Qnil
}

static VALUE _instance_method(VALUE self){
//Do something else here and return a VALUE or Qnil
}

void InitMyClass(){
VALUE cls=rb_define_class("MyClass", rb_cObject);
rb_define_module_function(cls, "a_class_method", _class_method, 2);
rb_define_method(cls, "an_instance_method", _instance_method, 1);
}

Stefano

Shea Martin

1/24/2007 4:16:00 PM

0


> rb_define_module_function(cls, "a_class_method", _class_method, 2);

Aahh, that was the one I was looking for.
~S

Stefano Crocco

1/24/2007 4:55:00 PM

0

Alle 17:00, mercoledì 24 gennaio 2007, Shea Martin ha scritto:
> Here is another one i can't find in the book or online:
>
> How do I call a global function (which resides in a script) from C.
>
> <script>
> def script_main( args )
> puts "something"
> end
> </script>
>
> <cpp>
> ruby_init();
> ruby_script("embedded");
>
> init_my_ruby_stuff();
>
> rb_load_file( "test.rb" )
> ID id = rb_intern( "script_main" );
> rb_funcall( rb_cObject, id, 0 );
>
> ruby_finalize();
>
> return 0;
> <cpp/>
>
> But this crashes with an access violation when I run it... am I doing
> something wrong?
>
> ~S

Your problem is that you're calling 'script_main', which is an instance method
of class object, as if it were a class method of Object. To do this, you
should access the top level object. I've tried to find the correct method to
do this, in vain. The best suggestion is this

VALUE top_level=rb_eval_string("self");
rb_funcall(self, rb_intern("script_main"),0);

As I said, there should be a better way, but this should work.

Stefano

Shea Martin

1/25/2007 4:11:00 PM

0

Stefano Crocco wrote:
> Alle 17:00, mercoledì 24 gennaio 2007, Shea Martin ha scritto:
>> Here is another one i can't find in the book or online:
>>
>> How do I call a global function (which resides in a script) from C.
>>
>> <script>
>> def script_main( args )
>> puts "something"
>> end
>> </script>
>>
>> <cpp>
>> ruby_init();
>> ruby_script("embedded");
>>
>> init_my_ruby_stuff();
>>
>> rb_load_file( "test.rb" )
>> ID id = rb_intern( "script_main" );
>> rb_funcall( rb_cObject, id, 0 );
>>
>> ruby_finalize();
>>
>> return 0;
>> <cpp/>
>>
>> But this crashes with an access violation when I run it... am I doing
>> something wrong?
>>
>> ~S
>
> Your problem is that you're calling 'script_main', which is an instance method
> of class object, as if it were a class method of Object. To do this, you
> should access the top level object. I've tried to find the correct method to
> do this, in vain. The best suggestion is this
>
> VALUE top_level=rb_eval_string("self");
> rb_funcall(self, rb_intern("script_main"),0);
>
> As I said, there should be a better way, but this should work.
>
> Stefano
>
I tried what you said:

VALUE script_obj = rb_eval_string("self");
ID script_main_id = rb_intern("script_main");
rb_funcall( script_obj, script_main_id, 0 );

but it crashes with the access violation.

I also tried this:

VALUE script_obj = rb_class_new_instance( 0, 0, rb_cObject );
ID script_main_id = rb_intern("script_main");
rb_funcall( script_obj, script_main_id, 0 );

and it has the same problem.

Any ideas?

~S

Stefano Crocco

1/25/2007 8:24:00 PM

0

Alle 17:15, giovedì 25 gennaio 2007, Shea Martin ha scritto:
> I tried what you said:
>
>         VALUE script_obj = rb_eval_string("self");
>         ID script_main_id = rb_intern("script_main");
>         rb_funcall( script_obj, script_main_id, 0 );
>
> but it crashes with the access violation.

According to one of your previous posts, you use rb_load_file to load a file,
of course thinking that that was the C function corresponding to the
ruby 'load' method. The problem is that this is not true. The C function
corresponding to 'load' is rb_load, which takes one VALUE (the name of the
file, as a ruby string) and one int (analogous to the second parameter of the
ruby load method). Of course you could use the function corresponding
to 'require', rb_require, which takes a char* argument with the name of the
file. So, you should replace the code

rb_load_file( "test.rb" )

with

rb_load(rb_str_new2("test.rb"),0);

or with

rb_require("test.rb");

I hope this solves your problem

Stefano

Shea Martin

1/26/2007 7:52:00 PM

0

> According to one of your previous posts, you use rb_load_file to load a file,
> of course thinking that that was the C function corresponding to the
> ruby 'load' method. The problem is that this is not true. The C function
> corresponding to 'load' is rb_load, which takes one VALUE (the name of the
> file, as a ruby string) and one int (analogous to the second parameter of the
> ruby load method). Of course you could use the function corresponding
> to 'require', rb_require, which takes a char* argument with the name of the
> file. So, you should replace the code
>
> rb_load_file( "test.rb" )
>
> with
>
> rb_load(rb_str_new2("test.rb"),0);
>
> or with
>
> rb_require("test.rb");
>
> I hope this solves your problem
>
> Stefano
>

I had fixed the problem using rb_require. Would it be better to use
rb_load? rb_load is not mentioned in the pick axe book... which again
brings up the question of if anyone knows of a reference for the ruby
embedded API.

Thanks,
~S