12
Help us understand the problem. What are the problem?

More than 5 years have passed since last update.

最近はMinillaでXSモジュールの雛形をつくることができます。

minil new -p XS Acme::MyModuele

すると、こんな感じのPerlコードと、

package Acme::MyModuele;
use 5.008001;
use strict;
use warnings;

our $VERSION = "0.01";

use XSLoader;
XSLoader::load(__PACKAGE__, $VERSION);

1;

こんな感じのXSコードが生成されます。

#ifdef __cplusplus
extern "C" {
#endif

#define PERL_NO_GET_CONTEXT /* we want efficiency */
#include <EXTERN.h>
#include <perl.h>
#include <XSUB.h>

#ifdef __cplusplus
} /* extern "C" */
#endif

#define NEED_newSVpvn_flags
#include "ppport.h"

MODULE = Acme::MyModuele    PACKAGE = Acme::MyModuele

PROTOTYPES: DISABLE

void
hello()
CODE:
{
    ST(0) = newSVpvs_flags("Hello, world!", SVs_TEMP);
}

XSはCをベースに独自のマクロを持った言語です。
上のコードでいうところの、 MODULEPACKAGECODE: などがそれに当たります。
詳しくは、 perlxs のドキュメントを読むといいでしょう。

XSの世界で定義したC関数(のように見えるモノ)はXSUBという特殊なC関数に変換され、Perlの世界から呼び出せるようになります。(普通のC関数ではなくなるため、hello() という名前でもなくなります。)
上のコードで言うならば、 void hello() はXSUBですが MODULEPACKAGE より前の行に定義したC関数は普通のC関数になります。

なお、XSの関数はXSUBという特殊なC関数になるわけですが、中のコードは普通のCコードです。PerlのC APIを呼び出すことでPerlのデータ構造に対する操作を行う事ができます。
PerlのC APIは EXTERN.hperl.h などで定義されているのでそれがつかえます。
PerlのAPIについてはperlapiperlgutsを見るといいです。

また、Perlも歴史を経て新しいバージョンと古いバージョンでC APIのインターフェースが変わっている事があります。
それを吸収してくれるマクロが ppport.h です。
Devel::PPPortとしてCPANに上がっています。
Minillaを使うと基本的に自動生成してくれるようになっています。
また、XSUtilを使ってこういう具合に指定しておくと各ビルド環境で生成するようにもできます。

Perlのデータ構造も普通のC構造体として定義されているので、普通のCコードから操作することができます。
そのため、Perlに対してAPIを提供する部分はXSUBで、単体として独立可能なコードは普通のCで書くのが個人的には良い書き方だと思います。

まとめ

XSこわくない!
CによるPerl拡張入門(α)がとても良いので読みましょう。

明日は @songmu さんです!

Register as a new user and use Qiita more conveniently

  1. You can follow users and tags
  2. you can stock useful information
  3. You can make editorial suggestions for articles
What you can do with signing up
12
Help us understand the problem. What are the problem?