Mac で Universal Binary な Python が簡単にビルド出来る件。

概要

昨日 Python 3.x のビルドが通らなくてなんとかしてた のだけど、その時に ./configure のオプションを眺めていたら --with-universal-archs というのを見付けた。

どうやら読む限り --enable-universalsdk と一緒に指定してね、ということと、詳しくは Mac/README.rst を読んでくれ、とのこと。

pyenv の python-build でビルドしてみる

どうやら --enable-universalsdk--with-universal-archsPYTHON_CONFIGURE_OPTS では渡せないようで、 CONFIGURE_OPTS で指定する必要があるようだ。

--enable-universalsdk の値は省略可能で、省略時は /usr/bin/xcodebuild -version -sdk macosx Path が使われてそう。

CONFIGURE_OPTS="--enable-universalsdk --with-universal-archs=universal2" \
PYTHON_CONFIGURE_OPTS="--build=$(/usr/bin/uname -p)-apple-darwin$(/usr/bin/uname -r)" \
pyenv install 3.9.6

上の例で PYTHON_CONFIGURE_OPTS を指定してるのは GNU 版 coreutils が入っているとビルド出来ないからで、環境によっては省略可能。

出てきたバイナリ

M1 MacBook Air でビルドした結果 ↓

$ pwd
/opt/homebrew/opt/pyenv/versions/3.9.6/bin

$ file python3.9
python3.9: Mach-O universal binary with 2 architectures: [x86_64:Mach-O 64-bit executable x86_64] [arm64]
python3.9 (for architecture x86_64): Mach-O 64-bit executable x86_64
python3.9 (for architecture arm64):  Mach-O 64-bit executable arm64

2018 Mac mini でビルドした結果 ↓

$ pwd
/usr/local/opt/pyenv/versions/3.9.6/bin

$ file python3.9
python3.9: Mach-O universal binary with 2 architectures: [x86_64:Mach-O 64-bit executable x86_64] [arm64]
python3.9 (for architecture x86_64): Mach-O 64-bit executable x86_64
python3.9 (for architecture arm64):  Mach-O 64-bit executable arm64

M1 環境でも Intel 環境でもちゃんとファットバイナリになってることが確認できる。

締め

Universal Binary の仕組み自体は Mac OSX 10.4 の頃の PowerPC から Intel に移行した時に使われているものがそのまま使われていて (たぶん) 、組み合わせは違えど今もなお現役の素晴しい技術だなと思う。新・OS X ハッキング! のこの記事 あたりからバックナンバーを眺めると勉強になる。

しかし Universal Binary を手元でビルドできて嬉しいのか、とか、こんなんどこで使うんだという気もするが、もしこれが Ruby だったら CocoaPods 周りで問題 が起きて面倒な事例とかがすぐに思い浮かぶし、自分がいかに Python を普段使いしてないかという話でもある。

なお Python 本体をビルドすること自体が楽しくなってしまって、手元で雑に動かしたかったサンプルコードはまだ動かしてない。