概要
休み明け一発目から古のperlを使った謎モジュールのビルドエラーの確認作業になった。cもmakefileもそれなりに読めるし余裕だろって思ってたらそんなことはなかったのでメモ
XSでハマったというよりはそもそもXSが何なのかをそんなに理解してなかったので理解用に書く
XSとは
XS は Perl と(Perl と一緒に使いたい)C のコード(または C ライブラリ)との 間の拡張インターフェースを作るのに使われるインターフェース記述 ファイルフォーマットです。
XS インターフェースはライブラリと動的または静的にリンクされて、 Perl とリンクすることのできる新しいライブラリを生成します。
XS インターフェース記述はは XS 言語で書かれており、 Perl 拡張インターフェースのコアコンポーネントです。
perldoc.jp
XSはCをベースに独自のマクロを持った言語。PerlからCコードを呼び出すぐらいにしかわかってなかったけどリファレンス読むと思ったより高機能なのが分かる
XS 言語の特徴
拡張子は(.xs)でファイルの中にはC言語のソースコードとXSUBが含まれます。XSUBはXSで言語で書かれC言語の関数にぱっと見は似ています。正直拡張を見ないとCの独自仕様かな?と思うくらいには似ているので理解するのも難しいです。
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "ppport.h"
MODULE = SomeModule PACKAGE = SomeModule
なのでXSを取得するにCとPerlあたりの知識が必須となっている。
使ってみる
minilという雛形生成ツールを使って最小コードのxsを生成してみた。
qiita.com
ぱっと見はC。SVとかその辺はそのままperlの用語に紐づく形となっている
#ifdef __cplusplus
extern "C" {
#endif
#define PERL_NO_GET_CONTEXT
#include <EXTERN.h>
#include <perl.h>
#include <XSUB.h>
#ifdef __cplusplus
}
#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);
}
SVの操作
XSからPerlのデータを操作する方法
SV の中身をダンプして出力
sv_dump(sv)
新しい SV をつくりたい。整数値から SV をつくりたい
SV* sv = newSViv(5963);
符号なし整数値から SV をつくりたい
SV* sv = newSVuv(5963);
文字列から SV をつくりたい
SV* sv = newSVpvn("hello", strlen("hello"));
SV から SV をつくりたい
SV* new_sv = newSVsv(sv);
SV の値が真か偽かがしりたい
bool b = SvTRUE(sv);
sprintf したい。
SV* sv = newSVpvf("%d", 3);
参照カウンターをインクリメントしたい
SvREFCNT_inc(sv);
参照カウンターをデクリメントしたい
SvREFCNT_dec(sv);
ppport.hのインターフェース
metacpan.org
PerlのC APIを呼び出すことでPerlのデータ構造に対する操作を行う事ができるのはなんとなく上まで書いていて理解はできました。CのAPIはPerlの歴史が経つにつれて変わっていくのが上記のCPANで公開されているモジュールから見て取れます。
モジュールを使うことである程度の変更は吸収してくれるようですが例えばperl5.10で追加された関数を使ったモジュールを5.8のperlでビルドしようとすると失敗するみたいなことは往々にして起き得ます。
仮に存在しない関数を使った場合この辺はビルド時にエラーになるので関数名がわかったら上記のcpanでchangelogを眺めてどこで追加されたのかを確認するのが良さそうです。
参考
xsubtut.github.io
tutorial.perlzemi.com