- Perl - XSでDLLを呼び出す(その1)

PerlC/C++で作成したプログラムを組み込むためには、XSインターフェースを実装したモジュールを作成する。
XSインターフェースの概念を説明すると長くなるし、私自身が完璧に理解している訳ではないので、こうすれば良いと言う方法を主に説明することにする。
使用するPerlはActivePerl 5.8.7である。

XSモジュールのビルド環境を構築する

XSモジュールのビルド環境を構築するためには、コマンドプロンプトで以下のコマンドを実行する。

> h2xs -n <modname> [hdrfile] ...

各オプションとパラメータの意味は以下の通りである。

項目 意味
-n Perlモジュール名を指定する
modname Perlモジュール名
hdrfile C/C++ヘッダファイル名


その他のオプションとして "-x -a" と言うものがあり、C/C++のヘッダファイルからXSインターフェース関数や構造体/共用体への設定/取得インターフェースが自動生成されるらしいが、Windowsにはcppstdinが存在しない(見つからない)ために正常に動作しないので、実際にどうなるのかは今のところ私には分からない。
それでも #define や enum で定義した定数を自動的に取り入れることができるので便利である。
それでは早速作って見よう。
便宜上、以降では作業用ディレクトリを "c:\xs" として説明する。

// example1.h
#define TEST_CONST_123 123
#define TEST_CONST_456 456
#define TEST_CONST_PI  3.14159265
#define TEST_CONST_HW  "Hello World"

上記の内容を "c:\xs\example1.h" として作成し、以下のコマンドを実行する。

> cd /d c:\xs
> h2xs -n Example1 example1.h

これにより以下のメッセージが示す通りのファイルが作成された。

Defaulting to backwards compatibility with perl 5.8.7
If you intend this module to be compatible with earlier perl versions, please specify a minimum perl version with the -b option.

Writing Example1/ppport.h
Writing Example1/lib/Example1.pm
Writing Example1/Example1.xs
Writing Example1/fallback/const-c.inc
Writing Example1/fallback/const-xs.inc
Writing Example1/Makefile.PL
Writing Example1/README
Writing Example1/t/Example1.t
Writing Example1/Changes
Writing Example1/MANIFEST

作業しやすいように予めカレントディレクトリを移動して置く。

> cd Example1

次にMakefile.plを変更してexample1.hをインクルードできるようにする。

    INC => '-I.', # e.g., '-I. -I/usr/include/other'
                        ↓
    INC => '-I. -I..', # e.g., '-I. -I/usr/include/other'

これでビルド環境を構築する準備ができたので、以下のコマンドを実行する。

> perl Makefile.pl

これにより以下のメッセージが示す通りにMakefileが作成された。

Checking if your kit is complete...
Looks good
Writing Makefile for Example1

取り敢えずビルドして見よう。

> nmake

以下のメッセージが表示され、Example1.dllが作成された。

Microsoft (R) Program Maintenance Utility   Version 6.00.9782.0
Copyright (C) Microsoft Corp 1988-1998. All rights reserved.

cp lib/Example1.pm blib\lib\Example1.pm
AutoSplitting blib\lib\Example1.pm (blib\lib\auto\Example1)
        E:\perl\bin\perl.exe E:\perl\lib\ExtUtils/xsubpp -typemap E:\perl\lib\ExtUtils\typemap Example1.xs > Example1.xsc && E:\perl\bin\perl.exe -MExtUtils::Command -e mv Example1.xsc Example1.c
Please specify prototyping behavior for Example1.xs (see perlxs manual)
        cl -c -I. -I.. -nologo -Gf -W3 -MD -Zi -DNDEBUG -O1 -DWIN32 -D_CONSOLE -DNO_STRICT -DHAVE_DES_FCRYPT -DBUILT_BY_ACTIVESTATE -DNO_HASH_SEED -DUSE_SITECUSTOMIZE -DPERL_IMPLICIT_CONTEXT -DPERL_IMPLICIT_SYS -DUSE_PERLIO -DPERL_MSVCRT_READFIX -MD -Zi -DNDEBUG -O1 -DVERSION=\"0.01\" -DXS_VERSION=\"0.01\" "-IE:\perl\lib\CORE" Example1.c
Example1.c
const-c.inc(55) : warning C4244: '=' : 'const double' から 'long' に変換しました。データが失われているかもしれません。
Running Mkbootstrap for Example1 ()
        E:\perl\bin\perl.exe -MExtUtils::Command -e chmod 644 Example1.bs
        E:\perl\bin\perl.exe -MExtUtils::Mksymlists -e "Mksymlists('NAME'=>\"Example1\", 'DLBASE' => 'Example1', 'DL_FUNCS' => {  }, 'FUNCLIST' => [], 'IMPORTS' => {  }, 'DL_VARS' => []);"
        link -out:blib\arch\auto\Example1\Example1.dll -dll -nologo -nodefaultlib -debug -opt:ref,icf -libpath:"e:\perl\lib\CORE" -machine:x86 Example1.obj E:\perl\lib\CORE\perl58.lib oldnames.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib netapi32.lib uuid.lib ws2_32.lib mpr.lib winmm.lib version.lib odbc32.lib odbccp32.lib msvcrt.lib -def:Example1.def
   ライブラリ blib\arch\auto\Example1\Example1.lib とオブジェクト blib\arch\auto\Example1\Example1.exp を作成中
        E:\perl\bin\perl.exe -MExtUtils::Command -e chmod 755 blib\arch\auto\Example1\Example1.dll
        E:\perl\bin\perl.exe -MExtUtils::Command -e cp Example1.bs blib\arch\auto\Example1\Example1.bs
        E:\perl\bin\perl.exe -MExtUtils::Command -e chmod 644 blib\arch\auto\Example1\Example1.bs

メッセージを良く見ると、嫌なwarningが表示されているが、これに関しては後日説明することにして、とにかくテストして見よう。

> nmake test

「All tests successful.」
うーん、簡単だ、すばらしい。

Microsoft (R) Program Maintenance Utility   Version 6.00.9782.0
Copyright (C) Microsoft Corp 1988-1998. All rights reserved.

        E:\perl\bin\perl.exe "-MExtUtils::Command::MM" "-e" "test_harness(0, 'blib\lib', 'blib\arch')" t\Example1.t
t\Example1....ok
All tests successful.
Files=1, Tests=2,  1 wallclock secs ( 0.00 cusr +  0.00 csys =  0.00 CPU)

何が上手くいったのか、さっぱり分からないが、少なくともビルド環境は手に入った。
次は出来上がったモジュールを使って見ようと思う。