はじめてのruby拡張ライブラリ
TRANSCRIPT
はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4
はじめてのRuby拡張ライブラリ
とみたまさひろ2010-05-22
はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4
自己紹介
とみた まさひろ✓
プログラマー✓
mailto:[email protected]✓
http://d.hatena.ne.jp/tmtms✓
http://twitter.com/tmtms✓
1/33
はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4
自己紹介
日本Rubyの会✓
日本MySQLユーザ会✓
Ruby/MySQL ライブラリ✓
Ruby歴, MySQL歴 十数年✓
2/33
はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4
自己紹介
こんな本書きました
3/33
はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4
NSEG #1 で
4/33
はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4
Ruby拡張ライブラリ
5/33
はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4
Rubyは遅い
6/33
はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4
こんなに遅い
7/33
はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4
Rubyが遅いのならCで書けばいいじゃない
8/33
はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4
CのライブラリをRubyから使いたい
9/33
はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4
ということで拡張ライ
ブラリ10/33
はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4
通常のライブラリ
Ruby で書かれている✓
拡張子 .rb✓
require 'hoge'✓
require 'hoge.rb'✓
11/33
はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4
拡張ライブラリ
C で書かれている✓
拡張子 .so (Linux の場合)✓
require 'hoge' (.rb が優先)✓
require 'hoge.o'✓
require 'hoge.so'✓
12/33
はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4
作り方13/33
はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4
専用ディレクトリが必要
$ ls hoge/extconf.rbhoge.c
14/33
はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4
hoge.c
拡張ライブラリ本体
/* require 'hoge' 時に呼ばれる関数 */void Init_hoge(void){ puts("Hello");}
15/33
はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4
extconf.rb
拡張ライブラリを作るための Makefile を作る
require 'mkmf'create_makefile 'hoge'
16/33
はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4
コンパイル&実行
$ ruby ./extconf.rbcreating Makefile$ make ...$ lsMakefile hoge.c hoge.soextconf.rb hoge.o$ ruby -e 'require "hoge"'Hello
17/33
はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4
クラス&メソッド
#include <ruby.h>
VALUE cHoge; /* Hoge クラス */
/* Hoge#xxx メソッド実行時に呼ばれる関数 */static VALUE hoge_xxx(VALUE obj){ ...}
/* require 'hoge' 時に呼ばれる関数 */void Init_hoge(void){ /* Object クラスを継承した Hoge クラスを作成 */ cHoge = rb_define_class("Hoge", rb_cObject); /* 引数0個のメソッド xxx を定義 */ rb_define_method(cHoge, "xxx", hoge_xxx, 0);}
18/33
はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4
メソッド引数
/* 引数なし */rb_define_method(cHoge, "xxx0", hoge_xxx0, 0);static VALUE hoge_xxx0(VALUE obj);
/* 引数1個 */rb_define_method(cHoge, "xxx1", hoge_xxx1, 1);static VALUE hoge_xxx1(VALUE obj, VALUE arg);
/* 引数2個 */rb_define_method(cHoge, "xxx2", hoge_xxx2, 2);static VALUE hoge_xxx2(VALUE obj, VALUE arg1, VALUE arg2);
19/33
はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4
不定個引数
rb_define_method(cHoge, "xxxx", hoge_xxxx, -1);
...
/* def xxxx(arg1, arg2=nil, arg3=nil) とほぼ同じ */static VALUE hoge_xxxx(int argc, VALUE *argv, VALUE obj){ VALUE arg1, arg2, arg3; /* 自分で引数を数えてもいいけど、専用関数あり */ /* 必須1個、オプション2個 */ rb_scan_args(argc, argv, "12", &arg1, &arg2, &arg3);}
/* def xxxx(arg1, arg2=nil, *other) とほぼ同じ */static VALUE hoge_xxxx(int argc, VALUE *argv, VALUE obj){ VALUE arg1, arg2; /* 必須1個、オプション1個、それ以上はここでは無視 */ rb_scan_args(argc, argv, "11*", &arg1, &arg2); /* argv[2]〜argv[argc-1] が残りの引数 */}
20/33
はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4
データ変換
RubyからC
NUM2INT(n) -> intNUM2LONG(n) -> longNUM2DBL(n) -> doubleRSTRING_PTR(s) -> char*RSTRING_LEN(s) -> 文字列の長さRARRAY_PTR(a) -> VALUE*RARRAY_LEN(a) -> 配列の要素数
21/33
はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4
データ変換
CからRuby
INT2NUM(int) -> Fixnum or BignumLONG2NUM(long) -> Fixnum or BignumDBL2NUM(double) -> Floatrb_str_new(char*, long) -> Stringrb_ary_new() -> 空の配列rb_ary_new3(long, ...) -> n個の要素を持つ配列
22/33
はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4
真偽値
Ruby Ctrue Qtruefalse Qfalsenil Qnil
23/33
はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4
定義済みクラス
Ruby CObject rb_cObjectModule rb_cModuleClass rb_cClassString rb_cStringArray rb_cArray
24/33
はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4
Rubyオブジェクトの操作
str.concat("hoge")→ rb_str_cat(str, "hoge", 4)
ary[n]→ rb_ary_at(ary, n)
hash[key]→ rb_hash_aref(hash, key)
Hoge::Fuga → Hoge.const_get(:Fuga)→ rb_const_get(cHoge, rb_intern("Fuga"))
obj.instance_variable_get(:@name)→ rb_iv_get(obj, "@name")
25/33
はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4
Rubyレベルのメソッド呼び出しも可
rb_funcall(obj, rb_intern("methodname"), arg, ...);
26/33
はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4
raise & rescue
/* 例外を発生させる */rb_raise(rb_eRuntimeError, "%s: %d", "abc", 123);...
/* begin func1(arg1) rescue func2(arg2) end みたいな */VALUE func1(VALUE arg1){ ...}VALUE func2(VALUE arg2){ ...}...rb_rescue(func1, arg1, func2, arg2)
27/33
はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4
クラスの一部のメソッドをCで書くこともできる
[Ruby]class Hoge def xxx() ... endend
[C]cHoge = rb_const_get(rb_cObject, rb_intern("Hoge"));rb_define_method(cHoge, "zzz", hoge_zzz, 0);
28/33
はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4
その他もろもろ
29/33
はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4
詳しくは README.EXT.ja
30/33
はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4
さらに知りたければソース
ruby-X.Y.Z/*.{h,c}
31/33
はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4
サンプルも多数あるよ ruby-X.Y.Z/ext/*
32/33
はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4
ご清聴ありがとうございました
33/33