はじめてのruby拡張ライブラリ

34
はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4 はじめてのRuby拡 張ライブラリ とみたまさひろ 2010-05-22

Upload: masahiro-tomita

Post on 26-Jun-2015

6.215 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: はじめてのRuby拡張ライブラリ

はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4

はじめてのRuby拡張ライブラリ

とみたまさひろ2010-05-22

Page 2: はじめてのRuby拡張ライブラリ

はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4

自己紹介

とみた まさひろ✓

プログラマー✓

mailto:[email protected]

http://d.hatena.ne.jp/tmtms✓

http://twitter.com/tmtms✓

1/33

Page 3: はじめてのRuby拡張ライブラリ

はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4

自己紹介

日本Rubyの会✓

日本MySQLユーザ会✓

Ruby/MySQL ライブラリ✓

Ruby歴, MySQL歴 十数年✓

2/33

Page 4: はじめてのRuby拡張ライブラリ

はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4

自己紹介

こんな本書きました

3/33

Page 5: はじめてのRuby拡張ライブラリ

はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4

NSEG #1 で

4/33

Page 6: はじめてのRuby拡張ライブラリ

はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4

Ruby拡張ライブラリ

5/33

Page 7: はじめてのRuby拡張ライブラリ

はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4

Rubyは遅い

6/33

Page 8: はじめてのRuby拡張ライブラリ

はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4

こんなに遅い

7/33

Page 9: はじめてのRuby拡張ライブラリ

はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4

Rubyが遅いのならCで書けばいいじゃない

8/33

Page 10: はじめてのRuby拡張ライブラリ

はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4

CのライブラリをRubyから使いたい

9/33

Page 11: はじめてのRuby拡張ライブラリ

はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4

ということで拡張ライ

ブラリ10/33

Page 12: はじめてのRuby拡張ライブラリ

はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4

通常のライブラリ

Ruby で書かれている✓

拡張子 .rb✓

require 'hoge'✓

require 'hoge.rb'✓

11/33

Page 13: はじめてのRuby拡張ライブラリ

はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4

拡張ライブラリ

C で書かれている✓

拡張子 .so (Linux の場合)✓

require 'hoge' (.rb が優先)✓

require 'hoge.o'✓

require 'hoge.so'✓

12/33

Page 14: はじめてのRuby拡張ライブラリ

はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4

作り方13/33

Page 15: はじめてのRuby拡張ライブラリ

はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4

専用ディレクトリが必要

$ ls hoge/extconf.rbhoge.c

14/33

Page 16: はじめてのRuby拡張ライブラリ

はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4

hoge.c

拡張ライブラリ本体

/* require 'hoge' 時に呼ばれる関数 */void Init_hoge(void){ puts("Hello");}

15/33

Page 17: はじめてのRuby拡張ライブラリ

はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4

extconf.rb

拡張ライブラリを作るための Makefile を作る

require 'mkmf'create_makefile 'hoge'

16/33

Page 18: はじめてのRuby拡張ライブラリ

はじめての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

Page 19: はじめてのRuby拡張ライブラリ

はじめての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

Page 20: はじめてのRuby拡張ライブラリ

はじめての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

Page 21: はじめてのRuby拡張ライブラリ

はじめての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

Page 22: はじめてのRuby拡張ライブラリ

はじめての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

Page 23: はじめてのRuby拡張ライブラリ

はじめての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

Page 24: はじめてのRuby拡張ライブラリ

はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4

真偽値

Ruby Ctrue Qtruefalse Qfalsenil Qnil

23/33

Page 25: はじめてのRuby拡張ライブラリ

はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4

定義済みクラス

Ruby CObject rb_cObjectModule rb_cModuleClass rb_cClassString rb_cStringArray rb_cArray

24/33

Page 26: はじめてのRuby拡張ライブラリ

はじめての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

Page 27: はじめてのRuby拡張ライブラリ

はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4

Rubyレベルのメソッド呼び出しも可

rb_funcall(obj, rb_intern("methodname"), arg, ...);

26/33

Page 28: はじめてのRuby拡張ライブラリ

はじめての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

Page 29: はじめてのRuby拡張ライブラリ

はじめての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

Page 30: はじめてのRuby拡張ライブラリ

はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4

その他もろもろ

29/33

Page 31: はじめてのRuby拡張ライブラリ

はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4

詳しくは README.EXT.ja

30/33

Page 32: はじめてのRuby拡張ライブラリ

はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4

さらに知りたければソース

ruby-X.Y.Z/*.{h,c}

31/33

Page 33: はじめてのRuby拡張ライブラリ

はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4

サンプルも多数あるよ ruby-X.Y.Z/ext/*

32/33

Page 34: はじめてのRuby拡張ライブラリ

はじめてのRuby拡張ライブラリ Powered by Rabbit 0.6.4

ご清聴ありがとうございました

33/33