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
$ 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
$ 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
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.
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 " ...
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"
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
$ 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
$ 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