読者です 読者をやめる 読者になる 読者になる

XSからパッケージを作成する

多くのPerlパッケージはPerlスクリプト(PMファイル)で作成される。
h2xsコマンドで作成されるXSの初期ビルド環境でも1つのPMファイルが用意され、そのPMファイルがpackage命令によってパッケージを作成する。
単一のパッケージを作成する場合はこの方法で完結するのだが、1つのパッケージに多数のサブパッケージが付随する場合、それらのサブパッケージごとにXSのビルド環境を用意するよりも、XSから動的にサブパッケージを作成した方が効率的かつ高速で、管理も楽である。

以下の例では、Pkg1::initサブルーチンを呼び出ことにより、Pkg1::Sub1パッケージを生成し、次にPkg1::Sub1::helloを呼び出すことによってAUTOLOADの仕組み(呼び出されたサブルーチンがないときに同じパッケージのAUTOLOADサブルーチンが呼び出される仕組み)が働き、Pkg1::Sub1::helloサブルーチンのエントリが動的に作成される。

/* h2xs -n Pkg1 */

#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h" 

/*
 * h2xsコマンドが生成する部分
 *          :
 *          :
 */

XS(XS_Pkg1_Sub1_hello)
{
    dXSARGS;
    printf("hello world\n");
    XSRETURN_EMPTY;
}

XS(XS_Pkg1_Sub1_autoload)
{
    dXSARGS;
    int i;
    for (i = 0; i < items; i++) {
        printf("ST[%d]:%s\n", i, SvPV_nolen(ST(i)));
    }
    newXS("Pkg1::Sub1::hello", XS_Pkg1_Sub1_hello, __FILE__);
    XSRETURN_EMPTY;
}

MODULE = Pkg1   PACKAGE = Pkg1

/*
 * h2xsコマンドが生成する部分
 *          :
 *          :
 */

void
init()
CODE:
    perl_eval_pv("\
package Pkg1::Sub1; \
sub AUTOLOAD \
{ \
    Pkg1::Sub1::autoload($AUTOLOAD); \
    goto &$AUTOLOAD; \
} \
1; \
", 1);
    newXS("Pkg1::Sub1::autoload", XS_Pkg1_Sub1_autoload, __FILE__);


上記のXSをビルドして、以下のスクリプトを実行する。

#!/usr/bin/perl -Iblib/arch -Iblib/lib
use Pkg1;
Pkg1::init();
Pkg1::Sub1::hello();
Pkg1::Sub1::hello();


出力結果は以下の通り。

ST[0]:Pkg1::Sub1::hello
hello world
hello world


2回目に呼び出したPkg1::Sub1::helloサブルーチンのエントリが作成済みであることが分かる。

上記のテクニックはC++のクラスを簡単にパッケージとして表現する手段として利用できるはずである。