複数モジュールを使うXSの簡単な実装方法
XSを使ってモジュールを作ろうとしたときに、複数のモジュールに分割するときにふと困りました。たとえば、SomeModuleとSomeModule::Utilの両方でXSの実装を行いたい場合です。方法を調べていたのですが、実装方法が結構煩雑で難しいなと感じました。
いろいろと試していたのですが、次の方法が簡単なように思えたので紹介しておきます。この方法の利点は、次のとおりです。
- Makefile.PLを修正する必要がない
- SomeModule.xsというファイルの名前を修正する必要がない
- SomeModule.xsという一枚のXSファイルだけでOK
- 標準ツールのh2xsでも大丈夫
h2xsでモジュールを作成
最初にh2xsでXS用のモジュールを作成します。
h2xs -A -n SomeModule
こうすると「SomeModule」というディレクトリが作成されます。次のようなファイルとディレクトリが作成されます。
Changes lib/ Makefile.PL MANIFEST ppport.h README SomeModule.xs t/
XSファイルの記述
XSファイルを作成していきます。「foo」と表示するfooという関数をSomeModuleに追加、「bar」と表示するbarという関数をSomeModule::Utilに追加してみます。
まず最初にXSファイルを開くと次のようになっていると思います。
#include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "ppport.h" MODULE = SomeModule PACKAGE = SomeModule
まず覚えてほしいことは、「MODULE = SomeModule PACKAGE = SomeModule」のセクションは一番下側に置く必要があるということです。この部分を最後においておかないとXSのロードに失敗してしまいます。
では記述しましょう。「MODULE = SomeModule::Util PACKAGE = SomeModule::Util」を追加します。そしてXSでbarを定義します。また「MODULE = SomeModule PACKAGE = SomeModule」のセクションに、fooを定義します。
#include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "ppport.h" MODULE = SomeModule::Util PACKAGE = SomeModule::Util void bar(...) PPCODE: { PerlIO_printf(PerlIO_stdout(), "bar\n"); XSRETURN(0); } MODULE = SomeModule PACKAGE = SomeModule void foo(...) PPCODE: { PerlIO_printf(PerlIO_stdout(), "foo\n"); XSRETURN(0); }
モジュールの作成
ここまでできれば、SomeModuleとSomeModule::Utilを作成するだけです。
SomeModuleのソースコード
SomeModule.pmのソースコードは最初のままでもかまいません。少し整理して以下のようにしました。
package SomeModule; use strict; use warnings; our $VERSION = '0.01'; require XSLoader; XSLoader::load('SomeModule', $VERSION); 1;
SomeModule::Utilのソースコード
SomeModule::Util::barも作ってみましょう。これは「lib/SomeModule/Util.pm」に保存してください。これはパッケージ名だけが宣言されたほとんど空のファイルです。
package SomeModule::Util; 1;
テストスクリプト
テストスクリプトを作成します。これは、XSファイルがあるディレクトリと同じディレクトリにおいてください。
use strict; use warnings; use SomeModule; use SomeModule::Util; SomeModule::foo(); SomeModule::Util::bar();
コンパイルして実行
コンパイルして実行してみましょう。
perl Makefile.PL make perl -Mblib test.pl
次のように出力されれば成功です。
foo bar
XSを複数モジュールで記述するのは、それほど難しくなさそうですね。