Tips

Homebrewの自動アップデートを止めよう!開発環境が壊れる前に

MacのソフトウェアをHomebrewで管理していて起きる問題の、最も多い原因は自動アップデートによるものだと感じます。問題の事例とその防止策である自動アップデートを止める方法をお伝えします。結論から知りたい方は、目次から「対処策」に飛んでください。これをしない場合、どんな目に合うかは全部をお読みになればご理解頂けます。

急にApacheが起動しなくなる

以下のようなエラーが出てApacheが起動しなくなりました。

詳しく知るためにhttpdコマンドも実行してみます。

いろんなことが書かれていますが、一番目につくのはこれ

/opt/homebrew/lib/httpd/modules/ にあったはずの、 libphp7.3.33.so が消えてるんです。

なんでだろうとかなり考えました。Symlinkが何かのきっかけで消えてしまったのだろうかなどと。

しかし、最近やったことを思い出してようやく原因と思しきことに至りました。

ちょっと前に、JavaをHomebrewでインストールしたんですよね。その際に、Updateが走って、色々なソフトウェアがアップデートされていました。

あぁ、Apacheもバージョンが上がったのかな、と思ってFormulaを確認してみました。

gitのログを確認しても、最近の更新は無いんですよね。なんでだろうと思いました。

Javaをインストールした時のターミナルの出力をもう一度確認したところ、以下の部分を見つけました。

これ、調べたり、考えてみたところ、アップデートされたソフトウェアの依存元からの結合が壊れた場合、依存元を再インストールするということのようです。

以下の記事(英語)で知りましたが「dependency」は「依存先」であるのに対し、「dependent」は「依存元」です。

What does dependency/dependant mean?

Apacheが依存しているソフトウェアがアップデートされた場合、Apachのバイナリーの中に依存先のバージョン番号などがビルド時に書きこまれていたら、再ビルドしないと動きません。なので、再インストールが走ったということのようです。この辺は後でわかったことですが。このような依存関係まで把握できるのはHomebrew賢いなーと思いました。もしかしたらこの辺もFormulaに記載しているのかもしれません。

話が外れましたが、消えてしまった libphp7.3.33.soですがこれは、PHPBrewでPHPをインストールした際にこのディレクトリに配置されました。

つまり、HomebrewでApacheを、PHPBrewでPHPを管理している場合、Apacheを再インストールしたら動かなくなってしまうということです。

もしかしたら、PHPもHomebrewで管理している場合はどうなるのかわかりませんが、とにかく、Apacheの再インストールはよく準備した上でするべきだということです。

PHPから呼んでるもののパスも変わっちゃってる

libphp7.3.33.soはPHPbrewが生成した場所には残っているので、それを消失してしまった場所に戻しました。

ちなみに、Homebrewの仕組み上、

/opt/homebrew/lib/httpd/modules/

/opt/homebrew/Cellar/httpd/2.4.57/lib/httpd/modules/

に必要なのですが、前者は後者のSymlinkなので、後者にとりあえず配置しました。

すると、前者にもいつのまにか当該ファイルのSymlinkが生成されていました。ただ、どのタイミングでSymlinkがはられるのかはよくわかりません。きちんと前者にこのファイルが配置されない場合は、なんらかの手段でSymlinkを生成しましょう。それか、Symlinkにこだわらずこのファイルをコピーしてきてしまってもいいかもしれません。

しかし、この状態でApacheを起動すると、また全く同じエラーが発生しました。libphp7.3.33.soはあるはずなんですけどね。

とりあえず、次のエラーに注目しました。

libphp7.3.33.soから参照しているファイルが無いということです。当該ファイルがあるはずのディレクトリを調べてみたところ、

あー、ファイル名に付与されたバージョン番号がエラーに表示されたものと違うんですよね。

このicu4cというソフトウェアは、前述したJavaをインストールした際にしっかりアップデートされていました。PHPもHomebrewで管理していたら、前述した「dependent(依存元)」に相当するので、PHPもこのタイミングで再インストールされていたかもしれません。しかしPHPbrewで管理しているのでそういうわけにはいきません。

もしかしたら、PHPをPHPbrewで再インストールしたら新しいファイル名の方を参照してくれるかもしれませんが、PHPの再インストールは以下に記載したとおり面倒なので避けました。

phpbrewでphp7.3.33のインストール時のエラーと解決策phpbrewで現時点で少し古めのphp7.3.33をインストールした際に、たくさんのエラーが出てそれを乗り越えたのでお伝えします。一つ...

なので、以下の方法で元のバージョンに戻すことにしました。

Homebrewで過去バージョンのアプリをインストールする方法Homebrewで何かをインストールする場合、デフォルトでは最新のバージョンがインストールされます。訳あって過去のバージョンのものをイン...

73.2をアンインストールしてからやったはずなのですが、なぜか両方出てきてしまいます。

仕方ないので、以下をします。

両バージョン消えてしまいそうなものですが、以下の記事によると最新の方だけ消してくれます。実際にこの後、72.1のみになりました。

【Homebrew】brew upgradeしたらPHP7.4が使えなくなった

まだこれだけでは足りなくて、以下をすることで、Symlinkを適切な場所にはります。

これで再びApacheの起動を試みると、エラーの内容が少し変わりました。

注目すべきは、

libxml2.2.dylibというファイルから、先ほどのicu4cに属するファイルを呼んでいるのですが、前のバージョンに戻す前の73系のファイル名で呼んでいるんですよね。つまり、libxml2もJavaインストール時にアップグレードされたんですけど、その時バイナリ内にicu4cのパスが書き込まれたということです。

というか、icu4cを戻すときに、「dependent(依存元)」 チェックに引っかかって再インストールされるべきものな気がするのですが。dependency(依存先)はたくさん再インストールされていたんですがね。最新化以外の時は、dependentチェックは走らないのですかね。それとも、dependentチェックはApacheくらいメジャーじゃないと設定されていないのですかね。

なので、libxml2は再インストールするだけで書き込まれたパスは直るかもしれませんが、なんとなくこちらもJavaインストール前のバージョンに戻すことにしました。

すると、Apacheは無事に起動しました。

対処策

これまで、あえて最新バージョン以外をインストールする場合にその都度に以下のようにつけていた

HOMEBREW_NO_AUTO_UPDATE というオプションですが、これはもうシェルの環境変数に指定してしまうべきです。

よく考えると、何かをインストールする時に、自動的にそれ以外のソフトウェアも全部アップデートしてしまうというのは暴力的です。今まで、暴力的すぎて現実味が無くて、問題視していなかったのですが、今回の問題が起きてしっかりわかりました。

シェルの設定ファイルに以下を追記します。私の場合は .zprofile です。

これを設定しておけば、前述した問題は発生していませんでした。

なぜ自動的にアップデート「する」のがデフォルトなのか理解に苦しみます。どんなソフトウェアでも、アップデートする場合は、「アップデートしますか?」って聞いてくれますよね。

ちなみに、先ほども紹介した以下の記事で説明した、API経由でインストールしないための環境変数も併せてここで設定しました。

Homebrewで過去バージョンのアプリをインストールする方法Homebrewで何かをインストールする場合、デフォルトでは最新のバージョンがインストールされます。訳あって過去のバージョンのものをイン...

なので、追記するのはこうなります。

なお、.zprofileなどの設定ファイルを頻繁に編集するようであれば、これらをGitで管理するのがおすすめです。そのためにdotfilesというディレクトリを作って管理する方法を以下で説明しています。

dotfilesのシンプルな作り方と管理法!Macのzshユーザ向けMacでzshの設定や環境変数の設定、Gitの設定などをしだすと、設定ファイルを頻繁に編集することになります。.zprofileや.gi...

あと、zshの設定をどのファイルに記載するべきかにいくつか考え方があります。それについて以下で考えてみました。

.zprofileか.zshrcか.zlogin!どれを使うべきか?Macでターミナルなどでデフォルトで使われるシェルがbashではなくzshになりましたが、設定をどこに記載するか迷います。.zprofi...

PHPbrewがおかしい

上記の対応策を設定した後の話です。

PHPbrewで設定を確認しようと思ったら、以下のようなエラーが。

PHPbrewって、Homebrewでインストールした(PHPbrewで管理していない)PHPを呼んでいるんですよね。そのPHPが前述したicu4cやlibxml2と同じく、Javaインストール時にアップデートされていました。そのバイナリーの中に、icu4cのアップデートされたファイル名が入っていましたが、先ほどicu4cのバージョンを戻したので、ファイルを見つけれれないということです。

ここまできて、icu4cのバージョンを戻すという対処策はあまり良い手段ではなかったということに気がつきました。Homebrewで管理しているソフトウェアがアップデートされ、PHPbrewで管理しているPHPが動かない事象が発生した場合、もう一度PHPbrewでそのPHPを再インストール(コンパイル)した方が手数が少なくてすみそうです。Homebrewで管理しているソフトウェアのバージョンを戻すと、それの依存元になっているHomebrewで管理しているソフトウェア(いくつあるかわからない)との依存関係が崩れるためです。

しかし、今回はもうicu4cを戻してしまったし、それの依存元であるlibxml2も再インストールしてしまったので、PHPも再インストールすることにします。

PHPをアンインストールします。

インストールします。

しかし、以下のようなWarningが出て適切に完了しません。

phpbrewを叩くと最初と違うエラーに変わっています。

linkすると、

また最初のエラーに戻るだけです。

ちなみに、

にしても同じでした。

ここで勘付きましたが、再インストールしても、参照しているパスが変わらないということは、ソースからコンパイルされていないということかな、という気がしました。なので、きちんとコンパイルされる方法でインストールしてみることにしました。

以下の英語の記事を参考にしました。

How can I force homebrew to recompile?

すると、先ほどのWarningも出ずにきちんとインストールできたようです。PHPbrewも無事動きました。

先ほどのlibxml2はこのようなオプションを指定しなくても、コンパイルからしてくれたみたいなのですが、PHPの場合はそうはいかないみたいですね。これもそれぞれのFormulaで設定されているのかもしれません。

MySQLがおかしい

上述したPHPbrewがおかしくなった一件から3か月位経ち、完全にこの件について忘れた頃でした。あるきっかけでMacを再起動したんですよね。

その後、ローカルのWordPressにブラウザからアクセスしてみたら、どうもMySQLが起動していないようでした。

普通にHombrewで起動したら成功したように見えますが、

MySQLは起動していません。(Apacheも起動していないのですが、それはまた別の理由でしたのでここでは無視します)

Homebrewの起動方法だと情報が少ないので、以下のように直接起動してみたところ、色々情報が出ました。

以下にログが吐かれていることがわかったので、見てみました。

/opt/homebrew/var/mysql/xxxxxnoMacBook-Air.local.err

すると、

あっ、これはここまで読んだ方なら見覚えがあるやつですね。

やはり、mysqlから参照しているファイル名に入っているバージョン番号が違うんですよね。

でも、なんで3か月も問題が起きなかったのでしょうか?

おそらく、前述したJavaインストール時にMySQLもアップデートされたのでしょうが、PHPと違って、MySQLはバックグラウンドで動作していたのでずっとアップデート前の状態でメモリー上に入っていたと思われます。なので、再起動するまで問題が起きなかったのでしょう。Apacheもバックグラウンドで動作していますが、設定ファイルを変更をして反映させるための再起動をする機会が多かったため、比較的すぐに気が付くことができました。MySQLの場合は、一度も設定ファイルを変更する機会がありませんでした。

なので、MySQLも再インストールします。

してから、

でインストールはできましたが、

なぜかエラーが出ました。リンクがおかしいのかな、と思って

するとコマンド自体は成功しますが、

なぜか起動していません。

やはり、またソースコードからコンパイルしなければいけないのかなと思って、

とします。

と怖いことを言われますが、無視します。

割と時間がかかって終わるのか心配でしたが、終わりました。

それでも、まだ起動できませんでした。また先ほどのログを見ると

と、気になるエラーが出ていました。ネットで調べてみると、以下を見つけました。

MySQLがERROR! The server quit without updating PID fileで起動できないときにやったこと

overrideという見慣れぬワードが表示されます。消したはずなのに、すぐにまたこのファイルが生成されます。

でも、これでなぜかMySQLが動き出していました。

さいごに

Macの根幹を支えるパッケージマネージャーであるHomebrewは、結構アグレッシブな仕様だったりします。この辺りしっかり理解することと、適切な対処をすることが大事ですが、それでもなおHomebrewを使う理由はあります。それを以下で説明していますので、ご覧ください。

Homebrewとは?本質的な価値を解説。何ができる?メリットは?Macで何かをインストールするための記事でよく紹介されるHomebrewって一体なんなのでしょうか?検索して調べてもわかったようでわから...