hnwの日記

GoでPHP拡張モジュールを書いた話

12/6のGo Conference 2015 WinterでGoでPHP拡張モジュールを書いたよ、という内容のLTをしてきました。



ざっくり言うと、Goって言ってもCのレベルに落ちてくれば連携なんて簡単でしょって思ってたけど、GoもPHP拡張もビルドプロセスが隠蔽されてるので、落としどころが見つからなくて苦労したよって話でした。もっと綺麗に連携できる方法を編み出した方は教えてください。

PHP拡張モジュール側のビルドについて補足

拡張モジュールを共有ライブラリじゃなく静的ライブラリとして作ればいいじゃん、って発想で作り始めましたが、実は拡張モジュールを静的ライブラリとして作るのは結構ダルいという事情があります。というのも、拡張モジュールをphpizeするとconfigureオプションで何を指定しても静的ライブラリが作られないようにm4マクロが展開されてしまうのです。


そこで、できあがったconfigureスクリプトを修正して静的ライブラリを作らせるようにしています。


そもそもライブラリでなくオブジェクトファイルを取り回す方が素直な気がするんですが、その方針だとリンク時にエラーが出てしまいました。もう少しPHP拡張側のビルドプロセスを熟知していたら解決できるのかもしれません。

cgo側のビルドについて補足

PHPのヘッダファイル類がデフォルトのインクルードパスに含まれることは稀です。PHP拡張モジュールをビルドする際は、通常であればphp-configコマンドで取り出したパスをインクルードパスとして追加することになるでしょう。phpizeコマンドはそのあたりも暗黙にやってくれるのが楽なんですよね。


つまり、cgoでPHP側の処理をGo言語に持ち込みたい場合も適切なインクルードパスを追加する必要があります。そこで、僕は下記のようにインクルードパスをベタ書きで追加していました。

/*
#cgo CFLAGS: -I/Users/hnw/.phpenv/versions/7.0.0/include/php -I/Users/hnw/.phpenv/versions/7.0.0/include/php/main -I/Users/hnw/.phpenv/versions/7.0.0/include/php/TSRM -I/Users/hnw/.phpenv/versions/7.0.0/include/php/Zend -I/Users/hnw/.phpenv/versions/7.0.0/include/php/ext -I/Users/hnw/.phpenv/versions/7.0.0/include/php/ext/date/lib

#include "php.h"
#include "php_ini.h"
*/


しかし、これでは僕の手元でしか動かないことになってしまいます。うまい手を探していたところ、CGO_CFLAGS環境変数の存在に気付きました(参照:「cgo - The Go Programming Language」)。これを使えばベタ書きする代わりに下記のように環境変数経由でインクルードパスが渡せます。

$ CGO_CFLAGS=$(php-config --includes) go build -buildmode=c-shared -o modules/goext.so goext.go

感想その他

@do_akiさんのPHP BLT #1のプレゼン「Writing php extensions in golang」とネタがかぶってしまいました。GoConの応募はそれより前だったので、そんなこともありますよねってことで。


個人的にcgoについてはマクロや共用体を便利に使えるような機能追加を期待していますが、Goにとって主要な関心事ではないと思うので、なかなか難しいかもしれません。


今回のコードを一応公開しておきます(hnw/phpext-in-golang)。何かの参考になれば。

さいごに

このエントリは闇PHP Advent Calendar 2015の6日目でした。