pyinstaller 生成 exe 的閃退問題解決方案

Galois發表於2020-06-06

簡單模組問題

如果在 pyinstaller project.py 的過程中,出現:

No module named 'xxx'

那就 pip install xxx 就行,比如:

$ pip install wxPython pypiwin32 tornado

這個 pip 對應於專案的虛擬環境。
其中 wxPython 對應 No module named 'wx'
其中 pypiwin32 對應 No module named 'win32com'
還有個老生常談的小問題,提一下,避免萌新看的一頭霧水,比如有些包有別名,比如你並不能通過 pip install wx 來解決 No module named 'wx' 的問題。這需要一些經驗,沒經驗的這些去搜尋引擎搜尋搜尋就知道了,基本解決方法都是 pip install ...,其中 ... 是這個模組的真名。

全網唯一答案系列

以上都是簡單的問題,如果不會出現 No module named xxx 的問題,就不用關心 pip install 了。
再遇到閃退等問題可以加上命令引數 -D
pyinstaller -D project.py,表示我們打包成一個資料夾,而不僅僅是個 exe 檔案,當然這個專案資料夾在 dist 下面。

在每次重新打包之前,務必刪除專案中的 builddist 目錄。

這時候還會碰到一些棘手的問題,比如:

SHtS2dLGIp.jpg!large

看最後的異常提示是 PyInstallerImportError 錯誤,可以看到 sklearn 下面缺少 .libs/vcomp140.dll 檔案,這是因為 pyinstaller 的執行過程中,沒有把虛擬環境(你的專案開發環境中 Lib/site-packages/ 內的包)中的該依賴檔案(vcomp140.dll)打包進來,這時候去原本我們的虛擬環境中找到這個檔案,複製出來,貼上進我們這個打包生成的資料夾內對印的 ./sklearn 目錄下的對應位置,但是我們看到這個目錄下面居然沒有 .libs 資料夾,那就在這裡(./sklearn)建立一個,然後把那個缺的依賴檔案(vcomp140.dll)複製進來就行。
可能看的會有點暈,這裡需要耐心點看,為了避免文字過多產生的表達歧義,再強調一下思路:「把生成的專案資料夾中缺失的依賴檔案,如 dll 檔案;從開發環境中的包裡找到它,並複製進來。」

打包除錯的時候需要注意不要隱藏控制檯,不然拿不到錯誤資訊,無法進行下一步 debug 操作。

我們可以看到這個問題被解決了,但是會有新的問題,基本都是 sklearn 的問題,這裡只是列舉我發生的問題,如果你寫的是別的專案,庫依賴也很嚴重,也會有這些問題,可能不是 sklearn,總之肯定是某個包缺失依賴檔案或模組檔案的問題。

現在來看看新的報錯資訊:

ydxld5hMCW.jpg!large

這個問題基本全網的答案都是諸如修改 project.spec 檔案中的 a=Analysis(...) 選項的 hiddenimports 配置:

hiddenimports=['cython',  'sklearn',  'sklearn.utils._cython_blas'],

然後刪除 builddist 後執行:

$ pyinstaller -D project.spec

或者是直接給 pyinstaller 命令加引數,比如這樣:

$ pyinstaller -F -w --hidden-import='sklearn.utils._cython_blas' --hidden-import='sklearn.neighbors.typedefs' --hidden-import='sklearn.neighbors.quad_tree' --hidden-import='sklearn.tree' --hidden-import='sklearn.tree._utils' project.py

如果你用這個方法解決不了,那就嘗試把缺失的模組從開發環境中的 site-packages 裡複製出來貼上進我們生成的 ./dist/project/ 裡面對應的模組所在位置(如果沒有找到對應的路徑,不存在這個資料夾之類的,就如以上說的建一個 .libs/ 資料夾一樣建立一個。)
比如我的生成專案資料夾位於:
C:\Users\Galois\Documents\project\dist\project

QQtYIubh0Y.png!large

當然,我們需要的專案可執行檔案 exe 也在這個目錄下。
接下來的操作基本就是對這個目錄裡面進行貼上缺失的模組,根據異常報錯資訊,比如我們剛才得到的報錯是:

ModuleNotFoundError: No module named 'sklearn.utils._cython_blas'

現在我們進入兩個地方:
生成的專案中的目錄:
C:\Users\Galois\Documents\project\dist\project\sklearn\utils
開發環境中的目錄(由於我不知道各位開發環境怎樣,這裡就直接用開發環境的相對目錄來說明路徑):
yourenv/Lib/site-packages/skearn/utils/

在這個開發環境中的這個路徑我們會看到一些 pyd 檔案,我們的操作諸如這張圖:

s6VV9FuD7W.png!large

我們可以看到報錯中的缺失模組 ‘sklearn.utils._cython_blas’ 的模組檔案在這裡其實被命名成了 _cython_blas.cp37-win_amd64.pyd,就是它了。

複製進來後,我們再雙擊生成的資料夾下的可執行檔案 ./project/dist/project/project.exe,捕捉一下新的錯誤,一直這樣捕捉錯誤,然後複製貼上操作修復錯誤,如果沒錯誤就成功了。除非你還有其它型別的錯誤。

我們又看到了新的報錯:

XEF6mLqIWx.jpg!large

同樣的方法,解決這個同樣型別的錯誤,思路「開啟開發環境對應的目錄找到生成專案目錄中缺失的 pyd 檔案複製進生成專案目錄中對應的位置」。

可能有人一遍有點懵,那我就不省略了,再重複下修復這個錯誤的示意圖:

6Nx3i1u0BM.png!large

接下來的 debug 就不詳細展示了,步驟思路一摸一樣,直到讓可執行檔案不再缺失模組為止,就成功了,最後執行下生成的可執行檔案 ./dist/project/project.exe

q46f9wT1qI.png!large

這就成功了。

本作品採用《CC 協議》,轉載必須註明作者和本文連結

不要試圖用百米衝刺的方法完成馬拉松比賽。

相關文章