TL; DR
PKG_CONFIG_PATH="/opt/brew/opt/libffi/lib/pkgconfig" gem install ffi
MacOS Mojaveで bundle install
したらエラーが起きてインストールに失敗しました.
nokogiri
のインストールに失敗したのかな...と思ってエラーを見てみると,
どうやらインストールに失敗しているのは ffi
のようです.
エラーを抜粋します.
configure: error: C++ preprocessor "/lib/cpp" fails sanity check
See `config.log' for more details
make[1]: *** No targets specified and no makefile found. Stop.
このエラーでグーグル検索をすると, C++ のコンパイラが入っていないのが原因だよ,
g++ を入れてあげれば直るよという記事が目に付きます.
なるほど?と思い手元の環境を確認するも, brew install gcc
によって C++ のコンパイラは
正常にインストールされているようです.
ここで,困ったなぁと思いながら GitHub の issue
を眺めに行くと以下の issue が見つかりました.
Fails to install on OSX 10.14 (Mojave): https://github.com/ffi/ffi/issues/651
sudo ln -s /usr/lib/libSystem.B.dylib /usr/local/lib/libgcc_s.10.4.dylib
で直るよという書き込みがありますが,エラーは解消されませんでした.
更に issue を読み進めると, libffiのインストールしなおそう という書き込みが見つかります.
これに従い, brew reinstall libffi
を実行してみます.
すると↓のようなログが出てきました.
libffi is keg-only, which means it was not symlinked into /opt/brew,
because some formulae require a newer version of libffi.
For compilers to find libffi you may need to set:
export LDFLAGS="-L/opt/brew/opt/libffi/lib"
For pkg-config to find libffi you may need to set:
export PKG_CONFIG_PATH="/opt/brew/opt/libffi/lib/pkgconfig"
keg-only
とは,インストールしたライブラリがシステム全体に影響を及ぼす可能性があるため,
homebrew の lib
などにはリンクを張らないという挙動のことを言うそうです.
(参考: https://qiita.com/halo57/items/e7511f3befbcb9fedd6a)
ls 'brew --prefix'/lib| grep ffi
(backtickをシングルクオートに変換しています) をしてみると,
確かに ffi に関係しそうな共有ライブラリや静的ライブラリが見当たりません.
一方, 'brew --prefix'/Cellar/libffi/x.x.x/lib` にはライブラリやヘッダファイルがありそうです.
というわけで,よしなにパスを通してあげる必要がありそうです.
さきほど示した issue を見ると,
PKG_CONFIG_PATH
と LDFLAGS
に libffi の lib ディレクトリと pkg-config ファイルを
渡してビルドをしているようです.
実際には, pkg-config がよしなにパスの設定をしてくれるので, LDFLAGS
の指定は不要です
pkg-config とは, .pc
という拡張子に記述したヘッダやライブラリのパスに関する設定を読み込んで
必要に応じてフラグを出力してくれたりするツールです.
libffi の pkg-config ファイルを以下に示します.
prefix=/opt/brew/Cellar/libffi/3.2.1
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
toolexeclibdir=${exec_prefix}/lib
includedir=${libdir}/libffi-3.2.1/include
Name: libffi
Description: Library supporting Foreign Function Interfaces
Version: 3.2.1
Libs: -L${toolexeclibdir} -lffi
Cflags: -I${includedir}
libffi がインストールされているパスやライブラリ,ヘッダが置かれているパスが記述されています.
PKG_CONFIG_PATH
に pkg-config ファイルへのパスを渡すと, configure
などがそれを読み込み
ビルド時のフラグをよしなにしてくれます.
このため, PKG_CONFIG_PATH='brew --prefix'/Cellar/libffi/3.2.1/lib/pkgconfig gem install ffi
としてやることでよしなにインストールが成功します(実際には PKG_CONFIG_PATH
に渡しているのは pkg-config ファイルが存在するディレクトリであることに注意してください).
以上です,お疲れ様でした.
ちなみに, pkg-config はコマンドラインでも使えます.
例えば,ライブラリを使うためのフラグがほしいときには pkg-config libffi.pc --libs
とします.
$ pkg-config libffi.pc --libs
-L/opt/brew/Cellar/libffi/3.2.1/lib -lffi
ヘッダを使いたいときは pkg-config libffi.pc --cflags
$ pkg-config libffi.pc --cflags
-I/opt/brew/Cellar/libffi/3.2.1/lib/libffi-3.2.1/include
両方いっぺんに使うときは↓
$ pkg-config libffi.pc --cflags --libs
-I/opt/brew/Cellar/libffi/3.2.1/lib/libffi-3.2.1/include -L/opt/brew/Cellar/libffi/3.2.1/lib -lffi