Rubyの拡張ライブラリの作り方
Rubyの拡張ライブラリの作り方を説明します.
1.基礎知識
Cの変数には型があり,データには型がありません.ですから,たとえばポインタをintの変数に代入すると,その値は整数として取り扱われます.逆にRubyの変数には型がなく,データに型があります.この違いのため,CとRubyは相互に変換しなければ,お互いのデータをアクセスできません.
RubyのデータはVALUEというCの型で表現されます.VALUE型のデータはそのデータタイプを自分で知っています.このデータタイプというのはデータ(オブジェクト)の実際の構造を意味していて,Rubyのクラスとはまた違ったものです.
VALUEからCにとって意味のあるデータを取り出すためには
- VALUEのデータタイプを知る
- VALUEをCのデータに変換する
の両方が必要です.(1)を忘れると間違ったデータの変換が行われて,最悪プログラムがcore dumpします.
1.1 データタイプ
Rubyにはユーザが使う可能性のある以下のタイプがあります.
T_NIL | nil |
T_OBJECT | 通常のオブジェクト |
T_CLASS | クラス |
T_MODULE | モジュール |
T_FLOAT | 浮動小数点数 |
T_STRING | 文字列 |
T_REGEXP | 正規表現 |
T_ARRAY | 配列 |
T_FIXNUM | Fixnum(31bit長整数) |
T_HASH | 連想配列 |
T_STRUCT | (Rubyの)構造体 |
T_BIGNUM | 多倍長整数 |
T_FILE | 入出力 |
T_TRUE | 真 |
T_FALSE | 偽 |
T_DATA | データ |
T_SYMBOL | シンボル |
その他に内部で利用されている以下のタイプがあります.
T_ICLASS |
T_MATCH |
T_UNDEF |
T_VARMAP |
T_SCOPE |
T_NODE |
ほとんどのタイプはCの構造体で実装されています.
1.2 VALUEのデータタイプをチェックする
ruby.hではTYPE()というマクロが定義されていて,VALUEのデータタイプを知ることが出来ます.TYPE()マクロは上で紹介したT_XXXXの形式の定数を返します.VALUEのデータタイプに応じて処理する場合には,TYPE()の値で分岐することになります.
switch (TYPE(obj)) { case T_FIXNUM: /* FIXNUMの処理 */ break; case T_STRING: /* 文字列の処理 */ break; case T_ARRAY: /* 配列の処理 */ break; default: /* 例外を発生させる */ rb_raise(rb_eTypeError, "not valid value"); break; }
それとデータタイプをチェックして,正しくなければ例外を発生する関数が用意されています.
void Check_Type(VALUE value, int type)
この関数はvalueがtypeで無ければ,例外を発生させます.引数として与えられたVALUEのデータタイプが正しいかどうかチェックするためには,この関数を使います.
FIXNUMとNILに関してはより高速な判別マクロが用意されています.
FIXNUM_P(obj) NIL_P(obj)
1.3 VALUEをCのデータに変換する
データタイプがT_NIL, T_FALSE, T_TRUEである時,データはそれぞれnil, false, trueです.このデータタイプのオブジェクトはひとつずつしか存在しません.
データタイプがT_FIXNUMの時,これは31bitのサイズを持つ整数です.FIXNUMをCの整数に変換するためにはマクロ「FIX2INT()」を使います.それから,FIXNUMに限らずRubyのデータを整数に変換する「NUM2INT()」というマクロがあります.このマクロはデータタイプのチェック無しで使えます(整数に変換できない場合には例外が発生する).同様にチェック無しで使える変換マクロはdoubleを取り出す「NUM2DBL()」があります。
char* を取り出す場合、version 1.6 以前では「STR2CSTR()」というマクロを使っていましたが、これは to_str() による暗黙の型変換結果が GC される可能性があるため、version 1.7 以降ではobsolete となり、代わりに StringValue() と StringValuePtr()を使う事を推奨しています。StringValue(var) は var が String であれば何もせず、そうでなければ var を var.to_str() の結果に置き換えるマクロ、StringValuePtr(var) は同様に var を置き換えてから var の文字列表現に対する char* を返すマクロです。var の内容を直接置き換える処理が入るので、var は lvalue である必要があります。
それ以外のデータタイプは対応するCの構造体があります.対応する構造体のあるVALUEはそのままキャスト(型変換)すれば構造体のポインタに変換できます.
構造体は「struct RXxxxx」という名前でruby.hで定義されています.例えば文字列は「struct RString」です.実際に使う可能性があるのは文字列と配列くらいだと思います.
ruby.hでは構造体へキャストするマクロも「RXXXXX()」(全部大文字にしたもの)という名前で提供されています(例: RSTRING()).
例えば,文字列strの長さを得るためには「RSTRING(str)->len」とし,文字列strをchar*として得るためには「RSTRING(str)->ptr」とします.配列の場合には,それぞれ「RARRAY(ary)->len」,「RARRAY(ary)->ptr」となります.
Rubyの構造体を直接アクセスする時に気をつけなければならないことは,配列や文字列の構造体の中身は参照するだけで,直接変更しないことです.直接変更した場合,オブジェクトの内容の整合性がとれなくなって,思わぬバグの原因になります.
1.4 CのデータをVALUEに変換する
VALUEの実際の構造は
- FIXNUMの場合
- 1bit左シフトして,LSBを立てる.
- その他のポインタの場合
- そのままVALUEにキャストする.
となっています.よって,LSBをチェックすればVALUEがFIXNUMかどうかわかるわけです(ポインタのLSBが立っていないことを仮定している).
ですから,FIXNUM以外のRubyのオブジェクトの構造体は単にVALUEにキャストするだけでVALUEに変換出来ます.ただし,任意の構造体がVALUEにキャスト出来るわけではありません.キャストするのはRubyの知っている構造体(ruby.hで定義されているstruct RXxxxのもの)だけです.
FIXNUMに関しては変換マクロを経由する必要があります.Cの整数からVALUEに変換するマクロは以下のものがあります.必要に応じて使い分けてください.
- INT2FIX()
- もとの整数が31bit以内に収まる自信がある時
- INT2NUM()
- 任意の整数からVALUEへ
INT2NUM()は整数がFIXNUMの範囲に収まらない場合,Bignumに変換してくれます(が,少し遅い).
1.5 Rubyのデータを操作する
先程も述べた通り,Rubyの構造体をアクセスする時に内容の更新を行うことは勧められません.で,Rubyのデータを操作する時にはRubyが用意している関数を用いてください.
ここではもっとも使われるであろう文字列と配列の生成/操作を行い関数をあげます(全部ではないです).
文字列に対する関数
- rb_str_new(const char *ptr, long len)
- 新しいRubyの文字列を生成する.
- rb_str_new2(const char *ptr)
- Cの文字列からRubyの文字列を生成する.この関数の機能はrb_str_new(ptr, strlen(ptr))と同等である.
- rb_tainted_str_new(const char *ptr, long len)
- 汚染マークが付加された新しいRubyの文字列を生成する.外部からのデータに基づく文字列には汚染マークが付加されるべきである.
- rb_tainted_str_new2(const char *ptr)
- Cの文字列から汚染マークが付加されたRubyの文字列を生成する.
- rb_str_cat(VALUE str, const char *ptr, long len)
- Rubyの文字列strにlenバイトの文字列ptrを追加する.
配列に対する関数
- rb_ary_new()
- 要素が0の配列を生成する.
- rb_ary_new2(long len)
- 要素が0の配列を生成する.len要素分の領域をあらかじめ割り 当てておく.
- rb_ary_new3(long n, ...)
- 引数で指定したn要素を含む配列を生成する.
- rb_ary_new4(long n, VALUE *elts)
- 配列で与えたn要素の配列を生成する.
- rb_ary_push(VALUE ary, VALUE val)
- rb_ary_pop(VALUE ary)
- rb_ary_shift(VALUE ary)
- rb_ary_unshift(VALUE ary, VALUE val)
- Arrayの同名のメソッドと同じ働きをする関数.第1引数は必ず配列でなければならない.
2.Rubyの機能を使う
原理的にRubyで書けることはCでも書けます.RubyそのものがCで記述されているんですから,当然といえば当然なんですけど.ここではRubyの拡張に使うことが多いだろうと予測される機能を中心に紹介します.
2.1 Rubyに機能を追加する
Rubyで提供されている関数を使えばRubyインタプリタに新しい機能を追加することができます.Rubyでは以下の機能を追加する関数が提供されています.
- クラス,モジュール
- メソッド,特異メソッドなど
- 定数
では順に紹介します.
2.1.1 クラス/モジュール定義
クラスやモジュールを定義するためには,以下の関数を使います.
VALUE rb_define_class(const char *name, VALUE super) VALUE rb_define_module(const char *name)
これらの関数は新しく定義されたクラスやモジュールを返します.メソッドや定数の定義にこれらの値が必要なので,ほとんどの場合は戻り値を変数に格納しておく必要があるでしょう.
クラスやモジュールを他のクラスの内部にネストして定義する時には以下の関数を使います.
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super) VALUE rb_define_module_under(VALUE outer, const char *name)
2.1.2 メソッド/特異メソッド定義
メソッドや特異メソッドを定義するには以下の関数を使います.
void rb_define_method(VALUE klass, const char *name, VALUE (*func)(), int argc) void rb_define_singleton_method(VALUE object, const char *name, VALUE (*func)(), int argc)
念のため説明すると「特異メソッド」とは,その特定のオブジェクトに対してだけ有効なメソッドです.RubyではよくSmalltalkにおけるクラスメソッドとして,クラスに対する特異メソッドが使われます.
これらの関数の argcという引数はCの関数へ渡される引数の数(と形式)を決めます.argcが0以上の時は関数に引き渡す引数の数を意味します.16個以上の引数は使えません(が,要りませんよね,そんなに).実際の関数には先頭の引数としてselfが与えられますので,指定した数より1多い引数を持つことになります.
argcが負の時は引数の数ではなく,形式を指定したことになります.argcが-1の時は引数を配列に入れて渡されます.argcが-2の時は引数はRubyの配列として渡されます.
メソッドを定義する関数はもう二つあります.ひとつはprivateメソッドを定義する関数で,引数はrb_define_method()と同じです.
void rb_define_private_method(VALUE klass, const char *name, VALUE (*func)(), int argc)
privateメソッドとは関数形式でしか呼び出すことの出来ないメソッ
ドです.
もうひとつはモジュール関数を定義するものです.モジュール関数とはモジュールの特異メソッドであり,同時にprivateメソッドでもあるものです.例をあげるとMathモジュールのsqrt()などがあげられます.このメソッドは
Math.sqrt(4)
という形式でも
include Math sqrt(4)
という形式でも使えます.モジュール関数を定義する関数は以下の
通りです.
void rb_define_module_function(VALUE module, const char *name, VALUE (*func)(), int argc)
関数的メソッド(Kernelモジュールのprivate method)を定義するた
めの関数は以下の通りです.
void rb_define_global_function(const char *name, VALUE (*func)(), int argc)
メソッドの別名を定義するための関数は以下の通りです。
void rb_define_alias(VALUE module, const char* new, const char* old);
クラスメソッドallocateを定義したり削除したりするための関数は以下の通りです。
void rb_define_alloc_func(VALUE klass, VALUE (*func)(VALUE klass)); void rb_undef_alloc_func(VALUE klass);
funcはクラスを引数として受け取って、新しく割り当てられたインスタンスを返さなくてはなりません。このインスタンスは、外部リソースなどを含まない、できるだけ「空」のままにしておいたほうがよいでしょう。
2.1.3 定数定義
拡張ライブラリが必要な定数はあらかじめ定義しておいた方が良いでしょう.定数を定義する関数は二つあります.
void rb_define_const(VALUE klass, const char *name, VALUE val) void rb_define_global_const(const char *name, VALUE val)
前者は特定のクラス/モジュールに属する定数を定義するもの,後者はグローバルな定数を定義するものです.
2.2 Rubyの機能をCから呼び出す
既に『1.5 Rubyのデータを操作する』で一部紹介したような関数を使えば,Rubyの機能を実現している関数を直接呼び出すことが出来ます.
# このような関数の一覧表はいまのところありません.ソースを見るしかないですね.
それ以外にもRubyの機能を呼び出す方法はいくつかあります.
2.2.1 Rubyのプログラムをevalする
CからRubyの機能を呼び出すもっとも簡単な方法として,文字列で与えられたRubyのプログラムを評価する以下の関数があります.
VALUE rb_eval_string(const char *str)
この評価は現在の環境で行われます.つまり,現在のローカル変数などを受け継ぎます.
2.2.2 IDまたはシンボル
Cから文字列を経由せずにRubyのメソッドを呼び出すこともできます.その前に,Rubyインタプリタ内でメソッドや変数名を指定する時に使われているIDについて説明しておきましょう.
IDとは変数名,メソッド名を表す整数です.RubyではIDに対応するオブジェクトとしてシンボル(Symbol)があり,
:識別子
でアクセスできます.Cからこの整数を得るためには関数
rb_intern(const char *name)
を使います.Rubyから引数として与えられたシンボル(または文字列)をIDに変換するには以下の関数を使います.
rb_to_id(VALUE symbol)
IDからシンボルを得るためには以下のマクロを使います.
VALUE ID2SYM(ID id)
シンボルからIDを得るためには以下のマクロを使います.
ID SYM2ID(VALUE symbol)
2.2.3 CからRubyのメソッドを呼び出す
Cから文字列を経由せずにRubyのメソッドを呼び出すためには以下の関数を使います.
VALUE rb_funcall(VALUE recv, ID mid, int argc, ...)
この関数はオブジェクトrecvのmidで指定されるメソッドを呼び出します.その他に引数の指定の仕方が違う以下の関数もあります.
VALUE rb_funcall2(VALUE recv, ID mid, int argc, VALUE *argv) VALUE rb_apply(VALUE recv, ID mid, VALUE args)
applyには引数としてRubyの配列を与えます.
2.2.4 変数/定数を参照/更新する
Cから関数を使って参照・更新できるのは,定数,インスタンス変数です.大域変数は一部のものはCの大域変数としてアクセスできます.ローカル変数を参照する方法は公開していません.
オブジェクトのインスタンス変数を参照・更新する関数は以下の通りです.
VALUE rb_ivar_get(VALUE obj, ID id) VALUE rb_ivar_set(VALUE obj, ID id, VALUE val)
idはrb_intern()で得られるものを使ってください.
定数を参照するには以下の関数を使ってください.
VALUE rb_const_get(VALUE obj, ID id)
定数を新しく定義するためには『2.1.3 定数定義』で紹介されている関数を使ってください.
3.RubyとCとの情報共有
C言語とRubyの間で情報を共有する方法について解説します.
3.1 Cから参照できるRubyの定数
以下のRubyの定数はCのレベルから参照できます.
- Qtrue
- Qfalse
- 真偽値.QfalseはC言語でも偽とみなされます(つまり0).
- Qnil
- C言語から見た「nil」.
3.2 CとRubyで共有される大域変数
CとRubyで大域変数を使って情報を共有できます.共有できる大域変数にはいくつかの種類があります.そのなかでもっとも良く使われると思われるのはrb_define_variable()です.
void rb_define_variable(const char *name, VALUE *var)
この関数はRubyとCとで共有する大域変数を定義します.変数名が`$'で始まらない時には自動的に追加されます.この変数の値を変更すると自動的にRubyの対応する変数の値も変わります.
またRuby側からは更新できない変数もあります.このread onlyの変数は以下の関数で定義します.
void rb_define_readonly_variable(const char *name, VALUE *var)
これら変数の他にhookをつけた大域変数を定義できます.hook付きの大域変数は以下の関数を用いて定義します.hook付き大域変数の値の参照や設定はhookで行う必要があります.
void rb_define_hooked_variable(const char *name, VALUE *var, VALUE (*getter)(), void (*setter)())
この関数はCの関数によってhookのつけられた大域変数を定義します.変数が参照された時には関数getterが,変数に値がセットされた時には関数setterが呼ばれる.hookを指定しない場合はgetterやsetterに0を指定します.
# getterもsetterも0ならばrb_define_variable()と同じになる.
それから,Cの関数によって実現されるRubyの大域変数を定義する関数があります.
void rb_define_virtual_variable(const char *name, VALUE (*getter)(), void (*setter)())
この関数によって定義されたRubyの大域変数が参照された時にはgetterが,変数に値がセットされた時にはsetterが呼ばれます.
getterとsetterの仕様は以下の通りです.
(*getter)(ID id, void *data, struct global_entry* entry); (*setter)(VALUE val, ID id, void *data, struct global_entry* entry);
3.3 CのデータをRubyオブジェクトにする
Cの世界で定義されたデータ(構造体)をRubyのオブジェクトとして取り扱いたい場合がありえます.このような場合には,DataというRubyオブジェクトにCの構造体(へのポインタ)をくるむことでRubyオブジェクトとして取り扱えるようになります.
Dataオブジェクトを生成して構造体をRubyオブジェクトにカプセル化するためには,以下のマクロを使います.
Data_Wrap_Struct(klass, mark, free, ptr)
このマクロの戻り値は生成されたDataオブジェクトです.
klassはこのDataオブジェクトのクラスです.ptrはカプセル化するCの構造体へのポインタです.markはこの構造体がRubyのオブジェクトへの参照がある時に使う関数です.そのような参照を含まない時には0を指定します.
# そのような参照は勧められません.
freeはこの構造体がもう不要になった時に呼ばれる関数です.この関数がガーベージコレクタから呼ばれます.これが-1の場合は,単純に開放されます.
Cの構造体の割当とDataオブジェクトの生成を同時に行うマクロとして以下のものが提供されています.
Data_Make_Struct(klass, type, mark, free, sval)
このマクロの戻り値は生成されたDataオブジェクトです.
klass, mark, freeはData_Wrap_Structと同じ働きをします.typeは割り当てるC構造体の型です.割り当てられた構造体は変数svalに代入されます.この変数の型は (type*) である必要があります.
Dataオブジェクトからポインタを取り出すのは以下のマクロを用います.
Data_Get_Struct(obj, type, sval)
Cの構造体へのポインタは変数svalに代入されます.
これらのDataの使い方はちょっと分かりにくいので,後で説明する例題を参照してください.
4.例題 - dbmパッケージを作る
ここまでの説明でとりあえず拡張ライブラリは作れるはずです.Rubyのextディレクトリにすでに含まれているdbmライブラリを例にして段階的に説明します.
(1) ディレクトリを作る
% mkdir ext/dbm
Ruby 1.1からは任意のディレクトリでダイナミックライブラリを作ることができるようになりました.Rubyに静的にリンクする場合にはRubyを展開したディレクトリの下,extディレクトリの中に拡張ライブラリ用のディレクトリを作る必要があります.名前は適当に選んで構いません.
(2) 設計する
まあ,当然なんですけど,どういう機能を実現するかどうかまず設計する必要があります.どんなクラスをつくるか,そのクラスにはどんなメソッドがあるか,クラスが提供する定数などについて設計します.
(3) Cコードを書く
拡張ライブラリ本体となるC言語のソースを書きます.C言語のソースがひとつの時には「ライブラリ名.c」を選ぶと良いでしょう.C言語のソースが複数の場合には逆に「ライブラリ名.c」というファイル名は避ける必要があります.オブジェクトファイルとモジュール生成時に中間的に生成される「ライブラリ名.o」というファイルとが衝突するからです.
Rubyは拡張ライブラリをロードする時に「Init_ライブラリ名」という関数を自動的に実行します.dbmライブラリの場合「Init_dbm」です.この関数の中でクラス,モジュール,メソッド,定数などの定義を行います.dbm.cから一部引用します.
-- Init_dbm() { /* DBMクラスを定義する */ cDBM = rb_define_class("DBM", rb_cObject); /* DBMはEnumerateモジュールをインクルードする */ rb_include_module(cDBM, rb_mEnumerable); /* DBMクラスのクラスメソッドopen(): 引数はCの配列で受ける */ rb_define_singleton_method(cDBM, "open", fdbm_s_open, -1); /* DBMクラスのメソッドclose(): 引数はなし */ rb_define_method(cDBM, "close", fdbm_close, 0); /* DBMクラスのメソッド[]: 引数は1個 */ rb_define_method(cDBM, "[]", fdbm_fetch, 1); : /* DBMデータを格納するインスタンス変数名のためのID */ id_dbm = rb_intern("dbm"); } --
DBMライブラリはdbmのデータと対応するオブジェクトになるはずですから,Cの世界のdbmをRubyの世界に取り込む必要があります.
dbm.cではData_Make_Structを以下のように使っています.
-- struct dbmdata { int di_size; DBM *di_dbm; }; obj = Data_Make_Struct(klass, struct dbmdata, 0, free_dbm, dbmp); --
ここではdbmstruct構造体へのポインタをDataにカプセル化しています.DBM*を直接カプセル化しないのはclose()した時の処理を考えてのことです.
Dataオブジェクトからdbmstruct構造体のポインタを取り出すために以下のマクロを使っています.
-- #define GetDBM(obj, dbmp) {\ Data_Get_Struct(obj, struct dbmdata, dbmp);\ if (dbmp->di_dbm == 0) closed_dbm();\ } --
ちょっと複雑なマクロですが,要するにdbmdata構造体のポインタの取り出しと,closeされているかどうかのチェックをまとめているだけです.
DBMクラスにはたくさんメソッドがありますが,分類すると3種類の引数の受け方があります.ひとつは引数の数が固定のもので,例としてはdeleteメソッドがあります.deleteメソッドを実装しているfdbm_delete()はこのようになっています.
-- static VALUE fdbm_delete(obj, keystr) VALUE obj, keystr; { : } --
引数の数が固定のタイプは第1引数がself,第2引数以降がメソッドの引数となります.
引数の数が不定のものはCの配列で受けるものとRubyの配列で受けるものとがあります.dbmライブラリの中で,Cの配列で受けるものはDBMのクラスメソッドであるopen()です.これを実装している関数fdbm_s_open()はこうなっています.
-- static VALUE fdbm_s_open(argc, argv, klass) int argc; VALUE *argv; VALUE klass; { : if (rb_scan_args(argc, argv, "11", &file, &vmode) == 1) { mode = 0666; /* default value */ } : } --
このタイプの関数は第1引数が与えられた引数の数,第2引数が与えられた引数の入っている配列になります.selfは第3引数として与えられます.
この配列で与えられた引数を解析するための関数がopen()でも使われているrb_scan_args()です.第3引数に指定したフォーマットに従い,第4変数以降に指定した変数に値を代入してくれます.このフォーマットは,第1文字目が省略できない引数の数,第2文字目が省略できる引数の数,第3文字目が対応する相手が無いあまりの引数があるかどうかを示す"*"です.2文字目と3文字目は省略できます.dbm.cの例では,フォーマットは"11"ですから,引数は最低1つで,2つまで許されるという意味になります.省略されている時の変数の値はnil(C言語のレベルではQnil)になります.
Rubyの配列で引数を受け取るものはindexesがあります.実装はこうです.
-- static VALUE fdbm_indexes(obj, args) VALUE obj, args; { : } --
第1引数はself,第2引数はRubyの配列です.
注意事項
Rubyと共有はしないがRubyのオブジェクトを格納する可能性のあるCの大域変数は以下の関数を使ってRubyインタプリタに変数の存在を教えてあげてください.でないとGCでトラブルを起こします.
void rb_global_variable(VALUE *var)
(4) extconf.rbを用意する
Makefileを作る場合の雛型になるextconf.rbというファイルを作ります.extconf.rbはライブラリのコンパイルに必要な条件のチェックなどを行うことが目的です.まず,
require 'mkmf'
をextconf.rbの先頭に置きます.extconf.rbの中では以下のRuby関数を使うことが出来ます.
have_library(lib, func): ライブラリの存在チェック have_func(func, header): 関数の存在チェック have_header(header): ヘッダファイルの存在チェック create_makefile(target): Makefileの生成
以下の変数を使うことができます.
$CFLAGS: コンパイル時に追加的に指定するフラグ(-Oなど) $CPPFLAGS: プリプロセッサに追加的に指定するフラグ(-Iや-Dなど) $LDFLAGS: リンク時に追加的に指定するフラグ(-Lなど) $objs: リンクされるオブジェクトファイル名のリスト
オブジェクトファイルのリストは、通常はソースファイルを検索して自動的に生成されますが、makeの途中でソースを生成するような場合は明示的に指定する必要があります。
ライブラリをコンパイルする条件が揃わず,そのライブラリをコンパイルしない時にはcreate_makefileを呼ばなければMakefileは生成されず,コンパイルも行われません.
(5) dependを用意する
もし,ディレクトリにdependというファイルが存在すれば,Makefileが依存関係をチェックしてくれます.
% gcc -MM *.c > depend
などで作ることが出来ます.あって損は無いでしょう.
(6) Makefileを生成する
Makefileを実際に生成するためには
ruby extconf.rb
とします.extconf.rbに require 'mkmf' の行がない場合にはエラーになりますので,引数を追加して
ruby -r mkmf extconf.rb
としてください.
ディレクトリをext以下に用意した場合にはRuby全体のmakeの時に自動的にMakefileが生成されますので,このステップは不要です.
(7) makeする
動的リンクライブラリを生成する場合にはその場でmakeしてください.必要であれば make install でインストールされます.
ext以下にディレクトリを用意した場合は,Rubyのディレクトリでmakeを実行するとMakefileを生成からmake,必要によってはそのモジュールのRubyへのリンクまで自動的に実行してくれます.extconf.rbを書き換えるなどしてMakefileの再生成が必要な時はまたRubyディレクトリでmakeしてください.
拡張ライブラリはmake installでRubyライブラリのディレクトリの下にコピーされます.もし拡張ライブラリと協調して使うRubyで記述されたプログラムがあり,Rubyライブラリに置きたい場合には,拡張ライブラリ用のディレクトリの下に lib というディレクトリを作り,そこに 拡張子 .rb のファイルを置いておけば同時にインストールされます.
(8) デバッグ
まあ,デバッグしないと動かないでしょうね.ext/Setupにディレクトリ名を書くと静的にリンクするのでデバッガが使えるようになります.その分コンパイルが遅くなりますけど.
(9) できあがり
後はこっそり使うなり,広く公開するなり,売るなり,ご自由にお使いください.Rubyの作者は拡張ライブラリに関して一切の権利を主張しません.
2006年12月09日(土) 05:58:47 Modified by aqualung