Python pyinstaller類庫使用學習總結

授客發表於2024-10-28

實踐環境

python3 .9.13

pyinstaller-6.10.0-py3-none-manylinux2014_x86_64.whl

CentOS 7.9

win11

實踐操作

生成Linux版可執行檔案

安裝Python

# yum install -y gcc zlib* openssl-devel libffi-devel
# wget https://www.python.org/ftp/python/3.6.13/Python-3.6.13.tgz
# mkdir -p /usr/local/python
# mv Python-3.9.13.tgz /usr/local/python
# tar -xvzf Python-3.9.13.tgz
# cd python-3.9.13
# ./configure --prefix=/usr/local/python/python3.9.13 --enable-shared
# make && make install

說明:

1、如果不安裝libffi-devel,執行pyinstaller時會報錯:ModuleNotFoundError: No module named '_ctypes',以下

# pyinstaller simulator.py
Traceback (most recent call last):
  File "/usr/bin/pyinstaller", line 8, in <module>
    sys.exit(_console_script_run())
  File "/usr/local/python/python3.9.13/lib/python3.9/site-packages/PyInstaller/__main__.py", line 231, in _console_script_run
    run()
  File "/usr/local/python/python3.9.13/lib/python3.9/site-packages/PyInstaller/__main__.py", line 172, in run
    parser = generate_parser()
  File "/usr/local/python/python3.9.13/lib/python3.9/site-packages/PyInstaller/__main__.py", line 137, in generate_parser
    import PyInstaller.building.build_main
  File "/usr/local/python/python3.9.13/lib/python3.9/site-packages/PyInstaller/building/build_main.py", line 28, in <module>
    from PyInstaller.building.api import COLLECT, EXE, MERGE, PYZ
  File "/usr/local/python/python3.9.13/lib/python3.9/site-packages/PyInstaller/building/api.py", line 33, in <module>
    from PyInstaller.building.splash import Splash  # argument type validation in EXE
  File "/usr/local/python/python3.9.13/lib/python3.9/site-packages/PyInstaller/building/splash.py", line 23, in <module>
    from PyInstaller.depend import bindepend
  File "/usr/local/python/python3.9.13/lib/python3.9/site-packages/PyInstaller/depend/bindepend.py", line 15, in <module>
    import ctypes.util
  File "/usr/local/python/python3.9.13/lib/python3.9/ctypes/__init__.py", line 8, in <module>
    from _ctypes import Union, Structure, Array
ModuleNotFoundError: No module named '_ctypes'

2、如果編譯Python時不攜帶--enable-shared選項,執行pyinstaller時會報類似如下錯誤:

  File "/usr/local/python/python3.9.13/lib/python3.9/site-packages/PyInstaller/building/build_main.py", line 671, in assemble
    raise PythonLibraryNotFoundError()
PyInstaller.exceptions.PythonLibraryNotFoundError: Python library not found: libpython3.9.so.1.0, libpython3.9.so
    This means your Python installation does not come with proper shared library files.
    This usually happens due to missing development package, or unsuitable build parameters of the Python installation.

    * On Debian/Ubuntu, you need to install Python development packages:
      * apt-get install python3-dev
      * apt-get install python-dev
    * If you are building Python by yourself, rebuild with `--enable-shared` (or, `--enable-framework` on macOS).

新增/usr/lib64/libpython3.9.so.1.0檔案

# find / -name libpython3.9.so.1.0
/root/Python-3.9.13/libpython3.9.so.1.0
/usr/local/python/python3.9.13/lib/libpython3.9.so.1.0
# cp /usr/local/python/python3.9.13/lib/libpython3.9.so.1.0 /usr/lib64/libpython3.9.so.1.0

說明:如果不執行該操作,執行pyinstaller時生成可執行檔案時可能報類似如下錯誤:

# pyinstaller simulator.py
/usr/local/python/python3.9.13/bin/python3.9: error while loading shared libraries: libpython3.9.so.1.0: cannot open shared object file: No such file or directory

安裝 pyinstaller

# pip3 install pyinstaller -i http://mirrors.aliyun.com/pypi/simple --trusted-host mirrors.aliyun.com

建立軟連線,避免直接執行 pyinstaller 命令時,提示 pyinstaller: command not found

# find / -name pyinstaller
/usr/local/python/python3.9.13/bin/pyinstaller
# 
# ln -fs /usr/local/python/python3.9.13/bin/pyinstaller /usr/binpyinstaller
# pyinstaller -v
6.10.0

生成可執行檔案

# pwd
/root/au02Simulator
# pyinstaller -y  simulator.py
87 INFO: PyInstaller: 6.10.0, contrib hooks: 2024.8
87 INFO: Python: 3.9.13
89 INFO: Platform: Linux-3.10.0-1160.el7.x86_64-x86_64-with-glibc2.17
89 INFO: Python environment: /usr/local/python/python3.9.13
90 INFO: wrote /root/au02Simulator/simulator.spec
93 INFO: Module search paths (PYTHONPATH):
['/usr/local/python/python3.9.13/lib/python39.zip',
 '/usr/local/python/python3.9.13/lib/python3.9',
 '/usr/local/python/python3.9.13/lib/python3.9/lib-dynload',
 '/usr/local/python/python3.9.13/lib/python3.9/site-packages',
 '/root/au02Simulator']
166 INFO: checking Analysis
172 INFO: checking PYZ
181 INFO: checking PKG
181 INFO: Bootloader /usr/local/python/python3.9.13/lib/python3.9/site-packages/PyInstaller/bootloader/Linux-64bit-intel/run
181 INFO: checking EXE
182 INFO: checking COLLECT
182 INFO: Building COLLECT COLLECT-00.toc
210 INFO: Building COLLECT COLLECT-00.toc completed successfully.
# cd dist/
# ll
total 0
drwxr-xr-x. 3 root root 40 Oct 24 12:46 simulator
# cd simulator/
# ll
total 1204
drwxr-xr-x. 4 root root    4096 Oct 24 12:46 _internal
-rwxr-xr-x. 1 root root 1227016 Oct 24 12:46 simulator

說明:這裡的simulator.py為程式入口檔案,即用python執行本程式時,位於其後的.py檔案

只生成一個檔案

# pyinstaller -y --onefile simulator.py
74 INFO: PyInstaller: 6.10.0, contrib hooks: 2024.8
75 INFO: Python: 3.9.13
76 INFO: Platform: Linux-3.10.0-1160.el7.x86_64-x86_64-with-glibc2.17
76 INFO: Python environment: /usr/local/python/python3.9.13
77 INFO: wrote /root/au02Simulator/simulator.spec
79 INFO: Module search paths (PYTHONPATH):
['/usr/local/python/python3.9.13/lib/python39.zip',
 '/usr/local/python/python3.9.13/lib/python3.9',
 '/usr/local/python/python3.9.13/lib/python3.9/lib-dynload',
 '/usr/local/python/python3.9.13/lib/python3.9/site-packages',
 '/root/au02Simulator']
146 INFO: checking Analysis
149 INFO: checking PYZ
157 INFO: checking PKG
158 INFO: Building because toc changed
158 INFO: Building PKG (CArchive) simulator.pkg
7881 INFO: Building PKG (CArchive) simulator.pkg completed successfully.
7882 INFO: Bootloader /usr/local/python/python3.9.13/lib/python3.9/site-packages/PyInstaller/bootloader/Linux-64bit-intel/run
7882 INFO: checking EXE
7883 INFO: Rebuilding EXE-00.toc because simulator missing
7883 INFO: Building EXE from EXE-00.toc
7883 INFO: Copying bootloader EXE to /root/au02Simulator/dist/simulator
7883 INFO: Appending PKG archive to custom ELF section in EXE
7900 INFO: Building EXE from EXE-00.toc completed successfully.
# cd dist/
# ll
total 12444
-rwxr-xr-x. 1 root root 12741136 Oct 24 12:50 simulator

注意,生成的檔案是不帶配置的,程式所需配置需要自己新增

生成Windows版可執行檔案

安裝 pyinstaller

同Linux,安裝完成後,會在${PYTHON_HOME}\Scripts目錄下生成pyinstaller.exe,為方便執行,將其所在路徑新增到環境變數

生成可執行檔案

同Linux

pyinstaller [選項] program_entry_file.py

pyinstaller常用選項

  • -y 檔輸出目錄下的存在舊生成檔案時,不提示刪除確認提示,直接刪除

  • -F,--onefile 打包為一個獨立檔案

  • --add-data <source>;<dest_dir> (適用Win) --add-data <source>:<dest_dir> (適用Linux) 用於將非python檔案如配置,打包程序序。

    • <source>是資原始檔的路徑,可以是相對路徑或絕對路徑,建議使用絕對路徑。
    • <dest_dir>是資原始檔在打包後在可執行檔案中的目標目錄路徑。是相對於應用程式頂層目錄的目標目錄,如果要將檔案放入應用程式頂層目錄,則使用 . 作為 <dest_dir>。注意:如果該目錄路徑不存在,則會自動建立

    --add-data 可重複使用,以支援單次新增多個檔案的需求

例子:

假設我們有一個Python專案,其中包含一個名為config.ini的配置檔案。希望在使用PyInstaller打包專案時,將這個配置檔案也一起打包進去。

cd /d D:\PyProjects\ZenTaoTestcaseHelper
pyinstaller --add-data "D:\PyProjects\ZenTaoTestcaseHelper\config.json;." testcase_helper.py

生成目標結果檔案路徑如下:

D:\PyProjects\ZenTaoTestcaseHelper\dist\testcase_helper\testcase_helper.exe
D:\PyProjects\ZenTaoTestcaseHelper\dist\testcase_helper\config.json

執行可執行檔案無法正確讀取配置檔案解決方案

實踐時遇到過這樣的情況:

直接使用python program_entry_file.py的方式執行程式時,可正確執行不報錯,直接執行打包生成的可執行檔案時,出現報錯,提示相關配置檔案不存在。

經過分析發現,直接執行可執行檔案時,讀取配置檔案的路徑不對,為了避免這種情況,可在程式碼中新增判斷,設定採用可執行檔案的方式執行時的配置檔案讀取路徑:

program_entry_file.py(程式入口檔案)中判斷是否是執行打包生成的可執行檔案,如果是,則設定環境變數,獲取可執行檔案所在目錄

sys_executable = sys.executable
if not sys_executable.endswith('python.exe') and not re.findall('python\d*$', sys_executable):
    os.environ['EXECUTABLE_DIR'] = os.path.dirname(sys.executable)

其它需要讀取配置檔案的py檔案中新增判斷

假設我們期望可執行檔案從位於同級目錄的conf目錄下的program.conf檔案中讀取配置

config_file_path = 'conf/program.conf'
if os.getenv('EXECUTABLE_DIR'):
    config_file_path = os.path.join(os.environ['EXECUTABLE_DIR'], config_file_path)

參考連結

https://pyinstaller.org/en/v6.2.0/usage.html

相關文章