Help us understand the problem. What is going on with this article?

macOS 10.15 Catalina 上で phpenv を使って PHP 5.6 を build するのにものすごく苦労した話

はじめに

この記事は 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_RPATHSPHP_BUILD_CONFIGURE_OPTS を設定するように php-build にフィードバックをこの年末年始にしようと思ってます。

今、ちょうど、 php-build のメインコミッターが travis の macOS 側の CI ベースを Xcode 10 にあげようとしているので、それに乗っかって、このフィードバックが取り込まれれば、Catalina でも phpenv install だけでいけるようになるはずです。

最後に

この件に関係するような記事で、 php-builddefault_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
kunit
2018年末に福岡に移住して、ロリポップ!、ヘテムル、ムームードメインといったサービスに携わっています とはいえまだまだ修行中...
https://kunit.jp/
pepabo
「いるだけで成長できる環境」を標榜し、エンジニアが楽しく開発できるWebサービス企業を目指しています。
https://pepabo.com
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした