Pyinstaller打包Python程序以及常見bugs
Pyinstaller可以將Python腳本打包成獨立的可執行程序,支持多平台Windows,Linux和Mac OS X等。
用pip安裝pyinstaller:
pip install pyinstaller
使用方法非常簡單:
pyinstaller myscript.py
這會產生兩個文件夾,build和dist,build保存著打包前的配置文件和完成後的結果信息,最終的打包程序位於dist中。
常用參數:
-h, --help
查看幫助-y, --noconfirm
不詢問-n NAME, --name NAME打包後文件名--distpath DIR指定打包位置
--add-data <SRC;DEST or SRC:DEST>添加數據文件--add-binary <SRC;DEST or SRC:DEST>添加二進位文件--hidden-import MODULENAME, --hiddenimport MODULENAME
打包隱藏的模塊-w, --windowed, --noconsole有GUI的程序可以不提供命令行界面--version-file FILE
加入版本文件
更多用法請見Using PyInstaller。
Pyinstaller在打包時會將儘可能地收集代碼相關的依賴,包括python解釋器,最後得到的軟體包,其他用戶無需安裝其他依賴也能使用。但這同時也意味著打包出來的結果很可能非常龐大。比如我一個不到30k的腳本,最後打包出來的軟體足足120m以上。
雖然Pyinstaller會儘力將所有的程序依賴都收集起來,但是難免會有遺漏的情況。在打包過程中經常可以看見報錯信息,說找不到某某依賴,有時候這不會影響最後的運行結果,但有時候也會導致打包好的exe運行失敗。
下面介紹幾個常見bugs和解決方法。
python腳本可以運行,但是exe程序閃退,這時需要用命令行運行exe,直接在命令行輸入完整路徑,然後就會列印錯誤信息。
接下來按照這個方案一步步排查錯誤,Make sure everything is packaged correctly。
ImportError: DLL load failed: 找不到指定的模塊
遇到這樣的問題指的是缺少dll文件,但是這個錯誤往往會讓人很困擾,因為它不會提示具體缺少什麼dll文件。想要正確的把缺少的dll找到,就得查看打包運行時的錯誤警告,除了在shell查看以外,還可以在/build/name/warnname.txt中查看。
找出缺失的dlls以後,可以在打包時加上--add-binary選項:
pyinstaller --add-binary /path/to/some.dll:. myscript.py
或者在.spec文件中添加更多的dlls:
a = Analysis(... binaries=[(/path/to/some.dll, .), ... ], ...)
或者在打包完成後,直接將dll文件複製到軟體包即可。
例如,我在打包需要scipy的項目時遇到了這個bug,從錯誤信息中發現缺少了很多dlls,直接搜索其相應的名字,發現其實都在這個文件夾中,Python36Libsite-packagesscipyextra-dll。然後將這些dlls全部複製到打包程序文件夾中就行了。關於這個bug還可以參考pyinstaller/issues/3235。
ModuleNotFoundError: No module named xxxxxx
有時pyinstaller的分析器認為它已經找到了所有需要的模塊,但實際卻沒有,這往往是存在隱藏的導入(hidden import)。當代碼使用__import__或exec或eval等函數時,可能會出現隱藏的導入。當擴展模塊使用python/c API進行導入時,也可能出現隱藏的導入。當這種情況發生時,分析器無法偵測,也不會有任何警告,只有在運行時才會出現錯誤。
解決辦法是在打包時加上--hidden-import=some.module
選項,或者在.spec文件中指定:
a = Analysis(... hiddenimports=[some.module, ... ], ...)
例如我在打包完成後,運行exe文件時遇到了錯誤:
ModuleNotFoundError: No module named scipy._lib.messagestream
所以要重新打包並加上隱藏的導入:
pyinstaller --hidden-import=scipy._lib.messagestream myscript.py
推薦閱讀:
※ABSP第七章:[lesson25續:替換,更為複雜的正則表達式還有一個練手project]
※09.基變換
※ELEMENTARY.02.Correct Sentence
※Flask源碼剖析
TAG:Python | Pyinstaller | Bug |