【问题标题】:Embedding Ruby, calling a function from C嵌入 Ruby,从 C 调用函数
【发布时间】:2010-05-10 08:41:55
【问题描述】:

我正在编写一个从 c 调用 ruby​​ 代码的应用程序。我遇到了一点困难,想知道是否有人可以为我指明仪式的方向。

我目前在我的 C 中。

#include ruby.h

main()
{
  ruby_init();
  rb_require("myRubyFile");
  rb_funcall(rb_module_new(), rb_intern("RubyFunction"), 0, NULL);
}

我的 ruby​​ 文件与我的 c 文件位于同一目录中,名为 myRubyFile.rb,包含函数 RubyFunction() 的定义。

这是对我真正想做的事情的缩减,只是让它对其他人更具可读性。我只需要一些关于这是否是从我的 c 文件中调用 ruby​​ 代码的正确方法的反馈。

问候

【问题讨论】:

  • 快速建议:1) 不要省略 ruby​​_init_loadpath()(我的 SEGV 没有这个),2) 不要命名方法 RubyFunction -- 当没有括号调用时,ruby 会寻找一个 constant 具有相同的名称,并且,3)您可能想要在特定于应用程序的类或模块中定义一个“静态”方法,而不是针对隐式 self 定义的方法(参见答案)。

标签: c ruby linux embedded-ruby


【解决方案1】:

简答:

extern VALUE rb_vm_top_self(void); /* Assumes 1.9.  Under 1.8, use the global
                                    * VALUE ruby_top_self
                                    */
...
rb_funcall(rb_vm_top_self(),           /* irb> RubyFunction()                   */
           rb_intern("RubyFunction"),  /* irb> self.RubyFunction() # same thing */
           0,
           NULL);

更长的答案:

rb_funcall 的第一个参数是方法调用的接收者

假设您在任何显式类或模块上下文之外 defined RubyFunction(),然后将其添加到每个 ruby​​ vm“顶级”的隐式主对象的特征类中.

在 ruby​​ 中,此对象可作为顶级 self 访问:

$ cat myRubyFile.rb
# file: myRubyFile.rb
def foo
  puts "foo"
end

$ irb
irb> require "myRubyFile"
=> true
irb> foo
foo
=> nil
irb> self.foo()    # same thing, more explicit
foo
=> nil
irb> self
=> main

在 1.9 下的 C 中,它可以如上所示访问。

【讨论】:

    【解决方案2】:

    我尝试使用以下方法:

    共享数据的基本结构

    typedef struct ruby_shared_data {
        VALUE obj;
        ID method_id;
        int nargs;
        VALUE args[4];
    } ruby_shared_data;
    

    在代码的某些部分创建一个调用 ruby​​ 对象的函数

    static VALUE ruby_callback(VALUE ptr) {
    
        ruby_shared_data *data = (ruby_shared_data*)ptr;
    
        return rb_funcall2(data->obj,data->method_id,data->nargs,data->args);
    }
    

    在您的代码的某些部分...

        ruby_shared_data rbdata;
    
        rbdata.obj = obj;
        rbdata.method_id = rb_intern("mycallback");
        rbdata.nargs = 1;
        rbdata.args[0] = rb_str_new2("im a parameter");
    
        int error = 0;
        VALUE result = rb_protect(ruby_callback,(VALUE)&rbdata,&error);
    
        if (error)
                throw "Ruby exception on callback";
    

    用 rb_protect 包装 rb_funcall 总是一个好主意。

    另一个有趣的事情是知道回调的参数,一种方法如下

    ruby_shared_data rbdata;
    
    rbdata.obj = callback;
    rbdata.method_id = rb_intern("arity"); 
    rbdata.nargs = 0;
    
    int error = 0;
    VALUE result = rb_protect(ruby_callback,(VALUE)&rbdata,&error);
    
    if (error)
            throw "Ruby exception on callback";
    
    narguments = NUM2INT(result);
    

    【讨论】:

      【解决方案3】:

      我不喜欢在 C 中调用 ruby​​,除非你有复杂的 C 项目,不想在 ruby​​ 中重新构建。

      在 C 和 ruby​​ 之间有两种交互方式。您可以使用用 C 编写的代码来扩展 ruby​​。请参阅 SWIG

      或者您可以嵌入 ruby​​,请参阅 hereherehere

      顺便说一句,你提到的是“嵌入”红宝石,而不是“扩展”红宝石。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-02-20
        • 1970-01-01
        • 2019-09-29
        相关资源
        最近更新 更多