経緯
ローカルのRubyバージョンを2.5.1から2.5.3にアップデートしたので、Railsアプリケーションのgemもアップデートした際、mysql2 gemのインストールでエラーが発生。
そのときのトラブルシュートの内容をまとめます。
エラーメッセージ
Fetching mysql2 0.5.2
Installing mysql2 0.5.2 with native extensions
Gem::Ext::BuildError: ERROR: Failed to build gem native extension.
current directory: /Users/name/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/mysql2-0.5.2/ext/mysql2
/Users/name/.rbenv/versions/2.5.3/bin/ruby -r ./siteconf20181128-2670-lgcxlu.rb extconf.rb
checking for rb_absint_size()... yes
checking for rb_absint_singlebit_p()... yes
checking for rb_wait_for_single_fd()... yes
-----
Using mysql_config at /usr/local/bin/mysql_config
-----
checking for mysql.h... yes
checking for errmsg.h... yes
checking for SSL_MODE_DISABLED in mysql.h... yes
checking for SSL_MODE_PREFERRED in mysql.h... yes
checking for SSL_MODE_REQUIRED in mysql.h... yes
checking for SSL_MODE_VERIFY_CA in mysql.h... yes
checking for SSL_MODE_VERIFY_IDENTITY in mysql.h... yes
checking for MYSQL.net.vio in mysql.h... yes
checking for MYSQL.net.pvio in mysql.h... no
checking for MYSQL_ENABLE_CLEARTEXT_PLUGIN in mysql.h... yes
checking for SERVER_QUERY_NO_GOOD_INDEX_USED in mysql.h... yes
checking for SERVER_QUERY_NO_INDEX_USED in mysql.h... yes
checking for SERVER_QUERY_WAS_SLOW in mysql.h... yes
checking for MYSQL_OPTION_MULTI_STATEMENTS_ON in mysql.h... yes
checking for MYSQL_OPTION_MULTI_STATEMENTS_OFF in mysql.h... yes
checking for my_bool in mysql.h... no
-----
Dont know how to set rpath on your system, if MySQL libraries are not in path mysql2 may not load
-----
-----
Setting libpath to /usr/local/Cellar/mysql/8.0.12/lib
-----
creating Makefile
current directory: /Users/name/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/mysql2-0.5.2/ext/mysql2
make "DESTDIR=" clean
current directory: /Users/name/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/mysql2-0.5.2/ext/mysql2
make "DESTDIR="
compiling client.c
compiling infile.c
compiling mysql2_ext.c
compiling result.c
compiling statement.c
linking shared-object mysql2/mysql2.bundle
ld: library not found for -lssl
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [mysql2.bundle] Error 1
make failed, exit code 2
Gem files will remain installed in /Users/name/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/mysql2-0.5.2 for inspection.
Results logged to /Users/name/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/extensions/x86_64-darwin-18/2.5.0-static/mysql2-0.5.2/gem_make.out
An error occurred while installing mysql2 (0.5.2), and Bundler cannot continue.
Make sure that `gem install mysql2 -v '0.5.2' --source 'https://rubygems.org/'` succeeds before bundling.
In Gemfile:
mysql2
エラーの内容
ld: library not found for -lssl
mysqlさんがlibssl.dylibを見つけられないと言って止まってしまいました。
原因調査
そもそもld
って?
まず、ld
はGNUリンカーと呼ばれるコマンドです。
$ man ld
ld(1) BSD General Commands Manual ld(1)
NAME
ld -- linker
SYNOPSIS
ld files... [options] [-o outputfile]
DESCRIPTION
The ld command combines several object files and libraries, resolves references, and produces an ouput file. ld can produce a final
linked image (executable, dylib, or bundle), or with the -r option, produce another object file. If the -o option is not used, the out-
put file produced is named "a.out".
-lssl
ってなに?
続いて、-lssl
とは、mysql2 gemインストール時にld
コマンドに与えられたオプションの一つです。
-lx This option tells the linker to search for libx.dylib or libx.a in the library search path. If string x is of the form y.o,
then that file is searched for in the same places, but without prepending `lib' or appending `.a' or `.dylib' to the file-
name.
つまり、mysql2 gemはlibssl.dylib
をライブラリ検索範囲から探してね、と指示している訳です。
ただし、エラーメッセージ内ではライブラリ検索パスを以下のように設定したと言っています。
Setting libpath to /usr/local/Cellar/mysql/8.0.12/lib
推定原因は?
実際に覗いてみると、お目当てのlibssl.dylib
がありません。こちらが原因と推定。
$ ll /usr/local/Cellar/mysql/8.0.12/lib
total 22408
-rw-r--r-- 1 name staff 5418880 11 27 08:46 libmysqlclient.21.dylib
-r--r--r-- 1 name staff 6038096 6 29 01:42 libmysqlclient.a
lrwxr-xr-x 1 name staff 23 6 29 01:42 libmysqlclient.dylib@ -> libmysqlclient.21.dylib
-r--r--r-- 1 name staff 9760 6 29 01:42 libmysqlservices.a
drwxr-xr-x 3 name staff 96 11 27 08:46 pkgconfig/
drwxr-xr-x 93 name staff 2976 6 29 01:42 plugin/
gem install
を掘り下げる
bundle install
を実行すると、gem間の依存関係を見ながらgem install
してくれるので、rubygems
ライブラリを見てみると、該当のエラーメッセージを発見。
def build_error(build_dir, output, backtrace = nil) # :nodoc:
gem_make_out = write_gem_make_out output
message = <<-EOF
ERROR: Failed to build gem native extension.
#{output}
Gem files will remain installed in #{@gem_dir} for inspection.
Results logged to #{gem_make_out}
EOF
raise Gem::Ext::BuildError, message, backtrace
end
このソースを追っていくと、ここで例外が発生した模様。
results = builder.build(extension, dest_path, results, @build_args, lib_dir)
これをもっと追っていくと、(中略)、buildオプションを指定すべきだったと分かります。
gem install
のマニュアルを見ると、確かにbuild-flags
なるものを指定できるとのこと。
ヒントになる記事を見つけたので、こちらを参考にすると、次の2つのオプションを指定すれば良いのでは?との結論に至ります。
https://stackoverflow.com/questions/51264240/rake-dbmigrate-error-with-mysql2-gem-library-not-loaded-libssl-1-0-0-dylib/51269245
- --with-cppflags
- --with-ldflags
対応策
ライブラリの場所を指定してgemをインストールできればいいですね。
$ brew info openssl
openssl: stable 1.0.2q (bottled) [keg-only]
SSL/TLS cryptography library
https://openssl.org/
/usr/local/Cellar/openssl/1.0.2n (1,792 files, 12.3MB)
Poured from bottle on 2018-03-03 at 15:08:02
/usr/local/Cellar/openssl/1.0.2o_1 (1,791 files, 12.3MB)
Poured from bottle on 2018-04-13 at 19:55:14
/usr/local/Cellar/openssl/1.0.2q (1,794 files, 12.1MB)
Poured from bottle on 2018-11-27 at 08:35:34
From: https://github.com/Homebrew/homebrew-core/blob/master/Formula/openssl.rb
==> Caveats
A CA file has been bootstrapped using certificates from the SystemRoots
keychain. To add additional certificates (e.g. the certificates added in
the System keychain), place .pem files in
/usr/local/etc/openssl/certs
and run
/usr/local/opt/openssl/bin/c_rehash
openssl is keg-only, which means it was not symlinked into /usr/local,
because Apple has deprecated use of OpenSSL in favor of its own TLS and crypto libraries.
If you need to have openssl first in your PATH run:
echo 'export PATH="/usr/local/opt/openssl/bin:$PATH"' >> ~/.bash_profile
For compilers to find openssl you may need to set:
export LDFLAGS="-L/usr/local/opt/openssl/lib"
export CPPFLAGS="-I/usr/local/opt/openssl/include"
For pkg-config to find openssl you may need to set:
export PKG_CONFIG_PATH="/usr/local/opt/openssl/lib/pkgconfig"
==> Analytics
install: 462,158 (30 days), 1,437,603 (90 days), 5,873,213 (365 days)
install_on_request: 61,379 (30 days), 190,015 (90 days), 782,106 (365 days)
build_error: 0 (30 days)
export LDFLAGS="-L/usr/local/opt/openssl/lib"
export CPPFLAGS="-I/usr/local/opt/openssl/include"
よって、以下を実行して解決。
$ gem install mysql2 -v '0.5.2' --source 'https://rubygems.org/' -- --with-cppflags=-I/usr/local/opt/openssl/include --with-ldflags=-L/usr/local/opt/openssl/lib
Building native extensions with: '--with-cppflags=-I/usr/local/opt/openssl/include --with-ldflags=-L/usr/local/opt/openssl/lib'
This could take a while...
Successfully installed mysql2-0.5.2
Parsing documentation for mysql2-0.5.2
Installing ri documentation for mysql2-0.5.2
Done installing documentation for mysql2 after 0 seconds
1 gem installed
めでたし。
毎回こんなオプションはつらい
という方はこちらもどうぞ。