Apple M1 systems Pyinstaller operating procedures
前言
最近將電腦換成了 MacBook Pro M1 Max,在使用 PyInstaller
轉成執行檔發現了一系列的問題,為了防止記憶隨著時間消散,在這邊特別紀錄一下,也供給其他人參考一下。
由於 M1 Chip 是 ARM 64 的架構,所以 Python 的 Libary 有許多未支援或修正的地方,所幸 Apple 早想到了這個問題,提出可同時支援這兩個平台架構的編譯程式 Universal 2,我們只要運用 Universal 2 所編譯出來的程式,即可無痛在 ARM 和 Intel 架構下執行!
接下來說明如何使用 Universal 2 編譯 Python 程式
1. 環境設置
Python 3.9.1 在 2021 年 12 月 7 日正式釋出,它是第一個支持 Universal 2 的 Python 版本,而目前在最新的 macOS Monterey 12.3.1 版本中,系統內建的 Python 版本為 3.8.9,也就是說在最新的系統內建 Python 環境下,是無法使用 Universal 2 進行編譯的。
為了解決這個問題,我使用的方法是利用 Pyenv 建立一個虛擬環境,重新打造一個支援 Universal 2
的 Pyhton 環境。
安裝 Homebrew
在執行所有作業前,需要先安裝Homebrew
,來作為後續安裝的基礎,而 Homebrew 目前也已經支援 M1 Chip,大部分的 Bug 也陸續得到了修復,可以正常使用,其安裝指令如下1
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
安裝 Pyenv 和 Pyenv-Virtualenv
接下來利用 Homebrew 來安裝Pyenv
和Pyenv-Virtualenv
,指令分別如下1
brew install pyenv
設置環境變數如下 (由於我使用的 Shell 是 ZSH,所以我是設置在
.zshrc
,請依照你所使用的 Shell 設置環境參數)1
2
3
4export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init --path)"
eval "$(pyenv init -)"緊接著再來安裝
Pyenv-Virtualenv
,指令如下1
brew install pyenv-virtualenv
安裝 macOS 64-bit universal2 Version Python
由於 Pyenv 預設安裝 Python 的版本會依照系統,自動選擇安裝Intel
或是ARM
版本,並不會主動安裝 universal2 版本,所以我們在設置虛擬環境時,需要設置Config
強制要求制定 universal2 版本,其指令如下1
2
3
4
5
6
7
8env \
PATH="$(brew --prefix tcl-tk)/bin:$PATH" \
LDFLAGS="-L$(brew --prefix tcl-tk)/lib" \
CPPFLAGS="-I$(brew --prefix tcl-tk)/include" \
PKG_CONFIG_PATH="$(brew --prefix tcl-tk)/lib/pkgconfig" \
CFLAGS="-I$(brew --prefix tcl-tk)/include" \
PYTHON_CONFIGURE_OPTS="--enable-framework --enable-universalsdk --with-universal-archs=universal2 --with-tcltk-includes='-I$(brew --prefix tcl-tk)/include' --with-tcltk-libs='-L$(brew --prefix tcl-tk)/lib -ltcl8.6 -ltk8.6'" \
pyenv install 3.10.3對於這個指令,稍微說明一下其含義
關於這段 PATH 說明
1
2
3
4
5
6PATH="$(brew --prefix tcl-tk)/bin:$PATH" \
LDFLAGS="-L$(brew --prefix tcl-tk)/lib" \
CPPFLAGS="-I$(brew --prefix tcl-tk)/include" \
PKG_CONFIG_PATH="$(brew --prefix tcl-tk)/lib/pkgconfig" \
CFLAGS="-I$(brew --prefix tcl-tk)/include" \
PYTHON_CONFIGURE_OPTS="--with-tcltk-includes='-I$(brew --prefix tcl-tk)/include' --with-tcltk-libs='-L$(brew --prefix tcl-tk)/lib -ltcl8.6 -ltk8.6'" \首先由於我的程式是使用
Tkinter
所撰寫的,而 macOS 系統內建的 Python,預先設置的 Tkinter 為 v8.5 版本,而此版本在 Arm 系統下,會出現 UI 錯誤,轉譯出的程式 UI Background 會出現全黑的狀況,這個問題需要在 v8.5.9 才會被修復,所以我們需要在Pyenv
的Config
中設置 PATH,讓 Pyenv 安裝 Python 時內建 Tkinter v8.6 版本。此解決辦法參考自 Stackoverflow 中的說明。
接下來說明此段 PATH 意義
1
--enable-framework --enable-universalsdk --with-universal-archs=universal2
這段主要是作為 universal binary 的建構,否則 Python 在設置建構文件時,僅會依照所安裝使用的系統,預設安裝
Intel
或ARM
二擇一的建構文件。此解決辦法參考自 Jack.Jansen Note 以及 pyenv arm64 builds confused by x86_64 libintl in /usr/local #1877
因此如果不需要設置
Tkinter
,則可以輸入以下 PATH1
2env PYTHON_CONFIGURE_OPTS="--enable-framework --enable-universalsdk --with-universal-archs=universal2" pyenv install -v 3.10.3
當安裝完 Python 後,需要先將 System 環境切換成新的 Python 環境,可以直接輸入以下指令,基本上就可以直接開始使用
1
pyenv global 3.10.3
但是我習慣在虛擬環境下使用,所以我會再建置一個
Virtualenv
,輸入以下指令1
pyenv virtualenv 3.10.3 Python3103
最後把環境切入
Python3911 Virtualenv
做使用,相關操作指令可以參考此教學1
pyenv activate Python3103
2. Pyinstaller 操作實例
接下來我們就可以開始編譯我們的程式,在上篇文章,我所使用的指令如下
1 | pyinstaller -F /Users/Documents/02_Program/GitHub/test/test.py |
這個指令正常使用是不會有問題的,可是他所使用的編譯環境會變成依照系統預設的環境進行轉譯,例如你現在所使用的系統為 Intel 那麼他轉譯出來檔案的 Type 就會是 Inte,所以如果想在 ARM 架構下 Run 此程式就會碰到問題,所以我們必須進一步使用 --target-arch
指令讓 pyinstaller 知道你想轉譯成什麼樣的程式。
以下可以看看我的實例,編譯指令分別對應以下圖示
1 | 預設指令 |
以上就是關於 PyInstaller
與 Tkinter
目前在 Apple 晶片使用上需要注意的地方,我認為這是一個過渡期,後續應該隨著時間支援性會越來越完善,也就不需要使用這種方式了。