12/6のGo Conference 2015 WinterでGoでPHP拡張モジュールを書いたよ、という内容のLTをしてきました。
ざっくり言うと、Goって言ってもCのレベルに落ちてくれば連携なんて簡単でしょって思ってたけど、GoもPHP拡張もビルドプロセスが隠蔽されてるので、落としどころが見つからなくて苦労したよって話でした。もっと綺麗に連携できる方法を編み出した方は教えてください。
拡張モジュールを共有ライブラリじゃなく静的ライブラリとして作ればいいじゃん、って発想で作り始めましたが、実は拡張モジュールを静的ライブラリとして作るのは結構ダルいという事情があります。というのも、拡張モジュールをphpizeするとconfigureオプションで何を指定しても静的ライブラリが作られないようにm4マクロが展開されてしまうのです。
そこで、できあがったconfigureスクリプトを修正して静的ライブラリを作らせるようにしています。
そもそもライブラリでなくオブジェクトファイルを取り回す方が素直な気がするんですが、その方針だとリンク時にエラーが出てしまいました。もう少しPHP拡張側のビルドプロセスを熟知していたら解決できるのかもしれません。
プレゼン中では細かすぎて紹介しなかった点を1点書いておきます。
PHPのヘッダファイル類がデフォルトのインクルードパスに含まれることは稀です。PHP拡張モジュールをビルドする際は、通常であればphp-configコマンドで取り出したパスをインクルードパスとして追加することになるでしょう。phpizeコマンドはそのあたりも暗黙にやってくれるのが楽なんですよね。
つまり、cgoでPHP側の処理をGo言語に持ち込みたい場合も適切なインクルードパスを追加する必要があります。しかし、現状のcgoでは下記のようにインクルードパスをベタ書きで追加するしか無い気がしています。ベタ書きしてしまうと配布に向かないですし、かなり困る点ではないでしょうか。pkg-configのように標準で連携できたらいいんですが、それもできないですしね…
/* #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" */
@do_akiさんのPHP BLT #1のプレゼン「Writing php extensions in golang」とネタがかぶってしまいました。GoConの応募はそれより前だったので、そんなこともありますよねってことで。
個人的にcgoについてはマクロや共用体を便利に使えるような機能追加を期待していますが、Goにとって主要な関心事ではないと思うので、なかなか難しいかもしれません。
今回のコードを一応公開しておきます(hnw/phpext-in-golang)。上に書いたような理由で僕の手元でしか動かないコードになっていますが、何かの参考になれば。
このエントリは闇PHP Advent Calendar 2015の6日目でした。