Perl - XSでDLLを呼び出す(その3)
今回は簡単なサブルーチンを実装して見る。
新しいモジュールを準備する
以下のコマンドで新しいモジュールを準備する。
> cd /d c:\xs > h2xs -n Example2 > cd Example2
出来上がったExample2.xsは以下の内容である。
なお、行頭に ">" の付いた行は各エリアの説明である。
#include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "ppport.h" #include "const-c.inc" > ここにはC言語のコードを埋め込むことができる。 > コメントは /* ... */ で記述する。 MODULE = Example2 PACKAGE = Example2 > これ以降はXSの文法に則って記述する。 > コメントは "# "(シャープとスペース)で始める。 INCLUDE: const-xs.inc > ここにXS構文で定義したサブルーチンを実装する。
単純な戻り値のサブルーチンの書き方
実装に入る前に、戻り値が1つだけの単純なサブルーチンの書式を概ね把握して置こう。
その書式は以下のようになる。
<戻り値のタイプ> <サブルーチン名>(<引き数名列>) INPUT: <引き数のタイプ> <引き数名>; : : PREINIT: <内部変数定義> INIT: <初期化コード> CODE: <処理コード> OUTPUT: RETVAL
上記の各フィールドの詳細は、今後に少しずつ説明して行く。
では早速、サブルーチンを実装して見よう。
渡された整数を返す
引き数で指定された整数をそのまま返すサブルーチンを実装する。
IV echo_iv(n) INPUT: IV n; CODE: RETVAL = n; OUTPUT: RETVAL
戻り値のタイプは整数(Integer Value)を表す "IV" である。
C言語の "int" と記述しても良い。
ただし、タイプ以外を書くことはできない。
例)IV # 整数を返す ← コメントさえ不可
ここで指定したタイプが、自動的に生成されるRETVAL変数のタイプを決定する。
今回は引き数名列が "n" 1つだけである。
INPUTフィールドに記述する "n" のタイプは戻り値と同様に "IV" である。
やはり "int" と記述しても同じ整数を意味する。
内部変数や初期化コードは不要なので、PREINITとINITフィールドはそれ自体を省略する。
CODEフィールドでは、サブルーチンの戻り値となるRETVAL変数に引き数の "n" を代入する。
OUTPUTフィールドではRETVAL変数を戻り値として指定する。
それではビルドを実行しよう。
> perl Makefile.pl > make
上手くできただろうか。
テストのために以下のスクリプトを "c:\xs\Example2\TestEx2.pl" として保存する。
use ExtUtils::testlib; use Example2; sub TestEx2 { print Example2::echo_iv(123) . "\n"; print Example2::echo_iv(456) . "\n"; print Example2::echo_iv(789.012) . "\n"; print Example2::echo_iv("345") . "\n"; print Example2::echo_iv("678.901") . "\n"; print Example2::echo_iv("234yen") . "\n"; print eval {Example2::echo_iv()}; print $@; print eval {Example2::echo_iv(567, 890)}; print $@; } TestEx2;
上記を実行した結果は以下の通りである。
123 456 789 345 678 234 Usage: Example2::echo_iv(n) at TestEx2.pl line 12. Usage: Example2::echo_iv(n) at TestEx2.pl line 14.
結果を見ると分かる通り、少数は整数に丸められ、文字列は可能な限り整数に変換される。
興味深いのは、不正な個数の引き数を指定したときに、サブルーチンの使用方法が終了メッセージとして得られる点だ。
それは、まるで以下のスクリプトを実行したかのようである。
package Example2; sub echo_iv { die "Usage: Example2::echo_iv(n)" if ($#_ != 0); return int($_[0]); } package main; sub TestEx2 { # TestEx2.plと同じ内容 } TestEx2;
次回はこの謎に迫って見ようと思う。