ブログ・ア・ラ・クレーム

技術的なメモとかライフログとか。

Mac で ngx_mruby 込みで nginx をビルドする際にいろいろハマってた

ちょっと前に解決した話なんですが備忘録的に書いておきます。 (2017/10/03 記述に漏れがあったので修正しました)

前提

最近の openssl の Formula は link を --force を付けたとしても禁止しています。理解はできるけどサクッとビルドしたい時にやや面倒・・・

$ brew link openssl --force
Warning: Refusing to link: openssl
Linking keg-only openssl means you may end up linking against the insecure,
deprecated system OpenSSL while using the headers from Homebrew's openssl.
Instead, pass the full include/library paths to your compiler e.g.:
  -I/usr/local/opt/openssl/include -L/usr/local/opt/openssl/lib

Homebrew の Formula が入らないよ問題

nginx-full Formula はナイスなことにオプションで ngx_mruby を加えてビルドすることができるようになっています。 http://hb.matsumoto-r.jp/entry/2016/02/10/224532

しかし最近以下の点でハマるようになっていました。

  • Homebrew がデフォルトで sandbox-exec してビルドするようになり、パーミッションの都合 --with-mruby-module ではビルドが通らなくなる
    • 一応 --no-sandbox すれば sandbox-exec しなくなるので回避できる
  • ngx_mruby のリンク途中でコケる

前者の問題は本質的には mruby-nginx-module の Formula の構成の問題です。 Homebrew で sandbox-exec してビルドする際、ビルド対象の Formula のディレクトリや /tmp などに書き込み権限を絞ってしまうため、現状の "nginx-full Formula から mruby-nginx-module Formula のビルドを行なう" ような操作が通らなくなります。 これは根が深い問題なので、今回はひとまず後者の問題を回避できるようにしました。

https://github.com/Homebrew/homebrew-nginx/pull/324

これで以下のようにすれば引き続き Homebrew で ngx_mruby をらくらくインストールすることができます。

# 残念ながら --no-sandbox は今のところ必要。しかたないね
$ brew install nginx-full --with-mruby-module --no-sandbox

ngx_mruby をソースからビルドする時困るよ問題

前述の通り openssl のインクルードパスなどを、 ngx_mruby の場合は nginx や mruby のビルド時にも渡るようにしてやらなければならないので一工夫がいります。 幸いにも ngx_mruby の configure, Makefile ではいくつか nginx, mruby のビルド時に任意のオプションを渡すための記述がされているのでそれらを駆使するのが良さそうです。

(2017/10/03 追記・修正) nginx の ビルド時には難ありです。

openssl のソースコードを手元に用意して、 ngx_mruby の --with-ngx-src-root にパスを渡すのがひとつのビルド方法に思われます。

./configure --with-ngx-src-root=/path/to/ngx_mruby/build/nginx_src --with-ngx_config_opt="--with-debug --with-http_stub_status_module --with-http_ssl_module --with-openssl=/path/to/openssl"
...

自分は面倒に感じてしまったので、 nginx の configure に以下のようなパッチを当てて、 Homebrew でインストールした openssl を参照するようにしてしまいました。。。

113a114,129
>         if [ $ngx_found = no ]; then
>
>             # Homebrew
>
>             ngx_feature="OpenSSL library in /usr/local/opt/"
>             ngx_feature_path="/usr/local/opt/openssl/include"
>
>             if [ $NGX_RPATH = YES ]; then
>                 ngx_feature_libs="-R/usr/local/opt/openssl/lib -L/usr/local/opt/openssl/lib -lssl -lcrypto $NGX_LIBDL"
>             else
>                 ngx_feature_libs="-L/usr/local/opt/openssl/lib -lssl -lcrypto $NGX_LIBDL"
>             fi
>
>             . auto/feature
>         fi
>

これを利用すれば以下の通りにビルドできます

$ ./configure --with-ngx-src-root=/path/to/ngx_mruby/build/nginx_src --with-ngx_config_opt="--with-debug --with-http_stub_status_module --with-http_ssl_module
...

$ NGX_MRUBY_CFLAGS="-I/usr/local/opt/openssl/include" NGX_MRUBY_LDFLAGS="-L/usr/local/opt/openssl/lib -lcrypto" make
...
checking for OpenSSL library ... not found
checking for OpenSSL library in /usr/local/ ... not found
checking for OpenSSL library in /usr/pkg/ ... not found
checking for OpenSSL library in /opt/local/ ... not found
checking for OpenSSL library in /usr/local/opt/ ... found
...

かなり遠回り感が出てしまいますが、自分の環境ではこれで無事ビルドできました

ところで

High Sierra では OpenSSL が LibreSSL に置き換わるらしいですね。こんな問題にはもうハマらなくて済むのか、あるいは別のハマりどころに結局苦しめられるのか・・・