Chapter 06

シェルの運用方針について

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

この章の操作は全て ARM Mac で行なっています。

x86_64 ターミナルと ARM64 ターミナルを用いて、結果を比較しながら確認します。

インストールの動作を比較するときは、適宜アンインストールを行っています。

arch コマンドを使う

Rosetta を入れると arch と言うコマンドが使えるようになります。[1]

mac arch command などで調べてもいまいち説明が見つからないので、man arch の冒頭を見てみます。

man arch

DESCRIPTION

The arch command with no arguments, displays the machine's architecture type.

The other use of the arch command is to run a selected architecture of a universal binary. A universal binary contains code that can run on different architectures. By default, the operating system will select the architecture that most closely matches the processor type. A 64-bit architecture is preferred over a 32-bit architecture on a 64-bit processor, while only 32-bit architectures can run on a 32-bit processor.

When the most natural architecture is unavailable, the operating system will try to pick another architecture. On 64-bit processors, a 32-bit architecture is tried. Otherwise, no architecture is run, and an error results.

The arch command can be used to alter the operating system's normal selection order. The most common use is to select the 32-bit architecture on a 64-bit processor, even if a 64-bit architecture is available.

引数なしで実行するとアーキテクチャを表示、そうでなければアーキテクチャを指定して実行、といったところでしょうか。

ユニバーサルバイナリのシェルを切り替える

確認してみましょう。

x86_64 ターミナル → x86_64 シェル → x86_64 シェル が ( 意味はないけど ) 可能です。

x86_64 ターミナル
$ uname -m
x86_64

$ arch -x86_64 /bin/zsh

$ uname -m
x86_64

x86_64 ターミナル → x86_64 シェル → ARM64 シェル が ( 前の章と違い ) 可能です。

x86_64 ターミナル
$ uname -m
x86_64

$ arch -arm64e /bin/zsh

$ uname -m
arm64

ARM64 ターミナル → ARM64 シェル → x86_64 シェル が可能です。

ARM64 ターミナル
$ uname -m
arm64

$ arch -x86_64 /bin/zsh

$ uname -m
x86_64

ARM64 ターミナル → ARM64 シェル → ARM64 シェル が ( 意味はないけど ) 可能です。

ARM64 ターミナル
$ uname -m
arm64

$ arch -arm64e /bin/zsh

$ uname -m
arm64

全てのパターンが感覚的に期待する通りに動いていますね。

brew を使い分ける

brew の挙動も確認しておきます。

ARM64 ターミナルでの x86_64 brew の利用

まず前の章では割愛しましたが、ただ ARM64 ターミナルから x86_64 brew を使うことはできません。

ARM64 ターミナル
$ uname -m
arm64

$ /usr/local/bin/brew install mysql-client
Error: Cannot install in Homebrew on ARM processor in Intel default prefix (/usr/local)!
Please create a new installation in /opt/homebrew using one of the
"Alternative Installs" from:
  https://docs.brew.sh/Installation
You can migrate your previously installed formula list with:
  brew bundle dump

arch -x86_64 を付与して同じコマンドを実行してみると、x86_64 バイナリのインストールに成功します。

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

$ arch -arm64e /opt/homebrew/bin/brew list | grep mysql  

$ arch -x86_64 /usr/local/bin/brew install mysql-client
bla bla bla

$ arch -x86_64 /usr/local/bin/brew list | grep mysql   
mysql-client

$ arch -arm64e /opt/homebrew/bin/brew list | grep mysql 

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

mysql はどのアーキテクチャのターミナルからでも、問題なく動きます。

x86_64 ターミナル
$ uname -m
x86_64

$ /usr/local/opt/mysql-client/bin/mysql -h 127.0.0.1 -u foo -pbar
mysql>
ARM64 ターミナル
$ uname -m
arm64

$ /usr/local/opt/mysql-client/bin/mysql -h 127.0.0.1 -u foo -pbar
mysql> 

インストールするバイナリのアーキテクチャは brew のアーキテクチャと連動することと、ターミナルやシェルをいちいち切り替えなくても arch を使えば brew を使い分けられることが確認できました。

x86_64 ターミナルでの ARM64 brew の利用

同じく前の章では割愛しましたが、ただ x86_64 ターミナルから ARM64 brew を使うことはできません。

x86_64 ターミナル
$ uname -m
x86_64

$ /opt/homebrew/bin/brew install mysql-client
Error: Cannot install under Rosetta 2 in ARM default prefix (/opt/homebrew)!
To rerun under ARM use:
    arch -arm64 brew install ...
To install under x86_64, install Homebrew into /usr/local.

arch -arm64e を付与して同じコマンドを実行してみると、ARM64 バイナリのインストールに成功します。

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

$ arch -arm64e /opt/homebrew/bin/brew list | grep mysql

$ arch -arm64e /opt/homebrew/bin/brew install mysql-client
bla bla bla

$ arch -x86_64 /usr/local/bin/brew list | grep mysql

$ arch -arm64e /opt/homebrew/bin/brew list | grep mysql
mysql-client

$ lipo -archs /opt/homebrew/Cellar/mysql-client/8.0.26/bin/mysql
arm64

mysql はどのアーキテクチャのターミナルからでも、問題なく動きます。

x86_64 ターミナル
$ uname -m
x86_64

$ /opt/homebrew/Cellar/mysql-client/8.0.26/bin/mysql -h 127.0.0.1 -u foo -pbar
mysql>
ARM64 ターミナル
$ uname -m
arm64

$ /opt/homebrew/Cellar/mysql-client/8.0.26/bin/mysql -h 127.0.0.1 -u foo -pbar
mysql> 

先ほどと完全に対称的なことができるのがわかりました。

が、どちらでも同じことが実現できるのなら、運用するのは片方だけで良いでしょう。

結論

arch を使えば全てのパターンが問題なく動くことが確認できました。

が、2 ケースだけ扱えるようにしておけば十分でしょう。

ターミナル シェル brew 取得結果 取得結果の利用 メモ
x86_64 x86_64 x86_64 x86_64 可能
x86_64 x86_64 ARM64 ( arch ) ARM64 可能
x86_64 ARM64 x86_64 ( arch ) x86_64 可能
x86_64 ARM64 ARM64 ARM64 可能
ARM64 x86_64 x86_64 x86_64 可能
ARM64 x86_64 ARM64 ( arch ) ARM64 可能
ARM64 ARM64 x86_64 ( arch ) x86_64 可能 対象が ARM64 未対応時
ARM64 ARM64 ARM64 ARM64 可能 基本

設定の要点はこうですね。

  • ターミナルとシェルを複数インストールする必要はない
  • ARM64 を基本として、困ったときだけ x86_64 バイナリを取得する
    • brewarch -arm64e /opt/homebrew/bin/brew のエイリアスにする
    • もう一方は brew86 ( arch -x86_64 /usr/local/bin/brew ) みたいな alias にする
  • 取得バイナリがなんであれ、ARM64 ターミナルから全然気にしないで使える
  • $PATH は ARM64 バイナリの方 > x86_64 バイナリの方 の優先順位で設定しておく
  • もし x86_64 シェルが使いたければ、デフォルトのユニバーサルバイナリで十分
    • zsh86 ( arch -x86_64 /bin/zsh ) みたいな alias を使う

参考にした記事

https://zenn.dev/ress/articles/069baf1c305523dfca3d

公開後追記 ( 2021/08 )

いくつか指摘をいただいたので、ここで訂正および補足をします。

1. コマンドのペーストミス

同じく前の章では割愛しましたが、ただ x86_64 ターミナルから ARM64 brew を使うことはできません。

でのコマンドが arch -arm64 /opt/homebrew/bin/brew install mysql-client になっていましたが、これだとエラーになりません。

本文を訂正しました。

2. brew の実態について補足 1

/opt/homebrew/bin/brew/usr/local/bin/brew はどちらも Homebrew/brew を持ってきているはずなので、実態自体には差分はありません。

shebang が /bin/bash になっているからどちらのアーキテクチャでも動くようです。

$ diff -u /usr/local/bin/brew /opt/homebrew/bin/brew

$ head -n 1 /usr/local/bin/brew
#!/bin/bash

2. brew の実態について補足 2

brew は実行環境のガードに HOMEBREW_PREFIX という値を使っています。

これは叩いた brew のインストール場所に応じているようで /usr/local/opt/homebrew になり、それが変に捻れていないかを判定しています。

HOMEBREW_DEFAULT_PREFIX/usr/localHOMEBREW_MACOS_ARM_DEFAULT_PREFIX/opt/homebrew でしょう。

/usr/local/Homebrew/Library/Homebrew/install.rb
def check_prefix
  if (Hardware::CPU.intel? || Hardware::CPU.in_rosetta2?) &&
     HOMEBREW_PREFIX.to_s == HOMEBREW_MACOS_ARM_DEFAULT_PREFIX
    if Hardware::CPU.in_rosetta2?
      odie <<~EOS
        Cannot install under Rosetta 2 in ARM default prefix (#{HOMEBREW_PREFIX})!
        To rerun under ARM use:
            arch -arm64 brew install ...
        To install under x86_64, install Homebrew into #{HOMEBREW_DEFAULT_PREFIX}.
      EOS
    else
      odie "Cannot install on Intel processor in ARM default prefix (#{HOMEBREW_PREFIX})!"
    end
  elsif Hardware::CPU.arm? && HOMEBREW_PREFIX.to_s == HOMEBREW_DEFAULT_PREFIX
    odie <<~EOS
      Cannot install in Homebrew on ARM processor in Intel default prefix (#{HOMEBREW_PREFIX})!
      Please create a new installation in #{HOMEBREW_MACOS_ARM_DEFAULT_PREFIX} using one of the
      "Alternative Installs" from:
        #{Formatter.url("https://docs.brew.sh/Installation")}
      You can migrate your previously installed formula list with:
        brew bundle dump
    EOS
  end
end

これを見る限り、arch を使うにしても brew 自体は 2 箇所にインストールしておかないとだめですね。

案の定 arch で x86_64 を指定して ARM brew を叩いてもエラーになりました。

ARM64 ターミナル
$ uname -m
arm64

$ arch -x86_64 /opt/homebrew/bin/brew install mysql-client

Error: Cannot install under Rosetta 2 in ARM default prefix (/opt/homebrew)!
To rerun under ARM use:
    arch -arm64 brew install ...
To install under x86_64, install Homebrew into /usr/local.

3. arch コマンドについて補足 1

Rosetta を入れると arch と言うコマンドが使えるようになります。

arch コマンド自体は Intel Mac にも入っていました。

Intel Mac と ARM Mac の man arch を抜粋して掲載します、興味がある方は読んでみてください。

man arch ( Intel Mac )

DESCRIPTION

The arch command with no arguments, displays the machine's architecture type.

The other use of the arch command it to run a selected architecture of a universal binary. A universal binary contains code that can run on different architectures. By default, the operating system will select the architecture that most closely matches the processor type. This means that an intel architecture is selected on intel processors and a powerpc architecture is selected on powerpc processors. A 64-bit architecture is preferred over a 32-bit architecture on a 64-bit processor, while only 32-bit architectures can run on a 32-bit processor.

When the most natural architecture is unavailable, the operating system will try to pick another architecture. On 64-bit processors, a 32-bit architecture is tried. If this is also unavailable, the operating system on an intel processor will try running a 32-bit powerpc architecture. Otherwise, no architecture is run, and an error results.

The arch command can be used to alter the operating system's normal selection order. The most common use is to select the 32-bit architecture on a 64-bit processor, even if a 64-bit architecture is available.


The arch_name argument must be one of the currently supported architectures:
i386 32-bit intel
x86_64 64-bit intel

man arch ( ARM Mac )

DESCRIPTION

The arch command with no arguments, displays the machine's architecture type.

The other use of the arch command is to run a selected architecture of a universal binary. A universal binary contains code that can run on different architectures. By default, the operating system will select the architecture that most closely matches the processor type. A 64-bit architecture is preferred over a 32-bit architecture on a 64-bit processor, while only 32-bit architectures can run on a 32-bit processor.

When the most natural architecture is unavailable, the operating system will try to pick another architecture. On 64-bit processors, a 32-bit architecture is tried. Otherwise, no architecture is run, and an error results.

The arch command can be used to alter the operating system's normal selection order. The most common use is to select the 32-bit architecture on a 64-bit processor, even if a 64-bit architecture is available.


The arch_name argument must be one of the currently supported architectures:
i386 32-bit intel
x86_64 64-bit intel
x86_64h 64-bit intel (haswell)
arm64 64-bit arm
arm64e 64-bit arm (Apple Silicon)

微妙に内容が違いますね、powerpc という単語が見えます。

Rosetta 1 および macOS における 32bit と 64bit の混在のために使われているようです。

参考

https://ja.wikipedia.org/wiki/Universal_Binary

3. arch コマンドについて補足 2

arch -arm64 よりは arch -arm64e の方が適切そうですが、よしなに解釈してくれるみたいなので打つのが楽な方を使っていました。

brew のエラーメッセージも arch -arm64 付けてみたらどうだと言っていますし、理解していればどちらもで良いと僕は思います。

と思っていましたが、本文は全て -arm64e に訂正しました。

脚注
  1. Rosetta を入れた後に知ったので自分の手で確認したわけではありませんが。 ↩︎