Perl - XSでDLLを呼び出す(その2)
前回の続きとして、作成したExample1モジュールを使って見る。
インストールする前に使用する
以下のスクリプトを "c:\xs\Example1\TestEx1.pl" として保存する。
use ExtUtils::testlib; # @INCにblib\archとblib\libを追加する use Example1; print TEST_CONST_123 . "\n"; print TEST_CONST_456 . "\n"; print TEST_CONST_PI . "\n"; print TEST_CONST_HW . "\n";
インストールする前のモジュールを使用するためには、@INC変数にそのモジュールのパスを登録しなければならない。
ExtUtils::testlibによってそれが実現される。
上記のスクリプトを実行すると以下の結果となる。
123 456 3 TEST_CONST_HW
おや?TEST_CONST_PIが整数部だけになってしまっている。
TEST_CONST_HWに至っては内容が定義されていないために、"\n" と連結されたことでそのままの文字列になってしまった。
どうやら、小数定数は整数に変換され、文字列定数は無視されるようだ。
そう言えば、ビルド時に「const-c.inc(55) : warning C4244: '=' : 'const double' から 'long' に変換しました。データが失われているかもしれません。」と警告メッセージが表示されていた。
調査した結果、この問題を解決するためにはMakefile.plとlib\Example1.pmを変更するのが一番良い手段のようだ。
Makefile.plは以下のように変更する。
my @names = (qw(TEST_CONST_123 TEST_CONST_456 TEST_CONST_PI)); ↓ my @names = (qw(TEST_CONST_123 TEST_CONST_456), {name => "TEST_CONST_PI", type => "NV"}, {name => "TEST_CONST_HW", type => "PV"});
この変更が必要な理由は、@namesに定義する定数のタイプを指定しない場合、デフォルトではIVになるように、上記記述直後の以下の記述でDEFAULT_TYPEを指定しているからである。
ExtUtils::Constant::WriteConstants( NAME => 'Example1', NAMES => \@names, DEFAULT_TYPE => 'IV', C_FILE => 'const-c.inc', XS_FILE => 'const-xs.inc', );
ついでに定数のタイプを以下にまとめて置こう。
名前 | 意味 | 説明 |
---|---|---|
IV | Integer Value | 整数値 |
NV | Number Value | 実数値 |
PV | Pointer Value | 文字列(SVがScalar Valueなので代用か?) |
lib\Example1.pmには以下のようにTEST_CONST_HWの記述を追加する。
our %EXPORT_TAGS = ( 'all' => [ qw( TEST_CONST_123 TEST_CONST_456 TEST_CONST_PI TEST_CONST_HW #←追加 ) ] );
our @EXPORT = qw( TEST_CONST_123 TEST_CONST_456 TEST_CONST_PI TEST_CONST_HW #←追加 );
=head2 Exportable constants TEST_CONST_123 TEST_CONST_456 TEST_CONST_PI TEST_CONST_HW
上記の追加を行わないと、TEST_CONST_HWの定義が無いので、その定数を使用することが出来ない。
ただし、最後のhead2はドキュメントに出力される内容なので無くても動作する。
どうやら、ActivePerl 5.8.7付属のh2xsコマンドでは小数や文字列を扱えないようだ。
それではもう一度ビルドとテストをして見よう。
> nmake clean > perl Makefile.pl > nmake > perl TestEx1.pl
これで各定数の内容が正しく表示されたはずである。
次回は簡単なサブルーチンを定義するコードを記述してみようと思う。