数年前、次のような記事を書きました。
上記記事を最新状況を踏まえて更新した、新バージョンの記事が本記事です。
最新の macOS には Python 環境はデフォルトでは同梱されていない
2022年の macOS Monterey 12.3 Update より、macOS には標準で同梱されないようになりました。よって、Pythonを使用するアプリケーションやスクリプトを配布する開発者は、
- ユーザが各自で Python 環境をインストールすることを要求する
- Python環境を丸ごと添付して配布する
といういずれかの手段を選ぶ必要があります。
ユーザにインストールさせる場合
ユーザが Python をインストールする方法としては、
- Xcode Command Line Tools
- Homebrew
- MacPorts
- pyenv
- Python の公式 pkg
- Anaconda / Miniconda
などの手が考えられます。このうち、最も簡便なのは Xcode Command Line Tools
でしょう。
xcode-select --install
としてインストールすると、
/Library/Developer/CommandLineTools/usr/bin/python3
が使えるようになります。
初回起動時の自動インストール
実は、現在の macOS でも
/usr/bin/python3
というコマンドはデフォルトで用意されていますが、これは“スタブ”と呼ぶべきもので、
- Xcode Command Line Tools がインストールされていなければインストールを促すダイアログを表示する
- インストールされていれば
/Library/Developer/CommandLineTools/usr/bin/python3
を起動する
という挙動をします。
ポータブルな Python 環境を用意したい!
ユーザにターミナル操作をさせることは避けたい
上記の「ユーザ各自にPython環境をインストールさせる」という方法の場合、「ユーザにターミナル操作をさせる」という手間が生じます。ですが、これはユーザ側にとって大きな負担になります。一般ユーザにとって「ターミナルにコマンドを打ち込む」という操作は、プログラマが想像するよりもはるかに忌避感の強い行為であり、猛烈に嫌がられます。「ターミナルにコマンドを打ち込む」ことを要求するアプリは、それが普及の妨げとなりえます。自分はアプリ作成において 「ユーザにターミナル操作を要求したら負け」 と考え、ターミナル操作を要求しない形で配布するように心がけています。
ポータブルな Python 環境を同梱して配布すると受け入れられやすい
そこで、Python環境を丸ごとパッケージ化して、それをアプリに同梱して配布する方法が使えます。.app
バンドルのアプリの場合、そのバンドル内にPython環境を封じ込めて(APPNAME.app/Contents/Frameworks/Python.framework
)配布し、アプリ内からはその中の Python バイナリ (APPNAME.app/Contents/Frameworks/Python.framework/Versions/Current/bin/python3
) を起動する、という形で使えば、ユーザにPython環境を用意させる手間が省けます。
ポータブルな Python 環境のビルド法
macOSで配布するためのポータブルな Python 環境のビルドには、relocatable-pythonというツールを使うのが便利です。
Step 0: Xcode Command Line Tools のインストール(確認)
まず、開発者自身のMac環境には、Xcode Command Line Tools がインストールされている必要があります。
xcode-select --install
Step 1: relocatable-python
レポジトリの clone
mkdir ~/WORKDIR
cd ~/WORKDIR
git clone https://github.com/gregneagle/relocatable-python
cd relocatable-python
Step 2: Python の最新バージョンを確認
Pythonの最新の正式リリースバージョンを確認します。本記事執筆時点では 3.13.3
でした。そこで、https://www.python.org/ftp/python/3.13.3/
にアクセスします。すると、その中に python-3.13.3-macos11.pkg
というファイル名が確認できます。この 3.13.3
と 11
という数値を記録しておきます。
Step 3: requirements.txt
を用意
これから作成する Portable Python Framework にデフォルトで同梱する pip ライブラリを記載した requirements.txt
を作成します。
なお、relocatable-python
レポジトリにはデフォルトで requirements_python3_recommended.txt
というファイルが用意されていますが、これには古い pyobjc
が指定されており、これを同梱しようとするとビルドが失敗してしまいます。よって、用意されている requirements_python3_recommended.txt
は使わず、自分で必要な requirements.txt
を用意しましょう。
例えば次のように指定します。
numpy # 配列・行列計算の基盤
scipy # 数値解析・統計・最適化
matplotlib # 可視化
pandas # データフレームによるデータ処理
requests # HTTP通信の標準的ライブラリ
Step 4: ビルド
次のようにビルドコマンドを実行します。オプションは以下の通りです。
-
--python-version
: Step 2 で確認したPythonのバージョン番号を指定 -
--os-version
: Step 2 で確認したOSのバージョン番号を指定 -
--pip-requirements
: Step 3 で作成したファイルを指定
./make_relocatable_python_framework.py --python-version 3.13.3 --os-version 11 --upgrade-pip --pip-requirements=requirements.txt
これにより、Python.framework
が生成されます。
Step 5: 署名
配布するには、Apple Developer Program に登録された正当な署名をしておくことが望ましいです。
codesign --force -s "Developer ID Application: <キーチェーンに登録した証明書名>" Python.framework
署名を終えたら、その署名が有効かどうか、
codesign --verify --verbose=4 Python.framework
として確認しましょう。
Step 6: バイナリの対応CPUアーキテクチャ確認
この方法で生成された Python バイナリ自体は、Intel Mac (x86_64
) / Apple Silicon (arm64
) の両方に対応した Universal Binary となっています。しかし、pip
でインストールされる周辺ライブラリは、ホストマシンのネイティブなバイナリしかインストールされないことが普通です。それでは、完全なポータビリティが実現できたとは言えません。
どのバイナリが Universal Binary になっているか否かを確認するには、
./python_universal_tester.sh 3.13.3
とするとよいです。Python.framework
内の各バイナリが、x86_64
/ arm64
のどちらに対応しているかを確認できます。
Pythonそのものだけではなく pip ライブラリを添付して配布する場合、完全なポータビリティを実現するには、Intel Mac と Apple Silicon Mac の両方で Python.framework
を生成して両方を同梱し、自分のアプリからは、uname -m
の実行結果に応じてどちらを呼び出すかを切り替える、などといった措置を講じる必要があるでしょう。
Step 7: 配布
app bundle として配布する場合、APPNAME.app/Contents/Frameworks/Python.framework
に同梱しておき、APPNAME.app/Contents/Frameworks/Python.framework/Versions/Current/bin/python3
を起動させるとよいでしょう。シェルスクリプトから Python インタプリタを起動させる場合、
export PATH=/path/to/APPNAME.app/Contents/Frameworks/Python.framework/Versions/Current/bin:$PATH
と冒頭で宣言して起動させるとよいでしょう。
zipで包む場合の注意
生成された Python.framework
を zip 圧縮して配布する場合、内部のシンボリックリンク構造を保って zip 化するため,-y
オプションを付けることを忘れぬようご注意ください。
zip -rqy PythonFramework.zip Python.framework