Edited at

mysql2 gemインストール時のトラブルシュート


経緯

ローカルのRubyバージョンを2.5.1から2.5.3にアップデートしたので、Railsアプリケーションのgemもアップデートした際、mysql2 gemのインストールでエラーが発生。

そのときのトラブルシュートの内容をまとめます。


エラーメッセージ


terminal

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リンカーと呼ばれるコマンドです。


ldのmanページ

$ 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コマンドに与えられたオプションの一つです。


-lオプション

     -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がありません。こちらが原因と推定。


/usr/local/Cellar/mysql/8.0.12/lib

$ 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ライブラリを見てみると、該当のエラーメッセージを発見。


ruby/lib/rubygems/ext/builder.rb

  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


https://github.com/ruby/ruby/blob/trunk/lib/rubygems/ext/builder.rb#L145

このソースを追っていくと、ここで例外が発生した模様。


build_extension

results = builder.build(extension, dest_path, results, @build_args, lib_dir)


https://github.com/ruby/ruby/blob/trunk/lib/rubygems/ext/builder.rb#L185-L186

これをもっと追っていくと、(中略)、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をインストールできればいいですね。


terminal

$ 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)



buildオプションの値

  export LDFLAGS="-L/usr/local/opt/openssl/lib"

export CPPFLAGS="-I/usr/local/opt/openssl/include"

よって、以下を実行して解決。


terminal

$ 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

めでたし。


毎回こんなオプションはつらい

という方はこちらもどうぞ。

https://qiita.com/thunders/items/101c6b329830fb1fb27d