PyInstaller 可以用來把 Python 程式打包起來,方便在其他機器上執行,
省去安裝 Python 以及所使用套件的時間(尤其在 windows 上)
安裝 PyInstaller
先到 官網 下載 PyInstaller 的壓縮檔,並且解壓縮,放置到適合的路徑即可。
使用方式
使用方式的部份大致分為兩部份介紹。
第一個比較簡單的使用方式是直接使用 PyInstaller 內的 pyinstaller.py
例如現在寫好了一個 hello.py 接著使用 pyinstaller.py
$ python path_to_PyInstaller/pyinstaller.py [OPTION] xxx.py ex. $ python path_to_PyInstaller/pyinstaller.py --onefile hello.py
執行後 pyinstaller 會為你的程式產生一個 .spec 檔(類似 makefile 的東西)
並且依據內容產生執行檔(pyinstaller 會提示你執行檔的位置)。
OPTION 的部份可以 $ python pyinstaller.py --help 查看,底下也列出一些供參考
--onefile 製作出獨立的執行檔 --onedir 製作出的檔案街放在同一個目錄下(預設值) --tk 製作包含TCL/TK的檔案。 --windowed 製作視窗程式。(程式執行時不會有文字視窗出現) --console 製作一般的console程式。 --upx 製作透過UPX壓縮過的執行檔。 --icon=<FILE.ICO> 指定程式的圖示。 --version=<FILE> 指定程式的版本資訊(需要準備一個檔案放這些資訊)。 --name=<NAME> 指定程式的名稱。若無此選項,則主script檔案的名稱將被使用。
另外有時可能 pyinstaller 沒有辦法正確分析程式相依性,或者有特別需求時可能需要
先修改 .spec 檔在打包,又或者要使用現有的 .spec 檔打包時可以參考下列作法。
首先先使用 utils/Makespec.py 產生 .spec 檔
$ python path_to_PyInstaller/utils/Makespec.py [OPTION] xxx.py ex. $ python path_to_PyInstaller/utils/Makespec.py [OPTION] hello.py
接著便會產生與主程式同名的 hello.spec 便可以對他先做需要的修改, .spec 的內容大致如下
# -*- mode: python -*- a = Analysis(['hello.py'], pathex=['/tmp'], hiddenimports=[], hookspath=None) pyz = PYZ(a.pure) exe = EXE(pyz, a.scripts, a.binaries, a.zipfiles, a.datas, name=os.path.join('dist', 'hello'), debug=False, strip=None, upx=True, console=True )
以筆者為例曾經在打包一個以 WxPython 撰寫的程式,打包完後執行會有以下的錯誤
ImportError: No module named scipy.sparse.csgraph._validation
那網路上查到比較多的作法都是在主程式裡加上一些 import 好讓
pyinstaller 可以正確的分析出這個相依性這個相依性,不過這個作法讓我不太舒服,
因為一些檢查語法的 plugin 一樣找不到這個相依性,就會提醒我 import 了一個沒用到的東西,
所以我決定把他寫進 .spec 中,在 .spec 裡有個 Analysis 的項目其中有個 hiddenimports,
以筆者的例子就需要把 scipy.sparse.csgraph._validation 這個 module 加進去,像是這樣
# -*- mode: python -*- a = Analysis(['hello.py'], pathex=['/tmp'], hiddenimports=['scipy.sparse.csgraph._validation'], hookspath=None) ..... 後略
這樣 pyinstaller 就會把這個 module 一同打包起來,就可以解決這個問題了。
編寫好 .spec 後就可以使用 utils/Build.py 來打包
$ python path_to_PyInstaller/utils/Build.py xxx.spec ex. $ python path_to_PyInstaller/utils/Build.py hello.spec
執行結果基本上和第一部份的相同。