PerlからC言語の関数を呼び出す
Perlで書いたCGIからc言語で書かれたライブラリの関数を呼び出してみた。
必要になる知識も多いので忘れないようにメモ
Perlからライブラリを呼び出すには?
環境など
使用する環境はLinux(debian)
ここでいうライブラリとは、
/usr/lib/や/usr/local/libなどの下に置かれてシステムから使用できるファイルで拡張子が".so“(※)のもの。
(※)
動的リンクで使われるライブラリが".so“、
静的リンクで使われるライブラリが".a“らしいが、
実際は同一のファイルの場合が多いみたい
やること
Perlからライブラリを呼び出す(以降『リンクする』と表記)手順は少々複雑だ。
なおライブラリの作成についてはここでは触れない。
ライブラリをリンクするには"XSLoader“モジュールを使う。
XSLoaderの概要によるとこのモジュールを読み込むためのモジュールを別途作り、
プログラムからは作ったモジュールを呼び出すのが吉みたい。
(たぶんプログラムから"require XSLoader;"しても行けそうだけど、ここは無難に従う)
################
# プログラム #
################
↓ "use MyLoader;"
################
# MyLoader.pm #
################
↓ "require XSLoader;"
################
# XSLoader.pm # ライブラリへのリンクを行う
################
というわけで、XSLoaderを呼び出すモジュールを作る必要がある。
h2xsコマンドを使うとモジュールを作成するための雛形が作れる。
なおh2xsはperlに同梱されているので、perlが動く環境なら使えるはず。
h2xs -A -n [作成するモジュール名]
これで指定したモジュール名のディレクトリが作成され、その中にモジュールを作成するための一式が用意される。
$ h2xs -A -n hoge
$ cd hoge
$ ls -l
-rw-r--r-- 1 *** *** 143 3月 1 07:08 Changes
-rw-r--r-- 1 *** *** 74 3月 1 07:08 MANIFEST
-rw-r--r-- 1 *** *** 803 3月 1 07:08 Makefile.PL
-rw-r--r-- 1 *** *** 1156 3月 1 07:08 README
-rw-r--r-- 1 *** *** 112 3月 1 07:08 hoge.xs
drwxr-xr-x 2 *** *** 4096 3月 1 07:08 lib
-rw-r--r-- 1 *** *** 174854 3月 1 07:08 ppport.h
drwxr-xr-x 2 *** *** 4096 3月 1 07:08 t
作成された一式の中で編集するのは***.xsと
プログラムから呼び出すためのモジュール(lib/****.pm)、
そしてビルドの設定をするMakefile.PLだ。
なお、作成したモジュールをインストールするには以下のようにする。念のため
$ perl Makefile.PL # Makefileの作成
$ make # 一式のビルド
***(ビルド中〜〜
***(ビルド中〜〜
$ sudo make install # インストール
モジュール作成
XS (Perl extension)
h2xsで用意されたxsファイルを編集する。
xsファイルはファイルの前半は普通にc言語で記述でき、
"MODUE = ****** PACKAGE = *******"
の行以降が独自のマークアップ書式となっているようだ。
また、XS言語ならではの変数や関数も用意されている。
その辺りはここのサイトが参考になった。
なおxsファイルではリンクされたライブラリの関数呼び出しと、
Perlとc言語間の引数・戻り値の型変換を行っている。
makeする際にxsファイルは同名のc言語ファイルにコンバートされて、
そして最終的にはライブラリとして"blib/arch/auto/***/***.so"が生成される。
以下はライブラリ"libhoge"の"print_hoge"関数を呼び出すサンプル。
Makefile.PL
WriteMakefileの中を適宜編集する。リンクするライブラリはLIBSとMYEXTLIBで指定。
use 5.014002; use ExtUtils::MakeMaker; WriteMakefile( NAME => 'hoge', VERSION_FROM => 'lib/hoge.pm', PREREQ_PM => {}, ($] >= 5.005 ? (ABSTRACT_FROM => 'lib/hoge.pm', AUTHOR => 'gm2bv') : ()), LIBS => ['-lhoge'], MYEXTLIB => '〜パス〜/libhoge', DEFINE => '', # e.g., '-DHAVE_SOMETHING' INC => '-I.', # e.g., '-I. -I/usr/include/other' );
hoge.xs
#include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "ppport.h" void print_hoge(); //関数宣言は必要。ヘッダをincludeでも良い MODULE = hoge PACKAGE = hoge void _print_hoge() CODE: print_hoge();
lib/hoge.pm
h2xsが自動生成した雛形を使用する。
このサンプルで編集したのは、@EXPORT配列の初期化部分とprint_hogeサブルーチンの箇所のみ
package hoge; use 5.014002; use strict; use warnings; require Exporter; our @ISA = qw(Exporter); our %EXPORT_TAGS = ( 'all' => [ qw( ) ] ); our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); our @EXPORT = qw( print_hoge # サブルーチンを外部で呼び出せるようにする ); our $VERSION = '0.01'; require XSLoader; XSLoader::load('hoge', $VERSION); # サブルーチンを定義 sub print_hoge { return _print_hoge(); } 1;
gdbによるデバッグ
Makefile.PLのWriteMakefileでデバッグオプションを設定する。
WriteMakefile( ****** OPTIMIZE => '-g -O2' ****** );
作ったモジュールを呼び出すテストスクリプトを書いて、gdbを起動する際にオプション"–args perl test.pl"を指定する。
おそらく環境や設定によると思うけど、gdb起動後に一度"run"して実行してからでないとブレークポイントが貼れなかったりした。
ここではデバッグさえこなせればいいので、よしなに。