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

macOS Mojaveでgem install ffiに失敗したときのメモ

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_PATHLDFLAGS に 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

Why do not you register as a user and use Qiita more conveniently?
  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
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