PERLAPI(1)               USER COMMANDS                 PERLAPI(1)



NAME
     perlapi - Perl 5 の C 拡張のアプリケーションプログラミングイ
               ンタフェース

DESCRIPTION
     導入

     XS は、Perl と Perl といっしょに使おうとする C ライブラリの
     間の拡張インタフェースを作るための言語です。 XS インタフェ
     ースは、Perl とリンクすることのできる、新しいライブラリを作
     るためのライブラリと組み合わせて使われます。 XSUB は、XS 言
     語内の関数で、Perl アプリケーションインタフェースの中核を成
     すものです。

     XS コンパイラは、xsubpp と呼ばれています。 このコンパイラは、
     実際には C の関数を装って XSUB に Perl の値を操作させるため
     に必要な構造を埋め込み、Perl に XSUB をアクセスさせるために
     必要なグルー関数を作ります。 コンパイラは、C 関数の引数や変
     数を Perl の値にマッピングする方法を決めるために、typemap を
     使用します。 デフォルトの typemap では、多くの一般的な C の
     型を扱っています。 新たにリンクされるライブラリのための、特
     殊な構造体や型を扱うときには、補助的な typemap を作らなけれ
     ばなりません。

     以下の多くの例では、Perl と ONC+RPC 結合ライブラリ関数のイン
     タフェースの作成に焦点をおいています。 特に、rpcb_gettime()
     関数が、XS 言語の多くの機能を示すために用いられています。
     この関数は、2 つの引数をとります。 一つめの引数が入力用で、
     ふたつめの引数が出力用です。 この関数はまた、ステータス値を
     返します。

             bool_t rpcb_gettime(const char *host, time_t *timep);

     C からは、以下のような形でこの関数が呼ばれます。

          #include <rpc/rpc.h>
          bool_t status;
          time_t timep;
          status = rpcb_gettime( "localhost", &timep );

     この関数と Perl の間で直接変換を行なうための XSUB を作れば、
     次のようなコードで、Perl からその XSUB が使われます。 変数
     $status と変数 $timep に、この関数の出力が得られます。

          use RPC;
          $status = rpcb_gettime( "localhost", $timep );

     以下に示す XS ファイルは、rpcb_gettime() 関数へのインタフェ
     ースの一例となる XS サブルーティン (XSUB のこと) を示してい
     ます。 この XSUB が C と Perl の間の直接変換を行ない、Perl
     からのインタフェースも確保します。 XSUB は上に示したような
     使い方で、Perl から起動されます。 XS ファイルではいつも、最



Perl manpages Last change: Release 5.0 Patchlevel 00            1






PERLAPI(1)               USER COMMANDS                 PERLAPI(1)



     初に EXTERN.h、perl.h、XSUB.h のための 3 つの #include 文を
     指定しないといけません。 この方法や他の方法の拡張は、後述し
     ます。

          #include "EXTERN.h"
          #include "perl.h"
          #include "XSUB.h"
          #include <rpc/rpc.h>

          MODULE = RPC  PACKAGE = RPC

          bool_t
          rpcb_gettime(host,timep)
               char *  host
               time_t  &timep
               OUTPUT:
               timep

     XSUB を使うものを含めて、どんな Perl への拡張も、ブートスト
     ラップのように起動時に、その拡張を Perl に組み込む Perl モジ
     ュールを用意するようになっています。 このモジュールが、拡張
     機能や変数を Perl プログラムにエクスポートし、拡張のための
     XSUB を Perl に組み込みます。 以下のモジュールは、このドキ
     ュメントのほとんどの例で使われ、前に示したように Perl から
     use コマンドで使われるはずです。 Perl モジュールについては、
     このドキュメント内でも、もう少し詳しく触れます。

          package RPC;

          require Exporter;
          require DynaLoader;
          @ISA = qw(Exporter DynaLoader);
          @EXPORT = qw( rpcb_gettime );

          bootstrap RPC;
          1;

     このドキュメントを通じて、さまざまな rpcb_gettime() XSUB へ
     のインタフェースを研究しています。 XSUB は、場合によって、
     順番や数の異なる引数をとるようになっています。 どの場合にも、
     XSUB は、Perl と実際の C の rpcb_gettime() 関数の間を取り持
     つもので、XSUB が実際の rpcb_gettime() 関数を常に正しい引数
     で呼ぶことを保証しなければなりません。 この抽象化された仲介
     によって、プログラマは、C 関数にいっそう Perl 風なインタフェ
     ースを用意することができるようになっているのです。


     XSUB 解剖学

     以下の XSUB では、Perl プログラムから sin() という C のライ
     ブラリ関数をアクセスできるようにしています。 この XSUB は、
     一つの引数をとり、一つの値を返す C の関数を模倣します。



Perl manpages Last change: Release 5.0 Patchlevel 00            2






PERLAPI(1)               USER COMMANDS                 PERLAPI(1)




          double
          sin(x)
            double<tab>x

     コンパイラは、引数の名前と型の間に 1 つのタブがあることを期
     待しており、型の前には空白は、あっても無くてもかまいません。
     C のポインタを使うときには、上記の rpcb_gettime() 関数で示し
     たように、間接指定演算子 * は、型の一部と考えるべきであり、
     アドレス演算子 & は、変数の一部と考えるべきです。 C の型に
     関する修飾子と単項演算子の扱いについては、typemap の節も参照
     してください。

     関数の引数リストでは、開き括弧の後や、閉じ括弧の前に空白を入
     れてはなりません。

        誤った表記                     正しい表記

        double                         double
        sin( x )                       sin(x)
          double  x                      double  x

     関数名と関数型は、行を改めて書かなくてはなりません。

        誤った表記                     正しい表記

       double sin(x)                    double
         double  x                      sin(x)
                                          double  x



     引数スタック

     引数スタックは、XSUB への引数として渡される値や XSUB からの
     返却値を蓄えるために使用します。 実際には、すべての Perl の
     関数が、スタック上の自分の範囲を決めて、同時にこのスタックに
     値を蓄えています。 このドキュメントでは、アクティブな関数に
     属するスタック上の最初の範囲を、その関数に対して位置 0 とい
     うようにして参照するようにします。

     x をスタック上のその XSUB の部分の位置を示すものとするとき、
     XSUB は、自分のスタック引数を ST(x) というマクロで参照できま
     す。 その関数の位置 0 は、XSUB には、ST(0) という形で伝えら
     れることになります。 XSUB への引数と XSUB からの返却値は、
     いつも ST(0) の位置から置かれることになっています。 多くの
     簡単なケースでは、xsubpp コンパイラは、typemap に入れる埋め
     込みプログラムで、引数スタックを扱うために必要なコードを生成
     します。 より複雑なケースでは、プログラマがそのコードを用意
     しなくてはなりません。





Perl manpages Last change: Release 5.0 Patchlevel 00            3






PERLAPI(1)               USER COMMANDS                 PERLAPI(1)



     RETVAL 変数

     RETVAL 変数は、常に C のライブラリ関数の関数型にマッチするマ
     ジック変数です。 xsubpp コンパイラは、XSUB ごとに、この変数
     を用意し、デフォルトでは、呼び出される C のライブラリ関数の
     返却値を保持するためにこの変数を使用します。 簡単なケースで
     は、RETVAL の値は、Perl が XSUB の返却値として受け取れるよう
     に、引数スタックの ST(0) に置かれます。

     XSUB の関数型を void とした場合には、この関数に対して、コン
     パイラは RETVAL 変数を用意しません。 PPCODE: ディレクティブ
     を使うときには、RETVAL 変数は必要ありません。


     MODULE キーワード

     MODULE キーワードは、XS コードを開始し、定義される関数のパッ
     ケージを示すために使われます。 最初の MODULE キーワードの前
     のテキストはすべて、C のコードとみなされ、透過的に出力に渡さ
     れます。 すべての XS モジュールには、XSUB をフックして、
     Perl に渡すために使われる bootstrap 関数を用意します。 この
     bootstrap 関数のパッケージ名は、XS ソースファイル中で最後の
     MODULE 文の値にマッチします。 MODULE の値は、一つの XS ファ
     イルの中では一定にしておくべきですが、そうしておかなければな
     らないと決められているものではありません。

     以下の例は、XS コードを開始し、すべての関数を RPC というパッ
     ケージに置くようにするものです。

          MODULE = RPC



     PACKAGE キーワード

     XS ソースファイル内で関数を、複数のパッケージに分けなければ
     ならないとき、PACKAGE キーワードが使われます。 このキーワー
     ドが使われるときには、MODULE キーワードとともに用い、その直
     後に置かなければなりません。

          MODULE = RPC  PACKAGE = RPC

          [ パッケージ RPC の XS コード ]

          MODULE = RPC  PACKAGE = RPCB

          [ パッケージ RPCB の XS コード ]

          MODULE = RPC  PACKAGE = RPC

          [ パッケージ RPC の XS コード ]




Perl manpages Last change: Release 5.0 Patchlevel 00            4






PERLAPI(1)               USER COMMANDS                 PERLAPI(1)



     このキーワードは省略可能であり、冗長な情報となることもありま
     すが、いつも使用するようにした方が良いでしょう。 このキーワ
     ードを使うことによって、XSUB が目的のパッケージに入れられる
     ことを保証するのです。


     PREFIX キーワード

     PREFIX キーワードは、Perl の関数名から取り除くプリフィクスを
     指定するものです。 C の関数がrcpb_gettime() で、PRIFIX の値
     が rcpb_ であれば、この関数は、Perl からは gettime() という
     ように見えます。

     このキーワードが使われるときには、PACKAGE キーワードのあとに
     置きます。 PACKAGE が使われなければ、MODULE キーワードのあ
     とに置きます。

          MODULE = RPC  PREFIX = rpc_

          MODULE = RPC  PACKAGE = RPCB  PREFIX = rpcb_



     OUTPUT: キーワード

     OUTPUT: キーワードは、XSUB の終了時に、(新しい値が Perl から
     見えるように) 特定の関数引数を更新しなければならないか、特定
     の値を呼び出しもとの Perl 関数に返さなければならないことを示
     します。 上記の sin() 関数のような簡単な関数では、RETVAL 変
     数が、自動的に出力値として使われます。 より複雑な関数では、
     xsubpp コンパイラがどの変数が出力変数であるかを判断するため
     に助けが必要となります。

     このキーワードは、通常 CODE: キーワードを補足するために使い
     ます。 CODE: キーワードが存在するとき、RETVAL 変数が、出力
     変数として認識されることはなくなります。 OUTPUT: キーワード
     を使用すると、コンパイラに RETVAL を実際に出力変数として使う
     ことを指示することになります。

     OUTPUT: キーワードは、関数の引数が出力変数であることを示すた
     めにも使われます。 これは、その引数が関数内で変更されている
     ときに、更新結果を Perl から見えるようにするために必要となる
     ことがあります。 関数引数を RETVAL 変数といっしょに OUTPUT:
     の下に並べる場合には、RETVAL 変数は最後に置かないといけませ
     ん。

          bool_t
          rpcb_gettime(host,timep)
               char *  host
               time_t  &timep
               OUTPUT:
               timep



Perl manpages Last change: Release 5.0 Patchlevel 00            5






PERLAPI(1)               USER COMMANDS                 PERLAPI(1)



     OUTPUT: キーワードはまた、出力引数を typemap ではなく、マッ
     チするコードに対応させるためにも使います。

          bool_t
          rpcb_gettime(host,timep)
               char *  host
               time_t  &timep
               OUTPUT:
               timep<tab>sv_setnv(ST(1), (double)timep);



     CODE: キーワード

     このキーワードは、C の関数に対して特別な扱いを要求する、比較
     的複雑な XSUB で使われます。 RETVAL 変数も使えますが、
     OUTPUT: キーワードの下に指定して、実際に値を返すことを示さな
     ければなりません。

     次の XSUB は、引数に特別な扱いが要求される C 関数のためのも
     のです。 Perl 側の用法をまず示します。

          $status = rpcb_gettime( "localhost", $timep );

     XSUB は以下の通りです。

         bool_t rpcb_gettime(host,timep)
               char *  host
               time_t  timep
               CODE:
                    RETVAL = rpcb_gettime( host, &timep );
               OUTPUT:
               timep
               RETVAL

     ここに示す多くの例で、CODE: ブロック (と他のブロック) が、中
     括弧 ({ と }) で囲まれます。 これによって、CODE: ブロックを
     複雑な INPUT typemap から保護し、結果の C のコードが正しいも
     のとなることを保証してくれます。


     NO_INIT キーワード

     NO_INIT キーワードは、ある関数引数が、出力値としてだけ使われ
     ることを示すために用います。 xsubpp コンパイラは、通常、引
     数スタックからすべての関数引数の値を読み取り、その関数のエン
     トリ上の C 変数へ、代入を行なうコードを生成します。 NO_INIT
     が指定されるとコンパイラは、ある引数が入力ではなく、出力に使
     われ、関数が終了する前に処理されることを認識します。

     次の例では、rpcb_gettime() 関数のバリエーションを示します。
     この関数では、変数 timep を出力のみの変数として使用していて、



Perl manpages Last change: Release 5.0 Patchlevel 00            6






PERLAPI(1)               USER COMMANDS                 PERLAPI(1)



     初期状態の値には関与しません。

          bool_t
          rpcb_gettime(host,timep)
               char *  host
               time_t  &timep = NO_INIT
               OUTPUT:
               timep



     関数引数の初期化

     関数の引数は、通常、引数スタックからの値で初期化されます。
     typemap には、Perl の値を C の引数に変換するために使われる、
     コードを入れています。 しかし、プログラマの方で、typemap を
     オーバライドして、別の初期化コードを与えることができます。

     次のコードでは、関数引数の初期化コードの与え方を示します。
     初期化コードは、出力に加えられる前に、コンパイラによって評価
     されるので、ダブルクォートのようなものを文字どおりに解釈させ
     たいときには、バックスラッシュで保護しなければなりません。

          bool_t
          rpcb_gettime(host,timep)
               char *  host = (char *)SvPV(ST(0),na);
               time_t  &timep = 0;
               OUTPUT:
               timep

     これは、引数のデフォルト値を指定するために、使うべきものでは
     ありません。 これは通常、関数引数を使用する前に、別のライブ
     ラリ関数で処理しなければならないときに使います。 デフォルト
     引数については、次の節で扱います。


     デフォルト引数値

     関数の引数に対するデフォルト値は、引数リスト内に代入文を置く
     ことで、指定することができます。 デフォルト値としては、数値
     か文字列を指定することができます。 デフォルトは、引数リスト
     の右側の引数から順にしか指定できません。

     rpcb_gettime() に対する XSUB にデフォルトの host 値を持てる
     ようにするには、XSUB への引数を並べ替えるとよいでしょう。
     その XSUB が、本当の rpcb_gettime() 関数を正しい引数順序で呼
     ぶことになります。 Perl から、この XSUB を呼ぶときには、次
     のどちらの形式でも使えることになります。

          $status = rpcb_gettime( $timep, $host );

          $status = rpcb_gettime( $timep );



Perl manpages Last change: Release 5.0 Patchlevel 00            7






PERLAPI(1)               USER COMMANDS                 PERLAPI(1)




     XSUB は次のようなものになるでしょう。 CODE: ブロックが、本
     当の rpcb_gettime() 関数を、正しい順序の引数で呼び出すために
     使われます。

          bool_t
          rpcb_gettime(timep,host="localhost")
               char *  host
               time_t  timep = NO_INIT
               CODE:
                    RETVAL = rpcb_gettime( host, &timep );
               OUTPUT:
               timep
               RETVAL



     可変長引数リスト

     引数リストに省略記号 (...) を指定することで、XSUB は可変長の
     引数リストを持てるようになります。 省略記号のこの使い方は、
     ANSI C のものと同様です。 xsubpp コンパイラが、すべての
     XSUB に用意している変数 items を調べることで、XSUB に渡され
     た引数の数を知ることができます。 この仕組みを使って、大きさ
     のわからない引数のリストを受け取る XSUB を作ることができます。

     rpcb_gettime() XSUB の host 引数は省略できますから、XSUB が
     可変個数の引数をとれることを示すために、省略記号を使うことが
     できます。 Perl は、この XSUB を次のどちらかの形式で呼び出
     すことができます。

          $status = rpcb_gettime( $timep, $host );

          $status = rpcb_gettime( $timep );

     省略記号を持つ XS コードです。

          bool_t
          rpcb_gettime(timep, ...)
               time_t  timep = NO_INIT
               CODE:
               {
               char *host = "localhost";

               if( items > 1 )
                    host = (char *)SvPV(ST(1), na);
               RETVAL = rpcb_gettime( host, &timep );
               }
               OUTPUT:
               timep
               RETVAL




Perl manpages Last change: Release 5.0 Patchlevel 00            8






PERLAPI(1)               USER COMMANDS                 PERLAPI(1)



     PPCODE: キーワード

     PPCODE: キーワードは、CODE: キーワードの別形式で、XSUB の返
     却値を扱うために、引数スタックを制御するコードを用意している
     ことを xsubpp コンパイラに伝えるものです。 単独の値よりも、
     値のリストを XSUB から返したいこともあるでしょう。 こういっ
     た場合には、PPCODE: を使って、明示的に値のリストをスタックに
     プッシュしなければなりません。 PPCODE: キーワードと CODE:
     キーワードは、同一の XSUB 内で同時に用いることはありません。

     次の XSUB では、C の rpcb_gettime() 関数を呼び、この関数から
     の二つの出力値 timep と status を、一つのリストにして Perl
     に返しています。

         void rpcb_gettime(host)
               char *  host
               PPCODE:
               {
               time_t  timep;
               bool_t  status;
               status = rpcb_gettime( host, &timep );
               EXTEND(sp, 2);
               PUSHs(sv_2mortal(newSVnv(status)));
               PUSHs(sv_2mortal(newSVnv(timep)));
               }

     実際に rpcb_gettime() を呼ぶためのコードと、返却値を正しく引
     数スタック上に置くためのコードを、用意しておかねばなりません。

     この関数の型を void とすることで、RETVAL 変数が必要ないか、
     使われないものであり、作る必要がないものであることを、xsubpp
     コンパイラに伝えることになります。 関数型 void は、ほとんど
     の場合、PPCODE: ディレクティブといっしょに使われるはずです。

     引数スタック上に二つの返却値の場所を確保するために、EXTEND()
     マクロを使っています。 PPCODE: ディレクティブの指定によって、
     xsubpp コンパイラが、sp というスタックポインタを作り、それが
     EXTEND() マクロ内で this ポインタとして使われます。 その後、
     PUSHs() マクロで値を順にスタックに積みます。

     これで、以下のようにして、Perl から rpcb_gettime() 関数を呼
     ぶことができるようになりました。

          ($status, $timep) = rpcb_gettime("localhost");



     Undef 値や空リストを返す

     関数の異常を示すために、状態変数を別に用意するよりも、単に
     undef 値や空リストを返したい場合があります。 rpcb_gettime()
     関数を、そのような場合にあてはめてみましょう。 この関数がう



Perl manpages Last change: Release 5.0 Patchlevel 00            9






PERLAPI(1)               USER COMMANDS                 PERLAPI(1)



     まくいったときには、時刻を返し、問題があったときには、undef
     値を返すようにしてみましょう。 次の Perl コードでは、$timep
     の値が undef か有効な時刻のどちらかになることになります。

          $timep = rpcb_gettime( "localhost" );

     次の XSUB では、関数型に void を用いて、RETVAL 変数を作らな
     いようにし、CODE: ブロックを使って、必要なコードはすべて用意
     していることをコンパイラに示しています。 sv_newmortal() の
     呼び出しで返却値を undef で初期化し、これをデフォルトの返却
     値としています。

          void
          rpcb_gettime(host)
               char *  host
               CODE:
               {
               time_t  timep;
               bool_t x;
               ST(0) = sv_newmortal();
               if( rpcb_gettime( host, &timep ) )
                    sv_setnv( ST(0), (double)timep);
               }

     次の例では必要となったときに、明示的に undef 値を返却値とし
     て設定する方法を示します。

          void
          rpcb_gettime(host)
               char *  host
               CODE:
               {
               time_t  timep;
               bool_t x;
               ST(0) = sv_newmortal();
               if( rpcb_gettime( host, &timep ) ){
                    sv_setnv( ST(0), (double)timep);
               }
               else{
                    ST(0) = &sv_undef;
               }
               }

     空リストを返すには、PPCODE: ブロックを使ったうえで、スタック
     上に返却値を積まないでおきます。










Perl manpages Last change: Release 5.0 Patchlevel 00           10






PERLAPI(1)               USER COMMANDS                 PERLAPI(1)



          void
          rpcb_gettime(host)
               char *  host
               PPCODE:
               {
               time_t  timep;
               if( rpcb_gettime( host, &timep ) )
                    PUSHs(sv_2mortal(newSVnv(timep)));
               else{
               /* スタックに何も積まないので、 */
               /* 暗黙のうちに空リストが返される。 */
               }
               }



     CLEANUP: キーワード

     このキーワードは、XSUB が終了する前に、特別な後処理を必要と
     する場合に使われます。 CLEANUP: キーワードを使用する場合に
     は、XSUB 内の、どの CODE: ブロック、PPCODE: ブロック、OUTPUT:
     セクションよりも後になければなりません。 CLEANUP: ブロック
     として記述されるコードは、XSUB 内の最後の実行文として、追加
     されます。


     BOOT: キーワード

     BOOT: キーワードは、拡張モジュールの bootstrap 関数にコード
     を追加するために使用します。 bootstrap 関数は、xsubpp コン
     パイラによって作られ、普通は Perl に任意の XSUB を登録するた
     めに必要な実行文が納められています。 BOOT: キーワードを使う
     と、bootstrap 関数にさらにの実行文を付け加えるように xsubpp
     コンパイラに伝えることができます。

     このキーワードは、最初の MODULE キーワード以降であれば、どこ
     でも使うことができ、行内に単独で使用します。 このキーワード
     以降、最初の空行までが、コードを記述したブロックとなります。

          BOOT:
          # bootstrap 関数の実行時に、
          # 以下のメッセージが表示されます。
          printf("Hello from the bootstrap!\n");



     コメントや C プリプロセッサディレクティブを使用する

     CODE: ブロック、PPCODE: ブロック、BOOT: セクション、CLEANUP:
     ブロック内では、コメントや C プリプロセッサディレクティブを
     記述することができます。 コンパイラは、プリプロセッサディレ
     クティブには触れずに渡し、コメント行を削除します。 行の最初



Perl manpages Last change: Release 5.0 Patchlevel 00           11






PERLAPI(1)               USER COMMANDS                 PERLAPI(1)



     に # を置くことで、XSUB にコメントを入れることができます。
     コメントが、C のプリプロセッサディレクティブに見えることの無
     いように注意し、そのように解釈されないようにすべきです。


     XS を C++ で使用する

     関数が、C++ のメソッドとして定義されているときには、その最初
     の引数はオブジェクトポインタとみなされます。 オブジェクトポ
     インタは、THIS という変数に入れられることになります。 対象
     となるオブジェクトは、C++ の new() 関数で生成され、Perl の
     sv_setptrobj() マクロで bless されたものです。 Perl による
     オブジェクトの bless は、T_PTROBJ typemap で扱うことができま
     す。

     メソッドが static で定義されているときには、その C++ の関数
     を class::method() という構文で呼び出すことになります。 メ
     ソッドが static でないならば、その関数を THIS->method() とい
     う構文で呼び出します。


     Perl 変数

     これから、XSUB でどのように Perl の変数 $host をアクセスする
     かを示します。 perl_get_sv() という関数が、内部的に SV (ス
     カラ変数) といわれている変数へのポインタを得るために使用され
     ます。 変数の名前には、パッケージ名 RPC が付け加えられます
     ので、perl_get_sv() で $host がどのパッケージにあるかがわか
     ります。 パッケージ名がないときには、perl_get_sv() では、パ
     ッケージ main で変数を探すことになります。 それから、SV の
     内容への char* ポインタを取得するため、マクロ SvPVX() を使っ
     て SV の被参照を行ないます。

          void
          rpcb_gettime()
               PPCODE:
               {
               char *host;
               SV *hostsv;
               time_t timep;

               hostsv = perl_get_sv( "RPC::host", FALSE );
               if( hostsv != NULL ){
                    host = SvPVX( hostsv );
                    if( rpcb_gettime( host, &timep ) )
                         PUSHs(sv_2mortal(newSVnv(timep)));
               }
               }







Perl manpages Last change: Release 5.0 Patchlevel 00           12






PERLAPI(1)               USER COMMANDS                 PERLAPI(1)



     この XSUB を呼ぶためには、次のような Perl コードを使います。

          $RPC::host = "localhost";
          $timep = rpcb_gettime();

     上記の例では、SV に C の char* が入っていましたが、Perl のス
     カラ変数には、数値やリファレンスも入れることができます。 SV
     に C の int が入っているときには、SV の被参照にマクロ SvIVX()
     を使い、C の double が入っているときには、SvNVX() を使います。

     SV が Perl のリファレンスのときには、SV の被参照にマクロ
     SvRV() が使えます。 結果は実際の Perl の変数を指す別の SV
     となります。 これは、SvPVX()、SvNVX()、SvIVX() で被参照する
     ことができます。 次の XSUB では、SvRV() を使っています。

         void rpcb_gettime()
               PPCODE:
               {
               char *host;
               SV *rv;
               SV *hostsv;
               time_t timep;

               rv = perl_get_sv( "RPC::host", FALSE );
               if( rv != NULL ){
                    hostsv = SvRV( rv );
                    host = SvPVX( hostsv );
                    if( rpcb_gettime( host, &timep ) )
                         PUSHs(sv_2mortal(newSVnv(timep)));
               }
               }

     次の Perl コードは、$MY::host へのリファレンスとなる、変数
     $RPC::host を生成します。 変数 $MY::host には、使用するホ
     スト名が入っています。

          $MY::host = "localhost";
          $RPC::host = \$MY::host;
          $timep = rpcb_gettime();

     perl_get_sv() の第 2 引数は、上の例に示したように、通常は
     FALSE にします。 この引数を TRUE とすると、変数が存在しない
     ときに、生成するようになります。 空の SV かも知れないものを
     扱うために段階を踏むのでなければ、TRUE は使用すべきではあり
     ません。

     XSUB では、Per の配列値、ハッシュ値、コード値をアクセスする
     ために、perl_get_av()、perl_get_hv()、perl_get_cv() を使うこ
     とができます。






Perl manpages Last change: Release 5.0 Patchlevel 00           13






PERLAPI(1)               USER COMMANDS                 PERLAPI(1)



     インタフェースの戦略

     Perl と C ライブラリの間のインタフェースを設計する段階では、
     ほとんどの場合、C から XS への直訳で十分です。 そのインタフ
     ェースは、多くは C 風のものとなり、特に C の関数が引数を変更
     するようなときには、直感的とはいえないものとなります。 もっ
     と Perl 風なインタフェースを作りたい場合には、インタフェース
     が、どちら寄りに傾くかを左右するような部分を特定するのに、以
     下のような戦略をとると良いでしょう。

     引数を変更する C 関数を見つけること。 こういった関数の XSUB
     は、Perl へリストを返すようにし、失敗時には undef や空リスト
     を返すようにすることができるでしょう。

     C と XSUB の関数のみで使用される値を見つけなさい。 Perl 側
     でその値の中身に触れる必要がないのであれば、その値を C から
     Perl へ変換する必要もありません。

     C の関数の引数リストと返却値から、ポインタを探しなさい。 ポ
     インタによっては、XS で変数名に単項演算子 & を付けて扱うこと
     ができますし、型名に * 演算子を使わなければならないものもあ
     ります。 一般に、& 演算子で処理する方が簡単です。

     C の関数で使われる構造体を特定しなさい。 多くの場合、そのよ
     うな構造体が bless されたオブジェクトとして Perl から扱える
     ように、T_PTROBJ typemap をこの構造体に使うとよいでしょう。


     Perl モジュール

     Perl モジュールは、XS コードから作られた拡張ライブラリと、
     Perl インタプリタとの間をつなぐ役割を果たします。 このモジ
     ュールを使って、Perl に拡張ライブラリの内容を知らせるのです。
     モジュールの名前とパッケージは、ライブラリの名前に合わせた方
     がよいでしょう。

     以下は、あるONC+ RPC 結合ライブラリ関数を拡張する Perl モジ
     ュールです。

          package RPC;

          require Exporter;
          require DynaLoader;
          @ISA = qw(Exporter DynaLoader);
          @EXPORT = qw( rpcb_gettime rpcb_getmaps rpcb_getaddr
                          rpcb_rmtcall rpcb_set rpcb_unset );

          bootstrap RPC;
          1;

     @EXPORT リスト内にある関数が、RPC 拡張に含まれています。
     RPC モジュールは、Exporter モジュールを使って、これらの関数



Perl manpages Last change: Release 5.0 Patchlevel 00           14






PERLAPI(1)               USER COMMANDS                 PERLAPI(1)



     名がモジュール外の Perl プログラムからも見えるようにしていま
     す。 DynaLoader モジュールによって、RPC モジュールは、拡張
     ライブラリをブートストラップできるようにします。 この拡張機
     能を実際にロードし、関数を使えるようにするために、

          use RPC;

     という Perl の実行文を使います。 DynaLoader についてより詳
     しくは、Perl のソースディレクトリの ext/DynaLoader にあるド
     キュメントを見てください。


     Perl のオブジェクトと C の構造体

     C の構造体を扱うときには、XS の型に T_PTROBJ か T_PRTREF を
     選択する必要があります。 どちらの型も複雑なオブジェクトへの
     ポインタを扱うように設計されています。 T_PTRREF 型では、
     Perl のオブジェクトが bless されていなくてもよいが、T_PTROBJ
     型では、オブジェクトが bless されていなければなりません。
     T_PTROBJ を使うことで、XSUB は Perl オブジェクトが期待する型
     であることを確認するようになりますから、型チェックを行なうこ
     とができます。

     次の XS コードでは、getnetconfigent() 関数を ONC TIRPC とい
     っしょに使っています。 getnetconfigent() 関数は、C の構造体
     へのポインタを返すもので、以下のプロトタイプで示されるもので
     す。 この例では、C のポインタを Perl のリファレンスにする方
     法を示すことにします。 Perl は、このリファレンスを bless さ
     れたオブジェクトへのポインタとみなして、このオブジェクトに対
     してデストラクタを起動しようとします。 デストラクタは、
     getnetconfigent() が使ったメモリを解放するために、XS ソース
     内で記述しす。 XS でのデストラクタは、DESTROY で終わる名前
     を持つ XSUB 関数を記述することで作ることができます。 XS デ
     ストラクタは、別の XSUB が malloc したメモリを、free するた
     めに使うことができます。

          struct netconfig *getnetconfigent(const char *netid);

     struct netconfig のために typedef を行なっています。 Perl
     のオブジェクトは、C での型の名前に Ptr というタグを付けたも
     のにマッチする名前のクラスで bless され、その名前は、Perl の
     パッケージ名として使われるときには、空白を入れません。 デス
     トラクタは、そのオブジェクトの属するクラスに対応するクラスに
     置かれ、Perl 側では DESTROY という名前で参照されますので、
     PREFIX キーワードを使用して関数名の先頭部分をみないようにし
     ます。









Perl manpages Last change: Release 5.0 Patchlevel 00           15






PERLAPI(1)               USER COMMANDS                 PERLAPI(1)



          typedef struct netconfig Netconfig;

          MODULE = RPC  PACKAGE = RPC

          Netconfig *
          getnetconfigent(netid)
               char *  netid

          MODULE = RPC  PACKAGE = NetconfigPtr  PREFIX = rpcb_

          void
          rpcb_DESTROY(netconf)
               Netconfig *  netconf
               CODE:
               printf("Now in NetconfigPtr::DESTROY\n");
               free( netconf );

     この例には、次のような typemap のエントリが必要になります。
     拡張に際して、新しい typemap を設けるときには、typemap の節
     の情報も参考にしてください。

          TYPEMAP
          Netconfig *  T_PTROBJ

     今回の例は、

          use RPC;
          $netconf = getnetconfigent("udp");

     という Perl の文で使用されます。

     Perl は $netconf で参照されるオブジェクトを消去するとき、そ
     のオブジェクトを用意された XSUB DESTROY 関数に送ります。
     Perl では、このオブジェクトが C の構造体であって、Perl のオ
     ブジェクトではないと知るすべがありませんし、関与もしません。
     この意味で、getnetconfigent() XSUB で作られたオブジェクトと、
     普通の Perl のサブルーティンで作られたオブジェクトの区別はあ
     りません。


     C のヘッダファイルと Perl

     h2xs コンパイラは、/usr/include の C のヘッダファイルを Perl
     の拡張モジュールに変換するために設計されています。 このコン
     パイラは、Perl ソースの ext ディレクトリの下に、ディレクトリ
     を作り、ここに Mekefile、Perl モジュール、XS ソースファイル、
     MANIFEST ファイルを入れます。

     次のコマンドは、<rpcsvc/rusers.h> ヘッダから、Rusers という
     拡張モジュールを作ります。

          h2xs rpcsvc/rusers



Perl manpages Last change: Release 5.0 Patchlevel 00           16






PERLAPI(1)               USER COMMANDS                 PERLAPI(1)




     Rusers 拡張モジュールがコンパイルされ、インストールされると、
     C のヘッダにあった #define 文を Perl から参照するために、こ
     のモジュールを使うことができます。

          use Rusers;
          print "RPC program number for rusers service: ";
          print &RUSERSPROG, "\n";


     新しい拡張モジュールの作成

     h2xs コンパイラは、テンプレートのソースファイルと Mekefile
     を生成できます。 多くの拡張モジュールで、このテンプレートを
     叩き台として使うことができます。 以下の例では、このドキュメ
     ントの RPC 関数を含む拡張モジュールを生成するために、どのよ
     うに h2xs を使うのかを示します。

     この拡張モジュールでは、自動ロード関数を使用しておらず、定数
     の定義もしていませんから、-A オプションを h2xs に付けていま
     す。 Perl のソースディレクトリで実行すると、h2xs コンパイラ
     は、ext/RPC ディレクトリを作成し、RPC.xs、RPC.pm、Makefile.PL、
     MANIFEST というファイルをそこに置きます。 RPC 関数の XS コ
     ードは、RPC.xs ファイルに付け加えます。 RPC.pm の @EXPORT
     リストは、RPC.xs から、その関数をインクルードするように更新
     しておきます。

          h2xs -An RPC

     動的ローディングを行なう拡張モジュールのコンパイルには、

          make dynamic

     というコマンドを ext/RPC ディレクトリで実行します。 拡張モ
     ジュールを Perl のバイナリに静的にリンクする場合には、Perl
     のソースディレクトリの makefile (Makefile ではなく、makefile
     を使います) を編集して、ext/RPC/RPC.a を static_ext 変数に追
     加します。 この変更を行なう前に、Perl を作ってないといけま
     せん。 makefile を更新したあとで、

          make

     というコマンドを、Perl のソースディレクトリで実行します。

     拡張モジュールを追加するために、Perl の Configure スクリプト
     を使うこともできます。 この場合、Perl を作成する前に、
     Configure の実行に先立って、拡張モジュールを Perl のソースデ
     ィレクトリの ext ディレクトリに置いておく必要があります。
     Configure を実行するときに、他の拡張モジュール共々、この拡張
     モジュールが ext ディレクトリで発見されると、作成される拡張
     モジュールのリストに加えられます。 make が実行されると、こ
     の拡張モジュールも、他の拡張モジュールといっしょに、組み込ま



Perl manpages Last change: Release 5.0 Patchlevel 00           17






PERLAPI(1)               USER COMMANDS                 PERLAPI(1)



     れることになります。

     Configure は、拡張モジュールが、そのディレクトリ名と一致する
     XS ソースファイルを用意しているときに、その存在を認識します。
     Configure は、Perl ソースディレクトリの MANIFEST にあげられ
     ている、すべての .SH ファイルを抽出した後で、拡張モジュール
     のディレクトリにも MANIFEST ファイルがあると、そのファイルで
     も .SH ファイルを探して抽出します。 その後、Perl のソースデ
     ィレクトリの Makefile が、拡張モジュールのディレクトリ名に一
     致する XS ファイルを見つけると、そのディレクトリで make を実
     行します。


     typemap

     typemap は、xsubpp コンパイラが、C の関数の引数や値を Perl
     の値にマッピングするために使用する、コードを集めたものです。
     typemap ファイルは、TYPEMAP、INPUT、OUTPUT というラベルを付
     けた、3 つのセクションに分けることができます。 INPUT セクシ
     ョンは、Perl の値を、特定の型の C の変数に変換する方法を、コ
     ンパイラに伝えるものです。 OUTPUT セクションは、特定の型の
     C の値から、Perl が認識できる値に変換する方法をコンパイラに
     伝えます。 TYPEMAP セクションでは、与えられた C の型を Perl
     の値にマッピングするために、どの INPUT コードと OUTPUT コー
     ドを使用するかを、コンパイラに教えます。 typemap のどのセク
     ションも、TYPEMAP、INPUT、OUTPUT のいずれかのキーワードで始
     まることになります。

     Perl のソースディレクトリの ext ディレクトリにあるデフォルト
     の typemap には、Perl の拡張モジュールで使用することができる
     便利な型をたくさん入れてあります。 拡張モジュールによっては、
     自分のディレクトリに、追加の typemap を定義して置いているも
     のもあります。 そのような追加の typemap は、デフォルトの
     typemap の INPUT と OUTPUT のマッピングを参照することができ
     ます。 xsubpp コンパイラでは、デフォルトの typemap のマッピ
     ングが、拡張モジュールの typemap でオーバライドすることが許
     されています。

     独自の typemap を必要とする拡張モジュールでは、ほとんどの場
     合、typemap ファイルの TYPEMAP セクションだけが必要になりま
     す。 getnetconfigent() の例で示した独自 typemap は、拡張モ
     ジュールの typemap の使用例としては、典型的なものかもしれま
     せん。 この typemap は、C の構造体と T_PTROBJ typemap を等
     しいものとして扱うために使われてます。 getnetconfigent() で
     使った typemap を再掲します。 C の型は、XS の型とタブで区切
     られ、C の単項演算子 * は、C の型名の一部とみなされます。

          TYPEMAP
          Netconfig *<tab>T_PTROBJ






Perl manpages Last change: Release 5.0 Patchlevel 00           18






PERLAPI(1)               USER COMMANDS                 PERLAPI(1)



EXAMPLES
     ファイル RPC.xs: いくつかの ONC+ RPC 結合ライブラリ関数への
     インタフェース

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

          #include <rpc/rpc.h>

          typedef struct netconfig Netconfig;

          MODULE = RPC  PACKAGE = RPC

          void
          rpcb_gettime(host="localhost")
               char *  host
               CODE:
               {
               time_t  timep;
               ST(0) = sv_newmortal();
               if( rpcb_gettime( host, &timep ) )
                    sv_setnv( ST(0), (double)timep );
               }

          Netconfig *
          getnetconfigent(netid="udp")
               char *  netid

          MODULE = RPC  PACKAGE = NetconfigPtr  PREFIX = rpcb_

          void
          rpcb_DESTROY(netconf)
               Netconfig *  netconf
               CODE:
               printf("NetconfigPtr::DESTROY\n");
               free( netconf );

     ファイル typemap: RPC.xs のための独自 typemap。

          TYPEMAP
          Netconfig *  T_PTROBJ













Perl manpages Last change: Release 5.0 Patchlevel 00           19






PERLAPI(1)               USER COMMANDS                 PERLAPI(1)



     ファイル RPC.pm: RPC 拡張のための Perl モジュール。

          package RPC;

          require Exporter;
          require DynaLoader;
          @ISA = qw(Exporter DynaLoader);
          @EXPORT = qw(rpcb_gettime getnetconfigent);

          bootstrap RPC;
          1;

     ファイル rpctest.pl: RPC 拡張のための Perl テストプログラム。

          use RPC;

          $netconf = getnetconfigent();
          $a = rpcb_gettime();
          print "time = $a\n";
          print "netconf = $netconf\n";

          $netconf = getnetconfigent("tcp");
          $a = rpcb_gettime("poplar");
          print "time = $a\n";
          print "netconf = $netconf\n";


AUTHOR
     Dean Roehrich <roehrich@cray.com> September 27, 1994


























Perl manpages Last change: Release 5.0 Patchlevel 00           20