Installing mysql2 Ruby gem on MacOS

The other day I was installing mysql2 gem on macOS for Ruby 2.6.2, something that was supposed to be quite a simple thing. I knew I would most likely have some trouble with compiling its native extension, but that usually and rather unglamorously boils down to finding the correct MySQL development libraries. However, there were unexpected twists and turns that motivated me for this writeup.

Installing mysql2 gem

$ asdf shell ruby 2.6.2
$ gem install mysql2
Building native extensions. This could take a while...
ERROR:  Error installing mysql2:
	ERROR: Failed to build gem native extension.
...
mysql client is missing. You may need to 'brew install mysql' or 'port install mysql', and try again.
...

Ok, so gem’s build script is politely telling me that I need to do first install MySQL using the Homebrew package manager. Since I don’t need the whole database server but only some development libraries (will be using MySQL from a Docker container), I tried installing the usual mysql-devel.

$ brew install mysql-devel
...
Error: No available formula with the name "mysql-devel"

After some googling, I figured MySQL client library is available at this mysql.com page i.e. there’s a homebrew formula called mysql-connector-c.

$ brew install mysql-connector-c
...
🍺 /usr/local/Cellar/mysql-connector-c/6.1.11: 79 files, 15.3MB
$ gem install mysql2
Building native extensions. This could take a while...
ERROR:  Error installing mysql2:
	ERROR: Failed to build gem native extension.
...
compiling statement.c
linking shared-object mysql2/mysql2.bundle
ld: library not found for -l-Wno-atomic-implicit-seq-cst
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [mysql2.bundle] Error 1

make failed, exit code 2

Dafuq?!

Linker trouble

Linker coldly reported library not found error so I had to take a bit longer look at the build log. Finally managed to found one rather interesting line more towards the beginning of it: Using mysql_config at /usr/local/bin/mysql_config.

After some reading how mysql2 gem builds its native extension and checking the content of mentioned mysql_config script, I suspected something might be wrong there - library called “-l-Wno-atomic-implicit-seq-cst” just didn’t make any sense.

Broken mysql_config

A more detailed look at that config script revealed the culprit:

# /usr/local/bin/mysql_config
...
# Create options 
libs="-L$pkglibdir"
libs="$libs -l "
embedded_libs="-L$pkglibdir"
embedded_libs="$embedded_libs -l "
...

Lines with libs and embedded_libs contained errors - they were cut off after the -l parameter. I quickly tracked the error to the https://dev.mysql.com/downloads/connector/c repository where the problematic file was present as well. The homebrew’s formula was simply fetching the package from that location without trying to fix the problem. This is how these lines were supposed to look like:

# Create options 
libs="-L$pkglibdir"
libs="$libs -lmysqlclient -lcrypto -lssl"
embedded_libs="-L$pkglibdir"
embedded_libs="$embedded_libs -lmysqlclient -lcrypto -lssl"

Almost done

Trying to install the gem now, ends up with yet another error:

$ gem install mysql2
...
ld: library not found for -lcrypto

This one is easy. We just need to give instructions to the linker where to find the necessary libcrypto (part of the openssl).

$ brew install openssl # if you haven't done that already
$ gem install mysql2 -- --with-ldflags=-L/usr/local/opt/openssl/lib

Alternative solution (TL;DR)

Another solution that doesn’t require fixing the mysql_config is providing all folders to the native extension’s build process via the command line. mysql2gem will then use those settings and not the ones provided by the mysql_config script:

$ gem install mysql2 -- \
  --with-ldflags=-L/usr/local/opt/openssl/lib \
                 -L/usr/local/opt/mysql-connector-c/lib -lmysqlclient -lcrypto -lssl \
  --with-cppflags=-I/usr/local/opt/mysql-connector-c/include

563 Words

2019-05-19 20:19 +0300

comments powered by Disqus