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 less than a walk in the park. I knew I would most likely have some hiccups when compiling gem’s native extension, but that usually and rather unglamorously boils down to finding the correct MySQL dev libraries. However, there were unexpected twists and turns.

Installing the 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 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 the MySQL client library was available at this mysql.com page. Luckily, there’s already a ready-made homebrew formula 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 - linker command “-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 (homebrew’s formula pulls package from there). After some tinkering, I managed to produce the correct version of the mysql_config file.:

# 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 command. 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

comments powered by Disqus