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 |