1. 程式人生 > >linux環境下使用pyinstaller分步打包python程式(使用spec檔案將python程式打包成一個可執行檔案)

linux環境下使用pyinstaller分步打包python程式(使用spec檔案將python程式打包成一個可執行檔案)

先貼上pyinstaler的官網指南,很多使用方法可以直接查到:

  • pyinstaller的安裝:

在自己的環境下執行:

pip install Pyinstaller

有什麼錯誤就根據錯誤提示去查,這個容易解決~

  • pyinstaller的初步使用:

進入程式所在的目錄下,命令列直接執行:

pyinstaller XX.py  # XX換成自己的檔名

執行可以在該目錄下得到兩個資料夾dist和build,還有一個XX.spec檔案,需要的可執行程式就在dist資料夾下。如果你的python程式沒有使用外部檔案,這時候進入dist資料夾下,命令列中使用 ./ 執行該檔案即可執行。

遇到一些錯誤如no module ...,很有可能是pyinstaller沒有自動匯入你呼叫的第三方庫,這裡貼幾篇文章作為參考。

  • pyinstaller分步生成可執行檔案

上一步中我們可以看到生成了一個spec檔案,簡單情況下,我們使用pyinstaller的一些options選項就足夠了,但在一些其他情況下,我們可以通過修改spec檔案,來對我們生成可執行檔案的過程進行自定義。

生成spec檔案可以通過命令:

pyi-makespec options name.py

其中,options和pyinstaller的options幾乎一致,可以參考官網文件:

這裡,我使用的命令如下:

pyi-makespec present_fasttext_txt.py -F --hidden-import fasttext.model

這樣生成的就是一個單一執行檔案

生成的spec可以開啟編輯:

# -*- mode: python -*-

block_cipher = None


a = Analysis(['present_fasttext_txt.py'],
             pathex=['/home/km/PycharmProjects/fasttext'],
             binaries=[],
             datas=[],
             hiddenimports=['fasttext.model'],
             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,
          a.binaries,
          a.zipfiles,
          a.datas,
          name='present_fasttext_txt',
          debug=False,
          strip=False,
          upx=True,
          runtime_tmpdir=None,
          console=True )

因為加了-F引數,所以沒有coll內容(查閱官網文件可以知道這個是用來在dist目錄下生成程式資料夾的)

當我們需要新增資原始檔時,在datas那個list中新增相應tuple,tuple的元素是兩個字串,第一個意為呼叫的資原始檔在系統下的路徑,第二個是該檔案相對於生成的程式的路徑,新增之後該spec檔案如下:

# -*- mode: python -*-

block_cipher = None


a = Analysis(['present_fasttext_txt.py'],
             pathex=['/home/km/PycharmProjects/fasttext'],
             binaries=[],
             datas=[('comment_fasttext_isinv.model.bin','.'),('comment_fasttext_isneg.model.bin','.'),('comment_fasttext_issug.model.bin','.'),('comment_fasttext_isbug.model.bin','.'),('comment_fasttext_ispraise.model.bin','.')],
             hiddenimports=['fasttext.model'],
             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,
          a.binaries,
          a.zipfiles,
          a.datas,
          name='present_fasttext_txt',
          debug=False,
          strip=False,
          upx=True,
          runtime_tmpdir=None,
          console=True )

可以看到我修改了datas部分,由於我呼叫的檔案就在我的當前目錄下,所以我直接寫的檔名,如果呼叫其他目錄下的檔案,要寫全名的,後面的‘.’,表示它存在程式的根目錄下。

這樣修改完了,執行:

pyinstaller present_fasttext_txt.spec

即可。

之後進入dist資料夾下,發現可執行程式比較大,大概有80M,應當是把資原始檔打包進去了。執行程式,發現報錯。顯示找不到檔案,經過排查發現原來還有關鍵的一步沒做。

  • 打包成一個exe之後資原始檔的路徑問題

之前的py程式中,由於資原始檔直接放在專案根目錄下面,所以呼叫的時候直接用的檔名。這導致,後面打包成exe檔案的時候,呼叫資原始檔時會在dist資料夾下搜尋檔案,當然,我的檔案打包到exe檔案中了,這樣呼叫顯然會出現找不到相應檔案的錯誤,所以,我們還要對python程式部分進行路徑上的修改。

參考博文:

要定義一個讀取相對路徑的函式:

import os, sys

def resource_path(relative_path):
    """
    定義一個讀取相對路徑的函式
      """
    if hasattr(sys, "_MEIPASS"):
        base_path = sys._MEIPASS
    else:
        base_path = os.path.abspath(".")
    return os.path.join(base_path, relative_path)

我之前的呼叫示例如下:

classifier1 = fasttext.load_model("comment_fasttext_isinv.model.bin", label_prefix='__label__')

修改之後為:

classifier1 = fasttext.load_model(resource_path("comment_fasttext_isinv.model.bin"), label_prefix='__label__')

修改程式後,再打包,一切ok~

相關推薦

no