サマリー
brew install {ライブラリ名}でバージョン指定できないのはなぜ?
-
brew install {ライブラリ名}の内部処理仕様によるもの。Formulaという「ライブラリインストールのためのレシピ」が複数バージョン管理に対応していない。- Formula……ライブラリのバージョン、ソースコードのダウンロード元URL、ビルド方法、依存関係などの詳細情報が記述されたRubyのファイルで、いわばパッケージの「レシピ」。brew installコマンド実行時には、レシピであるFormulaを使ってソフトウェアを「醸造」(インストール)する。
じゃあなんでそうなるのよ(brew install {ライブラリ名}実行時の内部処理概要)
-
brew install {ライブラリ名}では、まず指定されたライブラリ名と一致するFormulaを検索し、ヒットしたFormulaを元にインストール手順を進めていく。 - この時検索対象になるのは、ユーザー環境にて利用可能なtapに配置されたFormula。
- tap……Formulaを提供するリポジトリにアクセスするための「蛇口」。Githubリポジトリやローカルディレクトリなどを設定する。
-
homebrew-coreという Formula 配布用の Homebrew 公式 Github リポジトリが、デフォルトで tap に登録されている。
大抵の場合、brew install {ライブラリ名}した際は、このhomebrew-coreで公開されている Formula をインストールしている。 - 1つのFormulaには、1つのパッケージの1つのバージョンのインストール手順しか記載されていない
- 1パッケージの複数バージョンをインストール可能にするには、バージョン別に Formula を切るしかない
- homebrew-coreでは、たいていの場合各種パッケージの最新バージョンのFormulaしか配布していない。なので、homebrew-core しか tap に登録していない場合は、(基本的に)指定したライブラリの最新バージョンしかインストールできない
じゃあ任意のバージョンを指定したい場合はどうすればいい?
- もし旧バージョンをインストールしたいのであれば、ローカルディレクトリに任意バージョンの Formula を配置し、tap に登録する手法をとるのが良さそう
- 任意バージョンの Formula は、homebrew-core のコミット履歴を追跡し特定した上で、curlコマンドなりでインストールすれば、ローカルディレクトリに配置できる
本文
前段:Homebrewの概要
※本段落は、本題である「brew installでパッケージのバージョンを指定できない件」について説明する前段として、Homebrewの概念整理と用語集、brew installの内部処理をまとめたものです。
バージョン指定の件本題を読み進めたい場合は、homebrew-core で配布しているパッケージのバージョン あるいは 任意のバージョンを指定してパッケージをインストールする方法 までスキップしてください。
Homebrewとは
macOSおよびLinux向けのパッケージ管理システム。
コマンドラインからソフトウェアのインストール、アップデート、アンインストールを簡単に行うことができる。
アプリケーションを「自家醸造(Homebrew)」するというコンセプトで設計されており、多くの用語がビールの醸造に関連付けられている。
主な用語
-
Formula (フォーミュラ): ライブラリのバージョン、ソースコードのダウンロード元URL、ビルド方法、依存関係などの詳細情報が記述されたRubyのファイルで、いわばパッケージの「レシピ」。
brew installコマンド実行時には、レシピであるFormulaを使ってソフトウェアを「醸造」(インストール)する。 -
Cask (カスク): GUIアプリケーション(例:Google Chrome、Visual Studio Codeなど)を管理するための拡張機能。コマンドラインから簡単にGUIアプリをインストールできる。
-
Keg (ケグ): インストールされた各パッケージのバージョンを管理するディレクトリ。
Cellar内に存在する。 -
Cellar (セラー): ビールやワインを貯蔵する「貯蔵庫」を意味し、インストールされたすべてのパッケージの
Kegが保存されるディレクトリ。 -
Tap (タップ): Formulaを提供するリポジトリやディレクトリにアクセスするための「蛇口」。
homebrew-core というGithubリポジトリとデフォルトで接続されており、homebrew-coreで配布されているパッケージは世界中どこからでもインストールできる。また、homebrew-coreで提供していないFormulaやCaskも、配置先Gitリポジトリやローカルディレクトリをtapに登録することで、homebrewの管理対象にできる。
brew tapというコマンドを実行することで、ユーザー環境において利用できるtapの一覧を確認できる。 -
Bottle (ボトル): コンパイル済みのバイナリパッケージ。Bottleがある場合、Rubyソースコードからビルドする必要がなく、迅速なインストールが実現できる。
-
Brewfile (ブリューファイル): 複数のパッケージを一括で管理するための設定ファイル。
brew bundleコマンドを使うことで、このファイルに基づいて必要なパッケージをまとめてインストールできる。
brew install 時の内部処理の流れ
1. 情報の取得
まず、インストール対象のライブラリに関する情報を検索する。この情報は、Homebrewの公式リポジトリ(homebrew-core)や、ユーザーが追加したtapに格納されているFormula(レシピ)ファイルから取得される。
homebrew-core に存在するパッケージ名を指定した場合
→普通にインストールが始まる。(「2. 依存関係の解決」以降を参照)
存在しないパッケージ名を指定した場合
→似た名前のFormulaやCaskがないか検索する。なかったらエラーメッセージを吐く。
似た名前のFormulaがあった場合
$ brew install tblss
Warning: No available formula with the name "tblss". Did you mean tbls?
==> Searching for similarly named formulae and casks...
==> Formulae
tbls
To install tbls, run:
brew install tbls
似た名前のFormulaがない場合
$ brew install non-existent-package-name
Warning: No available formula with the name "non-existent-package-name".
==> Searching for similarly named formulae and casks...
Error: No formulae or casks found for non-existent-package-name.
2. 依存関係の解決
Formulaの情報が見つかると、Homebrewは指定されたライブラリが依存している他のライブラリがないかを確認する。
-
依存関係の確認:
Formulaにdepends_onという記述があれば、その依存ライブラリが既にシステムにインストールされているかをチェックする。 - 依存ライブラリのインストール: もし依存ライブラリがインストールされていなければ、指定ライブラリのインストールに先立って、依存ライブラリをインストールする。
3. パッケージのダウンロードとインストール
依存関係が解決された後、Homebrewは実際のパッケージをインストールする。
-
ボトル(Bottle)のダウンロード: Homebrewは、可能な限り事前にコンパイルされたバイナリパッケージであるBottleを使ってインストールする。(その方が、ライブラリのソースコードからビルドするより時短で効率的なため)
Bottleは、ユーザーのCPUアーキテクチャやmacOSのバージョンに合ったものがHomebrewのサーバーからダウンロードされる。 -
ソースからのビルド: もし適切なBottleが見つからない、またはユーザーが
--build-from-sourceオプションを指定した場合は、Formulaに記述された手順に従って、ソースコードがダウンロードされ、コンパイル・ビルドを行う。
参照:https://docs.brew.sh/Bottles
4. シンボリックリンクの作成
インストールが完了すると、Homebrewはユーザーが簡単にコマンドを実行できるように、必要なシンボリックリンクを作成する。
-
Cellarへの保存: インストールされた
tblsのパッケージは、Homebrewの「Cellar」ディレクトリ(/usr/local/Cellar/や/opt/homebrew/Cellar/など)に保存される。 -
シンボリックリンクの作成: 実行ファイル(この例では
tblsコマンド)へのシンボリックリンクが、HOMEBREW_PREFIX/bin(例えば/usr/local/bin)ディレクトリに作成される。このディレクトリは通常、ユーザーの$PATH環境変数に含まれているため、ターミナルからtblsと入力するだけでコマンドを実行できるようになる。
参照:インストール時のログ
以下の例では、tblsというライブラリをインストールしている。適切なbottleが公開されているため、これを引っ張ってきてインストールを進めている。
$ brew install tbls
==> Fetching downloads for: tbls
==> Downloading https://ghcr.io/v2/homebrew/core/tbls/manifests/1.87.0
######################################################################### 100.0%
==> Fetching tbls
==> Downloading https://ghcr.io/v2/homebrew/core/tbls/blobs/sha256:937c920099b2a
######################################################################### 100.0%
==> Pouring tbls--1.87.0.arm64_sonoma.bottle.tar.gz
🍺 /opt/homebrew/Cellar/tbls/1.87.0: 10 files, 84MB
==> Running `brew cleanup tbls`...
Disable this behaviour by setting `HOMEBREW_NO_INSTALL_CLEANUP=1`.
Hide these hints with `HOMEBREW_NO_ENV_HINTS=1` (see `man brew`).
Removing: /Users/{ユーザー名}/Library/Caches/Homebrew/tbls_bottle_manifest--1.85.2... (8.3KB)
Removing: /Users/{ユーザー名}/Library/Caches/Homebrew/tbls--1.85.2... (23.0MB)
==> No outdated dependents to upgrade!
==> Caveats
zsh completions have been installed to:
/opt/homebrew/share/zsh/site-functions
homebrew-core で配布しているパッケージのバージョン
上記の公式サイトから、「コアtap(homebrew/core)で配布しているパッケージの一覧」を参照することができる。
表にはパッケージ名のほか、公開中のバージョン情報も記載されている。
↓こんなかんじ。
上記画像のpython@3.10やpython@3.13のレコードを見てピンと来た方もいるかもしれないが、基本的に homebrew-core で配布しているパッケージのバージョンはひとつに固定される。
つまり、パッケージ内の任意のバージョンを指定してインストールすることはできない。
上記のpython@3.10やpython@3.13は、ユーザーがマイナーバージョンまで指定してインストールできるようにするために、Pythonのメジャー/マイナーバージョン単位で Formula を個別作成・公開している……ということになる。
ちなみに、以下のGithubリポジトリのmasterブランチの Formulaディレクトリ内から、配布されているパッケージの Formula を参照することができる。
任意の Formula の中身を見てみると、パッケージ単位でバージョンが一意に定まることがわかるはず。
例えば python@3.9なら、urlに指定された値からバージョンが 3.9.23 であることが読み取れる。
任意のバージョンを指定してパッケージをインストールする方法
例えば、テーブル定義書の生成ツールtblsの旧バージョンであるv1.85.2をローカル環境にインストールしたい場合を考える。
tbls を homebrew でインストールする場合は、brew install tblsを実行すれば良いのだが、これだとコマンド実行時点でhomebrew-coreのmainブランチで公開されているFormulaを元に処理が実行されるため、旧バージョンの v1.85.2 をインストールすることができない。
なので、ローカル環境の任意のディレクトリにv1.85.2のFormulaを手動で配置し、インストールtapに登録してあげる必要がある。
コアtapであるhomebrew-coreに tbls v1.85.2 がないのなら、別のtap(ローカル環境tap)を使えばいいじゃない!ということである。
手順参考
手順
1. ローカルにtapを作成する
brew tap-new {ユーザー名など(任意の名称)}/{Formula名(任意の名称)}コマンドを実行し、ローカルにtapを作成。
$ # brew tap-new {ユーザー名など(任意の名称)}/{Formula名(任意の名称)}
$ # 例
$ brew tap-new rummy_p/tbls1.85.2
上記コマンドを実行すると、/opt/homebrew/Library/Taps/rummy_p/homebrew-tbls1.85.2/ ディレクトリが作成されるはず。
またbrew tapコマンドでtap一覧を確認すると、rummy_p/tbls1.85.2もリストアップされるはず。
$ brew tap
homebrew/core
homebrew/services
rummy_p/tbls1.85.2
2. 作成したtapに任意のformulaを保存する
https://github.com/Homebrew/homebrew-core にて homebrewからインストールできるライブラリのFormula(全リリースバージョン分)が公開されているので、目当てのライブラリ(今回はtbls)の目当てのversion(今回はv1.85.2)用Formulaを探し当てる。
↓目当てのFormula(tbls v1.85.2)
https://github.com/Homebrew/homebrew-core/blob/443783a36291c84219a0a8e74f0303f81b1bc051/Formula/t/tbls.rb
これを以下コマンドでインストールし、1の手順で作成したtapに配置する。
$ curl \
https://raw.githubusercontent.com/Homebrew/homebrew-core/443783a36291c84219a0a8e74f0303f81b1bc051/Formula/t/tbls.rb \
-o /opt/homebrew/Library/Taps/rummy_p/homebrew-tbls1.85.2/Formula/tbls.rb
3. ローカルのFomulaをもとにtblsをインストールする
brew install {1の手順で作成したtapのディレクトリ}/{2の手順でインストールしたRubyファイルの名称(拡張子無し}コマンドを実行し、ローカルFormulaをもとにtblsをインストールする。
$ # brew install {1の手順で作成したtapのディレクトリ}/{2の手順でインストールしたRubyファイルの名称(拡張子無し}
$ # 例
$ brew install rummy_p/homebrew-tbls1.85.2/tbls
4. tblsの v1.85.2 がインストールできているか確認する。
下記のような具合で、1.85.2と出力できていればOK。
$ tbls version
1.85.2
余談
brew untapコマンドで、tapを削除することもできる。
$ # 例
$ brew untap rummy_p/tbls1.85.2

