Linux(CentOS)上で動作するC言語で書かれた既存のプログラムソースがあるのですが、これをPHP7のエクステンションとして読み込めるようにしました。プログラムはコマンドラインで動作しテキスト処理を行うだけの単純なものです。
参考資料
PHP7 でのエクステンションの書き方を調べた – Qiita
PHP Extensionの開発① – Qiita
1.PHP7ソースを入手

$ sudo yum install git
$ git clone git@github.com:php/php-src.git
$ cd php-src
$ git tag –list
:
php-7.1.24
:
$ php -v
PHP 7.1.24 (cli) (built: Nov 7 2018 18:45:17) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.1.0, Copyright (c) 1998-2018 Zend Technologies
$ git checkout php-7.1.24

自分の環境には git が入っていなかったので git のインストールから必要でした。
また、Permission Denied のエラーが表示されてしまったので、SSH Keyの登録を行いました。
自分の環境にインストールされているPHPのバージョンを確認したところ 7.1.24 だったので、git checkout でこのバージョンをダウンロードします。
2.エクステンションの雛形ファイルを作る

$ cd ext
$ ./ext_skel –extname=sampleext

sampleext というディレクトリが作成され、その中に必要なファイルが作られます。
まずは下記のコマンドを入力してエクステンションが作られるか確認します。

$ cd sampleext
$ vi config.m4
$ pipize
$ ./configure
$ make
$ php -d extension=./modules/sampleext.so sampleext.php
Congratulations! You have successfully modified ext/sampleext/config.m4. Module myext is now compiled into PHP.

config.m4 ファイルの下記の部分をアンコメントします。(dnl という文字を削除する)

PHP_ARG_WITH(myext, for myext support,
Make sure that the comment is aligned:
[ –with-myext Include myext support])

Conguratulations! ~~という表示が出れば成功です。
3.自分のプログラムのソースを準備する
既存プログラムはコマンドライン上で起動するものでしたが、シェアードライブラリとしてコンパイルすることでエクステンションから呼び出せるようだったので、コンパイルし直すことにしました。

$ mkdir myprg
$ cd myprg
※このフォルダ内にソースを準備する
$ vi Makefile
$ make

ソースファイルは php-src/ext/sanpleext/myprg/ の中に入れます。
シェアードライブラリとしてコンパイルするために Makefile の CFLAGS と CPPFLAGS に -shared -fPIC を追加します。

CFLAGS = -shared -fPIC -pipe -Wall -W -O2 -w
CXXFLAGS= -shared -fPIC -pipe -Wall -W -O2 -w

最終的にコンパイルされたライブラリは php-src/ext/sampleext/myprg/lib ディレクトリの中に libmyprg.so という名前で保存されるようにします。
4.PHPエクステンションにリンクする
既存プログラムのリンクは config.m4 を修正することで設定します。

$ cd ..
$ vi config.m4

config.m4 の修正点は以下のとおりです。

・if test “$PHP_SAMPLEEXT” != “no”; then の行から下の行のコメント(dnl)を解除
・SEARCH_PATH に ./myprg を追加
・PHP_ADD_INCLUDE(./myprg)
・LIBNAME=myprg
・LIBSYMBOL=myfunc

LIBNAME はリンクするシェアードライブラリの名前を指定します。上記のように書くと ./myprg/lib/libmyprg.so がリンクされます。
LIBSYMBOL はリンクするシェアードライブラリを取り違えていないか確認するためのもので、中に入っている関数名(シンボル)を指定することで、正しいライブラリであることが確認されます。
5.既存プログラムを呼び出す部分を修正する
PHP側とC言語側の間を取り持つのは sampleext.c になりますので、この中に作成していきます。
5-1.関数の宣言
下記の部分にPHPから呼び出すときの関数名を登録します。

const zend_function_entry sampleext_functions[] = {
PHP_FE(confirm_sampleext_compiled, NULL) /* For testing, remove later. */
PHP_FE(call_myfunc, NULL) /* added */
PHP_FE_END /* Must be the last line in sampleext_functions[] */
};

PHP_FE に指定する関数名は PHP 側で見えるものなので、C言語のプログラムソース内の関数と同じ名前でも大丈夫ですが、混乱を避けるために call_myfunc のように変えておくのが良いと思います。第2引数はとりえあずNULLでも動きますが、できれば指定したほうが良いようです(詳細は省略)。
5-2.関数本体の定義
PHP_FUNCTION(confirm_sampleext_compiled) が定義されていると思いますので、その下あたりに定義を追加します。

PHP_FUNCTION(call_myfunc)
{
zend_long a;
char *str;
size_t len;
int status;
ZEND_PARSE_PARAMETERS_START(2, 2)
Z_PARAM_LONG(a)
Z_PARAM_STRING(str, len)
ZEND_PARSE_PARAMETERS_END
/* 何らかの処理 */
status = myfunc(a, str);
RETURN_LONG(ret);
}

引数の受け取りについては他に詳しい記事がありますので参照していただくとして、上記の例では、引数2個、1個めは数値、2個めは文字列を受け取ります。
戻り値を返すには、RETURN_LONG を使うと数値、RETURN_STRING を使うと文字列を返せます。
6.動作確認
テスト用のPHPスクリプト(test_sampleext.php)を作成して走らせることで動作確認しました。

<?php
$r = call_myfunc(1, “abc”);
echo “$r\n”;

下記のようにして実行します。

$ php -d extension=./modules/sampleext.so test_sampleext.php

7.トライアンドエラー
2つの異なる世界のプログラムを連携させているので、一筋縄ではいかないと思います。実際、エラーメッセージとにらめっこしながら何度もコンパイルをやり直しました。

$ vi config.m4
$ phpize
$ ./configure
$ vi sampleext.c
$ make
$ php -d extension=./modules/sampleext.so test_sampleext.php

8.インストール
稼働中のPHPにインストールするには make install を使用します。
インストールされた sampleext.so を読み込むには /etc/php.ini を修正します。
sampleext.so が変更されたら apache を再起動する必要があります。

$ sudo make install
$ vi /etc/php.ini
extension=./modules/sampleext.so
$ sudo apachectl restart

カテゴリー: サーバ関連

0件のコメント

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください