MobiRuby/mruby-cfuncを読む
をテンプレートにして作成
[
トップ
] [
新規
|
一覧
|
単語検索
|
最終更新
|
ヘルプ
]
開始行:
#contents
*はじめに [#p8e0f8c7]
2012/9/9にMobiRubyがリリースされました。というわけでMobiR...
まずはCの関数をRubyから呼び出すためのライブラリであるmrub...
*test/main.c [#ccec9a58]
「MobiRubyってどこから読み始めればいいのかわからない」と...
test/main.cのうち、main()は以下のようになっています。
#code(C){{
struct mrb_state_ud {
struct cfunc_state cfunc_state;
};
int main(int argc, char *argv[])
{
mrb_state *mrb = mrb_open();
mrb->ud = malloc(sizeof(struct mrb_state_ud));
cfunc_state_offset = cfunc_offsetof(struct mrb_state_...
init_cfunc_module(mrb);
init_unittest(mrb);
if (mrb->exc) {
mrb_p(mrb, mrb_obj_value(mrb->exc));
}
init_cfunc_test(mrb);
if (mrb->exc) {
mrb_p(mrb, mrb_obj_value(mrb->exc));
}
}
}}
mrb_stateはmrubyの実行情報を格納する構造体です。mrb_state...
なお、cfunc_state_offsetはudで指定している構造体中のcfunc...
*init_cfunc_module(src/cfunc.c) [#y68d2642]
init_cfunc_module()にてmruby-cfuncの初期化が行われます。...
#code(C){{
void init_cfunc_module(mrb_state *mrb)
{
struct RClass *ns = mrb_define_module(mrb, "CFunc");
cfunc_state(mrb)->namespace = ns;
init_cfunc_type(mrb, ns);
init_cfunc_pointer(mrb, ns);
init_cfunc_struct(mrb, ns);
init_cfunc_closure(mrb, ns);
init_cfunc_call(mrb, ns);
mrb_define_class_method(mrb, ns, "mrb_state", cfunc_m...
init_cfunc_rb(mrb);
}
}}
というわけで、型、ポインタ、構造体、クロージャ、呼び出し...
**init_cfunc_type(src/cfunc_type.c) [#td018ecf]
CFunc::TypeをスーパークラスとしたC(libffi)の型を表現する...
#code(C){{
#define define_cfunc_type(name, ffi_type_ptr, ctype, c_to...
\
static mrb_value \
cfunc_type_ffi_##name##_c_to_mrb(mrb_state *mrb, void *p) \
{ \
return c_to_mrb(*(ctype*)p); \
} \
\
static void \
cfunc_type_ffi_##name##_mrb_to_c(mrb_state *mrb, mrb_valu...
{ \
*(ctype*)p = mrb_to_c(val); \
} \
\
static mrb_value \
cfunc_type_ffi_##name##_data_to_mrb(mrb_state *mrb, struc...
{ \
if(data->refer) { \
return c_to_mrb(*(ctype*)data->value._pointer); \
} \
else { \
return c_to_mrb(data->value._##name); \
} \
} \
\
static void \
cfunc_type_ffi_##name##_mrb_to_data(mrb_state *mrb, mrb_v...
{ \
if(data->refer) { \
*(ctype*)data->value._pointer = mrb_to_c(val); \
} \
else { \
data->value._##name = mrb_to_c(val); \
} \
}
define_cfunc_type(sint8, &ffi_type_sint8, int8_t, mrb_fix...
define_cfunc_type(uint8, &ffi_type_uint8, uint8_t, mrb_fi...
define_cfunc_type(sint16, &ffi_type_sint16, int16_t, mrb_...
define_cfunc_type(uint16, &ffi_type_uint16, uint16_t, mrb...
define_cfunc_type(sint32, &ffi_type_sint32, int32_t, mrb_...
define_cfunc_type(uint32, &ffi_type_uint32, uint32_t, mrb...
define_cfunc_type(sint64, &ffi_type_sint64, int64_t, mrb_...
define_cfunc_type(uint64, &ffi_type_uint64, uint64_t, mrb...
define_cfunc_type(float, &ffi_type_float, float, mrb_floa...
define_cfunc_type(double, &ffi_type_double, double, mrb_f...
}}
といった感じにRubyとCの変換関数を定義し、
#code(C){{
#define define_mrb_ffi_type(name_, type_) \
{ \
.name = #name_, \
.ffi_type_value = &ffi_type_##type_, \
.mrb_to_c = &cfunc_type_ffi_##type_##_mrb_to_c, \
.c_to_mrb = &cfunc_type_ffi_##type_##_c_to_mrb, \
.mrb_to_data = &cfunc_type_ffi_##type_##_mrb_to_data, \
.data_to_mrb = &cfunc_type_ffi_##type_##_data_to_mrb \
}
static struct mrb_ffi_type types[] = {
define_mrb_ffi_type(Void, void),
define_mrb_ffi_type(UInt8, uint8),
define_mrb_ffi_type(SInt8, sint8),
define_mrb_ffi_type(UInt16, uint16),
define_mrb_ffi_type(SInt16, sint16),
define_mrb_ffi_type(UInt32, uint32),
define_mrb_ffi_type(SInt32, sint32),
define_mrb_ffi_type(UInt64, uint64),
define_mrb_ffi_type(SInt64, sint64),
define_mrb_ffi_type(Float, float),
define_mrb_ffi_type(Double, double)
};
}}
と各型について変換に使う関数を関数ポインタとして設定する...
そして上記で定義した情報を各型クラスにインスタンス変数((...
#code(C){{
mrb_value
cfunc_type_get_value(mrb_state *mrb, mrb_value self)
{
struct cfunc_type_data *data = (struct cfunc_type_dat...
struct mrb_ffi_type *mft = rclass_to_mrb_ffi_type(mrb...
return mft->data_to_mrb(mrb, data);
}
struct mrb_ffi_type*
rclass_to_mrb_ffi_type(mrb_state *mrb, struct RClass *cls)
{
while(cls) {
mrb_value ffi_type = mrb_obj_iv_get(mrb, (struct ...
if(mrb_test(ffi_type)) {
return (struct mrb_ffi_type*)DATA_PTR(ffi_typ...
}
cls = cls->super;
}
mrb_raise(mrb, E_TYPE_ERROR, "Cannot convert to c val...
return NULL;
}
}}
**init_cfunc_pointer(src/cfunc_pointer.c) [#f4c7a823]
Cのポインタを表現するCFunc::Pointerの定義を行っています。...
**init_cfunc_struct(src/cfunc_struct.c) [#zad96f81]
Cの構造体を表現するCFunc::Structの定義を行っています。cfu...
**init_cfunc_closure(src/cfunc_closure.c) [#q0cd6e6a]
次はクロージャを表現するCFunc::Closureの定義です。Cで言う...
**init_cfunc_call(cfunc_call.c) [#n809437d]
次にCの関数を呼び出すCFunc::callを定義しています。
**init_cfunc_rb [#sdbf008d]
最後にinit_cfunc_rb()が呼び出されています。このinit_cfunc...
src/Makefile
# mrby complie
$(OBJMRB) : %.o : %.rb
$(MRBC) -Cinit_$(*F) $<
$(CC) $(ALL_CFLAGS) -MMD $(INCLUDES) -c $(basename $<)....
というわけでビルドプロセスとしてsrc/mrb/cfunc_rb.rbがコン...
*init_cfunc_test [#w3331eb8]
mruby-cfuncの初期化が終わったので次は使い方の方を見ていき...
**配列の作り方 [#fe2a6d4f]
以下のように書きます。
ci = CFunc::CArray(CFunc::Int).new(10)
個人的には、
ci = CFunc::Int[10]
と書けた方がうれしいです。pull request送ってみるか。
**メモリ確保方法 [#e3af45d8]
以下のように書きます。
@ptr = CFunc::Pointer.malloc(7)
**C関数の呼び出し方 [#tb6b7e75]
以下のように書きます。strcpyの戻り値は実際にはchar*ですが...
CFunc::call(CFunc::Void, "strcpy", @ptr, @str)
**構造体の定義 [#n71852b0]
以下のように書きます。
class STest < CFunc::Struct
define CFunc::SInt8, :x,
CFunc::SInt16, :y,
CFunc::SInt32, :z
end
個人的にはやや気に食わない。RubyのStructのように
CFunc::Struct.new("STest", CFunc::SInt8, :x, CFunc::SInt...
と定義できた方がうれしいです。まだ型と名前の間の","が気に...
**構造体メンバーへのアクセス [#j29480ae]
以下のように書きます。
@stest[:x] = 10
ん〜、これもメンバーアクセスメソッドを用意して
@stest.x = 10
と書きたい((増井さんによるとmruby-cocoaのプロパティアクセ...
**クロージャの定義 [#d4fbbdff]
以下のように書きます。第1引数が戻り値で第2引数に配列でク...
@closure = CFunc::Closure.new(CFunc::Int, [CFunc::Int, C...
a.value * b.value
end
@closureを渡すことで、
int closure(int a, int b)
{
return a * b;
}
という関数を定義して関数ポインタが要求されるところに渡す...
*おわりに [#m1d079fb]
今回はmruby-cfuncを眺めました。読んでいて、「Cで書かない...
終了行:
#contents
*はじめに [#p8e0f8c7]
2012/9/9にMobiRubyがリリースされました。というわけでMobiR...
まずはCの関数をRubyから呼び出すためのライブラリであるmrub...
*test/main.c [#ccec9a58]
「MobiRubyってどこから読み始めればいいのかわからない」と...
test/main.cのうち、main()は以下のようになっています。
#code(C){{
struct mrb_state_ud {
struct cfunc_state cfunc_state;
};
int main(int argc, char *argv[])
{
mrb_state *mrb = mrb_open();
mrb->ud = malloc(sizeof(struct mrb_state_ud));
cfunc_state_offset = cfunc_offsetof(struct mrb_state_...
init_cfunc_module(mrb);
init_unittest(mrb);
if (mrb->exc) {
mrb_p(mrb, mrb_obj_value(mrb->exc));
}
init_cfunc_test(mrb);
if (mrb->exc) {
mrb_p(mrb, mrb_obj_value(mrb->exc));
}
}
}}
mrb_stateはmrubyの実行情報を格納する構造体です。mrb_state...
なお、cfunc_state_offsetはudで指定している構造体中のcfunc...
*init_cfunc_module(src/cfunc.c) [#y68d2642]
init_cfunc_module()にてmruby-cfuncの初期化が行われます。...
#code(C){{
void init_cfunc_module(mrb_state *mrb)
{
struct RClass *ns = mrb_define_module(mrb, "CFunc");
cfunc_state(mrb)->namespace = ns;
init_cfunc_type(mrb, ns);
init_cfunc_pointer(mrb, ns);
init_cfunc_struct(mrb, ns);
init_cfunc_closure(mrb, ns);
init_cfunc_call(mrb, ns);
mrb_define_class_method(mrb, ns, "mrb_state", cfunc_m...
init_cfunc_rb(mrb);
}
}}
というわけで、型、ポインタ、構造体、クロージャ、呼び出し...
**init_cfunc_type(src/cfunc_type.c) [#td018ecf]
CFunc::TypeをスーパークラスとしたC(libffi)の型を表現する...
#code(C){{
#define define_cfunc_type(name, ffi_type_ptr, ctype, c_to...
\
static mrb_value \
cfunc_type_ffi_##name##_c_to_mrb(mrb_state *mrb, void *p) \
{ \
return c_to_mrb(*(ctype*)p); \
} \
\
static void \
cfunc_type_ffi_##name##_mrb_to_c(mrb_state *mrb, mrb_valu...
{ \
*(ctype*)p = mrb_to_c(val); \
} \
\
static mrb_value \
cfunc_type_ffi_##name##_data_to_mrb(mrb_state *mrb, struc...
{ \
if(data->refer) { \
return c_to_mrb(*(ctype*)data->value._pointer); \
} \
else { \
return c_to_mrb(data->value._##name); \
} \
} \
\
static void \
cfunc_type_ffi_##name##_mrb_to_data(mrb_state *mrb, mrb_v...
{ \
if(data->refer) { \
*(ctype*)data->value._pointer = mrb_to_c(val); \
} \
else { \
data->value._##name = mrb_to_c(val); \
} \
}
define_cfunc_type(sint8, &ffi_type_sint8, int8_t, mrb_fix...
define_cfunc_type(uint8, &ffi_type_uint8, uint8_t, mrb_fi...
define_cfunc_type(sint16, &ffi_type_sint16, int16_t, mrb_...
define_cfunc_type(uint16, &ffi_type_uint16, uint16_t, mrb...
define_cfunc_type(sint32, &ffi_type_sint32, int32_t, mrb_...
define_cfunc_type(uint32, &ffi_type_uint32, uint32_t, mrb...
define_cfunc_type(sint64, &ffi_type_sint64, int64_t, mrb_...
define_cfunc_type(uint64, &ffi_type_uint64, uint64_t, mrb...
define_cfunc_type(float, &ffi_type_float, float, mrb_floa...
define_cfunc_type(double, &ffi_type_double, double, mrb_f...
}}
といった感じにRubyとCの変換関数を定義し、
#code(C){{
#define define_mrb_ffi_type(name_, type_) \
{ \
.name = #name_, \
.ffi_type_value = &ffi_type_##type_, \
.mrb_to_c = &cfunc_type_ffi_##type_##_mrb_to_c, \
.c_to_mrb = &cfunc_type_ffi_##type_##_c_to_mrb, \
.mrb_to_data = &cfunc_type_ffi_##type_##_mrb_to_data, \
.data_to_mrb = &cfunc_type_ffi_##type_##_data_to_mrb \
}
static struct mrb_ffi_type types[] = {
define_mrb_ffi_type(Void, void),
define_mrb_ffi_type(UInt8, uint8),
define_mrb_ffi_type(SInt8, sint8),
define_mrb_ffi_type(UInt16, uint16),
define_mrb_ffi_type(SInt16, sint16),
define_mrb_ffi_type(UInt32, uint32),
define_mrb_ffi_type(SInt32, sint32),
define_mrb_ffi_type(UInt64, uint64),
define_mrb_ffi_type(SInt64, sint64),
define_mrb_ffi_type(Float, float),
define_mrb_ffi_type(Double, double)
};
}}
と各型について変換に使う関数を関数ポインタとして設定する...
そして上記で定義した情報を各型クラスにインスタンス変数((...
#code(C){{
mrb_value
cfunc_type_get_value(mrb_state *mrb, mrb_value self)
{
struct cfunc_type_data *data = (struct cfunc_type_dat...
struct mrb_ffi_type *mft = rclass_to_mrb_ffi_type(mrb...
return mft->data_to_mrb(mrb, data);
}
struct mrb_ffi_type*
rclass_to_mrb_ffi_type(mrb_state *mrb, struct RClass *cls)
{
while(cls) {
mrb_value ffi_type = mrb_obj_iv_get(mrb, (struct ...
if(mrb_test(ffi_type)) {
return (struct mrb_ffi_type*)DATA_PTR(ffi_typ...
}
cls = cls->super;
}
mrb_raise(mrb, E_TYPE_ERROR, "Cannot convert to c val...
return NULL;
}
}}
**init_cfunc_pointer(src/cfunc_pointer.c) [#f4c7a823]
Cのポインタを表現するCFunc::Pointerの定義を行っています。...
**init_cfunc_struct(src/cfunc_struct.c) [#zad96f81]
Cの構造体を表現するCFunc::Structの定義を行っています。cfu...
**init_cfunc_closure(src/cfunc_closure.c) [#q0cd6e6a]
次はクロージャを表現するCFunc::Closureの定義です。Cで言う...
**init_cfunc_call(cfunc_call.c) [#n809437d]
次にCの関数を呼び出すCFunc::callを定義しています。
**init_cfunc_rb [#sdbf008d]
最後にinit_cfunc_rb()が呼び出されています。このinit_cfunc...
src/Makefile
# mrby complie
$(OBJMRB) : %.o : %.rb
$(MRBC) -Cinit_$(*F) $<
$(CC) $(ALL_CFLAGS) -MMD $(INCLUDES) -c $(basename $<)....
というわけでビルドプロセスとしてsrc/mrb/cfunc_rb.rbがコン...
*init_cfunc_test [#w3331eb8]
mruby-cfuncの初期化が終わったので次は使い方の方を見ていき...
**配列の作り方 [#fe2a6d4f]
以下のように書きます。
ci = CFunc::CArray(CFunc::Int).new(10)
個人的には、
ci = CFunc::Int[10]
と書けた方がうれしいです。pull request送ってみるか。
**メモリ確保方法 [#e3af45d8]
以下のように書きます。
@ptr = CFunc::Pointer.malloc(7)
**C関数の呼び出し方 [#tb6b7e75]
以下のように書きます。strcpyの戻り値は実際にはchar*ですが...
CFunc::call(CFunc::Void, "strcpy", @ptr, @str)
**構造体の定義 [#n71852b0]
以下のように書きます。
class STest < CFunc::Struct
define CFunc::SInt8, :x,
CFunc::SInt16, :y,
CFunc::SInt32, :z
end
個人的にはやや気に食わない。RubyのStructのように
CFunc::Struct.new("STest", CFunc::SInt8, :x, CFunc::SInt...
と定義できた方がうれしいです。まだ型と名前の間の","が気に...
**構造体メンバーへのアクセス [#j29480ae]
以下のように書きます。
@stest[:x] = 10
ん〜、これもメンバーアクセスメソッドを用意して
@stest.x = 10
と書きたい((増井さんによるとmruby-cocoaのプロパティアクセ...
**クロージャの定義 [#d4fbbdff]
以下のように書きます。第1引数が戻り値で第2引数に配列でク...
@closure = CFunc::Closure.new(CFunc::Int, [CFunc::Int, C...
a.value * b.value
end
@closureを渡すことで、
int closure(int a, int b)
{
return a * b;
}
という関数を定義して関数ポインタが要求されるところに渡す...
*おわりに [#m1d079fb]
今回はmruby-cfuncを眺めました。読んでいて、「Cで書かない...
ページ名: