1. 程式人生 > >用 PyInstaller 打包基於 PyQt 的程式遇到的坑

用 PyInstaller 打包基於 PyQt 的程式遇到的坑

原文連結

之前寫了個指令碼自己平常工作用,最近因為需要把指令碼給其他同事用,為了避免它們還需要配置環境,於是用 PyQt 寫了個介面,然後用 PyInstaller 打包成 exe 。打包過程中遇到了一些坑,紀錄一下。

PyQt

之前寫過一個蝦米歌單匯出小指令碼,exe 版本是用的 Python 自帶的 Tkinter 寫的,所以這次嘗試用 PyQt。寫的時候遇到了工作列閃爍和打包後程序介面圖示不顯示的問題。

  • 工作列閃爍提示

    後臺執行程式的時候,如果使用 QFileDialog ,程式彈出儲存對話方塊的時候會在工作列閃爍提示。但不是每個 Widget 都會有這個功能,但是這時候可以通過 QtWidget

     的 activateWindow() 和 QApplication.alert() 來實現,但這兩者使用的時候會有點區別。

    activateWindow() 是例項方法,只要程式視窗切換到前臺被激活了就不會再閃爍。而 QApplication.alert(QWidget, msecs: int = 0) 是靜態方法,msecs 值為 0 的時候,和 activateWindow() 的效果一致,但是需要在閃爍停了之後啟用程式才會工作列視窗顏色才會恢復正常,否則還是黃色,直到閃爍停了之後再啟用一次程式。msecs 不為 0 的時候,超過這個時間後,工作列視窗就會自動恢復正常。所以 activateWindow()

     是比較好的選擇,除非不要求一直在工作列提示。

  • 資原始檔在打包時的處理

    把程式碼用 PyInstaller 打包到一個檔案的時候,會出現圖示或圖片都不顯示的情況。這種時候就需要用 Qt’s resource system 來對其進行打包。

    首先新建一個 .qrc 檔案,內容格式如下:

    <RCC>
      <qresource prefix="/" >
        <file>img/image1.png</file>
        <file>img/image2.png</file>
        <file>img/image3.png</file
    >
    </qresource> </RCC>

    然後去檔案目錄下執行 pyrcc5 -o images_qr.py images.qrc 命令,最後在程式碼中 import image_qr.py,並且修改下圖片路徑,一定要在路徑前面加上冒號。

    import image_qr.py
    # your code
    self.setWindowIcon(QtGui.QIcon(':/img/image1.png'))

PyInstaller

之前用 cx_freeze 打過包,但感覺不理想,搜尋了下發現 PyInstaller 用得比較多,就使用了這個,第一次用的時候沒遇到問題,但是因為 Python 是裝的 64 位的,所以打包之後的程式無法在 32 位的機器上使用。這就意味著我必須要在 Python 32 位的環境下打包,但重新配置了下環境之後,遇到了 ImportError 和無法連結到動態庫的問題。

  • ImportError: DLL load failed

    用 PyInstaller 給程式打包的時候遇到了pyi_rth_qt5plugins returned -1 的 Fatal Error 提醒。這個錯誤資訊幾乎是毫無用處的,修改 .spec 檔案,開啟 debug 模式以及顯示 console 後,在 running pyi_rth_qt5plugins.py 的時候發生了 ImportError: DLL load failed 找不到指定的模組 錯誤。

    回頭想起了在編譯的時候看到了很多 WARNNING 訊息,回過頭檢視,發現了很多 lib not found 的問題。但是仔細檢查了 Python 庫之後,這些 DLL 明明在 C:\Python35-32\Lib\site-packages\PyQt5\Qt\bin 目錄下,最後的搜尋得到的解決辦法是把這個目錄新增到環境變數裡。

    問題得到了解決,猜測原因是因為之前使用 pip 安裝 PyQt 的時候, pypi.python.org 總是連線不順暢,最後去下了個 .whl 檔案直接安裝,導致沒有對應環境變數打包的時候找不到 DLL。

    # 環境: Python == 3.5.2 ,PyInstaller == 3.1.1
    
    10951 WARNING: lib not found: Qt5Svg.dll dependency of C:\python35-32\lib\site-packages\PyQt5\Qt\plugins\imageformats\qsvg.dll
    11206 WARNING: lib not found: Qt5Gui.dll dependency of C:\python35-32\lib\site-packages\PyQt5\Qt\plugins\imageformats\qsvg.dll
    11437 WARNING: lib not found: Qt5Core.dll dependency of C:\python35-32\lib\site-packages\PyQt5\Qt\plugins\imageformats\qsvg.dll
    11763 WARNING: lib not found: Qt5Gui.dll dependency of C:\python35-32\lib\site-packages\PyQt5\Qt\plugins\imageformats\qtga.dll
    12017 WARNING: lib not found: Qt5Core.dll dependency of C:\python35-32\lib\site-packages\PyQt5\Qt\plugins\imageformats\qtga.dll
    12224 WARNING: lib not found: Qt5Gui.dll dependency of C:\python35-32\lib\site-packages\PyQt5\Qt\plugins\platforms\qminimal.dll
    12418 WARNING: lib not found: Qt5Core.dll dependency of C:\python35-32\lib\site-packages\PyQt5\Qt\plugins\platforms\qminimal.dll
    12625 WARNING: lib not found: Qt5Gui.dll dependency of C:\python35-32\lib\site-packages\PyQt5\Qt\plugins\platforms\qwindows.dll
    12833 WARNING: lib not found: Qt5Core.dll dependency of C:\python35-32\lib\site-packages\PyQt5\Qt\plugins\platforms\qwindows.dll
  • api-ms-win-crt-runtime 錯誤

    PyInstaller 打包之後的程式執行的時候發生 api-ms-win-crt-runtime 動態庫之類的錯誤,似乎只有在 Python 3.5 下打包才會遇到。因為 Universal CRT (KB2999226)缺失,可以通過安裝此更新來解決問題。或者直接下載 Visual C++ Redistributable (x86 ,x64 )。

這次的幾個坑讓我更堅定這類工具最好不要用最新版本,一不見得更穩定,二是遇到問題資料也比較少,在這類不必要的麻煩上花太多時間不值得,除非新版本能有很大的收益。