Ruby/DL は、UNIX の dlopen(3) や Windows の
LoadLibrary()
などのダイナミックリンカへのインタフェースを提供す
る。
通常は、dl/import.rbの DL::Importable モジュールを使用する。
これはライブラリ関数にアクセスするための高水準の関数を持っている。
あるモジュールを拡張するには以下のように DL::Importable を使用する。
require "dl/import"
module LIBC
extend DL::Importable
end
以後、このモジュールの dlload と extern メソッドを使用できる。以下のよ
うに dlload 使ってライブラリをロードし、それぞれのライブラリ関数に対し
て extern を使用することでラッパーメソッドを定義する。
module LIBC
extend DL::Importable
dlload "libc.so.6","libm.so.6"
extern "int strlen(char*)"
end
# Note that we should not include the module LIBC from some reason.
LIBC.strlen を使用することで、ライブラリ関数 strlen() を使用できる。与
えられた関数名の最初の文字が大文字なら、定義されるメソッド名の最初の文
字は小文字になる。
以下のように dl/struct.rb で定義される struct や union 関数を使用す
ることで構造体や共用体のメモリイメージを作成することもできる。
require "dl/import"
require "dl/struct"
module LIBC
extend DL::Importable
Timeval = struct [ # define timeval structure.
"long tv_sec",
"long tv_uses",
]
end
val = LIBC::Timeval.malloc # allocate memory.
上の例で、メモリの割り当てに LIBC::Timeval.new ではなく、
LIBC::Timeval.malloc を使用していることに注意。LIBC::Timeval.new は、
作成済みの PtrData オブジェクトをラップするためのものだ。
以下のように モジュール関数 callback を使用したコールバックを定義できる。
module Foo
extend DL::Importable
def my_comp(str1,str2)
str1 <=> str2
end
COMPARE = callback "int my_comp(char*,char*)"
end
ここで Foo::COMPARE は、my_comp メソッドを起動する Symbol オブジェクトだ。
DL::Importable モジュールはとても便利だ。しかし、ときにはdlsym() のよ
うな低レベル関数を直接使わなければならない場面に出くわす。このような場
合には DL モジュールの関数を使用することになるだろう。これについては次
の節で説明する。
モジュール DL は数個のモジュール関数と定数を持つ 3 つのクラスから成っ
ている。クラス Symbol は呼び出す事ができるシンボルに相当する。クラス
PtrData は、C のポインタのようなメモリブロックを示す。クラス Handle か
ら具体化されたオブジェクトはオープンしたライブラリの操作を持つ。
- RTLD_GLOBAL
- RTLD_LAZY
- RTLD_NOW
- MAX_ARG
- MAX_CBARG
- MAX_CBENT
- handle = dlopen(lib){|handle| ... }
- sym = set_callback(cbtype, entry){|args| ... }
- sym = set_callback(cbtype, entry, proc)
- proc や指定したブロックを呼ぶ entry-th pre-defined function を作成
する。entry-th pre-defined function は cbtype と entry で指定され
る。cbtype はコールバックのプロトタイプ。cbtype については `Type
specifiers' も参照。
- sym = get_callback(cbtype, entry)
- 上記 `set_callback' 関数によって与えられた Proc オブジェクトを返す。
- ptr = malloc(size, [free = nil])
- size バイトのメモリ領域を割り当て、PtrData オブジェクトを ptr とし
て返す。
- ptr = strdup(str)
- 文字列 str を複製した新しい文字列へのポインタに相当する PtrData オ
ブジェクトを返す。
- size = sizeof(type)
型のサイズを返す。`sizeof("C") + sizeof("L")' は、
`sizeof("CL")' と等価ではない。後者は構造体 `struct foo { char c;
long l; }' の十分なサイズを返すと推定されるが、そのサイズは C の
`sizeof(foo)' と同じではないかもしれない。
(訳注: sizeof メソッドは独自にアラインメントを考慮してサイズを決定
するが C 言語のそれとは異なるかもしれないということを言っている)
(訳注: sizeof("L3") のように型の後に数字を付けることもできる。指定
できる型については Type specifiers を参照)
- handle = Handle.new(lib){|handle| ... }
- ライブラリ lib をオープンし、Handle オブジェクト handle を返す。ブ
ロックを指定すれば、(訳注: オープンしたハンドルをブロック引数に渡
してブロックを実行する)ハンドルはブロックの終りで自動的にクローズ
される。
- Handle#close
- 上記の Handle.new(lib) によってオープンされたハンドルをクローズする。
- sym = Handle#sym(func, prototype = "0"),
sym = Handle#[func, prototype = nil]
- 関数 func (訳注:やグローバル変数?)へのポインタを取得し、Symbol オ
ブジェクトや DataPtr オブジェクトを返す。prototype は型修飾からな
る文字列で関数のプロトタイプを示す。Type specifiers も
参照。
- sym = Symbol.new(addr, type = nil, name = nil)
- type が nil でないなら 型 type の Symbol オブジェクト sym を作成する。
関数が割り当てられているなら addr はそのアドレス。type が nil なら
DataPtr オブジェクトを返す。
- Symbol::char2type(char)
- 型に相当する文字 char を取り、C 言語の型修飾を返す。
- str = Symbol#proto()
- str = Symbol#name()
- str = Symbol#cproto(),
str = Symbol#to_s()
- str = Symbol#inspect()
- 人間が読みやすい形式の文字列を返す(訳注:意訳)。
- r,rs = Symbol#call(arg1,arg2,...,argN),
r,rs = Symbol#[](arg1,arg2,...,argN)
- パラメータ arg1, arg2, ... argN で関数を呼び出す。結果は、戻り値 r
やパラメータrs からなる。rs は配列。
- ptr = Symbol#to_ptr
- 対応する PtrData オブジェクト ptr を返す。
- ptr = PtrData.new(addr, [size = 0, free = nil])
- アドレス addr を指すポインタに相当する PtrData オブジェクトを返す。
GC は free 関数を使用してメモリを解放する。
- PtrData#free=(sym)
- シンボルオブジェクト sym を指定した場合、GC は sym に相当する関数
を使ってメモリを解放する。
- sym = PtrData#free
- GC がメモリを解放するのに使用するシンボルオブジェクト sym を返す。
sym は普通 `PtrData#free=' や `PtrData.new' によって設定される。
- size = PtrData#size, PtrData#size=(size)
- サイズ size を割り当てたメモリを取得および設定する。
- ary = PtrData#to_a(type, [size])
- type で指定された型の配列を返す。type は 'S','P','I','L','D' そし
て 'F' のいずれか。
- str = PtrData#to_s([len])
- 長さ len の文字列を返す。len を省略した場合は、文字列の終りは '\0'。
- ptr = PtrData#ptr,+@
- ポインタが指す値を PtrData オブジェクト ptr で返す。(訳注:?)
(訳注:PtrDataが指す値をポインタであるとして、PtrData にして返す(?))
- ptr = PtrData#ref,-@
- 参照を PtrData オブジェクト ptr で返す。(訳注:?)
(訳注:PtrDataへの参照を、PtrData にして返す(?))
(訳注:PtrDataを指すポインタを、PtrData にして返す(?))
- ptr = PtrData#+
- PtrData オブジェクトを返す。(訳注: 引数バイトを足した新しい
PtrData オブジェクトを返す)
- ptr = PtrData#-
- PtrData オブジェクトを返す。(訳注: 引数バイトを引いた新しい
PtrData オブジェクトを返す)
- PtrData#struct!(type, *members)
- 構造体メンバをシンボルでアクセスするデータ型を定義する(PtrData#[]
も参照)
- PtrData#union!(type, *members)
- 共用体メンバをシンボルでアクセスするデータ型を定義する(PtrData#[]
も参照)
- val = PtrData#[key], PtrData#[key, num = 0]
- key が文字列やシンボルなら、このメソッドは構造体/共用体メンバの値
を返す。それは PtrData#{struct!,union!} によって定義された型を持つ。
key が整数でこのオブジェクトがポインタ ptr に相当するなら、`(ptr +
key).to_s(num)' の値を返す
- PtrData#[key,num]=val, PtrData#[key]=val
- key が文字列やシンボルなら、このメソッドは構造体/共用体メンバの値
を val にする。key が整数で val が文字列なら memcpy(3) を使ってメ
モリ領域 ptr への値の num バイトをコピーする。
プロトタイプは以下の型修飾子から成る。プロトタイプの最初の要素は戻り値
の型を意味する。残りの要素は各引数の型を意味する。
C : 文字 (char)
c : 文字を指すポインタ (char *)
H : short 整数 (short)
h : short 整数を指すポインタ (short *)
I : 整数 (char, short, int)
i : 整数を指すポインタ (char *, short *, int *)
L : long 整数 (long)
l : long 整数へのポインタ (long *)
F : 実数 (float)
f : 実数へのポインタ (float *)
D : 実数 (double)
d : 実数へのポインタ(double *)
S : 不変(immutable)の文字列 (const char *)
s : 変更可能(mutable)な文字列 (char *)
A : 配列 (const type[])
a : 変更可能(mutable)な配列 (type[])
P : ポインタ (void *)
p : 変更可能(mutable)なポインタ (void *)
0 : void 関数(これはプロトタイプの最初の文字でなければならない)
cbtype は型修飾子 0, C, I, H, L, F, D, S そして P から成る。例えば:
DL.callback('IPP'){|ptr1,ptr2|
str1 = ptr1.ptr.to_s
str2 = ptr2.ptr.to_s
str1 <=> str2
}