Hatena::Groupcside

Cside::StudyMemo このページをアンテナに追加 RSSフィード

メインブログに書くまでもない自分用メモを垂れ流す。日々是勉強也。

カテゴリー

2011-04-14

[][]XSメモ2

概念的なことから、もう少し具体的なことへ。

// 作成
sv = newSViv( integer );
sv = newSVuv( unsigned_integer );
sv = newSVnv( floating_point );
sv = newSVpv( "文字列", size );

// Sv(I|U|N|P)VでSVを基本型に変換できる。
// SVの基本型:IV(整数)、UV(正整数)、NV(浮動小数点数)、PV(文字列)、以上4つ。

// 参照
STRLEN len;  // STRLENは型。
string           = SvIV(sv, len);

integer          = SvIV(sv);
unsigned_integer = SvUV(sv);
floating_point   = SvNV(sv);

SV等の型が持っているデータ

(S|H|S|G)Vもすべて、

  1. sv_anyというポインタ
  2. sv_flags
  3. sv_refcnt

試しに動かしてみた

前回のエントリでも書いた 二乗値を返すだけのプログラム。

以下、いろいろ変えつつ書いてみた。(全部コンパイルもテストも通った)

引数を型で受けるやつは、CODE:セクションの外でやらないとエラーになった。

int
calc_double(sv)
        SV *sv;
    PREINIT:
        int x;
    CODE:
        x = SvIV(SV);
        RETVAL = x * 2;
    OUTPUT:
        RETVAL
int
calc_double(x)
        int x;
    CODE:
        RETVAL = x * 2;
    OUTPUT:
        RETVAL
int
calc_double(int x)
    CODE:
        RETVAL = x * 2;
    OUTPUT:
        RETVAL

ttp://d.hatena.ne.jp/ksmemo/20081213/p1 (数値計算)をコピペして動かしてみたメモ:

  • まず、そのままではコンパイル通らなかった
  • インデントをちゃんと整形したら変なエラーは出なくなったけど、関数の中で関数を宣言したことを怒られた
    • 外に出したらちゃんとコンパイル通った

ttp://d.hatena.ne.jp/ksmemo/20081214/p1 (文字列操作)のメモ

  • Cの文字列操作の作法に習って、char* で受け、配列を返す。あとは特に特筆事項なし。
char
toUpper(str)
        char* str;
CODE:
    RETVAL = str;
OUTPUT:
    RETVAL
  • 戻り値返さないならこう
void
hello(name)
    char* name
CODE:
    printf("Hello %s!\n", name);

補足:C++ on XS

まだC++は自分は習得してないので、やるならもう少し先になりそうであるが。

  • ttp://d.hatena.ne.jp/ksmemo/20081217/p1
  • site:ttp://blog.livedoor.jp/kurt0027/ xs
  • などなど

2011-04-13

[][]XSメモ1(難しすぎワロタ)

モダンPerl入門 (CodeZine BOOKS)

XSとは

PerlからC APIを読み出すときに必要とされる様々な手続きを自動化するためのマクロ言語・抽象化レイヤーのこと。(たまにPerlから読み出し可能なCで書かれたコードを広義に「XSで書かれている」と言うこともあるが。)

最もシンプルな例・二乗値を返す Double.pm をXSで。

Makefile.PL

use strict;
use ExtUtils::MakeMaker;

WriteMakefile(
    NAME => 'Double',
    VERSION_FROM => 'lib/Double.pm',
);

lib/Double.pm

package Double;

use strict;
use XSLoader;

our $VERSION = '0.00001';

# .xsファイルから生成される.so(share object)ファイルを読み込むだけ
XSLoader::load __PACKAGE__, $VERSION;

## 代わりに下みたいなのでもできるっぽい?
# our %EXPORT_TAGS = ( 'all' => [ qw(
#      calc_double
# ) ] );

1;

Double.xs

#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"  // この順に読み込む

MODULE = Double    PACKAGE = Double

int                     // 関数宣言
calc_double(sv)
        SV *sv;
    PREINIT:            // 一時変数宣言
        int x;
    CODE:               // コード本体
        x = SvIV(sv);
        RETVAL = x * 2;
    OUTPUT:             // 戻り値
        RETVAL

このXSマクロをCコード + Cマクロに変更するためにxsubppというコマンドが存在する。makeで呼び出される。


関数の定義は、上のようにXSマクロでもできるが、別箇所で素のC関数として定義されているものをPerlに組み込むことも出来る。

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

int calc_double( int x ) {  // 素のCはMODULEより前に書く
    return x * 2;
}

MODULE = Double    PACKAGE = Double

int
calc_double(sv)
        SV *sv;
    CODE:
        RETVAL = calc_double( SvIV(sv) );
    OUTPUT:
        RETVAL

これはこれでシンプルだが、もっとシンプルに出来る。実体が素のC関数として別途定義されてる時はxsubppがコード部分を自動生成してくれるので、関数の名前とシグネチャを指定するだけで書ける。

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

int calc_double( int x ) {
    return x * 2;
}

MODULE = Double    PACKAGE = Double

PROTOTYPES: DISABLED

int
calc_double(x)
    int x;       // 戻り値の設定や、SvIV湯の呼び出しも、一切明示的に指定する必要がなくなる。

C関数を別の.cファイルに移動させるときは、Makefile.PLに以下のように変更を加える。

use strict;
use ExtUtils::MakeMaker;

WriteMakefile(
    NAME => 'Double',
    VERSION_FROM => 'lib/Double.pm',
    Object => '$(O_FILES)'
);

Perl基本型

  • SV:スカラ(Scalar Value)
  • AV:配列(Array Value)
  • HV:ハッシュ(Hash Value)
  • HE:ハッシュの要素(Hash Element)
  • IV:整数値(Integer Value)このサブセットとして32bit整数値のI32や16bit整数値のI16があります
  • UV:符号なし整数値。U32とU16もある
  • NV:浮動点少数値(double)
  • PV:文字列
  • RV:リファレンス

参考になりそうなサイト