はじめに
この記事は GMOペパボ Advent Calendar 2019 19日目の記事です。
新しく入ったメンバーが macOS 10.15 Catalina 上で PHP 5.6 を build しようとしてハマっていたのを、いろいろ試行錯誤してなんとか解決した(というか回避した)ので、その話を書こうと思います。
Mojave + XCode 10 から /usr/include がつくられなくなった
この話は、macOS 10.15 Catalina から始まった話ではなく、macOS 10.14 Mojave の仕様変更がそもそもの発端になっています。
どのような仕様変更があったかというと、Mojave + XCode 10 から /usr/include
が作られなくなりました。 (/usr/lib
は今まで通りあります)
じゃあ、ヘッダーファイルはどこにあるんだ?ということですが、次の場所にインストールされています。
- /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include
xcrun --show-sdk-path
というコマンドを実行すると、SDKのパスが返却されます。
Mojave で実行すると /Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk
が返却されますが、これは /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk
へのシンボリックリンクになっています。
Mojave + XCode 10 では、無理やり /usr/include
を作るための回避策が準備されており、以下のコマンドを実行すると作ることができました。
sudo installer -pkg /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg -target / -allowUntrusted
この回避策は、Catalina + XCode 11 では使えなくなっており、Catalina では /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include
といい感じに付き合っていく必要があります。
そして本題の PHP 5.6 を phpenv でいれる話
Catalina でも PHP 5.6 を使えるようにしようということで、いつもどおり次のコマンドを実行してもらいました。
phpenv -i development 5.6.40
その結果、よく見る Configure エラーが出たので、はいはいって感じで対処していきました。(このあたりはまだ平和)
(注意) ご存知の方はご存知だと思いますが、次のものがまとめて出るのではなく、アレがないといわれえた結果アレを入れると次はコレというように順々に出ていく感じで一つ一つ潰していく感じです
configure: WARNING: This bison version is not supported for regeneration of the Zend/PHP parsers (found: 2.3, min: 204, excluded: 3.0).
configure: WARNING: You will need re2c 0.13.4 or later if you want to regenerate PHP parsers.
configure: error: Cannot find OpenSSL's <evp.h>
configure: error: Cannot find libz
configure: error: Cannot find libzconfigure: error: Please reinstall the BZip2 distribution
configure: error: Please reinstall the libcurl distribution -
easy.h should be in <curl-dir>/include/curl/
configure: error: Please specify the install prefix of iconv with --with-iconv=<DIR>
configure: error: Please reinstall libedit - I cannot find readline.h
configure: error: mcrypt.h not found. Please reinstall libmcrypt.
上記のエラーに対応するために、必要なものを homebrew を使ってインストール。
brew install bison@2.7 re2c zlib bzip2 curl libiconv libedit mcrypt
あわせて、 PHP 5.6 では OpenSSL 1.0 が必要なので、つい最近書いた次の記事の通り、OpenSSL 1.0.2t をインストールした。
brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/64555220bfbf4a25598523c2e4d3a232560eaad7/Formula/openssl.rb
ここまでの下準備をしつつ、次のコマンドでインストールが完了すると思ってた時期がありました。(実際、Mojaveだとこれでちゃんとインストールできます)
YACC=$(brew --prefix bison@2.7)/bin/bison \
PHP_BUILD_CONFIGURE_OPTS="--with-openssl=/usr/local/Cellar/openssl/1.0.2t --with-zlib-dir=/usr/local/opt/zlib --with-bz2=/usr/local/opt/bzip2 --with-curl=/usr/local/opt/curl --with-libedit=/usr/local/opt/libedit --with-iconv=/usr/local/opt/libiconv --with-mcrypt=/usr/local/opt/mcrypt --with-tidy" \
PHP_BUILD_EXTRA_MAKE_ARGUMENTS=-j4 \
phpenv install -i development 5.6.40
上記のコマンドを実行した結果、出たのが次のエラーになります。(config.log の関連部分を抜粋)
Undefined symbols for architecture x86_64:
"_libiconv", referenced from:
_do_convert in gdkanji.o
_zif_iconv_substr in iconv.o
_zif_iconv_mime_encode in iconv.o
_php_iconv_string in iconv.o
__php_iconv_strlen in iconv.o
__php_iconv_strpos in iconv.o
__php_iconv_appendl in iconv.o
...
"_libiconv_close", referenced from:
_do_convert in gdkanji.o
_zif_iconv_substr in iconv.o
_zif_iconv_mime_encode in iconv.o
_php_iconv_string in iconv.o
__php_iconv_strlen in iconv.o
__php_iconv_strpos in iconv.o
__php_iconv_mime_decode in iconv.o
...
"_libiconv_open", referenced from:
_do_convert in gdkanji.o
_zif_iconv_substr in iconv.o
_zif_iconv_mime_encode in iconv.o
_php_iconv_string in iconv.o
__php_iconv_strlen in iconv.o
__php_iconv_strpos in iconv.o
__php_iconv_mime_decode in iconv.o
...
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [sapi/cli/php] Error 1
どうも iconv 関連がうまくリンクできてないという結果に...
なぜこうなったのか
- 本来は
/usr/local/opt/libiconv/lib
以下のライブラリファイルの方をリンクしてほしいのに、XCode 11 の SDK 側のライブラリとリンクしてしまい、シンボルのズレが発生している - 実際に見てしまっているのは
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib
を優先でみている -
configure
コマンドを実行した結果生成されたMakefile
を見る限り、PHP_RPATHS
が次のようになっていた
PHP_RPATHS = -R /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib -R /usr/local/Cellar/openssl/1.0.2t/lib -R /usr/local/opt/zlib/lib -R /usr/local/opt/bzip2/lib -R /usr/local/Cellar/curl/7.67.0/lib -R /usr/local/opt/curl/lib -R /usr/local/lib -R /usr/local/opt/libiconv/lib -R /usr/local/Cellar/icu4c/64.2/lib -R /usr/local/opt/mcrypt/lib -R /usr/local/opt/libedit/lib
どのように回避したのか
PHP_RPATHS
を指定することにより、homebrew のライブラリを優先的にリンクするようにしました。
最終的には次のようなコマンドで、Catalina で PHP 5.6 を build することに成功しました。
(注意) 最低限だと PHP_RPAHTS
に /usr/local/opt/libiconv/lib
だけを指定すれば回避できるはずですが、他のライブラリも XCode 11 SDK 側が優先されるといやだなぁということで全部指定してます
YACC=$(brew --prefix bison@2.7)/bin/bison \
PHP_RPATHS="/usr/local/Cellar/openssl/1.0.2t/lib /usr/local/opt/zlib/lib /usr/local/opt/bzip2/lib /usr/local/opt/curl/lib /usr/local/opt/libedit/lib /usr/local/opt/libiconv/lib /usr/local/opt/mcrypt/lib" \
PHP_BUILD_CONFIGURE_OPTS="--with-openssl=/usr/local/Cellar/openssl/1.0.2t --with-zlib-dir=/usr/local/opt/zlib --with-bz2=/usr/local/opt/bzip2 --with-curl=/usr/local/opt/curl --with-libedit=/usr/local/opt/libedit --with-iconv=/usr/local/opt/libiconv --with-mcrypt=/usr/local/opt/mcrypt --with-tidy" \
PHP_BUILD_EXTRA_MAKE_ARGUMENTS=-j4 \
phpenv install -i development 5.6.40
こんなのやってられるか!!!
という声が多数あがりそうなので、PHP_RPATHS
や PHP_BUILD_CONFIGURE_OPTS
を設定するように php-build
にフィードバックをこの年末年始にしようと思ってます。
今、ちょうど、 php-build
のメインコミッターが travis の macOS 側の CI ベースを Xcode 10 にあげようとしているので、それに乗っかって、このフィードバックが取り込まれれば、Catalina でも phpenv install
だけでいけるようになるはずです。
最後に
この件に関係するような記事で、 php-build
の default_configure_options
を変更するという方法を書かれているものがありますが、正直なところ、このファイルを変更することはおすすめできません。
このファイルは php-build
に含まれるファイルなので、このファイルを変更してしまうと、 php-build
が更新されるたびに conflict するので、素直に php-build
を更新できなくなります。(いちいち毎回毎回変更点をマージする、めんどくさいですよね...)
php-bulid
の configure のオプションを変更する場合には、今回の対処でやったように PHP_BUILD_CONFIGURE_OPTS
環境変数を使うことをおすすめします。
php-build
へのフィードバックが取り込まれ次第、この記事を更新して、もうこんな苦労しないでいいよという風にしたいと思います。
(追記) ちなみに...
試行錯誤していた際に一番長くなった時には次のように指定してました(最終的に CPPFLAGS と PHP_LDFLAGS は指定しないでいいことに気がついたので、上記のようなものになっています)
YACC=$(brew --prefix bison@2.7)/bin/bison \
PHP_RPATHS="/usr/local/Cellar/openssl/1.0.2t/lib /usr/local/opt/zlib/lib /usr/local/opt/bzip2/lib /usr/local/opt/curl/lib /usr/local/opt/libedit/lib /usr/local/opt/libiconv/lib /usr/local/opt/mcrypt/lib" \
CPPFLAGS="-I/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include -I/usr/local/Cellar/openssl/1.0.2t/include -I/usr/local/opt/zlib/include -I/usr/local/opt/bzip2/include -I/usr/local/opt/curl/include -I/usr/local/opt/libedit/include -I/usr/local/opt/libiconv/include -I/usr/local/opt/mcrypt/include" \
PHP_LDFLAGS="-L/usr/local/Cellar/openssl/1.0.2t/lib -L/usr/local/opt/zlib/lib -L/usr/local/opt/bzip2/lib -L/usr/local/opt/curl/lib -L/usr/local/opt/libedit/lib -L/usr/local/opt/libiconv/lib -L/usr/local/opt/mcrypt/lib" \
PHP_BUILD_CONFIGURE_OPTS="--with-openssl=/usr/local/Cellar/openssl/1.0.2t --with-zlib-dir=/usr/local/opt/zlib --with-bz2=/usr/local/opt/bzip2 --with-curl=/usr/local/opt/curl --with-libedit=/usr/local/opt/libedit --with-iconv=/usr/local/opt/libiconv --with-mcrypt=/usr/local/opt/mcrypt --with-tidy" \
PHP_BUILD_EXTRA_MAKE_ARGUMENTS=-j4 \
phpenv install -i development 5.6.40