phpenv から PHPNG を使う
anyenv + phpenv の環境では、~/.anyenv/envs/phpenv/versions のサブディレクトリにインストールされた PHP がバージョン切り替えの対象になります。php-build を用いずにソースコードから独自にビルドする場合でも、./configure の --prefix オプションを適切に設定すれば、phpenv の管理対象に含められます。
今回は、この実例として、PHPNG をソースコードからビルドして phpenv で切り替えられるようにしてみます。インストール手順は公式サイトの記載にしたがいます。詳細は下記のウェブページを参照してください。
PHPNG のインストール
$ git clone https://git.php.net/repository/php-src.git
公式サイトの説明どおりにビルドを進めます。
$ cd php-src $ ./buildconf $ ./configure \ --prefix=$HOME/.anyenv/envs/phpenv/versions/phpng \ --with-config-file-path=$HOME/.anyenv/envs/phpenv/versions/phpng/etc \ --with-libdir=lib64 \ --enable-mbstring \ --enable-zip \ --enable-bcmath \ --enable-pcntl \ --enable-ftp \ --enable-exif \ --enable-calendar \ --enable-sysvmsg \ --enable-sysvsem \ --enable-sysvshm \ --enable-wddx \ --with-curl \ --with-mcrypt \ --with-iconv \ --with-gmp \ --with-pspell \ --with-gd \ --with-jpeg-dir=/usr \ --with-png-dir=/usr \ --with-zlib-dir=/usr \ --with-xpm-dir=/usr \ --with-freetype-dir=/usr \ --with-t1lib=/usr \ --enable-gd-native-ttf \ --enable-gd-jis-conv \ --with-openssl \ --with-mysql=/usr \ --with-pdo-mysql=/usr \ --with-gettext=/usr \ --with-zlib=/usr \ --with-bz2=/usr \ --with-recode=/usr \ --with-mysqli=/usr/bin/mysql_config \ --with-apxs2=/usr/bin/apxs
./configure に渡すオプションで、ウェブサイトの記載内容から変更したものは以下のとおりです。なお、さまざまな --with-* が指定されていることもあり、依存関係はそれなりに多いようです。私の環境でも、yum で *-devel パッケージをいくつか追加する必要がありました*1。
- --prefix
- phpenv の管理対象にするため、${HOME}/.anyenv/envs/phpenv/versions/phpng を指定します。phpng の部分は自由に変更できます
- --with-config-file-path
- --prefix の指定に合わせて、${HOME}/.anyenv/envs/phpenv/versions/phpng/etc を指定します
- --with-libdir
- これは phpenv には無関係な設定ですが、私の環境では、ここに lib64 を指定する必要がありました*2
- --with-apxs2
- Apache のモジュールを作成するため、このオプションを指定します。私の環境では /usr/bin/apxs を指定しました
make を実行する前に、Makefile を編集して libphp7.so の出力先を変更しておきます。これは、前々回の記事で紹介した tkuchiki 氏のパッチと同様の修正です。詳細は「php-build が libphp5.so を上書きしないようにするパッチ - tkuchikiの日記」を参照してください。以下のように INSTALL_IT ではじまる行を編集します。${exec_prefix} は、デフォルトでは --prefix と同じディレクトリになるので、~/.anyenv/envs/phpenv/versions/phpng/libexec 以下に libphp7.so が出力されるようになります。
$ diff -u Makefile- Makefile --- Makefile- 2014-10-20 22:41:57.000218259 +0900 +++ Makefile 2014-10-20 22:43:13.786665139 +0900 @@ -105,7 +105,7 @@ INCLUDES = -I/home/y-uti/src/php-src/ext/date/lib -I/home/y-uti/src/php-src/ext/ereg/regex -I/usr/include/libxml2 -I/usr/X11 -I/usr/include/freetype2 -I/home/y-uti/src/php-src/ext/mbstring/oniguruma -I/home/y-uti/src/php-src/ext/mbstring/libmbfl -I/home/y-uti/src/php-src/ext/mbstring/libmbfl/mbfl -I/usr/include/mysql -I/home/y-uti/src/php-src/ext/sqlite3/libsqlite -I/usr/include/pspell -I/home/y-uti/src/php-src/ext/zip/lib -I$(top_builddir)/TSRM -I$(top_builddir)/Zend EXTRA_INCLUDES = INCLUDE_PATH = .:/home/y-uti/.anyenv/envs/phpenv/versions/phpng/lib/php -INSTALL_IT = $(mkinstalldirs) '$(INSTALL_ROOT)/usr/lib64/httpd/modules' && $(mkinstalldirs) '$(INSTALL_ROOT)/etc/httpd/conf' && /usr/bin/apxs -S LIBEXECDIR='$(INSTALL_ROOT)/usr/lib64/httpd/modules' -S SYSCONFDIR='$(INSTALL_ROOT)/etc/httpd/conf' -i -a -n php7 libphp7.la +INSTALL_IT = $(mkinstalldirs) '${exec_prefix}/libexec' && $(mkinstalldirs) '$(INSTALL_ROOT)/etc/httpd/conf' && /usr/bin/apxs -S LIBEXECDIR='${exec_prefix}/libexec' -S SYSCONFDIR='$(INSTALL_ROOT)/etc/httpd/conf' -i -a -n php7 libphp7.la LFLAGS = LIBTOOL = $(SHELL) $(top_builddir)/libtool --silent --preserve-dup-deps LN_S = ln -s
Makefile を編集した後、make コマンドを実行して PHPNG をインストールします。php.ini は自動的には作られないようなので、php.ini-production ファイルをコピーしておきます。
$ make
$ make install
$ cp ./php.ini-production ~/.anyenv/envs/phpenv/versions/phpng/etc/php.ini
これで、phpenv から PHPNG を選択できるようになりました。phpenv versions で確認してみます。
$ phpenv versions phpenv v0.0.4-dev * system (set by /home/y-uti/.anyenv/envs/phpenv/version) 5.3.29 5.5.18 5.6.2 phpng
phpenv global で切り替えて、PHP のバージョンを確認します。バージョン 7.0.0-dev となっていることがわかります。
$ phpenv global phpng phpenv v0.0.4-dev phpng $ php -v PHP 7.0.0-dev (cli) (built: Oct 20 2014 22:50:33) Copyright (c) 1997-2014 The PHP Group Zend Engine v2.8.0-dev, Copyright (c) 1998-2014 Zend Technologies
Apache module の切り替え
ここまでの手順で PHPNG をインストールした状態では、httpd からモジュールをロードすることができません。原因は次の二つです。
- phpenv の現在の実装は、モジュールのファイル名が libphp5.so であることを前提にしている
- httpd から libphp7.so をロードするには、モジュール名に php7_module を指定しなければいけない
一つ目の問題を確認します。PHPNG をインストールすると、以下のように libphp7.so が作成されます。
$ ls -l ~/.anyenv/envs/phpenv/versions/phpng/libexec 合計 36888 -rwxr-xr-x. 1 y-uti users 37770539 10月 20 22:51 libphp7.so*
ところが、phpenv global でバージョンを切り替えると、libphp5.so へのシンボリックリンクが作成されます。リンク先の libphp5.so ファイルは存在しません。
$ ls -l ~/.anyenv/envs/phpenv/lib 合計 0 lrwxrwxrwx. 1 y-uti users 68 10月 21 05:36 libphp5.so -> /home/y-uti/.anyenv/envs/phpenv/versions/phpng/libexec/libphp5.so
二つ目の問題は、libphp7.so をロードするために conf ファイル自体を切り替える必要があるということです。PHP 5.x 同士の切り替えであれば、conf ファイルに次のように書いておけば問題ありませんでした。指定されているファイルはシンボリックリンクで、PHP のバージョンに応じてリンク先のファイルがロードされる仕組みでした。
$ cat /etc/httpd/conf.modules.d/10-php.conf # # PHP is an HTML-embedded scripting language which attempts to make it # easy for developers to write dynamically generated webpages. # <IfModule prefork.c> # LoadModule php5_module modules/libphp5.so LoadModule php5_module /home/y-uti/.anyenv/envs/phpenv/lib/libphp5.so </IfModule>
ところが、PHPNG の libphp7.so をロードするにはモジュール名を php7_module としなければいけないので、so ファイルの切り替えだけでは上手くいきません。conf ファイル自体を切り替える仕組みを作り込む必要があります。
以下では、これらの問題を解決して httpd から libphp7.so をロードできるようにする方法を紹介します*3。
まず、以下のようにして、PHP 5.x 用と PHP 7.x 用の conf ファイルをそれぞれ作成します。php5.conf ではモジュール名を php5_module に、php7.conf では php7_module にします。モジュールのファイル名は普通は libphp5.so または libphp7.so なのですが、シンボリックリンクを作成して切り替えることを意識して、敢えてバージョン番号を削っています。
$ mkdir ~/.anyenv/envs/phpenv/etc/httpd $ cd ~/.anyenv/envs/phpenv/etc/httpd $ vi php5.conf # # PHP is an HTML-embedded scripting language which attempts to make it # easy for developers to write dynamically generated webpages. # <IfModule prefork.c> LoadModule php5_module /home/y-uti/.anyenv/envs/phpenv/lib/libphp.so </IfModule> $ sed 's/php5_module/php7_module/' php5.conf >php7.conf
次に、phpenv-global スクリプトの実装を変更します。配布元のリポジトリとの差分は以下のようになります。
$ git diff remotes/origin/HEAD phpenv-global diff --git a/libexec/phpenv-global b/libexec/phpenv-global index 96f5b39..089dc88 100755 --- a/libexec/phpenv-global +++ b/libexec/phpenv-global @@ -44,12 +44,17 @@ echo ${PHPENV_VERSION} # Link Apache apxs lib APXS="" +if [ "${PHPENV_VERSION}" == "system" ]; then + APXS="$(which apxs 2>/dev/null)" +fi php-config --configure-options 2>/dev/null | grep -q apxs && \ APXS="$(php-config --configure-options| sed 's/.*=\(.*apxs[^ ]*\) .*/\1/')" [[ -d "${PHPENV_ROOT}/lib" ]] || mkdir "${PHPENV_ROOT}/lib" if [ -n "${APXS}" ]; then + LIBPHP_VERSION="$(php -r 'echo substr(phpversion(), 0, 1);')" [[ "${PHPENV_VERSION}" == "system" ]] && \ - ln -fs "$(${APXS} -q LIBEXECDIR)/libphp5.so" "${PHPENV_ROOT}/lib/libphp5.so" || \ - ln -fs "${PHPENV_ROOT}/versions/${PHPENV_VERSION}/libexec/libphp5.so" "${PHPENV_ROOT}/lib/libphp5.so"; + ln -fs "$(${APXS} -q LIBEXECDIR)/libphp${LIBPHP_VERSION}.so" "${PHPENV_ROOT}/lib/libphp.so" || \ + ln -fs "${PHPENV_ROOT}/versions/${PHPENV_VERSION}/libexec/libphp${LIBPHP_VERSION}.so" "${PHPENV_ROOT}/lib/libphp.so"; + ln -fs "${PHPENV_ROOT}/etc/httpd/php${LIBPHP_VERSION}.conf" "${PHPENV_ROOT}/etc/httpd/php.conf" fi
前半の三行の差分は、phpenv global system を実行したときにデフォルトの libphp5.so にリンクを張るための設定です。これは以前の記事で紹介した内容で、今回の記事には関係しません。
次の差分が、今回の変更のポイントです。ここで、PHP のメジャーバージョンに合わせて LIBPHP_VERSION が 5 または 7 になります。
+ LIBPHP_VERSION="$(php -r 'echo substr(phpversion(), 0, 1);')"
あとは、${LIBPHP_VERSION} を使って、so ファイルと conf ファイルへのシンボリックリンクを作成します。
これで、~/.anyenv/envs/phpenv/etc/httpd/php.conf を読み込めば正しくモジュールがロードされるようになります。最後に、このファイルへのシンボリックリンクを作成します。
$ cd /etc/httpd/conf.modules.d $ sudo mv 10-php.conf 10-php.conf.orig $ sudo ln -s ~/.anyenv/envs/phpenv/etc/httpd/php.conf 10-php.conf
結果を確認してみます。このように PHP/7.0.0-dev の表示が得られました。もちろんウェブブラウザからアクセスして確認しても同じです。
$ phpenv global phpng $ sudo systemctl reload httpd.service $ curl http://localhost/phpinfo.php 2>/dev/null | grep 'Apache Version' <tr><td class="e">Apache Version </td><td class="v">Apache/2.4.6 (CentOS) PHP/7.0.0-dev </td></tr>