[Mac]dyld: Library not loadedでPostgreSQL起動せず

ローカルPCとして使っているMacBook ProでRedmineを使うためにPostgreSQLを起動しようとしたところ、`dyld: Library not loaded`というエラーメッセージが表示されて起動できなかったので対策しました。

## 対策の流れ
以下の手順で対策を行いました。

1. `brew upgrade`でPostgreSQLをアップグレード
2. `brew postgresql-upgrade-database`でアップグレード前のPostgreSQLデータベースをアップグレード後のバージョンに対応できるようマイグレーション
3. （`brew upgrade`の副作用に対する対策）`/Users/XXXX/.rbenv/shims/rails`に記載の`rbenv`のバージョンを修正

1.と2.の対策でPostgreSQLは無事に起動するようになりました。
`brew upgrade`でPostgreSQLをアップグレードした際に一緒に`rbenv`までアップグレードされたので、Redmineを起動するためには3.の対策が必要となりました。

以下に詳細な検討結果を記載します。

## 不具合発生状況
Redmineを使うために、データベースとして使っているPostgreSQLを起動しようとしたところ、以下のエラーが発生して起動できませんでした。

```c
$ postgres -D /usr/local/var/postgres/
dyld: Library not loaded: /usr/local/opt/icu4c/lib/libicui18n.62.dylib
  Referenced from: /usr/local/bin/postgres
  Reason: image not found
Abort trap: 6
```

## 原因
**Dynamic Loader**と呼ばれる、共有ライブラリをロードしたりリンクしたりするためのファイル`dyld`が（気が付かないうちに）アップデートされていて、ファイル名が変わっていたことが原因でした。
おそらく最近何度か実施していたmacOSのシステムアップデートの際に置き換わったのだと思います。

`dyld: Library not loaded`というエラーメッセージが示すファイル`libicui18n.62.dylib`のディレクトリを見てみると、以下のようにファイル名が`libicui18n.62.dylib`から`libicui18n.63.dylib`のように変わっていました。

```c
$ ls /usr/local/opt/icu4c/lib/
icu			libicui18n.63.dylib	libicuio.dylib		libicutu.63.dylib	libicuuc.dylib
libicudata.63.1.dylib	libicui18n.a		libicutest.63.1.dylib	libicutu.a		pkgconfig
libicudata.63.dylib	libicui18n.dylib	libicutest.63.dylib	libicutu.dylib
libicudata.a		libicuio.63.1.dylib	libicutest.a		libicuuc.63.1.dylib
libicudata.dylib	libicuio.63.dylib	libicutest.dylib	libicuuc.63.dylib
libicui18n.63.1.dylib	libicuio.a		libicutu.63.1.dylib	libicuuc.a
```

PostgreSQLから`libicui18n.62.dylib`を参照しに行っている箇所を書き換えれば直るのでしょうが、ピンポイントにどこをどう書き換えるかわからなかったので、Homebrewを使ってPostgreSQLをまるごとアップグレードしてやることにしました。

## 対策1. `brew upgrade`でPostgreSQLをアップグレード
`brew upgrade`でアップグレードを試みました。

```c
$ brew upgrade
Updating Homebrew...
（以下、ログを抜粋）
==> Upgrading 15 outdated packages:
libtiff 4.0.9_4 -> 4.0.10_1, postgresql 10.5 -> 11.2, imagemagick@6 6.9.10-11_1 -> 6.9.10-27, libpng 1.6.35 -> 1.6.36, heroku/brew/heroku 7.19.4 -> 7.22.9, freetype 2.9.1 -> 2.10.0, redis 4.0.11 -> 5.0.4, readline 7.0.5 -> 8.0.0, ruby-build 20180822 -> 20190401, memcached 1.5.10 -> 1.5.12, heroku/brew/heroku-node 11.3.0 -> 11.10.1, node 11.12.0 -> 11.13.0, openssl 1.0.2p -> 1.0.2r, elasticsearch 6.2.4 -> 6.7.0, rbenv 1.1.1 -> 1.1.2

==> postgresql
To migrate existing data from a previous major version of PostgreSQL run:
  brew postgresql-upgrade-database

To have launchd start postgresql now and restart at login:
  brew services start postgresql
Or, if you dont want/need a background service you can just run:
  pg_ctl -D /usr/local/var/postgres start
```

PostgreSQLは**10.5**から**11.2**にアップグレードされました。
しかし、PostgreSQLを起動しようとすると、またしてもエラーが発生しました。

```c
$ pg_ctl -D /usr/local/var/postgres/ start
waiting for server to start....2019-04-09 10:55:56.386 JST [24116] FATAL:  database files are incompatible with server
2019-04-09 10:55:56.386 JST [24116] DETAIL:  The data directory was initialized by PostgreSQL version 10, which is not compatible with this version 11.2.
 stopped waiting
pg_ctl: could not start server
Examine the log output.
```

アップグレード前の10.5で初期化されたデータベースが、アップグレード後の11.2とコンパチではないとのこと。

## 対策2. `brew postgresql-upgrade-database`でアップグレード前のPostgreSQLデータベースをアップグレード後のバージョンに対応できるようマイグレーション
`brew upgrade`のときのログをよく読んでみると、前のメジャーバージョンからデータをマイグレーションするためのコマンドが示されていました。

> To migrate existing data from a previous major version of PostgreSQL run:
>  brew postgresql-upgrade-database

これをそのまま実行すると無事にマイグレーションされ、PostgreSQLが起動できるようになりました。

```c
$ brew postgresql-upgrade-database
$ postgres -D /usr/local/var/postgres/
```

これでPostgreSQLが起動しない問題については一件落着だったのですが、もともとやりたかったRedmineの起動を行ったところ、以下のエラーが発生してしまいました。

```ruby
$ RAILS_ENV=production rails s
/Users/XXXX/.rbenv/shims/rails: line 21: /usr/local/Cellar/rbenv/1.1.1/libexec/rbenv: No such file or directory
```

`rbenv`へのリンクがエラーの原因のようです。

## 対策3. （`brew upgrade`の副作用に対する対策）`/Users/XXXX/.rbenv/shims/rails`に記載の`rbenv`のバージョンを修正
これはさきほどの`brew upgrade`の副作用として、`rbenv`がアップグレードされたことに起因するエラーとなっています。
`brew upgrade`のときのログを再び見直してみると、`rbenv`が**1.1.1**から**1.1.2**に上がっていました。

```c
$ brew upgrade
Updating Homebrew...
（以下、ログを抜粋）
==> Upgrading rbenv
==> Downloading https://homebrew.bintray.com/bottles/rbenv-1.1.2.mojave.bottle.tar.gz
######################################################################## 100.0%
==> Pouring rbenv-1.1.2.mojave.bottle.tar.gz
🍺  /usr/local/Cellar/rbenv/1.1.2: 36 files, 65KB
Removing: /usr/local/Cellar/rbenv/1.1.1... (36 files, 62.7KB)
```

ログを見ると、すでに1.1.1は削除されています。
エラーメッセージからも明らかなように`/Users/XXXX/.rbenv/shims/rails`の21行目で参照している1.1.1を1.1.2に書き換えてやりました。

``` /Users/XXXX/.rbenv/shims/rails
exec "/usr/local/Cellar/rbenv/1.1.2/libexec/rbenv" exec "$program" "$@"
```

`echo`コマンドとかで書き換えるのが通例かもしれませんが、書き換わったことを確認したいのでvimで開いて直接編集しました。

これで無事に`rails s`でRedmineを起動することができ、最初の目的を達成することができました。

## 所感
環境構築に関する課題は、しばしばプログラミング以上に頭の痛い問題として立ちはだかってきますが、「ピンポイントに解決しようとするとドツボにはまりそうだからHomebrewにまかせてしまおう」とか、「素直にファイルを書き換えれば簡単に直りそう」とかいった判断の勘所を掴めるようになってきているようです。

今まではトラブルが発生すると思考停止して為すすべがなく、ひたすらググって途方に暮れていましたが、環境構築についても徐々に成長してきていることを実感して嬉しく思ったので記事にしてみました。