今回から実際に拡張モジュールを作っていきます。まずは定番の
はじめてのspecファイル
CodeGen_
<?xml version="1.0" encoding="UTF-8"?>
<extension name="helloworld" version="1.0.0">
<summary>Hello, Extension World!</summary>
<description><?data
This is my first PHP extension module.
?></description>
<maintainers>
<maintainer>
<user>rsk</user>
<name>Ryusuke Sekiyama</name>
<email>[email protected]</email>
<role>lead</role>
</maintainer>
</maintainers>
<license>PHP</license>
<channel>__uri</channel>
<release>
<version>1.0.0</version>
<date>2008-01-21</date>
<state>stable</state>
<notes><?data
- Initial release.
?></notes>
</release>
<function name="helloworld" role="public">
<proto>void helloworld()</proto>
<summary>Hello, World!</summary>
<description><?data
Outputs "Hello, World!" and linebreak.
?></description>
<code><?data
php_printf("Hello, World!%s", PHP_EOL);
?></code>
<test>
<code><?data
helloworld();
?></code>
<result mode="plain"><?data
Hello, World!
?></result>
</test>
</function>
</extension>
このようにspecファイルではXML宣言の後にルート要素として<extension>タグを配置し、
モジュール情報
モジュールの説明は<extension>タグ直下の<summary>タグに概要を、 加えて<maintainers>タグにモジュールのメンテナ、 関数の定義は<function>タグで記述します。リスト1では1つだけしかありませんが、 関数名は<function>タグのname属性で指定します。これは必須の属性です。role属性は省略可能で、 ここで、 リスト2にあるように、 関数の実装は<code>タグに記述します。今回はprintf(3)のZend API版であるphp_ 今回はspecファイルに関数の実装を書きましたが、 <test>タグではmake testで実行されるテストケースを記述します。<code>タグの内容が実行されるPHPコード、 ところでリスト1には内容が <?data ?> という処理命令で囲まれているタグがあります。これは内容をCDATA関数定義
<function name="helloworld" role="public">
<proto>void helloworld()</proto>
<summary>Hello, World!</summary>
<description><?data
Outputs "Hello, World!" and linebreak.
?></description>
<code><?data
php_printf("Hello, World!%s", PHP_EOL);
?></code>
<test>
<code><?data
helloworld();
?></code>
<result mode="plain"><?data
Hello, World!
?></result>
</test>
</function>
XML特殊文字について
ソースコードを生成する
specファイルの用意ができたら、
$ pecl-gen helloworld.xml Creating 'helloworld' extension in './helloworld' Your extension has been created in directory ./helloworld. See ./helloworld/README and/or ./helloworld/INSTALL for further instructions.
さらに続けてlsコマンドで生成されたファイルを確認してみると、
$ ls helloworld CREDITS config.m4 helloworld.dsp package.xml tests LICENSE config.w32 helloworld.xml package2.xml README helloworld.c manual php_helloworld.h

マニュアルやpackage.
ビルド、テスト、インストール
さてpecl-genの次はモジュールをビルドします。ここから先の作業は最初にphpizeコマンドでconfig.
標準以外のパスにインストールされているPHPに対して拡張モジュールをビルドしたい場合は、
$ cd helloworld $ phpize Configuring for: PHP Api Version: 20041225 Zend Module Api No: 20060613 Zend Extension Api No: 220060519 $ ./configure --enable-helloworld (省略) $ make (省略) Build complete. Don't forget to run 'make test'.
無事ビルドできたら、
このときphp.
$ make test (省略) ===================================================================== Running selected tests. PASS helloworld() function [tests/helloworld.phpt] ===================================================================== Number of tests : 1 1 Tests skipped : 0 ( 0.0%) -------- Tests warned : 0 ( 0.0%) ( 0.0%) Tests failed : 0 ( 0.0%) ( 0.0%) Tests passed : 1 (100.0%) (100.0%) --------------------------------------------------------------------- Time taken : 0 seconds =====================================================================
テストが成功したら、
$ sudo make install Installing shared extensions: /usr/local/lib/php/extensions/no-debug-non-zts-20060613/
Hello, World!
インストールできたら、
今回はphp.
$ php -d extension=helloworld.so -r 'helloworld();' Hello, World!
make testで確認済みとはいえ、
おわりに
これで基本的なspecファイルの書き方と、
実は<extension>タグの子要素はすべて省略しても構わないのですが、
本連載で紹介するspecファイルもできる限り詳しい記述をするように務めますが、
次回はOpenCVライブラリを使ってWEBカメラの画像をキャプチャする拡張モジュールを制作し、
サンプルファイルのダウンロード
次のページは今回使ったCodeGen_
付録A 今回使用したCodeGen_PECLタグ
以下に今回使ったCodeGen_
属性名 | 省略可 | 説明 |
---|---|---|
name | × | モジュール名。 |
version | △ | バージョン番号。省略すると警告が出るが、 |
タグ名 | 省略可 | 内容または子要素となるタグの説明 |
---|---|---|
summary | ○ | モジュールの概要。 |
description | ○ | モジュールの説明。 |
maintainers | ○ | 1つ以上の<maintainer>タグで各メンテナの情報を記述する |
license | ○ | ライセンスの種類。BSD、 |
channel | ○ | PEARパッケージのチャンネル。デフォルト値は |
release | ○ | リリース情報 |
changelog | ○ | 更新履歴。過去のバージョンの<release>が子要素になる。 |
function | ○ | 関数定義 |
タグ名 | 省略可 | 説明 |
---|---|---|
user | ○ | CVSアカウントなどの短いユーザ名。デフォルト値は |
name | ○ | フルネーム。デフォルト値は |
○ | メールアドレス。デフォルト値は |
|
role | ○ | 役割。lead、 |
タグ名 | 省略可 | 説明 |
---|---|---|
version | ○ | バージョン番号。ソースコードにも反映される。デフォルト値は |
date | ○ | リリースの日付。省略するとpecl-genを実行した日時になる。 |
state | ○ | リリースの状態。stable、 |
notes | ○ | リリースノート。 |
属性名 | 省略可 | 説明 |
---|---|---|
name | × | 関数名。 |
role | ○ | public |
タグ名 | 省略可 | 内容または子要素となるタグの説明 |
---|---|---|
summary | ○ | 関数の概要。 |
description | ○ | 関数の説明。 |
proto | ○ | 関数のプロトタイプ。戻り値と引数を特定の書式にしたがって記述する |
code | ○ | 関数の実装をC言語 |
test | ○ | テストケース |
タグ名 | 省略可 | 内容または子要素となるタグの説明 |
---|---|---|
code | × | テスト内容のPHPコード。 |
result | ○ | 期待される出力。デフォルト値は |
値 | 結果の評価方法 |
---|---|
plain | 内容が出力と等しいかを調べる。 |
format | 内容はフォーマット文字列として扱われ、 |
regex | 内容は正規表現として扱われ、 |
付録B 今回使用したZend API
Zend APIには、
定義 | 説明 |
---|---|
int php_ |
フォーマットに従って文字列を出力する フォーマットの書式と対応する引数の型はprintf(3)とほぼ同じ |
int php_ |
長さを指定してデータを出力する |
int php_ |
長さを指定してデータを出力する |
また、
定義 | 説明 |
---|---|
int PHPWRITE(const char *str, uint str_ |
長さを指定してデータを出力する。 |
PUTS(const char *str) | ヌル終端文字列を出力する。 do-whileブロックとして定義されており、 |
char PUTC(char c) | 1文字出力する。cは変数でないといけない。戻り値はc。 |
定義 | 説明 |
---|---|
int PHPWRITE_ |
長さを指定してデータを出力する。 |
PUTS_ |
ヌル終端文字列を出力する。 do-whileブロックとして定義されており、 |
char PUTC_ |
1文字出力する。cは変数でないといけない。戻り値はc。 |
付録C TSRM(Thread Safe Resource Manager)について
付録BでTSRMLS_
Windows版以外のPHPはマルチスレッド非対応でコンパイルされることが多く、