Macで何かをインストールするための記事でよく紹介されるHomebrewって一体なんなのでしょうか?検索して調べてもわかったようでわからない気分になります。なので今回は真剣にHomebrewの内部でどんなことが起きているかや、エコシステムがどうなっているのかを調査し、本質的な価値をご説明します。それを踏まえてメリットとデメリットをまとめます。とはいえ、これは個人の見解であり、推測も多く含まれることをご了承ください。仕組み等よりも、とにかくメリットだけを知りたい方は、目次から飛んでご覧ください。
Homebrewのバージョンは3.6.18を前提にした記事にはなりますが、それ以降のバージョンもそんなに本質は変わらないはずです。
もくじ
一般的な記事の解説でわかる?
Homebrewって何?って思って日本語で検索して出てくる記事で大体言われるのが、
Macのパッケージ管理システムで、ソフトウェアのインストール、アンインストール、バージョン管理を一元化できる便利なツールです!
みたいな説明しか書かれていないのではないでしょうか?その後に、具体的なインストール方法や代表的なコマンドがちょろっと説明されるだけです。
これでよく皆さんHomebrewを使う気になるなーとふと思いました。
僕もずっとそんな説明だけでわかったつもりになりながら長年使っていたのですが、最近Macを買い替えてセットアップし直す機会がありました。あるソフトウェアをインストールしようとした時、すぐにHomebrewでインストールできるかわからなかったんです。色々調べていくうちに面倒になって、もうHomebrewではなくて公式のインストーラーでインストールしちゃおうかな思ったりしました。
結局、そのソフトウェアはちゃんとHomebrewでインストールできることがわかったのですが、公式のインストーラを最初から使ってればこんなに時間を使うこともなかったのになーと思いました。
そこでわざわざHomebrew経由でインストールする意味って何だろうって思ったりしました。なので、Homebrewの本質的な価値について調べることにしました。
なお、ここから伝える価値は、MacPortsなどの同種のツールにも言えることかもしれません。それらとの違いが知りたい方は、そのような記事はたくさんあるので、それらをご覧ください。逆にそれらに共通した価値を説明する記事が少ないように見受けられたので、今回調べてみることにしました。
便利さの背後には巨大なエコシステムがある
そもそもそんなに便利なら、なぜAppleが買収などをしてMac OSの標準機能にしないのでしょうか?
特に明言されているわけではないので、私の推測ですが、オープンソースであり多くのコントリビューターがいるからだと思います。オープンソースのコントリビューターは基本は無償でボランティア的に、ソフトウェアを開発します。なので、ビジネスに取り込まれると、性質が変わってしまう恐れがあるのでしょう。
ただ、MySQLがOracleに買収された例もあります。なので単にオープンソースということだけがHomebrewを買収しない理由ではないです。
HomebrewとMySQLの大きな違いは、前者はソフトウェア本体だけでなく、formulaやCaskといったインストールしたいソフトウェアごとに作られたファイルが膨大にあるということです。(formulaやCaskについては後で詳しく説明します)
MySQLの開発のエコシステムというのは、基本的にMySQLというソフトウェア本体を開発する人だけで構成されています。
しかし、Homebrewでは、例えばChromeをインストールするためのCaskを作る人もいれば、名も知らないMacアプリのCaskを作っている人もいます。
当然Chromeの背後にはGoogleという会社があるように、ソフトウェアごとに存在するステイクホルダーが多岐に渡ります。
FormulaやCaskを作る人は、そのような多くの会社やステイクホルダーと、Macをつなぐ役割をしていると言えます。
それなのに、仮にAppleがHomebrewを買収してしまったら、FormulaやCaskを作る人たちは、Appleのために仕事をしていることになってしまいます。そうなるとAppleはそういう人に給料を払う必要が出てきます。Homebrew本体だけならコストを賄えるかもしれませんが、膨大な数があるFormulaやCaskは難しいでしょう。また、FormulaやCaskに少しでも不具合が出たら責任を取らなければなりません。不具合を完全に無くすには、Chromeなどソフトウェア側の人と密にやりとりするなどコミュニケーションコストも膨大になります。
なので、AppleはHomebrewを買収せず、どこの企業にも属さない有志のオープンソースという形態が維持され続けていると思われます。
逆に言うと、特定の企業が運営することができない、中間的な存在である「FormulaやCaskを作る人達のエコシステム」がHomebrewの本質的価値だと考えています。
そういった、エコシステムがあってこその便利さなのに、
コマンド一つでインストールできる便利なツールだよ!
って説明で終わるのってどうなんだろうって思うんですよね。
FormulaとCaskってつまり何なの?
ここからは肝心のFormulaとCaskが何なのかについて説明していきます。ちなみに、複数形になると、CaskはCasksで普通なのですが、FormulaはFormulaeになります。
公式のページ(英語)には
Formulaは「パッケージの定義」と書かれています。
Caskは「Mac OSのネイティブアプリをインストールするための、Homebrewの拡張」と書かれていますが、一つ一つのCaskは「Mac OSのネイティブアプリをインストールするための、パッケージの定義」ということだと思います。
FormulaとCaskも同じ目的のものと思っていいです。ただ、カバーする対象が違うということです。前者は主にコマンドラインで使うプログラム、後者はMac OSのネイティブアプリが対象になります。CUIとGUIの違いと思っても良いでしょう。
「パッケージの定義」っていう言葉がとてもわかりにくいです。なぜこのような言葉を使っているかわからないのですが、私の理解では、
インストールやアンインストールのための手順(料理で言うとレシピ)
だと思っています。
材料をどこから持ってきて、どうやって調理して、捨てる時はどうやって捨てるか、みたいなことが書かれているのです。
実際に、以下のGithubリポジトリからFormulaのファイルを一つ開いてみてみるとわかります。
Homebrew/homebrew-core/Formula
ソースコードをダウンロードするURL、どうやってコンパイルするか、などが書かれているのがわかると思います。独自のDSLで記載されていますが、直感的にもある程度理解できると思います。
いくつかのファイルを見ていくと気がつくと思いますが、URLの形式も、バージョンの記載法も、コンパイルの仕方も、ソフトウェアによって全然違うんですよね。まぁ、当然ですよね。それぞれのソフトウェアは別の人が作っていますから。
全て同じコマンドで扱えるようにするために、それらの違いを吸収するのがFormulaやCaskの役割ということです。Homebrewの内部的な動きを解説している記事は少ないのですが、次の英語の記事がわかりやすかったです。
How does Homebrew work internally?
FormulaやCaskのメンテナンスって想像するとかなり面倒くさいです。ソフトウェア側のダウンロードURLが変わったり、バージョンの数字が上がったりするごとに更新していく必要があります。まぁ、この役割って、もしかしたらそのソフトウェアを開発している会社などがユーザーを増やすためにやっている場合もあるかもしれませんが、有志のユーザーがやっている場合もあるでしょう。
どちらにしても、こんな面倒な作業を無償でやってくれて、感謝しかないです。
ちなみに、うすうす気が付いている方も多いと思いますが、Homebrewで使われている単語はビールに関連したものが多いです。brewは「醸造」なので、homebrewは「自家醸造」となります。割ときちんと概念に例えられているので、この辺の英語が分かると理解しやすいかもしれません。
formulaって「公式」っていう意味の方がメジャーですが、「製法」って意味もあります。まさに先ほどレシピに例えましたが、そのままですよね。また、Caskは「大樽」という意味があります。その他にも色々あるのですが、以下の記事が参考になりました。
FormulaとCaskってなぜ分かれているの?
元々、HomebrewはRuby On Railsというフレームワークに関係するプログラマーのコミュニティで人気が出てメジャーになりました。私もそのコミュニティに足を踏み入れていたことがあるのでわかるのですが、彼らはコマンドライン大好きなんですよね。
なので、彼らが開発で必要なCUIのソフトウェアを管理するために主に使われていたようです。徐々にHomebrewの人気が拡大する中で、普通のGUIアプリもこれで管理できたら便利じゃない?って発想になってきたと思われます。ただ、CUIと同じリポジトリに入れるのではなく、Caskというリポジトリにそれらを入れる運用になりました。
なので、以前はCaskを使いたい場合は、Homebrewをインストールするだけでは足りず、
1 |
$ brew tap caskroom/cask |
というコマンドで、Caskのリポジトリをローカルに持ってくる必要がありました。そして、各アプリをインストールする際も、
1 |
$ brew cask install google-chrome |
というように、 cask というオプションを指定する必要がありました。
しかし現在は、Homebrewをインストールしただけで、既にCaskのリポジトリもダウンロードされ、インストールする際の cask というオプションも不要になりました。なので、Formulaのソフトウェアと全く同じようにインストールできます。
ちなみに、 tap というオプションが出てきました。tapという英語は、ビールの世界では、「口を切る」という意味だそうです。なので、「新しく入った樽の口を切る」みたいに使うんだと思います。
なので、
1 |
$ brew tap caskroom/cask |
というコマンドは、「大樽の口を切ってビールを注げる準備をしている」イメージをしてもらえばいいと思います。
とはいえ、現在はCaskはtapしないで使えるし、installのコマンドもFormulaと同じなので、分ける必要はないのではないかと思えます。呼び方も同じにしてもいい気もします。
ちなみに、tapはCaskが入っているリポジトリを使えるようにするだけではなく、Homebrewの拡張機能を使えるようにするためにも使われます。例えば、以下のCaskのupgradeを管理しやすくする拡張機能などがあります。
何がtapされているかを確認するには、
1 |
$ brew tap |
というコマンドでもできますし、以下のディレクトリを見ることでも確認できます。
/opt/homebrew/Library/Taps/
このディレクトリにあるhomebrewには、FormulaやCaskのリポジトリが配置されています。それ以外は拡張機能だと思っていいでしょう。
FormulaやCaskと拡張機能を同じように扱うというのは少し分かりにくい気がします。役割が全然違うので。実装しやすいのでこのように設計しているのだと思いますが。
GUI以外のCaskもある
現在Caskはtapしなくても使えると言いましたが、それはGUIのCaskという意味です。実は、GUI以外のCaskも色々あります。HomebrewのGithubにたくさんCaskのリポジトリが確認できます。
GUIのCaskはhomebrew-caskというリポジトリですが、例えば、ドライバー専用のCaskがあり、それはhomebrew-cask-driversというリポジトリです。ただ、このドライバー専用のCaskはtapしないと使えません。
私は最近BoseのBluetoothスピーカーを買ったのですが、それをMacに接続してファームウェアアップデートをする必要がありました。その際、公式のドライバーをMacにインストールする必要があるのですが、調べてみるとHomebrewでインストールできることがわかりました。そして、このドライバー専用のCaskをtapして、インストールすることができました。
他にもフォントをインストールするためのCaskもあります。
このように複数のCaskが存在しています。ちなみに、CUIのFormulaが入っているのはhomebrew-coreというリポジトリです。これも一つのCaskと見ることもできると思います。
全員が全てのCaskを使うわけでもないので、選択的に使えるようにしているため、リポジトリを分けているんだと思います。CUIとGUIについては使う人が多いので、デフォルトで使えるようにしているんだと思います。ただ、CUIだけCaskではなく、Formulaと呼ぶ理由はわからないのですが。
あと、ローカルにあるそれぞれのCask例えばhomebrew-core/Formulaディレクトリで、コマンドラインで ls を実行すると大変なことになります。表示されるファイル数が多すぎるためです。単純にファイル数が膨大になるので、リポジトリを分けているというのもあるかもしれません。
ちなみに、それぞれのCaskをtapと呼ぶ説明をよく目にします。その場合、tapをtapすることになるので、ちょっとわかりにくいので、やはりCaskと呼んだ方がいい気がします。
インストールしたいものがHomebrewに対応してなかったら?
世の中にはMacで使えるソフトウェアが無限と言っていいほどあり、それが全てHomebrewに対応しているとは限りません。というのは、上述したように、FormulaやCaskを書いているのは有志の人だからです。
その場合、自分でFormulaやCaskを書くことができます。それをローカルだけにとどめて自分だけで使ってもいいですし、プルリクエストをして公式のFormulaやCaskに入れてもらうのもいいでしょう。そうすれば、あなたが書いたFormulaやCaskによって、他の誰かが手動でインストールする手間を省いてあげることができます。
書き方や貢献の仕方は公式ページに丁寧に説明されています。
Homebrewのメリット
以上を踏まえて、私なりのメリットデメリットを挙げていきます。
インストールやアンインストールの手順が統一できる
やはりこれが一番大きいメリットだと思います。Macで使うソフトウェアって、インストール方法ってそれぞれ違うんですよね。CUIソフトウェアだとビルドしたりするので、本当に色々やり方があります。GUIアプリであっても、ワンクリックで完了するものもあれば、dmgファイルをマウントしてそこからApplicationsディレクトリに手動でコピーする必要があるものなど微妙に違います。
それが以下のコマンド一つでインストールできるのは楽です。
1 |
$ brew install xxxxx |
(xxxxはFormula名やCask名)
最新版ではなくなっているソフトウェアを簡単に検出できる
通常そのソフトウェアが最新版であるかどうかは、ソフトウェアごとに確認します。面倒なものになると、わざわざホームページを確認しなければならないものもあります。しかし、Homebrewを使うと以下のコマンドで簡単に検出することができます。
1 |
$ brew outdated |
以上が私が考えるメリットです。
Homebrewのデメリット
デメリットはこの手のツールへの私の期待が大きすぎてがっかりしただけの可能性もあるので、人によっては大してデメリットに感じないかもしれません。
その名前がインストールしたいソフトウェアなのか分かりづらい
上述したように、Homebrewでソフトウェアをインストールする時、Formula名やCask名を指定します。自分のインストールしたいソフトウェア名のFormula名やCask名を知る必要があるということです。
通常のインストール方法だと、そのソフトウェアのホームページからダウンロードするので間違えようがありませんが、Homebrewだと似たような名前のものを指定してしまって、別のソフトウェアをインストールしてしまいかねません。
私はsketchというデザインアプリをインストールしたかったのですが、一般的な名前過ぎてどういう名前で指定していいか最初分かりませんでした。sketchという単語を含むソフトウェアが複数あったためです。
狙ったソフトウェアかきちんと判別する方法としては、まず、以下のbrew searchコマンドでインストールしたい対象の思い浮かぶ文字列を入れて探してみます。
1 2 3 4 |
$ brew search sketch ==> Casks graphsketcher sketch-toolbox sketchpacks skitch sketch sketchbook sketchup wireframe-sketcher |
さらに、それっぽい名前をsearch infoコマンドで指定します。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
$ brew info sketch ==> sketch: 51.3-57544 (auto_updates) https://www.sketchapp.com/ /opt/homebrew/Caskroom/sketch/51.3-57544 (120B) From: https://github.com/Homebrew/homebrew-cask/blob/HEAD/Casks/sketch.rb ==> Name Sketch ==> Description None ==> Artifacts Sketch.app (App) ==> Analytics install: 487 (30 days), 1,130 (90 days), 5,728 (365 days) |
3行目に表示されるURLにブラウザでアクセスしてみます。それが狙ったソフトウェアのホームページかどうかで確認できます。
ソフトウェア側の自動アップグレードを止められない
Homebrewは何かと自動的に全てのソフトウェアをアップグレードしようとしてきますが、これは以下の記事で説明したように、環境変数を設定することで止められますし、それをおすすめします。
なので、コマンドラインでそれぞれのソフトウェアのアップグレードを一元的にできるというのが一つのメリットです。
しかし、中にはソフトウェア側で自動的にアップグレードしてしまうものもがあります。
例えば、Evernoteです。Evernoteは起動のたびに、最新版の確認をし、あれば勝手にアップグレードしてしまいます。Homebrewを何も触っていないのに、勝手にバージョンが変わっていて結構気持ち悪いです。この自動アップグレードの機能はOFFにできません。
私の環境ではこのようなソフトウェアはEvernoteだけなのでまだ我慢できますが、これが多くなると何のためのHomebrew?って思ってしまいそうです。
バージョン指定という概念がなく常に最新版を使う思想
これが一番がっかりした点です。同じRubyコミュニティから生まれたRubyのライブラリ管理ツールのBundlerでは、当然のようにバージョンを指定できるように作られています。
様々な理由で、最新版ではなく、特定のバージョンを使いたいケースも多いので、これはとても重要な機能です。
しかし、Homebrewはどう考えても、最新版に常にアップグレードすることを前提にデザインされているように思えます。以下の記事で説明した手順で特定のバージョンを指定してインストールすることもできますが、かなりトリッキーな手順になってしまいます。
なぜバージョン指定をしづらくしているかを考えてみました。BundlerなどでインストールするRubyのソフトウェアと、このようにMacに直接インストールするソフトウェアでは事情が違うということかもしれません。
Rubyのソフトウェアは基本的にGitHubなどのソースコード管理システムで管理され、過去のソースコードも半永久的に残り続けます。なので過去のバージョンもほぼ確実に入手できます。それに対し、Mac用のソフトウェアはデベロッパー側のサーバーに配置されるケースが多いです。全バージョンを配置し続けるのも無駄なので、古いバージョンは公開しないケースも多いのかもしれません。なので、Homebrewは最新版を使うという設計にしてしまっているのかもしれません。
ちなみに、上の記事で説明したように、pinという機能で、現在のバージョンに固定(勝手に最新版にアップグレードしないように)することはできます。
同じ環境を作るのにあまり役立たないBrewfile
Homebrewだと、Brewfileというものを使えば、違うMacに同じ環境を簡単に構築できるというような記事が多いです。
Brewfile で Homebrew のライブラリを管理しよう!
例えば、新しいMacに買い替えた時や、会社で他のメンバーのMacに自分と同じ環境を作ってあげたい時などに簡単に構築できるということです。
でも、このBrewfile、やはりバージョン指定できないんですよね。なので、簡単に同じソフトウェアをインストールできると言っても、同じバージョンではない可能性があるんですよね。RubyのBundlerだと、GemfileやGemfile.lockといったファイルで完全に同じバージョンを再現することが簡単にできます。それに対してこのBrewfileはあまり意味がないように思えてしまいます。
本当に同じバージョンの環境を作りたいなら、少し面倒なのですが、まずは、以下のコマンドで現在どのバージョンがインストールされているか表示させます。JSON形式なので見づらいですが。
1 |
$ brew info --json=v2 --installed |
そして、先程紹介した記事の方法で、一つずつバージョンを指定してインストールするしかないかなと思います。
最新版に対応するまでタイムラグが出る場合がある
常に最新版を使う設計になっていると話しましたが、正確にいうと、各ソフトウェアの最新版がリリースされてからHomebrewでインストールできるようになるまでに、タイムラグがある場合があります。
というのは、前述したように、インストール手順が記された各FormulaやCaskは有志の人が書いています。それが完成して公式のリポジトリに反映するまでの時間がかかるということです。
なので、ソフトウェアの公式ホームページなどでリリースが発表されても、Homebrewではまだインストールできない、といったことも起こり得ます。
ただ、FormulaやCaskは自分で書くこともできるので、急いでいるなら自分で書いてインストールしてしまえばいいかもしれません。大半はバージョン番号が変わるくらいの修正で対応可能だと思いますし。
アンインストール時の設計がふわっとしていて関連ファイルが残ってしまう?
Caskにはアンインストール時に削除する関連ファイルが指定されていたりします。
もし、バージョンによってこの削除する対象のファイルが変わったらどうなるのでしょうか?
例えば、あるアプリのバージョン1.0では、削除対象が
- ファイルA
- ファイルB
だったとします。
しかし、バージョン1.1ではそもそもファイルBを使わなくなったので、アンインストール時の削除対象が
- ファイルA
としか記されていなかったとします。
すると、バージョン1.0から使い始めて、1.1にアップグレードして、その後にこのアプリをアンインストールしたとします。すると、ファイルBは削除されずに永遠に残ってしまうのではないでしょうか?
この辺り私の仕組みの理解不足かもしれません。もしかしたら、インストール時のCaskも残しているなど、よしなにやってくれる仕組みになっているのかもしれませんが、普通に仕組みを想像するとこのような懸念があります。そのうち実験して検証してみたいと思います。
さいごに
デメリットの数がメリットの数を大幅に上回る記事になってしまいました。ではなぜHomebrewを使っているのかというと、やはりメリットの一つ目の「インストールやアンインストールの手順が統一できる」という点が大きいからです。このメリットは、多くの人が関わるHomebrewのエコシステム抜きにはあり得ません。
世のHomebrewを紹介する記事は、こんなに便利なものが天から降ってきたみたいな書き方に私には思えます。でも、単に便利さを享受するだけでなく、自分もエコシステムの一部で、やろうと思えば誰かのために貢献できるんだということを認識することが、Homebrewの価値を理解する役立つと思います。