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

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

More than 1 year has passed since last update.

経緯

ローカルの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

HrsUed
SIer→Web系エンジニア/温泉ソムリエ
innova-jp
コンテンツマーケティングに特化したクラウドサービスの開発・運営、および、コンテンツ制作管理システムを運営・開発している会社です。
http://innova-jp.com/
Why not register and get more from Qiita?
  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
No 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
ユーザーは見つかりませんでした