ffi
に限ったことではないかも知れないけど、度々Bundlerでインストールしようと思うと、gemのコンパイルでコケることがある。
過去にffi
だけじゃなくmysql2
とかでもコケたことあった。
今回はffi
の話になるけど、bundle install
でコケた時の対処法とどこを調べたのかなどのメモを残しておく。
前提
- 非エンジニアです
- Ruby…というかプログラミングは勉強中です
- Cのことはよくわかりません。なんもわからん
起こったこと
MiddlemanをBundlerでインストールしようとすると、ffi
というgemのインストールでコケる
結論
ffi
で使うコンパイラーが見つからなくてエラーになるっぽい- Homebrew使ってる場合は、
libffi
が入っているか確認してみる libffi
が入っている場合、LDFLAGS
とCPPFLAGS
とPKG_CONFIG_PATH
の場所を確認してみる- PATHの場所は
-L/usr/local/opt/libffi/**
になってなかったら、brew link --force libffi
して、インストールされているlibffi
へリンクをはる- シェルの設定にPATHの設定が書かれているか確認してみる
- 上記が確認できたら
bundle install
してみる - 成功したら解決です
余談
試して見てないのでわからないけど、これでも解決するかも知れないと思ったメモ。
ffi
の公式READMEに書いてあるbundle config build.ffi --enable-system-libffi
かbundle config build.ffi --disable-system-libffi
とする
参考にした記事とか
エラー内容
Installing padrino-helpers 0.13.3.4 Gem::Ext::BuildError: ERROR: Failed to build gem native extension. current directory: /Users/ksm/dev/odde/vendor/bundle/ruby/3.0.0/gems/ffi-1.14.2/ext/ffi_c /Users/ksm/.rbenv/versions/3.0.0/bin/ruby -I /Users/ksm/.rbenv/versions/3.0.0/lib/ruby/3.0.0 -r ./siteconf20210205-86979-qhqxqz.rb extconf.rb checking for ffi_prep_closure_loc() in -lffi... yes checking for ffi_prep_cif_var()... yes checking for ffi_raw_call()... yes checking for ffi_prep_raw_closure()... yes creating extconf.h creating Makefile current directory: /Users/ksm/dev/odde/vendor/bundle/ruby/3.0.0/gems/ffi-1.14.2/ext/ffi_c make "DESTDIR=" clean current directory: /Users/ksm/dev/odde/vendor/bundle/ruby/3.0.0/gems/ffi-1.14.2/ext/ffi_c make "DESTDIR=" compiling AbstractMemory.c compiling ArrayType.c compiling Buffer.c compiling Call.c compiling ClosurePool.c compiling DynamicLibrary.c compiling Function.c Function.c:847:17: error: implicit declaration of function 'ffi_prep_closure_loc' is invalid in C99 [-Werror,-Wimplicit-function-declaration] ffiStatus = ffi_prep_closure_loc(closure->pcl, &fnInfo->ffi_cif, callback_invoke, closure, code); ^ Function.c:847:17: note: did you mean 'ffi_prep_closure'? /Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/include/ffi/ffi.h:269:1: note: 'ffi_prep_closure' declared here ffi_prep_closure( ^ 1 error generated. make: *** [Function.o] Error 1 make failed, exit code 2 Gem files will remain installed in /Users/ksm/dev/odde/vendor/bundle/ruby/3.0.0/gems/ffi-1.14.2 for inspection. Results logged to /Users/ksm/dev/odde/vendor/bundle/ruby/3.0.0/extensions/x86_64-darwin-19/3.0.0/ffi-1.14.2/gem_make.out An error occurred while installing ffi (1.14.2), and Bundler cannot continue. Make sure that `gem install ffi -v '1.14.2' --source 'https://rubygems.org/'` succeeds before bundling. In Gemfile: middleman was resolved to 4.3.11, which depends on middleman-core was resolved to 4.3.11, which depends on listen was resolved to 3.0.8, which depends on rb-inotify was resolved to 0.10.1, which depends on ffi
implicit declaration of function 'ffi_prep_closure_loc' is invalid in C99
ってところ。
無効な関数が使われているとのこと。
これが原因でmakeが失敗してるっぽい……っていうところはわかった。
やってみたこと
- Bundlerを使わずに
ffi
をgem install
してみる。- すんなりインストールできた。
- Bundlerを使わずにMiddlemanを
gem install
してみる。- すんなり終わった(Webrickがload errorになって動きはしなかったが…)
この辺は記事を書きながらログを探してたんだけど、残ってなかった。 作業ログを出力する方法があるっぽいので、今度ちゃんと設定しておこう…。
とにかくBundlerを使わずにMiddlemanもffiもインストールできるので、こちらの問題ではなさそう?というアタリをつける。
ただ引っかかっているのはffi
のインストールなので、ffiのGitHubにいって似たような問題にぶち当たってる人がいないか探してみる。
結構いた。
直接「これをやれば解決する!」みたいなissueはなかなか見つけられなかったけど、gem ffi のインストールに失敗するときのコンパイラオプション指定方法 - Qiitaという記事を見つけて、Homebrewでlibffi
をインストールしている環境ではlibffi
のPATH指定がうまくいかないという記述を見つけて、それっぽいissueを探してみる。
Failed to build gem native extension on macOS High Sierra · Issue #653 · ffi/ffi
ちょっとバージョンなどは古いけどこの辺が一番近そう。 さらにREADMEもおさらいしてみる。
When installing the gem on CRuby (MRI), you will need:
A C compiler (e.g., Xcode on macOS, gcc or clang on everything else) Optionally (speeds up installation):
The libffi library and development headers - this is commonly in the libffi-dev or libffi-devel packages
The ffi gem comes with a builtin libffi version, which is used, when the system libffi library is not available or too old.
自分のHomebrewにlibffi
が入ってるか確認してみる
❯❯❯ % brew list [...] docker-machine git libffi luajit pcre2 ruby [...]
入ってるやんけ。(自分は入れた覚えがない)
macOSのコンパイラー使わせるようにしたかったらlibffi
邪魔かもしれないと思ってuninstallしようとしてみると
❯❯❯ % brew uninstall libffi ✘ 1 Error: Refusing to uninstall /usr/local/Cellar/libffi/3.3_2 because it is required by cairo, fontforge, glib, gobject-introspection, graphviz, gts, harfbuzz and pango, which are currently installed. You can override this and force removal with: brew uninstall --ignore-dependencies libffi
えぇぇ(;´Д`)
とりあえず依存を無視してuninstallしてみる
❯❯❯ % brew uninstall --ignore-dependencies libffi ✘ 1 Uninstalling /usr/local/Cellar/libffi/3.3_2... (17 files, 540.5KB) libffi 3.3 is still installed. Run `brew uninstall --force libffi` to remove all versions. ❯❯❯ % brew uninstall --force libffi Uninstalling libffi... (16 files, 489.5KB)
これでbundle install
したらいけるかな
❯❯❯ % bundle install Fetching gem metadata from https://rubygems.org/............ Fetching gem metadata from https://rubygems.org/. [...] Using middleman-cli 4.3.11 Installing ffi 1.14.2 with native extensions Gem::Ext::BuildError: ERROR: Failed to build gem native extension. current directory: /Users/ksm/dev/odde/vendor/bundle/ruby/3.0.0/gems/ffi-1.14.2/ext/ffi_c /Users/ksm/.rbenv/versions/3.0.0/bin/ruby -I /Users/ksm/.rbenv/versions/3.0.0/lib/ruby/3.0.0 -r ./siteconf20210205-2342-l0vi57.rb extconf.rb checking for ffi_prep_closure_loc() in -lffi... yes checking for ffi_prep_cif_var()... yes checking for ffi_raw_call()... yes checking for ffi_prep_raw_closure()... yes creating extconf.h creating Makefile current directory: /Users/ksm/dev/odde/vendor/bundle/ruby/3.0.0/gems/ffi-1.14.2/ext/ffi_c make "DESTDIR=" clean current directory: /Users/ksm/dev/odde/vendor/bundle/ruby/3.0.0/gems/ffi-1.14.2/ext/ffi_c make "DESTDIR=" compiling AbstractMemory.c compiling ArrayType.c compiling Buffer.c compiling Call.c compiling ClosurePool.c compiling DynamicLibrary.c compiling Function.c Function.c:847:17: error: implicit declaration of function 'ffi_prep_closure_loc' is invalid in C99 [-Werror,-Wimplicit-function-declaration] ffiStatus = ffi_prep_closure_loc(closure->pcl, &fnInfo->ffi_cif, callback_invoke, closure, code); ^ Function.c:847:17: note: did you mean 'ffi_prep_closure'? /Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/include/ffi/ffi.h:269:1: note: 'ffi_prep_closure' declared here ffi_prep_closure( ^ 1 error generated. make: *** [Function.o] Error 1 make failed, exit code 2
マジか………死にたくなるな……(ぐったり)
libffi
を使ってコンパイルするようにする
READMEにもThe libffi library and development headers
が必要と書いてあるので、libffi
を再インストールします。
❯❯❯ % brew install libffi Updating Homebrew... ==> Auto-updated Homebrew! Updated 7 taps (puma/puma, homebrew/cask-versions, homebrew/core, homebrew/cask, homebrew/bundle, homebrew/services and rcmdnk/file). ==> New Formulae aliddns cloudflare-wrangler dasel libprelude msc-generator parliament ansible@2.9 coin3d grokmirror luv nuclei truffle cherrytree cpplint htmltest mpdecimal osmcoastline vitess ==> Updated Formulae Updated 4949 formulae. ==> Renamed Formulae glibmm@2.64 -> glibmm@2.66 pangomm@2.42 -> pangomm@2.46 ==> New Casks brewlet duckstation pathephone signet wolfram-engine decloner gdat pokemon-trading-card-game-online slippi-dolphin xcodes deskreen kieler prezi-video spotter yesplaymusic digital mathinspector sengi vine-server zy-player ==> Updated Casks Updated 667 casks. ==> Deleted Casks archi barxtemp oni project-slippi-dolphin ==> Downloading https://homebrew.bintray.com/bottles/libffi-3.3_2.catalina.bottle.tar.gz Already downloaded: /Users/ksm/Library/Caches/Homebrew/downloads/a70dda64619e2cda8bf245943e01e373ef2201564554472c957b150050571f65--libffi-3.3_2.catalina.bottle.tar.gz ==> Pouring libffi-3.3_2.catalina.bottle.tar.gz ==> Caveats libffi is keg-only, which means it was not symlinked into /usr/local, because macOS already provides this software and installing another version in parallel can cause all kinds of trouble. [...] ==> Pouring pango-1.48.1.catalina.bottle.tar.gz 🍺 /usr/local/Cellar/pango/1.48.1: 64 files, 3MB Removing: /usr/local/Cellar/pango/1.48.0... (64 files, 3MB) Removing: /Users/ksm/Library/Caches/Homebrew/pango--1.48.0.catalina.bottle.tar.gz... (733.4KB) ==> Checking for dependents of upgraded formulae... ==> No broken dependents found! ==> Caveats ==> libffi libffi is keg-only, which means it was not symlinked into /usr/local, because macOS already provides this software and installing another version in parallel can cause all kinds of trouble. For compilers to find libffi you may need to set: export LDFLAGS="-L/usr/local/opt/libffi/lib" export CPPFLAGS="-I/usr/local/opt/libffi/include" For pkg-config to find libffi you may need to set: export PKG_CONFIG_PATH="/usr/local/opt/libffi/lib/pkgconfig" ==> python@3.9 Python has been installed as /usr/local/bin/python3 Unversioned symlinks `python`, `python-config`, `pip` etc. pointing to `python3`, `python3-config`, `pip3` etc., respectively, have been installed into /usr/local/opt/python@3.9/libexec/bin You can install Python packages with pip3 install <package> They will install into the site-package directory /usr/local/lib/python3.9/site-packages See: https://docs.brew.sh/Homebrew-and-Python
For compilers to find libffi you may need to set
とFor pkg-config to find libffi you may need to set
と書いてあるところがあるので、
.zshrc
にPATHの設定を追加する
# Load path libffi with Homebrew export LDFLAGS="-L/usr/local/opt/libffi/lib" export CPPFLAGS="-I/usr/local/opt/libffi/include" export PKG_CONFIG_PATH="/usr/local/opt/libffi/lib/pkgconfig"
$SHELL -l
で再起動して、bundle install
してみる
❯❯❯ % bundle install Fetching gem metadata from https://rubygems.org/............ Fetching gem metadata from https://rubygems.org/. Resolving dependencies... Using concurrent-ruby 1.1.8 Using minitest 5.14.3 Using thread_safe 0.3.6 Using public_suffix 4.0.6 Using backports 3.20.2 Using bundler 2.2.3 Using coffee-script-source 1.12.2 Using execjs 2.7.0 Using contracts 0.13.0 Using erubis 2.7.0 Using fastimage 2.2.2 Using tilt 2.0.10 Using hashie 3.6.0 Using rb-fsevent 0.10.4 Using memoist 0.16.2 Using thor 1.1.0 Using parallel 1.20.1 Using rack 2.2.3 Using servolux 0.13.0 Using i18n 0.9.5 Fetching ffi 1.14.2 Using temple 0.8.2 Using dotenv 2.7.6 Using fast_blank 1.0.0 Using rexml 3.2.4 Using uglifier 3.2.0 Using middleman-cli 4.3.11 Using tzinfo 1.2.9 Using haml 5.2.1 Using activesupport 5.2.4.4 Using coffee-script 2.4.1 Using padrino-support 0.13.3.4 Using hamster 3.0.0 Using padrino-helpers 0.13.3.4 Using addressable 2.7.0 Using kramdown 2.3.0 Installing ffi 1.14.2 with native extensions Fetching sassc 2.4.0 Fetching rb-inotify 0.10.1 Installing rb-inotify 0.10.1 Installing sassc 2.4.0 with native extensions Fetching listen 3.0.8 Installing listen 3.0.8 Fetching middleman-core 4.3.11 Installing middleman-core 4.3.11 Fetching middleman 4.3.11 Installing middleman 4.3.11 Bundle complete! 1 Gemfile dependency, 41 gems now installed. Bundled gems are installed into `./vendor/bundle`
やっとできた………。お疲れ様だ、俺ちゃん。