ターミナルのバイナリとシェルのバイナリについて
ターミナルのバイナリ
ターミナル.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 つのターミナルを起動して確認してみます。
$ uname -m
x86_64
$ uname -m
arm64
ログインシェルのアーキテクチャはターミナルのアーキテクチャに応じて決まるようです。
※ uname -m
の詳細挙動については細かく調べきれなかったのですが、Rosetta を使用したことで x86_64 バイナリを ARM64 バイナリに変換して使っているが、「x86_64 バイナリを使えているよ」という風に見せているものだと考えることにしました。
シェルの別のバイナリを用意する
試してみたいことがあるので、説明の順番が前後しますが、brew
を用意します。
brew
自体にも x86_64 バイナリと ARM64 バイナリがあり、シェルのアーキテクチャとバイナリのアーキテクチャを揃えないといけません。
2 つのターミナルで brew
を 2 つ準備し、両方で zsh
をインストールしてみます。
( インストール手順は調べれば詳しい記事がたくさんあるので割愛します。)
$ /usr/local/bin/brew install zsh
bla bla bla
$ brew list | tail -n 3
xorgproto
xz
zsh
$ /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
を起動するとどうなるか確認してみます。
$ 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 シェルを使う
こちらも確認します。
$ 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
にはまだ何も入っていません。
$ /usr/local/bin/brew list | grep mysql
ARM64 brew
にもまだ何も入っていません。
$ /opt/homebrew/bin/brew list | grep mysql
x86_64 brew
でインストールします。
$ /usr/local/bin/brew install mysql-client
bla bla bla
x86_64 brew
で x86_64 バイナリを入れたことになりました。
$ /usr/local/bin/brew list | grep mysql
mysql-client
$ lipo -archs /usr/local/opt/mysql-client/bin/mysql
x86_64
ARM64 brew
には影響はありません。
$ /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 シェルを切り替える
十分理解はできたので、次の章では実際にどう運用するかをまとめます。
参考にした記事
-
Rosetta を使用したら実際は ARM64 に変換されているはずなので、x86_64 ターミナルという表記はあまり正しい表現ではないかもしれません。が、シェルなどの表記と合わせた形にすることで読みやすくなるだろうという意図でこうしました。 ↩︎