Chapter 05

brew とバイナリについて

ほげさん
ほげさん
2021.08.14に更新

ターミナルのバイナリとシェルのバイナリについて

ターミナルのバイナリ

ターミナル.app も iTerm.app ( 要インストール ) も Universal バイナリです。

どちらか片方だけ Rosetta を使用して開く を有効にしておきます。

この本では以降 Rosetta を使用して開く 方のターミナルを x86_64 ターミナル、そうでない方を ARM64 ターミナルと記載します。[1]

コマンドのバイナリ

ARM Mac にデフォルトインストールされている zsh を確認すると、Universal バイナリであることがわかります。

$ lipo -archs /bin/zsh
x86_64 arm64e

/bin にあるものは全て Universal バイナリです。

$ ls /bin | xargs -Icmd lipo -archs /bin/cmd | uniq
x86_64 arm64e

ログインシェルのアーキテクチャ

ログインシェルは /bin/zsh なので Universal バイナリです。

$ dscl localhost -read Local/Default/Users/$USER UserShell
UserShell: /bin/zsh

2 つのターミナルを起動して確認してみます。

x86_64 ターミナル
$ uname -m
x86_64
ARM64 ターミナル
$ uname -m
arm64

ログインシェルのアーキテクチャはターミナルのアーキテクチャに応じて決まるようです。

uname -m の詳細挙動については細かく調べきれなかったのですが、Rosetta を使用したことで x86_64 バイナリを ARM64 バイナリに変換して使っているが、「x86_64 バイナリを使えているよ」という風に見せているものだと考えることにしました。

シェルの別のバイナリを用意する

試してみたいことがあるので、説明の順番が前後しますが、brew を用意します。

brew 自体にも x86_64 バイナリと ARM64 バイナリがあり、シェルのアーキテクチャとバイナリのアーキテクチャを揃えないといけません。

2 つのターミナルで brew を 2 つ準備し、両方で zsh をインストールしてみます。
( インストール手順は調べれば詳しい記事がたくさんあるので割愛します。)

x86_64 ターミナル
$ /usr/local/bin/brew install zsh
bla bla bla

$ brew list | tail -n 3
xorgproto
xz
zsh
ARM64 ターミナル
$ /opt/homebrew/bin/brew install zsh
bla bla bla

$ brew list | tail -n 3
sqlite
xz
zsh

実態もインストールしたものの管理も独立していることがわかります。

それぞれの zsh を確認してみます。

$ lipo -archs /usr/local/bin/zsh
x86_64

$ lipo -archs /opt/homebrew/bin/zsh
arm64

これで今は /bin/usr/local/bin/opt/homebrew/bin に 3 つの zsh があることになりました。
意識する必要はありませんが、Rosetta が変換している ARM64 バイナリまで含めると、6 つのバイナリがあることになります。

さすがに煩雑が過ぎるので、以降は Rosetta による変換は割愛し、まるで x86_64 バイナリを自然に使えているかのように図示します。

ARM64 ターミナルで x86_64 シェルを使う

せっかく zsh がたくさん手に入ったので、ARM64 ターミナルから x86_64 の zsh を起動するとどうなるか確認してみます。

ARM64 ターミナル
$ uname -m
arm64

$ /usr/local/bin/zsh

$ ps -p $$
  PID TTY           TIME CMD
93373 ttys007    0:00.36 /usr/local/bin/zsh

$ uname -m
x86_64

使えていますね。アーキテクチャは混在できます。

x86_64 ターミナルで ARM64 シェルを使う

こちらも確認します。

x86_64 ターミナル
$ uname -m
x86_64

$ /opt/homebrew/bin/zsh

$ ps -p $$
  PID TTY           TIME CMD
93438 ttys008    0:00.20 /opt/homebrew/bin/zsh

$ uname -m
x86_64

プロセスとしては ARM64 の zsh みたいですが、アーキテクチャは x86_64 となりました。

混在できるのかなと思っていたのですが、Rosetta 環境下での uname -m の動きが追いきれませんでした。

ひとまずはこちらはできない ( 意味がない ) と理解しておくこにとします。
( 次の章で解決します。)

ターミナルとシェルの整理

できないことと意味のないことを除き Rosetta の変換もないように捉えて整理すると、意味のある部分はこうなります。

  • ARM64 のシェルは自然に使える
  • x86_64 のシェルは一手間いれれば使える
    • ターミナルを複数用意しておく
    • もしくはシェルを複数用意しておく

brew のバイナリについて

zsh を用意する都合で前後しましたが、brew についても整理します。

ARM64 ターミナルでの brew 利用

ARM64 ターミナルなので ARM64 シェルにまずログインしています。

素直に ARM64 brew を使えば ARM64 のバイナリがインストールできるのは、すでに zsh のインストールで確認した通りです。

では、ARM64 ターミナルから x86_64 シェルに入り x86_64 brew を使うとどうなるでしょうか。

x86_64 brew にはまだ何も入っていません。

ARM64 ターミナル
$ /usr/local/bin/brew list | grep mysql   

ARM64 brew にもまだ何も入っていません。

ARM64 ターミナル
$ /opt/homebrew/bin/brew list | grep mysql

x86_64 brew でインストールします。

ARM64 ターミナル
$ /usr/local/bin/brew install mysql-client
bla bla bla

x86_64 brew で x86_64 バイナリを入れたことになりました。

ARM64 ターミナル
$ /usr/local/bin/brew list | grep mysql
mysql-client

$ lipo -archs /usr/local/opt/mysql-client/bin/mysql
x86_64

ARM64 brew には影響はありません。

ARM64 ターミナル
$ /opt/homebrew/bin/brew list | grep mysql

整理するとこういうことですね。

ターミナル シェル brew 結果
ARM64 ARM64 ARM64 ARM64
ARM64 ARM64 x86_64 エラーだった
ARM64 x86_64 ARM64 エラーだった
ARM64 x86_64 x86_64 x86_64

brew がインストールするバイナリのアーキテクチャは、macOS やターミナルではなく brew のアーキテクチャに依存しているようです。

整理

brew を使い分けたいならシェルのアーキテクチャを使い分ければ良いということがわかりました。

シェルのアーキテクチャを使い分ける方法は 2 つです。

方法 1. x86_64 シェル用のターミナルと ARM64 シェル用のターミナルを別で用意する

方法 2. ARM64 ターミナルを用意し、x86_64 シェルと ARM64 シェルを切り替える

十分理解はできたので、次の章では実際にどう運用するかをまとめます。

参考にした記事

脚注
  1. Rosetta を使用したら実際は ARM64 に変換されているはずなので、x86_64 ターミナルという表記はあまり正しい表現ではないかもしれません。が、シェルなどの表記と合わせた形にすることで読みやすくなるだろうという意図でこうしました。 ↩︎