TL;DR: Below is a tragic story of a how I lost about 8 hours of my life because different gems were looking for different versions of openssl that weren't there. In the course of coming here to beg for help and writing up everything I tried I've managed to implement the hackiest fix imaginable, at which point I have to get back on with actual work. But this solution seems totally inadequate for reasons I outline below. So I'm asking: Is there a proper way of specifying system dependencies for a ruby gem?
====MY ORIGINAL PROBLEM===========
I rvm installed
ruby 2.6.0 over the weekend and for some reason this triggered homebrew to update openssl on my Mac to openssl@1.1. I now can't run my work's Rails app (running 5.1.7, ruby 2.4.0) because I get this error:
Roberts-MBP:website-upgrade Rob$ rails t
/Rob.rvm/gems/ruby-2.4.0/gems/mysql2-0.5.2/lib/mysql2.rb:33:in `require': dlopen(/Rob.rvm/gems/ruby-2.4.0/gems/mysql2-0.5.2/lib/mysql2/mysql2.bundle, 9): Library not loaded: /usr/local/opt/openssl/lib/libssl.1.0.0.dylib
Referenced from: /usr/local/opt/mysql/lib/libmysqlclient.20.dylib
Reason: image not found - /Rob.rvm/gems/ruby-2.4.0/gems/mysql2-0.5.2/lib/mysql2/mysql2.bundle (LoadError)
Basically the same error is described in this SO post:
rake db:migrate error with mysql2 gem - Library not loaded: libssl.1.0.0.dylib
Some solutions there suggest making symlinks to your installation of openSSL, or copying the files to where it wants them to be. This doesn't work for me; it seems that libraries of the old (1.0.x) and new (1.1) versions are incompatible.
Simply uninstalling and reinstalling the mysql gem leaves me with the same error. Following another suggestion from that post, I tried:
Roberts-MBP:website-upgrade Rob$ gem install mysql2 -- with-cppflags=-I/usr/local/opt/openssl@1.1/include --with-ldflags=-L/usr/local/opt/openssl@1.1/lib
Fetching: mysql2-0.5.3.gem (100%)
Building native extensions with: 'with-cppflags=-I/usr/local/opt/openssl@1.1/include --with-ldflags=-L/usr/local/opt/openssl@1.1/lib'
This could take a while...
Successfully installed mysql2-0.5.3
Parsing documentation for mysql2-0.5.3
Installing ri documentation for mysql2-0.5.3
Done installing documentation for mysql2 after 0 seconds
1 gem installed
Roberts-MBP:website-upgrade Rob$ rails t
Could not find mysql2-0.5.2 in any of the sources
Run `bundle install` to install missing gems.
Noticing that the mysql versions don't match here, I deleted my Gemfile.lock
and tried to run the tests again:
Roberts-MBP:website-upgrade Rob$ rails t
Roberts-MBP:website-upgrade Rob$ /Rob.rvm/gems/ruby-2.4.0/gems/mysql2-0.5.3/lib/mysql2.rb:36:in `require': dlopen(/Rob.rvm/gems/ruby-2.4.0/gems/mysql2-0.5.3/lib/mysql2/mysql2.bundle, 9): Library not loaded: /usr/local/opt/openssl/lib/libssl.1.0.0.dylib
Referenced from: /usr/local/opt/mysql/lib/libmysqlclient.20.dylib
Reason: image not found - /Rob.rvm/gems/ruby-2.4.0/gems/mysql2-0.5.3/lib/mysql2/mysql2.bundle (LoadError)
Wondering if the problem could be anything to do with bundler, I ran gem uninstall mysql2
, and checked that this actually deletes the directory /Rob.rvm/gems/ruby-2.4.0/gems/mysql2-0.5.3/
. Then tried, as per https://bundler.io/v2.0/man/bundle-config.1.html :
bundle config build.mysql2 --with-cppflags=-I/usr/local/opt/openssl@1.1/include --with-ldflags=-L/usr/local/opt/openssl@1.1/lib
bundle install
bundle exec rails t
But I still get the same error, which makes me wonder if this dependency on v.1.0 is hardcoded somehow.
I tried downgrading the openssl version. I tried to do this with homebrew and could only see the new version. I googled around and used the script from https://github.com/kelaberetiv/TagUI/issues/86 The result was that now spring complained that it can't find the library for openssl@1.1.
Roberts-MBP:website-upgrade Rob$ rails t
/Rob.rvm/gems/ruby-2.4.0/gems/spring-2.1.0/lib/spring/env.rb:3:in `require': dlopen(/Rob.rvm/rubies/ruby-2.4.0/lib/ruby/2.4.0/x86_64-darwin18/digest/md5.bundle, 9): Library not loaded: /usr/local/opt/openssl@1.1/lib/libcrypto.1.1.dylib (LoadError)
Referenced from: /Rob.rvm/rubies/ruby-2.4.0/lib/ruby/2.4.0/x86_64-darwin18/digest/md5.bundle
I ran brew install openssl
to reset.
======THE FIX==========================================
Trying to reproduce this last step this morning, however, I got a mess, and it was in disentangling this mess that I fixed my problem. I was getting messages like 1.0.2t is already installed
when I tried to run brew uninstall
. I updated my locate database and found that I actually had both 1.0.2 and @1.1 installed (presumably after trying this yesterday, but mysql2 was looking in the directory symlinked against @1.1. Changing the symlink to 1.0.2, I can now run my tests.
But this is awful. I have no way of knowing if some other gem is going to look in that symlink for v1.1. It feels like there should be a systematic way of specifying system dependencies of gems - either telling a gem which version to use, or at least a proper way of running multiple versions concurrently and telling a gem where to find the version it needs. How can I do this properly?
EDIT in response to comment: Here's my gemfile:
source 'https://rubygems.org'
ruby '2.4.0'
git_source(:github) do |repo_name|
repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/")
"https://github.com/#{repo_name}.git"
end
gem 'rails', '~> 5.1.2'
gem 'postmark-rails', '~> 0.15.0'
gem 'mysql2'
gem 'passenger', '= 5.1.5'
gem 'jbuilder', '~> 2.5'
gem 'jquery-rails'
gem 'figaro'
gem 'fastercsv', '~> 1.5', '>= 1.5.5'
gem 'jwt'
gem 'rack-cors'
gem 'rest-client'
gem 'sentry-raven'
gem 'activerecord-session_store'
gem 'timecop'
gem 'webpacker', '~> 3.5'
gem 'write_xlsx'
gem 'pry-rails'
gem 'ddtrace'
group :development, :test do
gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
gem 'capybara', '~> 2.13'
gem 'selenium-webdriver'
gem 'minitest', '5.10.3'
end
group :development do
gem 'web-console', '>= 3.3.0'
gem 'listen', '>= 3.0.5', '< 3.2'
gem 'spring'
gem 'spring-watcher-listen', '~> 2.0.0'
end
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]