Inline-0.43 > Inline::C

名前

Inline::C - CでPerlサブルーチンを作成

説明

Inline::C は、CでPerlサブルーチンを作成することを可能にするモジュールです。バージョン0.30から、Inlineモジュールは複数のプログラミング言語をサポートし、各言語はそれぞれ独自のサポートモジュールを持ちます。このドキュメントはプログラミング言語CでInlineを使う方法について説明します。それはPerl C内部にも少しだけ入っていきます。

今すぐプログラムの例を試してみたいのであれば、Inline::C-Cookbookを試してみてください。Inline全般については、Inlineをご覧ください。

使用方法

実際にはInline::Cを直接使うことはありません。これは単にInline.pmをCで使うためのサポート・モジュールに過ぎません。そこで使い方は常に以下のようになります:

    use Inline C => ...;

あるいは

    bind Inline C => ...;

関数定義

CのためのInline文法はあなたCのコードでの特定の関数定義(あるいは記述)を解釈します。記述がInlineによって解釈されると、それがPerlの空間で利用できるようになります。つまり、Inlineはその関数をPerlサブルーチンであるかのように呼び出すために必要な"糊"の部分を生成します。もし記述が理解できなければ、Inlineはそれを単に無視するだけです。何も言いません。それはPerlの空間からは利用することはできません、それがたとえCの空間からは利用できたとしても。

InlineはANSI/プロトタイプ形式の関数定義を検索します。それは以下のような形式になります:

    戻り値のデータ型 関数名 ( データ型-名前の組み合わせの集合 ) { ... }

よく使われるデータ型は:int, long, double, char*, そして SV*です。しかし、あなたはInlineがtypemapで見つけることができるすべての型を使うことが出来ます。InlineはデフォルトでPerlと一緒に配布されるtypemapを利用します。あなたはTYPEMAPSコンフィグレーション・オプションでさらに多くのtypemapを指定することができます。

voidという戻り値のデータ型も利用することが出来ます。以下に正しい関数定義の例を示します。

    int Foo(double num, char* str) {
    void Foo(double num, char* str) {
    SV* Foo() {
    void Foo(SV*, ...) {
    long Foo(int i, int j, ...) {

以下の定義は理解されません:

    Foo(int i) {               # 戻り値の型がありません
    int Foo(float f) {         # floatの(デフォルトの)typemapはありません
    unsigned int Foo(int i) {  # 'unsigned int' は理解されません
    int Foo(num, str) double num; char* str; {
    void Foo(void) {           # void は戻り値の型としてだけ有効です

Inlineは、関数のプロトタイプではなく、関数の定義だけを検索することに注意してください。定義は関数本体の直接前にある書き方です。またInlineはヘッダのような外部ファイルも調べません。ライブラリはリンクすることができますし、Cの空間から呼び出すことが出来ます;しかしInlineに渡されたコードだけが、結びつけのために使われます。

C 構成設定オプション

Inline構成設定オプションを指定する方法の情報については、Inlineをご覧ください。このセクションでは、Cのために利用できる各構成設定オプションについて説明します。ほとんどのオプションが同じ名前のMakeMakerあるいはXSのオプションに対応します。ExtUtils::MakeMakerperlxsをご覧ください。

AUTO_INCLUDE

自動的にインクルードされる追加のステートメントを指定します。それらはデフォルトに追加されます。改行文字が自動的に追加されます。

    use C => Config => AUTO_INCLUDE => '#include "yourheader.h"';

AUTOWRAP

もし'ENABLE => AUTOWRAP'とすれば、Inline::CはあなたのCのコードの中の関数宣言(プロトタイプ宣言)を解析します。それがバインドできる各宣言について、外部ライブラリにあるかもしれない本当の関数を呼び出すダミーのラッパーを生成します。これはそうでなければ空のラッパー関数を必要とするだけの関数のためには、とても便利です。

これはh2xsから取得できる基本的な機能と同じです。これは外部ライブラリとバインドするためにはとても有効でしょう。

BOOT

XS BOOTセクションで実行されるCのコードを指定します。XSのパラメータに対応します。

CC

使用するコンパイラを指定します。

CCFLAGS

追加のコンパイラ・フラグを指定します。

FILTERS

ソースコード・フィルタのリストを指定することを可能にします。1個以上が要求されるのであれば、配列リファレンスでそれをまとめるようにしてください。フィルターはサブルーチンのリファレンスあるいは、補足のInline::Filtersモジュールによって提供されるフィルタの名前にすることができます。

あなたのソースコードはInlineによって解析される直前にフィルターに掛けられます。フィルタに掛けられる前に、MD5フィンガープリントが作成されます。ソースコード・フィルタはPODドキュメントの取り外し、#includeステートメントの事前展開など、あなたの好きなことをするために使うことが出来ます。例えば:

    use Inline C => DATA =>
               FILTERS => [Strip_POD => \&MyFilter => Preprocess ];

フィルタは指定された順番に呼び出されます。さらなる詳細はInline::Filtersをご覧ください。

INC

利用するインクルードパスを指定します。MakeMakerのパラメータに対応します。

    use C => Config => INC => '-I/inc/path';

LD

使用するリンカを指定します。

LDDLFLAGS

使用するリンカ・フラグを指定します。

注意: このフラグは単に追加するのではなく、完全に既存のフラグを上書きします。そのため、それらも使用する必要があるのであれば、それらをここで再び指定してください。 =head2 LIBS

あなたのコードにリンクされるべき外部ライブラリを指定します。MakeMakerのパラメータに対応します。

    use C => Config => LIBS => '-lyourlib';

あるいは

    use C => Config => LIBS => '-L/your/path -lyourlib';

MAKE

使用する'make'ユーティリティの名前を指定します。

MYEXTLIB

リンクされるべき、ユーザがコンパイルしたオブジェクトを指定します。MakeMakerのパラメータに対応します。

    use C => Config => MYEXTLIB => '/your/path/yourmodule.so';

OPTIMIZE

これはMakeMaker OPTIMIZE設定を制御します。この値を'-g'に設定することにより、あなたはInline拡張のためのデバッグ・サポートが有効になります。これによりgdbのようなデバッガを使ってあなたのCのコードにブレークポイントを設定することが可能になります。

PREFIX

それらがPerlに結び付けられたとき、Cの関数から外されるプレフィックス(prefix)を指定します。共有ライブラリAPIのためのラッパーを生成し、Perlでの元の名前に結びつけるために便利です。またPerlの内部関数と名前がぶつかるときにも便利です。XSのパラメータに対応します。

    use C => Config => PREFIX => 'ZLIB_';

TYPEMAPS

利用する追加のtypemapファイルを指定します。これらのデータ型はCの解析の動きを変えます。MakeMakerのパラメータに対応します。

    use C => Config => TYPEMAPS => '/your/path/typemap';

CとPerlの結びつけ

この関数はPerlの変数がCの変数に相互に、どのように対応付けられるのかについて説明します。

まず、あなたはPerlがどのようにサブルーチンに引数をやり取りしているかを知っておく必要があります。基本的に、それはスタックを使用します(Stackとしても知られています)。subが呼ばれたとき、丸括弧の中の全ての引数はスカラのリストに展開されます。そしてStackにプッシュされます。そしてサブループンはStackから、そのパラメータをポップします。subが終了するとき、それはその全ての戻り値をStackにプッシュして戻します。

Stackは、内部的にはSVで知られているスカラの配列です。実際にStackは、SVへのポインタあるいはSV*の配列です;このためStackの各要素は、本来、SV*なのです。これについてのFMTYEWTKは、perldoc perlgutsをご覧ください。

そこで変数の対応に戻ります。XSは"typemaps"として知られている物を、各SV*Cデータ型に変えたり戻したりするために使用します。これはさまざまなXSマクロ呼び出し、キャスト、そしてPerl APIを通して成し遂げられます。perldoc perlapiをご覧ください。XSは、typedefで定義されたstructのように、より凝った標準ではないデータ型のために、あなたがあなた自身のtypemapを定義することを可能にします。

Inlineは、デフォルトのPerl typemapファイルをそのデフォルトのデータ型のために使用します。このファイルは/usr/local/lib/perl5/5.6.1/ExtUtils/typemap、あるいはあなたのPerlインストール方法によって、それに似たものになります。それには40種類以上のデータ型が入っています。それらは自動的にInlineによって使われます。(何か可能かをしるために、一度はこのファイルを見ておくべきでしょう。)

Inlineは、これらのデータ型のためにあなたのコードを解析し、それらを対応付けるためのXSコードを生成します。最もよく使われるデータ型は以下のものです:

 - int
 - long
 - double
 - char*
 - void
 - SV*

デフォルトに入っていないデータ型を扱う必要があるのであれば、単に一般的なSV*データ型を関数定義で使ってください。そして、あなたのコードの中で、あなた自身が対応付けてください。代わりとして、あなた自身のtypemapファイルを生成し、TYPEMAPS構成設定オプションを使って指定することができます。

戻り値のデータ型の1つvoidはInlineには特別な意味を持っています。それはStackにあなた自身が返す値をプッシュしようとしているという意味になります。これは値のリストを返す必要があるということです。もしあなたは本当に何も返したくないのであれば(voidの昔ながらの意味)、単に何もプッシュしないでください。

もし省略や...が引数リストの末尾で使われれば、それは任意の数のSV*が続くかもしれないという意味になります。ここではあなたはStackの値をあなた自身がポップして取り出す必要があります。

下記の"例"をご覧ください。

Inline Stack マクロ

Inline Cを書くとき、(デフォルトでは)以下の行が自動的にあなたのコードの前につけられます:

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

ファイルINLINE.hは、Perl StackをCの関数から扱うために便利なマクロが定義されています。

Inline_Stack_Vars

もしあなたが他の物を使いたいのであれば、これを使う必要があります。これは他のマクロによって使われる、いくつかのローカル変数を設定します:sp, items, ax and mark。それが何であるかは重要ではありません。しかし名前の衝突の可能性を避けるために、それに触れています。

注意: このマクロは変数を宣言するので、あなたの他の変数宣言と一緒に関数の先頭に置いておく必要があります。それは実行ステートメントの前、そして他のInline_Stackマクロよりも前になければなりません。

Inline_Stack_Items

Stackに渡された引数の数を返します。

Inline_Stack_Item(i)

Stackでの特定のSV*を参照します。iは0始まりのインデックス番号です。値を取得や設定ために使うことが出来ます。

Inline_Stack_Reset

Stackに何か値をプッシュして戻す前に使ってください。これはStackの内部ポインタをStackのはじめにリセットします。

Inline_Stack_Push(sv)

Stackに戻り値をプッシュします。値のデータ型はSV*型でなければなりません。

Inline_Stack_Done

戻り値の全てをプッシュした後、このマクロを呼ばなければいけません。

Inline_Stack_Return(n)

Stackでのnの要素を返します。

Inline_Stack_Void

あなたが本当に何も返さないことを示す特殊なマクロです。以下のものと同じです:

    Inline_Stack_Return(0);

このマクロは実際に、あなたの関数からリターンすることに注意してください。

これらのマクロは、あなたのコーディングの好みに合わせて異なる3つの形式で使うことが出来ます。以下の以下のマクロはすべて同等です。

    Inline_Stack_Vars
    inline_stack_vars
    INLINE_STACK_VARS

この機能のすべてはXSマクロ呼び出しを通しても利用することができます。それではなぜ機能が重複しているのでしょうか?なぜ私がこの一連のマクロを提供するように決めたのかという理由はいくつかあります。第一にStackへアクセスするための便利な方法として。第二に一貫性があり自己説明的であり分かりにくくないコーディングのために。第三に将来の互換性のために。それは彼らのCのコードのために、多くの人がXSマクロを使いはじめたならば、Perl6ではそのインターフェースが崩れてしまうかもしれないと思われました。このセットを使うことにより、たぶん引数の取扱いでの将来の互換性を保証することが出来ます。

もちろん、あなたが他のPerl APIを使えば、あなたのコードはおそらくPerl6の下では崩れてしまうでしょう。そのためこれは100%の保証ではありません。しかし引数の取扱いは最もよく、あなたが使いそうなインターフェースですから、そうすることが賢いことのようにみえます。

Cのサブルーチンの書き方

あなたのC関数の定義は以下の4つのカテゴリのどれか1つに入ります。各カテゴリ毎に特に注意する点があります。

  1.     int Foo(int arg1, char* arg2, SV* arg3) {

    これが最も単純なケースです。戻り値のデータ型がvoidではなく、固定した数の引数リストを持っています。あまり心配する必要はありません。すべての変換は自動的に行われます。

  2.     void Foo(int arg1, char* arg2, SV* arg3) {

    このカテゴリでは、戻り値の型がvoidです。つまりあなたは何も返したくないか、リストを返したいという意味です。後者のケースでは、あなた自身でStackに値をプッシュする必要があります。これを簡単に行うためのInlineマクロがいくつかあります。コードは以下のようになります:

        int i, max; SV* my_sv[10];
        Inline_Stack_Vars;
        Inline_Stack_Reset;
        for (i = 0; i < max; i++)
          Inline_Stack_Push(my_sv[i]);
        Inline_Stack_Done;

    Stackポインタをリセットした後、このコードは一連の戻り値をプッシュします。最後に戻り値のスタックの最後をマークするためInline_Stack_Doneを使います。

    あなたが本当に何も返したくないのであれば、Inline_Stack_マクロを使わないでください。あなたがそれを使ったならば、関数の最後でInline_Stack_Voidを使って設定してください。

  3.     char* Foo(SV* arg1, ...) {

    このカテゴリでは、引数の数が決まっていません。つまりStackからあなた自身が値をポップする必要があるということです。以下のようにしてください:

        int i;
        Inline_Stack_Vars;
        for (i = 0; i < Inline_Stack_Items; i++)
          handle_sv(Inline_Stack_Item(i));

    Inline_Stack_Item(i)の戻り値のデータ型はSV*です。

  4.     void* Foo(SV* arg1, ...) {

    このカテゴリでは、戻り値の型としてvoidを持ち、引数の数が決まっていません。単に、カテゴリ3と4からのテクニックを組み合わせてください。(訳者注:これは2,3の間違いでしょう)

以下にいくつかの例を挙げます。それぞれ、あなた自信が実行して試すことができる完全なプログラムです。より多くの例についてはInline::C-Cookbookをご覧ください。

例 #1 - 挨拶(=Greetings)

この例は1つの文字列の引数(名前)を取り、挨拶を出力します。関数は文字列と数値で呼び出されます。2番目のケースでは数値は文字列へ強制的に変換されます。

#include <stdio.h>とする必要がないことに注意してください。デフォルトでインクルードされるperl.hヘッダ・ファイルは、自動的に標準的なCのヘッダファイルをあなたに代わってロードします。

    use Inline C;
    greet('Ingy');
    greet(42);
    __END__    
    __C__
    void greet(char* name) {
      printf("Hello %s!\n", name);
    }

例 #2 - さらに挨拶の言葉

これは、文字列(char*)ではなく、名前(=name)がSV*(スカラ値(=Scalar Value)へのポインタ)である点を除けば、上記の例に似ています。つまりSVを文字列に自分自身で変換する必要があるということです。これはPerl内部APIの一部であるSvPVX関数を使うことにより実現できます。さらなる情報についてはperldoc perlapiをご覧ください。

問題はSvPVXが自動的に文字列を数値に変換しないことです。そのため42に挨拶しようとすると、ちょっとビックリすることになります。このプログラムは、Perlの内部をいじったときによく発生するように、セグメント・フォルトになります。

    use Inline C;
    greet('Ingy');
    greet(42);
    __END__    
    __C__
    void greet(SV* sv_name) {
      printf("Hello %s!\n", SvPVX(sv_name));
    }

例 #3 - 問題の修正

代わりにSvPV関数を使うことにより、例#2での問題を修正することができます。この関数は、それに文字列が含まれていなければ、SVを文字列化します。SvPVはその2番目のパラメータとして、文字列の長さを返します。私たちは長さについて気にしていないので、そこにPL_naを置くだけにすることができます。それはその目的のための特別な変数です。

    use Inline C;
    greet('Ingy');
    greet(42);
    __END__
    __C__
    void greet(SV* sv_name) {
      printf("Hello %s!\n", SvPV(sv_name, PL_na));
    }

参考資料

Inlineについての一般的な情報についてはInlineをご覧ください。

CでInlineを使ったサンプル・プログラムについてはInline::C-Cookbookを、ご覧ください。

サポートされている言語とプラットホームについてはInline-Supportをご覧くださ。い。

独自のInline言語サポート・モジュールを書くための情報についてはInline-APIをご覧ください。

Inlineのメーリングリストはinline@perl.orgです。

参加するためには、inline-subscribe@perl.orgにメールしてください。

バグと欠陥

  1. Cの関数名に、たまたまPerlによって内部的に使われているものを使うと、実行時にロードエラーになります。現在のところこれを防いだり、警告する機能はありません。今はPerlの内部シンボルがファイル名'symbols.perl'で、Inlineモジュール・ディストリビューションに入っています。コードではこれらを使わないようにしてください。

作者(AUTHOR)

Brian Ingerson <INGY@cpan.org>

著作権(COPYRIGHT)

Copyright (c) 2000, 2001. Brian Ingerson. All rights reserved.

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

See http://www.perl.com/perl/misc/Artistic.html

翻訳者

川合孝典 <kwitknr@cpan.org>