簡體   English   中英

RubyInline包含另一個生成的文件,以從該文件調用函數

[英]RubyInline include another generated file to call a function from that file

我有兩個針對Ruby的C擴展(用於Rails應用程序)。 我使用config.after_initializeapplication.rb初始化它們。

這是第一堂課:

class Object
  require 'inline'

  inline do |builder|

    builder.c <<-EOC
      static VALUE 
      rb_obj_is_number(){
        // code to return Qtrue or Qfalse
      }
    EOC

  end

  alias is_number rb_obj_is_number

end

這是第二個(需要從上面使用rb_obj_is_number() ):

class Array
  require 'inline'

  inline do |builder|

    builder.c <<-EOC
      static VALUE 
      rb_ary_some_fun(){
        double result = 0;
        long i, len = RARRAY_LEN(self);
        VALUE *c_arr = RARRAY_PTR(self);

        for(i=0; i<len; i++) {
          if ( TYPE(rb_obj_is_number(c_arr[i])) == T_TRUE ) {       
            result += NUM2DBL(c_arr[i]);
          }
        }
        return rb_float_new(result);
      }
    EOC
  end

  alias some_fun rb_ary_some_fun

end

嘗試從一個文件調用另一個文件的函數時,出現以下錯誤:

dyld: lazy symbol binding failed: Symbol not found: _rb_obj_is_number

我猜這是因為我沒有在第二個文件中包含第一個生成的文件。 我該怎么做才能使rb_obj_is_number被編譯器識別?

您的函數在單獨的編譯單元中被聲明為static ,因此rb_ary_some_fun當然看不到rb_obj_is_number 馬上想到兩個選擇:

一種選擇是將rb_obj_is_number的C實現rb_obj_is_number一個字符串,兩個builder.c調用均可訪問。 這將為您提供函數的兩個副本,但:

  • 兩種實現都是static因此不會出現名稱空間問題。
  • 該實現可能很小,以至於不會出現多余的膨脹。
  • 兩種實現都來自相同的String,因此將它們保持相同不會有問題。

您將擁有以下內容:

# In some library file...
module CUtil
  IS_NUMBER = %q{
    static VALUE rb_obj_is_number(void) { /*...*/ }
  }
end

# When monkey patching Object...
class Object
  require 'inline'
  inline do |builder|
    builder.c CUtil::IS_NUMBER
  end
  alias is_number rb_obj_is_number
end

# When monkey patching Array...
class Array
  require 'inline'
  inline do |builder|
    builder.c <<-EOC
      #{CUtil::IS_NUMBER}
      static VALUE rb_ary_some_fun(void) { /*...*/ }
    EOC
  end
  alias some_fun rb_ary_some_fun
end

那是一大堆糾結,所以我不建議這樣做。 不過,在某些情況下,這種方法很有意義。

正確的方法是從C is_number作為Ruby方法進行調用。將is_number作為一種方法進行調用可使其被覆蓋,猴子補丁等,就像其他任何方法一樣。 您將使用rb_funcall這樣的東西:

/* There's no need to call this over and over again inside a loop. */
ID is_number = rb_intern("is_number");
/* ... */
if(rb_funcall(c_arr[i], is_number, 0) == Qtrue) {
    result += NUM2DBL(c_arr[i]);
}

另外,我建議您使用正確的函數簽名(即rb_obj_is_number(void) ),以確保編譯器不會以K&R模式結尾。 您還應該調整編譯器的警告標志,以使它大聲抱怨這種事情。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM