hotoolong's blog

プログラムのことやエンジニアリングに関することを記事にしています。

brewのformulaアップグレード時の依存関係のアップグレードによる弊害に対応する

イントロ

googlerをアップグレードしたところopensslのバージョンがあがって
他のツールが壊れてしまったのを戻す作業をした履歴です。
困ってる人の役に当てればと思います。

エラーと調査

ことの始まりは

$ brew upgrade googler

googlerの新しいバージョンがでてるからupgradeしました。

==> Upgrading 1 outdated package:
googler 3.7.1 -> 4.0_1
==> Upgrading googler 3.7.1 -> 4.0_1
==> Installing dependencies for googler: openssl@1.1, xz and python@3.8
==> Installing googler dependency: openssl@1.1
==> Downloading https://homebrew.bintray.com/bottles/openssl@1.1-1.1.1f.mojave.bottle.tar.gz
==> Downloading from https://akamai.bintray.com/25/25ab844d2f14fc85c7f52958b4b89bdd2965bbd9c557445829eff6473f238744?__gda__=exp=1586836802~hmac=b9c5e50d09
6a9d953daac8c75
######################################################################## 100.0%
==> Pouring openssl@1.1-1.1.1f.mojave.bottle.tar.gz
==> Caveats
A CA file has been bootstrapped using certificates from the system
keychain. To add additional certificates, place .pem files in
  /usr/local/etc/openssl@1.1/certs

and run
  /usr/local/opt/openssl@1.1/bin/c_rehash

openssl@1.1 is keg-only, which means it was not symlinked into /usr/local,
because macOS provides LibreSSL.

If you need to have openssl@1.1 first in your PATH run:
  echo 'set -g fish_user_paths "/usr/local/opt/openssl@1.1/bin" $fish_user_paths' >> ~/.config/fish/config.fish

For compilers to find openssl@1.1 you may need to set:
  set -gx LDFLAGS "-L/usr/local/opt/openssl@1.1/lib"
  set -gx CPPFLAGS "-I/usr/local/opt/openssl@1.1/include"

For pkg-config to find openssl@1.1 you may need to set:
  set -gx PKG_CONFIG_PATH "/usr/local/opt/openssl@1.1/lib/pkgconfig"

==> Summary
🍺  /usr/local/Cellar/openssl@1.1/1.1.1f: 8,057 files, 18MB
==> Installing googler dependency: xz
==> Downloading https://homebrew.bintray.com/bottles/xz-5.2.5.mojave.bottle.tar.gz
==> Downloading from https://akamai.bintray.com/44/44483961b5d2b535b0ece1936c9d40b4bc7d9c7281646cca0fb476291ab9d4dc?__gda__=exp=1586836818~hmac=45f8f52462
3d23ee5d13f2dad
######################################################################## 100.0%
==> Pouring xz-5.2.5.mojave.bottle.tar.gz
🍺  /usr/local/Cellar/xz/5.2.5: 92 files, 1.1MB
==> Installing googler dependency: python@3.8
==> Downloading https://homebrew.bintray.com/bottles/python@3.8-3.8.2.mojave.bottle.tar.gz
==> Downloading from https://akamai.bintray.com/51/511b4f2c3993f000516938ed0700936c8a7d8c054b5171fa733ac7d344291c30?__gda__=exp=1586836821~hmac=0271b874c6
5db4ee2c7f66f1d
######################################################################## 100.0%
==> Pouring python@3.8-3.8.2.mojave.bottle.tar.gz
==> /usr/local/Cellar/python@3.8/3.8.2/bin/python3 -s setup.py --no-user-cfg install --force --verbose --install-scripts=/usr/local/Cellar/python@3.8/3.8.
2/bin --install
==> /usr/local/Cellar/python@3.8/3.8.2/bin/python3 -s setup.py --no-user-cfg install --force --verbose --install-scripts=/usr/local/Cellar/python@3.8/3.8.
2/bin --install
==> /usr/local/Cellar/python@3.8/3.8.2/bin/python3 -s setup.py --no-user-cfg install --force --verbose --install-scripts=/usr/local/Cellar/python@3.8/3.8.
2/bin --install
==> Caveats
Python has been installed as
  /usr/local/opt/python@3.8/bin/python3

You can install Python packages with
  /usr/local/opt/python@3.8/bin/pip3 install <package>
They will install into the site-package directory
  /usr/local/opt/python@3.8/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages

brew upgrade すると
dependencyになっている formula がアップグレードされます。
openssl も バージョンアップされてしまいます。
以前もこの問題で python がアップグレードしてパスが変更されてしまいいろいろ動作できないソフトがあって困ったことがありました。

今回も気づかず
暫くして
rails cをしてみたところ以下のようなエラーに

$ rails c 
/rails_project/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.4.6/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `requir
e': dlopen(/rails_project/vendor/bundle/ruby/2.7.0/gems/mysql2-0.5.3/lib/mysql2/mysql2.bundle, 9): Library not loaded: /usr/local
/opt/openssl/lib/libssl.1.0.0.dylib (LoadError)
  Referenced from: /rails_project/vendor/bundle/ruby/2.7.0/gems/mysql2-0.5.3/lib/mysql2/mysql2.bundle
  Reason: image not found - /rails_project/vendor/bundle/ruby/2.7.0/gems/mysql2-0.5.3/lib/mysql2/mysql2.bundle

あれ?
起動しない

LoadErrorになっている。
opensslのライブラリが参照できなくなっている

opensslのバージョンが上がっていることに気づく

エラー内容をGoogleで調べているとライブラリを読み込ませると動く模様

mysql2をインストールしたときに参照しているopensslを参照できないようなので

一旦mysql2は削除して入れ直すことに

$ brew info openssl

を確認すると

  set -gx LDFLAGS "-L/usr/local/opt/openssl@1.1/lib"
  set -gx CPPFLAGS "-I/usr/local/opt/openssl@1.1/include"

とあり、ライブラリのパスが確認できます。

bindle 時に利用できるように以下のように config に設定します。

$ bundle config --local build.mysql2 "--with-ldflags=-L/usr/local/opt/openssl@1.1/lib"

mysql2を入れ直すためアンインストールします。

$ bundle exec gem uninstall mysql2

再度インストール

$ bundle install

起動してみます。

$ rails c

インストール時にはライブラリを参照してくれてそうだけどエラーは解消しませんでした。

/rails_project/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.4.6/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `requir
e': dlopen(/rails_project/vendor/bundle/ruby/2.7.0/gems/mysql2-0.5.3/lib/mysql2/mysql2.bundle, 9): Library not loaded: /usr/local/opt/openssl/lib/libssl.1.0.0.dylib (LoadError)
  Referenced from: /usr/local/opt/mysql/lib/libmysqlclient.20.dylib
  Reason: image not found - /rails_project/vendor/bundle/ruby/2.7.0/gems/mysql2-0.5.3/lib/mysql2/mysql2.bundle

rails cでライブラリの古い方を見てしまうようです。
PATHなどを確認して古いopensslのライブラリを参照しないようにしてますが
いろいろ調べてるがこれ以上はわからない状態でした。

opensslのインストール先を確認

$ brew --prefix openssl
/usr/local/opt/openssl@1.1

PATHに古いopensslが残っていて古いバージョンを参照していました。

$ which openssl
/usr/local/opt/openssl/bin/openssl

PATHの設定を見直して新しいバージョンを参照させて、再度bundleしなおしても駄目でした。

お手上げ感があったのですが、
mysql2.bundleがイマイチよくわかっておらず調べていると

qastack.jp

どうもmysql自体のインストール時に参照するライブラリを決め打ちしてそうということがわかり

一旦mysqlを停止してみました。

$ sudo mysql.server stop
Password:
dyld: Library not loaded: /usr/local/opt/openssl/lib/libssl.1.0.0.dylib
  Referenced from: /usr/local/Cellar/mysql/5.7.17/bin/my_print_defaults
  Reason: image not found
Shutting down MySQL
... SUCCESS!

あら、rails c したときと同じようなエラーが、、、

起動もできなくなったので、
opensslのバージョンを戻すことに

brew で uninstall すると 依存関係のあるformulaが多いので怒られるが
--ignore-dependenciesをつけるとアンインストールできます。

$ brew uninstall --ignore-dependencies openssl
Uninstalling /usr/local/Cellar/openssl@1.1/1.1.1f... (8,057 files, 18MB)

古いopensslのライブラリをインストールする

$ brew install https://github.com/tebelorg/Tump/releases/download/v1.0.0/openssl.rb
Updating Homebrew...

これで1.0.2tがインストールされた。
(他のやりかたでインストールできるかもしれないが調べきれてない。)

mysqlを起動してみる

$ sudo mysql.server start 

Starting MySQL
.. SUCCESS!

起動できた!

bundle configの内容をバージョンダウンしたopensslに合わせる(戻す)

$ bundle config --local build.mysql2 "--with-ldflags=-L/usr/local/opt/openssl/lib"

再度mysql2を入れ直す

$ bundle exec gem uninstall mysql2
$ bundle install

まとめ

結局opensslのバージョンを一旦戻すことにした。
おそくらbrew upgrade で影響のある formula を上げていけばいいのだが、
上げたくないものもあるので、悩ましいところ。

brew で formula の依存関係を確認することができる。
brew deps コマンドが使える
今回のgooglerの場合だと以下の通り

$ brew deps --tree googler
googler
└── python@3.8
    ├── gdbm
    ├── openssl@1.1
    ├── readline
    ├── sqlite
    │   └── readline
    └── xz

ということで python経由でopensslのバージョンアップがされてしまったと気付ける。

逆にopensslがどのformulaが利用してるかというと以下のように uses オプションが使える。

$ brew uses --installed  openssl
asdf                  glib                  imagemagick           mysql                 python@3.8            shared-mime-info      vim
docutils              gnupg                 libevent              poco                  rbenv                 tmux
erlang                gnutls                libheif               python                ruby                  unbound

またautoupgradeさせない方法もあった。

$ brew pin openssl

というようにするとバージョンが固定されるようです。 解除するには

$ brew unpin openssl

とすると解除できます。
積極的に活用しようと思います。