python pyinstaller 打包項目

一、pyinstaller 打包項目

1.1 安裝pyinstaller

直接安裝:pip install pyinstaller
或者源碼安裝:https://pypi.org/project/PyInstaller/#files

依次執行:
  tar zxvf PyInstaller-3.6.tar.gz PyInstaller-3.6  
  cd PyInstaller-3.6
  sudo python3 setup.py build
  sudo python3 setup.py install

更多可以參考:http://www.pyinstaller.org
參考手冊:https://pyinstaller.readthedocs.io/en/v3.6/

1.2 簡單打包命令

【官方使用文檔】

pyinstaller [-F/-D] [-w/-c] [-i xxx.ico] xxx.py/xxx.spec

  • xxx.py/xxx.spec:需要打包的程序main文件或者spec文件。spec文件在使用py文件進行打包時會在相同路徑下自動生成,spec中的內容也是根據命令行中輸入的內容來生成的,也可以使用命令pyi-makespec [options] xxx.py來生成一個純粹的spec文件,而不會去執行打包的操作。
  • -F/–onefile:將整個程序打包爲一個exe文件,需要注意的是,與-D模式生成的exe程序相比,在啓動速度上會慢一點,原因是它需要先解壓exe文件並生成一個唯一的臨時環境來運行程序,關閉環境時也會自動刪除這個臨時環境,-D模式的程序本身就是解壓好的,運行完也不需要執行刪除操作,當程序比較大時,這個差別就很明顯了。
  • -D/–onedir:默認選項,與F/–onefile參數作用相反,將程序打包爲一個文件夾,文件夾中包含啓動程序的exe文件和其他依賴的資源文件和DLL文件等。
  • -w:表示程序運行後隱藏命令行窗口,當你不需要使用命令行窗口作爲程序的I/O時,比如GUI程序,可以使用這個參數選項。
  • -c:默認選項,與 -w 相反,提供一個命令行窗口進行 I/O。
  • -i/–icon:指定exe程序圖標。

1.3 命令行指定參數選項方式打包:

  1. build文件夾:運行後會在同路徑下生成一個build文件夾,這個文件夾的作用相當於PyInstaller的工作空間,PyInstaller運行相關的文件和日誌都在這個文件夾中,打包完成後可以直接刪除。
  2. dist文件夾:運行完成後會在同路徑下生成一個dist文件夾,這個文件夾下有一個跟程序同名的文件夾,打包好的exe程序就在這個文件夾下。
  3. 多py文件:如果命令行中指定的py文件不止一個,比如“pyinstaller xxx1.py xxx2.py”,pyinstaller會依次分析並執行,並把第一個py名稱作爲spec和dist文件下的文件夾和程序的名稱。
  4. 其他常用參數選項
    –specpath DIR :指定生成spec文件的路徑,默認爲當前路徑。
    -n NAME/–name NAME:指定spec文件和程序的名稱,默認爲傳入的py腳本或spec文件名稱。
    -h/–help :顯示PyInstaller幫助信息。
    -v/–version:顯示PyInstaller版本信息。
    –distpath DIR:指定生成dist的目錄,默認爲“./dist”。
    –workpath WORKPATH:指定pyinstaller的工作目錄,即build文件夾,默認爲“./build”。
    -y/–noconfirm:替換輸出目錄時不詢問,默認輸出目錄是“SPECPATH/dist/SPECNAME”。
    –upx-dir UPX_DIR:指定UPX程序的路徑,默認爲“程序執行路徑”,即雙擊某個文件時,系統自動查找對應程序的路徑。UPX爲一個壓縮程序,需要自行下載,可以將exe壓縮爲zip格式的文件,並且壓縮效率非常高,如果打包後的exe程序非常大的話,爲了避免客戶下載時文件太大的問題,可以使用這個UPX工具。
    –noupx:不需要UPX(即便可用)。
    -a/–ascii:不支持Unicode,默認爲支持(如果可用的話)。
    –clean:在pyinstaller開始執行之前清除緩存並刪除臨時文件(一般存儲在C:\Users\Administrator\AppData\Roaming\pyinstaller)。
    –log-level LEVEL:指定打印的日誌等級,默認爲INFO,日誌等級有:TRACE,DEBUG,INFO,WARN,ERROR,CRITICAL。如果在打包時遇到了問題,爲了方便定位問題,可以使用這個參數來查看特定級別的日誌信息。

1.4 數據綁定和搜索相關的參數選項:

–add-data SRC;DEST:指定需要添加非二進制文件路徑或者文件夾路徑,比如圖片和pdf文件等,這個選項可以使用多次。這個命令其實就是將需要的文件或者文件夾拷貝到指定的路徑下,在-D模式下,可以看情況在程序打包完成後自己手動拷貝過去。
–add-binary SRC;DEST:指定需要添加的二進制文件路徑,比如DLL文件、動態鏈接庫或者共享文件對象等,這個選項可以使用多次。同-add-data命令一樣,是一個拷貝數據的功能。
-p DIR/–paths DIR:指定import語句的查找路徑(與PYTHONPATH一樣),多個路徑之間可以使用分號“;”連接,或者多次使用這個選項來進行指定。
–hidden-import MODULENAME/–hiddenimport MODULENAME:指定腳本中需要隱式導入的模塊,比如在__import__、imp.find_module()、exec、eval等語句中導入的模塊,這些模塊PyInstaller是找不到的,需要手動指定導入,這個選項可以使用多次。
–additional-hooks-dir HOOKSPATH:指定額外hook文件(可以是py文件)的查找路徑,這些文件的作用是在PyInstaller運行時改變一些Python或者其他庫原有的函數或者變量的執行邏輯(並不會改變這些庫本身的代碼),以便能順利的打包完成,這個選項可以使用多次。
–runtime-hook RUNTIME_HOOKS:指定自定義的運行時hook文件路徑(可以是py文件),在打好包的exe程序中,在運行這個exe程序時,指定的hook文件會在所有代碼和模塊之前運行,包括main文件,以滿足一些運行環境的特殊要求,這個選項可以使用多次。
–exclude-module EXCLUDES:指定可以被忽略的可選的模塊或包,因爲某些模塊只是PyInstaller根據自身的邏輯去查找的,這些模塊對於exe程序本身並沒有用到,但是在日誌中還是會提示“module not found”,這種日誌可以不用管,或者使用這個參數選項來指定不用導入,這個選項可以使用多次。
–key KEY:指定用於Python字節碼加密的key,key是一個16個字符的字符串。

1.5 程序的運行模式

  • -D模式程序的運行
    運行程序的時候,其實開始運行的是一個pyinstaller生成的引導加載程序bootloader,bootloader是根據不同的操作系統生成的,運行bootloader時,會創建一個臨時的Python環境以便運行Python程序,所以使用exe程序時不用安裝Python也能運行這個程序。
  • -F模式程序的運行
    運行程序的時候,也會有一個BootLoader,但是會根據操作系統創建一個名爲_MEIxxxxxx的文件夾,用作這個程序的臨時運行環境(不只是Python環境),這個xxxxxx是一個隨機的數字。-F模式程序啓動的時候因爲需要解壓並拷貝依賴和資源文件到臨時運行環境_MEIxxxxxx,所以啓動速度是比-D模式程序要慢的,運行結束後會刪除臨時運行環境的文件夾。在Linux和相關係統中,可能有“no-execution”選項,但是對於-F模式程序是不兼容的。由於_MEIxxxxxx是唯一的,所以可以同時運行多個程序,多個程序時互不干涉的。如果程序崩潰了,或者強行結束了(比如在Windows的任務管理器中殺死了進程),_MEIxxxxxx文件夾是不會被刪除的,所以頻繁崩潰或者結束進程會導致有多個_MEIxxxxxx文件夾,會非常佔用磁盤空間,可以使用–runtime-temdir指定_MEIxxxxxx的存放位置。-F模式程序如果在運行時遇到了權限問題,可以使用-D模式程序替代。
  • shell腳本/批處理腳本
    使用命令行打包時,可能需要指定的參數選項很多,這時候可以將需要執行的全部命令信息,包括這些參數選項的指定,都放在一個shell腳本或者批處理文件中來執行。

1.6 運行時信息:

__file__: 所有基於模塊的使用到__file__屬性的代碼,在源碼運行時表示的是當前腳本的絕對路徑,但是打包後就是當前模塊的模塊名(即文件名xxx.py)。
sys.frozen:源碼運行時沒有這個屬性,打包後的程序添加了這個屬性,值爲True。
sys._MEIPASS: 源碼運行時沒有這個屬性,打包後的程序添加了這個屬性,表示程序運行的絕對路徑。對於-D模式程序,表示的是這個exe程序所在文件夾的絕對路徑,對於-F模式程序表示的是_MEIxxxxxx的文件夾絕對路徑,_MEIxxxxxx爲exe解壓後創建的臨時運行環境的文件夾名稱,對於exe程序每一次運行來說,它是唯一的。
sys.excutable:代碼運行時表示運行的解釋器絕對路徑,如C:\Python36\python.exe,在打包的程序中就是exe程序文件的絕對路徑,這個是用來定位用戶運行該程序的真實位置。
sys.argv[0]:一般來說就是運行程序的絕對路徑,但是在不同平臺或者不同的方式啓`動程序時,會有所不同,比如通過符號鏈接運行的程序sys.argv[0]就是符號名稱,而不是真實的程序路徑。

1.6.1 數據文件的修改

–add-data這種通過拷貝形式的數據文件,在-D模式下如果在運行時修改了,那麼對應的數據文件是真的被修改了,但是在-F模式下,由於每次運行會單獨創建一個臨時運行環境,修改的內容也是臨時運行環境中的內容,並且運行完後會自動刪除臨時運行環境,所以這種數據文件是無法直接更改exe中的數據文件的,也就意味着每次運行程序,數據文件都會是exe程序中原來的那一份,修改的內容會隨着臨時運行環境的關閉而刪除了,不會同步到exe程序中的。

1.6.2 發生錯誤時
  • 當發生“module not found”警告時,其實很多找不到對應模塊的消息都不用管,只是PyInstaller根據自身的邏輯去查找的,因爲它們並不是跟你的最終程序有關的。
  • 當發生導入失敗時,這纔是真正的錯誤,需要去關注和解決的。
  • 當打包成功,且中間沒有發生任何警告提示,但是運行程序時提示某個模塊找不到,可能就是“–hidden-import=”的問題了,當使用__import__、imp.find_module()、exec、eval或者Python/C API時,pyinstaller不會自動去導入這些裏面涉及的導包,所以這些包就需要使用“–hidden-import=”來指定具體需要導入的包了。
  • –runtime-hook=xxx.py中指定的py會依次在打包的主程序main腳本之前運行,可以用來改變一些函數或者變量,以滿足特殊場景的要求。

1.7 spec配置文件方式打包

  1. 生成spec文件:pyi-makespec [options] xxx.py [other scripts…],生成spec文件時可以什麼都不指定,然後在生成的spec文件中單獨配置,默認爲-D模式下的spec文件,也可以指定生成-F模式的spec文件。當然也可以在第一次就將參數選項指定好,以後就只維護spec文件。
  2. 參數選項:生成spec文件的參數選項和命令行模式下執行PyInstaller打包是完全一樣的。
  3. spec文件類型:spec文件其實就是一個py文件,在編輯時可以直接將它當成一個py文件來使用。
  4. spec文件優勢:一般情況而言,直接使用PyInstaller命令行直接打包即可,但是以下情況使用spec文件的話會方便一些:
    1. 程序需要綁定一些數據文件,可以在spec文件中單獨用一個列表變量來指定,可讀性和可維護性會高很多。
    2. 需要include一些PyInstaller不知道的動態鏈接庫,如:.dll/.so文件,同樣可以在spec文件中單獨用一個列表變量來指定。
    3. 需要往可執行文件中添加一些運行時選項,如hook文件。
1.7.1 關於spec文件:
如果有需要,可以通過PyCharm、eclipse等工具打開安裝目錄中的PyInstaller文件夾來查看源碼信息
  • a:Analysis類的實例,要求傳入各種腳本用於分析程序的導入和依賴。a中內容主要包括以下四部分:scripts,即可以在命令行中輸入的Python腳本;pure,程序代碼文件中的純Python模塊,包括程序的代碼文件本身;binaries,程序代碼文件中需要的非Python模塊,包括–add-binary參數指定的內容;datas,非二進制文件,包括–add-data參數指定的內容。
  • pyz:PYZ的實例,是一個.pyz文件,包含了所有pure中的所有Python模塊。
  • exe:EXE類的實例,這個類是用來處理Analysis和PYZ的結果的,也是用來生成最後的exe可執行程序。
  • coll:COLLECT類的實例,用於創建輸出目錄。在-F模式下,是沒有COLLECT實例的,並且所有的腳本、模塊和二進制文件都包含在了最終生成的exe文件中。
  1. Analysis參數scripts:也是第一個參數,它是一個腳本列表,可以傳入多個py腳本,效果與命令行中指定多py文件相同,即py文件不止一個時,比如“pyinstaller xxx1.py xxx2.py”,pyinstaller會依次分析並執行,並把第一個py名稱作爲spec和dist文件下的文件夾和程序的名稱。

  2. Analysis參數pathex:同命令“-p DIR/–paths DIR”,其實默認就有一個spec的目錄,如果使用命令添加的話,會首先添加命令中指定的目錄,再添加默認的路徑。

  3. Analysis參數datas:即添加數據文件,命令是–add-data,spec文件中是Analysis的datas=[]參數,datas是一個元素爲元組的列表,每個元組有兩個元素,都必須是字符串類型,元組的第一個元素爲數據文件或文件夾,元組的第二個元素爲運行時這些文件或文件夾的位置。例如:datas=[(‘src/README.txt’, ‘.’), ],也可以在命令行中這樣寫:pyinstaller --add-data ‘src/README.txt;.’ myscript.py,表示打包時將文件src/README.txt添加(copy)到相對於spec文件的根目錄下,指定文件時是相對於spec來進行尋找的,而不是要打包的exe程序路徑。也可以使用通配符:datas= [ (’/mygame/sfx/*.mp3’, ‘sfx’ ) ],表示將/mygame/sfx/目錄下的所有.mp3文件都copy到sfx文件夾中。也可以添加整個文件夾:datas= [ (’/mygame/data’, ‘data’ ) ],表示將/mygame/data文件夾下所有的文件都copy到data文件夾下。

  4. Analysis參數binaries:添加二進制文件,效果同命令–add-binary,也是一個列表,定義方式與datas參數一樣。
    Analysis參數hiddenimports:同命令“–hidden-import MODULENAME/–hiddenimport MODULENAME”。
    Analysis參數hookspath:同命令“–additional-hooks-dir HOOKSPATH”。
    Analysis參數runtime_hooks:同命令“–runtime-hook RUNTIME_HOOKS”。
    Analysis參數excludes:同命令“–exclude-module EXCLUDES”。
    exe參數console:設置是否顯示命令行窗口,和命令-w/-c作用一樣。
    exe參數icon:設置程序圖標,和命令-i/–icon作用一樣。某些情況,直接執行“pyinstaller xxx.py”時生成的spec中沒有這個參數,需要手動添加,參數值就是圖片路徑的字符串。
    PyInstaller全局變量:這些全局變量可以在spec文件使用。

    • DISTPATH:相對於dist文件夾的相對路徑,如果–distpath參數選項被指定了,則使用被指定的參數值。
    • HOMEPATH:pyinstaller查找的絕對路徑,一般是Python解釋器的site-packages文件夾的絕對路徑。
    • SPEC:在命令行中指定的spec文件路徑。
    • SPECPATH:os.path.split(SPEC)的第一個值。
    • specnm:spec文件的文件名,不含文件類型後綴。
    • workpath:相對於build文件夾的相對路徑,如果workpath=參數選項被指定了,這使用被指定的值。
    • WARNFILE:在build文件夾中警告文件的全路徑,一般是warn-myscript.txt
  5. 指定了相同的參數:當命令行和spec中指定了相同的參數選項,那麼命令行的參數選項會被忽略。

二編譯問題及解決

pyinstaller 打包報錯:

  1. RecursionError: maximum recursion depth exceeded
    在 filename.spec 文件頭添加下面語句:
    import sys
    sys.setrecursionlimit(5000)
    再次執行:pyinstaller filename.spec

  2. UnicodeDecodeError: 'utf-8' codec can't decode byte 0xce in position 110: invalid continuation byte
    Unicode解碼錯誤:“UTF-8”編解碼器無法解碼位置130中的字節0xCE:無效的繼續字節
    1.首先嚐試將中文解釋都去掉
    2.控制檯中輸入 chcp 65001,然後執行打包
    來源:https://blog.csdn.net/qq_41185868/article/details/80599390
    3.[17260] Error loading Python lib '/home/wangsp/ocr_server_multi_file2/dist/ocr_server/libpython3.6m.so': dlopen: /home/wangsp/ocr_server_multi_file2/dist/ocr_server/libpython3.6m.so: cannot open shared object file: No such file or directory
    重新編譯

關於隱藏導入:https://zhuanlan.zhihu.com/p/35338321

三. cx_Freeze打包項目

cx_Freeze是一個跨平臺的將python轉換成可執行程序的項目。
項目主頁:http://cx-freeze.sourceforge.net/
可以下載rpm包安裝。
安裝完以後只需要運行:cxfreezeyourprogram.py
就會在當前目錄生成一個dist的目錄,裏面包含了可執行程序以及依賴模塊的庫文件。
項目主頁上說可以通過distutils的build_exe命令生成單一的可執行程序,不過貌似不行…所以這個相對於pyinstaller可能還是稍有不便。

更多可以參考:http://cx-freeze.sourceforge.net/cx_Freeze.html

一個Python應用程序,其中添加了Cython模塊。需要使用cx_Freeze構建的可執行版本。
該可執行文件會引發ImportError並試圖導入.pyx模塊。
我進行了修改setup.py,以查看是否可以先編譯.pyx以便cx_Freeze可以成功打包,但是報錯:No module named fx



from cx_Freeze import setup, Executable
from Cython.Build import cythonize


setup(name='projectname',
      version='0.0',
      description=' ',
      options={"build_exe": {"packages":["pygame","fx"]},'build_ext': {'compiler': 'mingw32'}},
      ext_modules=cythonize("fx.pyx"),
      executables=[Executable('main.py',targetName="myproject.exe",base = "Win32GUI")],
      requires=['pygcurse','pyperclip','rsa','dill','numpy']
      )
	  
	  

解決的辦法是有兩個單獨的調用setup();一個fx.pyx用Cython 構建,然後一個用cx_Freeze打包exe。這是修改後的setup.py:
from cx_Freeze import Executable
from cx_Freeze import setup as cx_setup
from distutils.core import setup
from Cython.Build import cythonize

setup(options={'build_ext': {'compiler': 'mingw32'}},
      ext_modules=cythonize("fx.pyx"))

cx_setup(name='myproject',
      version='0.0',
      description='',
      options={"build_exe": {"packages":["pygame","fx"]}},
      executables=[Executable('main.py',targetName="myproject.exe",base = "Win32GUI")],
      requires=['pygcurse','pyperclip','rsa','dill','numpy']
      )

先執行:python setup-cython.py build_ext --inplace
後執行:python setup-cython.py build
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章