溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

總結(jié)Pyinstaller打包發(fā)布經(jīng)驗

發(fā)布時間:2020-07-20 10:16:55 來源:億速云 閱讀:505 作者:小豬 欄目:開發(fā)技術(shù)

這篇文章主要為大家展示了總結(jié)Pyinstaller打包發(fā)布經(jīng)驗,內(nèi)容簡而易懂,希望大家可以學(xué)習一下,學(xué)習完之后肯定會有收獲的,下面讓小編帶大家一起來看看吧。

使用Pyinstaller打包Python項目包含了大量的坑,這篇文章總結(jié)實踐得到的Pyinstaller打包經(jīng)驗。本文的例子為Python3.6代碼,Pyinstaller3.4,在windows下打包為64位和32位版本。

Pyinstaller基本使用方法

Pyinstaller可以通過簡單的命令進行python代碼的打包工作,其基本的命令為:

pyinstaller -option xxx.py

options的詳情可參考官方幫助文檔https://pyinstaller.readthedocs.io/en/stable/usage.html

這邊只介紹用到的option:-d生成一個文件目錄包含可執(zhí)行文件和相關(guān)動態(tài)鏈接庫和資源文件等;-f僅生成一個可執(zhí)行文件

-D, --onedirCreate a one-folder bundle containing an executable (default)
-F, --onefileCreate a one-file bundled executable.

對于打包結(jié)果較大的項目,選用-d生成目錄相比單可執(zhí)行文件的打包方式,執(zhí)行速度更快,但包含更加多的文件。本文的例子選中-D方式打包。

Python項目的打包方法

以一個多文件和目錄的Python項目為例,項目文件包含:1.Python源代碼文件;2.圖標資源文件;3.其它資源文件

以圖中項目為例,Python源代碼文件在多個目錄下:bin, lib\app, lib\models, lib\views;圖標資源文件在lib\icon目錄下;其它資源文件在data目錄下,包括文本文件,視頻文件等等。

總結(jié)Pyinstaller打包發(fā)布經(jīng)驗

1.spec文件生成

為了進行自定義配置的打包,首先需要編寫打包的配置文件.spec文件。當使用pyinstaller -d xxx.py時候會生成默認的xxx.spec文件進行默認的打包配置。通過配置spec腳本,并執(zhí)行pyinstaller -d xxx.spec完成自定義的打包。

通過生成spec文件的命令,針對代碼的主程序文件生成打包對應(yīng)的spec文件

 pyi-makespec -w xxx.py

打開生成的spec文件,修改其默認腳本,完成自定義打包需要的配置。spec文件是一個python腳本,其默認的結(jié)構(gòu)如下例所示

# -*- mode: python -*-
 
block_cipher = None
 
 
a = Analysis(['fastplot.py'],
       pathex=['D:\\install_test\\DAGUI-0.1\\bin'],
       binaries=[],
       datas=[],
       hiddenimports=[],
       hookspath=[],
       runtime_hooks=[],
       excludes=[],
       win_no_prefer_redirects=False,
       win_private_assemblies=False,
       cipher=block_cipher)
pyz = PYZ(a.pure, a.zipped_data,
       cipher=block_cipher)
exe = EXE(pyz,
     a.scripts,
     exclude_binaries=True,
     name='fastplot',
     debug=False,
     strip=False,
     upx=True,
     console=False )
coll = COLLECT(exe,
        a.binaries,
        a.zipfiles,
        a.datas,
        strip=False,
        upx=True,
        name='fastplot')

spec文件中主要包含4個class: Analysis, PYZ, EXE和COLLECT.

  • Analysis以py文件為輸入,它會分析py文件的依賴模塊,并生成相應(yīng)的信息
  • PYZ是一個.pyz的壓縮包,包含程序運行需要的所有依賴
  • EXE根據(jù)上面兩項生成
  • COLLECT生成其他部分的輸出文件夾,COLLECT也可以沒有

2.spec文件配置

首先給出舉例python項目的spec文件配置

# -*- mode: python -*-
import sys
import os.path as osp
sys.setrecursionlimit(5000)
 
block_cipher = None
 
 
SETUP_DIR = 'D:\\install_test\\FASTPLOT\\'
 
a = Analysis(['fastplot.py',
       'frozen_dir.py',
       'D:\\install_test\\FASTPLOT\\lib\\app\\start.py',
       'D:\\install_test\\FASTPLOT\\lib\\models\\analysis_model.py',
       'D:\\install_test\\FASTPLOT\\lib\\models\\datafile_model.py',
       'D:\\install_test\\FASTPLOT\\lib\\models\\data_model.py',
       'D:\\install_test\\FASTPLOT\\lib\\models\\figure_model.py',
       'D:\\install_test\\FASTPLOT\\lib\\models\\time_model.py',
       'D:\\install_test\\FASTPLOT\\lib\\models\\mathematics_model.py',
       'D:\\install_test\\FASTPLOT\\lib\\views\\constant.py',
       'D:\\install_test\\FASTPLOT\\lib\\views\\custom_dialog.py',
       'D:\\install_test\\FASTPLOT\\lib\\views\\data_dict_window.py',
       'D:\\install_test\\FASTPLOT\\lib\\views\\data_process_window.py',
       'D:\\install_test\\FASTPLOT\\lib\\views\\data_sift_window.py',
       'D:\\install_test\\FASTPLOT\\lib\\views\\mathematics_window.py',
       'D:\\install_test\\FASTPLOT\\lib\\views\\para_temp_window.py',
       'D:\\install_test\\FASTPLOT\\lib\\views\\mainwindow.py',
       'D:\\install_test\\FASTPLOT\\lib\\views\\paralist_window.py',
       'D:\\install_test\\FASTPLOT\\lib\\views\\plot_window.py'],
       pathex=['D:\\install_test\\FASTPLOT'],
       binaries=[],
       datas=[(SETUP_DIR+'lib\\icon','lib\\icon'),(SETUP_DIR+'data','data')],
       hiddenimports=['pandas','pandas._libs','pandas._libs.tslibs.np_datetime','pandas._libs.tslibs.timedeltas',
       'pandas._libs.tslibs.nattype', 'pandas._libs.skiplist','scipy._lib','scipy._lib.messagestream'],
       hookspath=[],
       runtime_hooks=[],
       excludes=[],
       win_no_prefer_redirects=False,
       win_private_assemblies=False,
       cipher=block_cipher)
                   
      
pyz = PYZ(a.pure, a.zipped_data,
       cipher=block_cipher)
exe = EXE(pyz,
     a.scripts,
     exclude_binaries=True,
     name='fastplot',
     debug=False,
     strip=False,
     upx=True,
     console=True)
coll = COLLECT(exe,
        a.binaries,
        a.zipfiles,
        a.datas,
        strip=False,
        upx=True,
        name='fastplot')

a) py文件打包配置

針對多目錄多文件的python項目,打包時候需要將所有相關(guān)的py文件輸入到Analysis類里。Analysis類中的pathex定義了打包的主目錄,對于在此目錄下的py文件可以只寫文件名不寫路徑。如上的spec腳本,將所有項目中的py文件路徑以列表形式寫入Analysis,這里為了說明混合使用了絕對路徑和相對路徑。

b) 資源文件打包配置

資源文件包括打包的python項目使用的相關(guān)文件,如圖標文件,文本文件等。對于此類資源文件的打包需要設(shè)置Analysis的datas,如例子所示datas接收元組:datas=[(SETUP_DIR+'lib\\icon','lib\\icon'),(SETUP_DIR+'data','data')]。元組的組成為(原項目中資源文件路徑,打包后路徑),例子中的(SETUP_DIR+'lib\\icon','lib\\icon')表示從D:\\install_test\\FASTPLOT\\lib\\icon下的圖標文件打包后放入打包結(jié)果路徑下的lib\\icon目錄。

c)Hidden import配置

pyinstaller在進行打包時,會解析打包的python文件,自動尋找py源文件的依賴模塊。但是pyinstaller解析模塊時可能會遺漏某些模塊(not visible to the analysis phase),造成打包后執(zhí)行程序時出現(xiàn)類似No Module named xxx。這時我們就需要在Analysis下hiddenimports中加入遺漏的模塊,如例子中所示。

d)遞歸深度設(shè)置

在打包導(dǎo)入某些模塊時,常會出現(xiàn)"RecursionError: maximum recursion depth exceeded"的錯誤,這可能是打包時出現(xiàn)了大量的遞歸超出了python預(yù)設(shè)的遞歸深度。因此需要在spec文件上添加遞歸深度的設(shè)置,設(shè)置一個足夠大的值來保證打包的進行,即

import sys
sys.setrecursionlimit(5000)

e)去除不必要的模塊import

有時需要讓pyinstaller不打包某些用不到的模塊,可通過在excludes=[]中添加此模塊實現(xiàn),如

excludes=['zmq']

3.使用spec執(zhí)行打包命令

pyinstaller -D xxx.spec

打包生成兩個文件目錄build和dist,build為臨時文件目錄完成打包后可以刪除;dist中存放打包的結(jié)果,可執(zhí)行文件和其它程序運行的關(guān)聯(lián)文件都在這個目錄下。

總結(jié)Pyinstaller打包發(fā)布經(jīng)驗

Visual C++ run-time .dlls包含

針對在Windows<10發(fā)布使用,且Python>=3.5的情況,Pyinstaller打包的程序可能會出現(xiàn)不包含Visual C++ run-time .dlls的情況,Python>=3.5需要使用Visual Studio 2015 run-time,也就是Universal CRT,這些runtime在Win10本身或Win7到Win8.1版本的更新包里,但程序打包后使用的系統(tǒng)里并不一定安裝了。因此需要參考Universal CRT的建議,應(yīng)用以下的方法解決這個問題:

Build on Windows 7 which has been reported to work.

Include one of the VCRedist packages (the redistributable package files) into your application's installer. This is Microsoft's recommended way, see “Distributing Software that uses the Universal CRT“ in the above-mentioned link, numbers 2 and 3.

Install the Windows Software Development Kit (SDK) for Windows 10 and expand the .spec-file to include the required DLLs, see “Distributing Software that uses the Universal CRT“ in the above-mentioned link, number 6.

Python模塊的打包問題

程序調(diào)用的很多包,在打包時候可能會出現(xiàn)一些問題,針對這寫問題需要做一些處理才能保證打包的程序正常執(zhí)行。

1.PyQt plugins缺失

使用PyQt編寫UI交互界面的python代碼在進行打包時可能會出現(xiàn)一些特別的問題。

執(zhí)行使用了PyQt的打包程序,常會出現(xiàn)這樣的錯誤,提示缺少Q(mào)t platfrom plugin “windows”,如下圖

總結(jié)Pyinstaller打包發(fā)布經(jīng)驗

打包后程序運行后,使用png格式的圖標可以正常顯示,但使用的ico格式圖標不顯示(對于所有圖標和關(guān)聯(lián)文件都無法使用的情況涉及到路徑問題,后文會另外解釋)。

這兩個錯誤產(chǎn)生的問題都是因為打包時沒有將PyQt相關(guān)的動態(tài)鏈接庫目錄生成到打包目錄下,因此可以通過將這些需要的文件目錄拷貝到打包生成目錄下,解決plugin缺失問題。以使用PyQt5編寫的python軟件打包為例,完成打包后的結(jié)果目錄下包含PyQt5文件夾,將PyQt5\Qt\plugins下的所有內(nèi)容(如下圖)拷貝到打包結(jié)果目錄。這樣就可以解決PyQt plugins缺失的問題。

總結(jié)Pyinstaller打包發(fā)布經(jīng)驗

2.動態(tài)鏈接庫缺失問題

更一般的,打包后可能會缺失某些動態(tài)鏈接庫,造成執(zhí)行程序出錯,如

ImportError: DLL load failed: 找不到指定的模塊

在打包過程中一般會有與此相關(guān)的warning提示(lib not found)無法找到這些動態(tài)鏈接庫。例如在32位版本的打包中,可能會出現(xiàn)scipy模塊相關(guān)的dll文件無法找到。這時就需要在打包的spec文件中指定動態(tài)鏈接庫路徑,使其關(guān)聯(lián)到打包后的路徑中。

binaries=[('C:\\Program Files\\Python36-32\\Lib\\site-packages\\scipy\\extra-dll','.')]

Analysis下的binaries是為打包文件添加二進制文件,缺失的動態(tài)鏈接庫可以通過這種方式自動加入到打包路徑中。

3.窗體風格變化問題

在某些情況下,如在精簡環(huán)境下的python程序打包中,執(zhí)行打包后的程序會出現(xiàn)窗體風格變?yōu)槔鲜降膚in風格,這是由于打包時候PyQt的styles動態(tài)庫沒有找到。因此只需要在Python 目錄下找到 Lib\site-packages\PyQt5\Qt\plugins\styles,將styles整個目錄復(fù)制到打包結(jié)果目錄。

4.UnicodeDecodeError

當打包時出現(xiàn)類似錯誤時:

UnicodeDecodeError: 'utf-8' codec can't decode byte 0xce in position 122

可在打包的命令行中輸入chcp 65001設(shè)置命令行顯示utf-8字符,然后再執(zhí)行打包命令。或者,修改pyinstaller包下的compat.py,根據(jù)報錯對應(yīng)的行將

out = out.decode(encoding)

改為

out = out.decode(encoding, 'replace')

凍結(jié)打包路徑

執(zhí)行打包后的程序,經(jīng)常會出現(xiàn)程序使用的圖標無法顯示,程序使用的關(guān)聯(lián)文件無法關(guān)聯(lián)。或者,在打包的本機上運行正常,但是將打包后的程序放到其它機器上就有問題。這些現(xiàn)象都很有可能是由程序使用的文件路徑發(fā)生改變產(chǎn)生的,因此在打包時候我們需要根據(jù)執(zhí)行路徑進行路徑“凍結(jié)”。

1.使用絕對路徑

在python代碼中使用絕對路徑調(diào)用外部文件可以保證打包時候路徑可追溯,因此在本機上運行打包后程序基本沒問題。但是當本機上對應(yīng)路徑的資源文件被改變,或者將打包程序應(yīng)用到別的機器,都會出現(xiàn)搜索不到資源文件的問題。這種方式不是合適的打包發(fā)布python軟件的方式。

2.使用凍結(jié)路徑

增加一個py文件,例如叫frozen_dir.py

# -*- coding: utf-8 -*-
"""
Created on Sat Aug 25 22:41:09 2018
frozen dir
@author: yanhua
"""
import sys
import os
 
def app_path():
  """Returns the base application path."""
  if hasattr(sys, 'frozen'):
    # Handles PyInstaller
    return os.path.dirname(sys.executable)
  return os.path.dirname(__file__)

其中的app_path()函數(shù)返回一個程序的執(zhí)行路徑,為了方便我們將此文件放在項目文件的根目錄,通過這種方式建立了相對路徑的關(guān)系。

源代碼中使用路徑時,以app_path()的返回值作為基準路徑,其它路徑都是其相對路徑。以本文中使用的python項目打包為例,如下所示

import frozen_dir
SETUP_DIR = frozen_dir.app_path()
 
FONT_MSYH = matplotlib.font_manager.FontProperties(
        fname = SETUP_DIR + r'\data\fonts\msyh.ttf',
        size = 8)
 
DIR_HELP_DOC = SETUP_DIR + r'\data\docs'
DIR_HELP_VIDEO = SETUP_DIR + r'\data\videos'

通過凍結(jié)路徑,使用了基準目錄下的data目錄下的fonts, docs, videos。

主程序中也做了類似的調(diào)整,改變其設(shè)置路徑方法

import frozen_dir
 
SETUP_DIR = frozen_dir.app_path()+r'\lib'
sys.path.append(SETUP_DIR)

使用這樣的方法進行打包,打包后的可執(zhí)行程序就可以在其它機器上運行。

其它問題

由于操作系統(tǒng)和運行環(huán)境的不同,pyinstaller打包中還可能遇到很多其它問題,最后總結(jié)一些我在打包中遇到的其它坑:

1.權(quán)限問題

通常時在打包時出現(xiàn)的某些文件拒絕訪問或沒有權(quán)限執(zhí)行某些操作等。解決這個的方法一般有這幾個方面:

a)使用管理員權(quán)限運行cmd或其它命令行窗口

b)關(guān)閉殺毒軟件

c)使用完全權(quán)限的管理員賬戶

2.中文路徑

pyinstaller打包后的路徑使用中文沒有問題,不過為了減少打包時候出錯的可能,盡量將打包使用的資源文件和代碼文件路徑設(shè)置為英文。

3.打包后文件的大小

通常python打包為可執(zhí)行文件都會得到一個較大的包,這是無法避免的,但是我們還是可以通過一些方法來盡量精簡打包后的執(zhí)行程序:

a)在代碼中減少不必要的import,如from xxx import *

b)在精簡的運行環(huán)境(如原生python環(huán)境)下打包,缺什么包就下什么包,避免不必要的python包被打包入程序。尤其是anaconda這樣的集成環(huán)境下打包的結(jié)果會大很多。

c)使用UPX

以上就是關(guān)于總結(jié)Pyinstaller打包發(fā)布經(jīng)驗的內(nèi)容,如果你們有學(xué)習到知識或者技能,可以把它分享出去讓更多的人看到。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI