WxPython跨平台开发框架之使用PyInstaller 进行打包处理

使用PyInstaller 打包Python项目是一个常见的需求,它可以将Python程序及其所有依赖项打包成一个独立的可执行文件或者安装文件,方便在没有安装Python环境的机器上运行。本随笔介绍WxPython跨平台开发框架中使用PyInstaller 进行打包处理,包括在WIndow平台下生成独立的exe文件,松散结构的exe文件和目录,以及在MacOS上生成安装包的处理过程。

1. 安装和使用 PyInstaller 进行程序打包处理

PyInstaller是目前最流行的Python打包工具之一。它可以将Python脚本打包成独立的可执行文件,支持Windows、Linux和macOS平台。

打包后的可执行文件可以在没有 Python 环境的机器上运行。PyInstaller 会自动分析程序的依赖关系,并将所有必要的库和资源打包到一个文件或者一个文件夹中。

cx_Freeze是另一个常用的Python打包工具,同样支持跨平台。

Py2exe是专门用于将Python脚本打包成Windows平台可执行文件的工具。

首先,确保您的Python环境已经安装。然后,通过pip安装PyInstaller。在VSCode或者其他编辑器的命令行(终端)中执行以下命令:

复制代码
pip install pyinstaller

在项目目录下,使用PyInstaller命令来打包您的Python脚本。假设您的主程序文件名为main.py,则可以使用以下命令:

复制代码
pyinstaller --onefile main.py

这里的--onefile选项指示PyInstaller生成一个单独的可执行文件,而不是一个包含多个文件的文件夹。PyInstaller还支持许多其他选项,如--icon来指定应用程序的图标,--windowed--noconsole来避免在Windows上打开命令行窗口等。

PyInstaller完成打包后,会在dist目录下生成可执行文件(或文件夹,如果您没有使用--onefile选项)。进入dist目录,您应该能看到一个名为main(或您指定的名称,如果使用了--name选项)的可执行文件。

如果一切正常,您的Python程序现在应该会在没有Python环境的情况下运行。

使用PyInstaller打包Python项目是一个简单而强大的方法,可以让您的程序更加便携和易于分发。通过遵循上述步骤,您可以轻松地将您的Python项目打包成一个可执行文件。

常用选项

PyInstaller 提供了很多命令行选项,用于定制打包过程。以下是一些常用的选项:

--onefile

生成单个可执行文件。默认情况下,PyInstaller 会生成一个文件夹,里面包含了可执行文件和所有相关的依赖项。如果你希望打包成一个独立的可执行文件(可能会更大),可以使用 --onefile 选项。

--noconsole

如果你正在创建一个 GUI 应用程序(如使用 wxPython 或 PyQt),并且不希望显示控制台窗口,可以使用 --noconsole 选项。此选项会隐藏控制台窗口,适用于 Windows 和 macOS。

--icon

为生成的可执行文件指定一个图标。图标文件可以是 .ico(Windows)或 .icns(macOS)格式。

--onedir

生成一个包含可执行文件和所有依赖项的文件夹,而不是单个文件。你可以将整个文件夹分发给其他用户。
build 文件夹被PyInstaller用来收集和准备捆绑的文件,它包含分析的结果和一些额外的日志。在大多数情况下,你可以忽略这个文件夹的内容,除非你想调试问题。

dist (代表 "分发")文件夹包含要分发的文件。这包括你的应用程序,捆绑成一个可执行文件,以及任何相关的库(例如WxPython、PyQt6 等)和二进制.so 文件。

2、使用.spec文件进行定制打包处理

打包过程中,PyInstaller 会生成一个 .spec 文件。这个文件包含了 PyInstaller 的配置信息,其中包含了构建过程的所有配置信息。你可以修改这个文件来定制打包过程。

如果我们执行下面代码

复制代码
pyinstaller main.py

或者指定更多的参数的代码

复制代码
pyinstaller --onefile --icon=your_icon.ico main.py

PyInstaller 都会生成一个 .spec 文件,然后可以编辑 main.spec 文件,例如:

复制代码
# main.spec
# -*- mode: python ; coding: utf-8 -*-

block_cipher = None

a = Analysis(['main.py'],
             pathex=['/path/to/your/script'],  # 项目的路径
             binaries=[],
             datas=[('data/*.txt', 'data')],  # 资源文件
             hiddenimports=['some_module'],  # 隐藏导入模块
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False)

pyz = PYZ(a.pure)

exe = EXE(pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          name='main',
          debug=False,
          strip=False,
          upx=True,
          console=False)  # 设置是否显示控制台

一般情况下,我们的.spec文件会比这个更多的内容,虽然原则上.spec文件支持跨平台的配置,不过我们在实际中往往根据不同的平台配置特定的.spec文件。

你可以手动修改 .spec 文件来添加资源文件、修改导入模块、定制输出路径等。

你可以通过编辑.spec 文件,在EXE、COLLECT和BUNDLE块下添加一个name= ,为PyInstaller 提供一个更好的名字,以便为应用程序(和dist 文件夹)使用。

EXE下的名字是可执行文件的名字,BUNDLE下的名字是应用程序包的名字。

修改完成后,执行以下命令来重新打包:

解决常见问题

  • 缺少依赖库 :如果打包后运行时出现缺少模块的错误,可以尝试将缺少的模块加入到 hiddenimports 中,或者通过 --hidden-import 选项指定:

  • 大文件 :如果使用 --onefile 时打包后的文件太大,考虑使用 --onedir 或通过压缩文件等方法进行优化。

  • **处理资源文件:**如果你的应用程序包含非 Python 代码的资源(如图像、配置文件、数据文件等),你需要通过 --add-data 选项指定资源文件的路径,或者在 .spec 文件中修改 datas 选项。

  • 动态链接库 ,如果你的应用程序依赖于特定的动态链接库(如 DLL 文件或 .so 文件),你需要将这些库包含到打包中。可以在 .spec 文件的 binaries 选项中指定:

  • 多平台支持: PyInstaller 支持 Windows、Linux 和 macOS 等多个平台,但需要在相应的平台上打包。例如,如果你要为 Windows 用户创建可执行文件,最好在 Windows 上运行 PyInstaller 来生成 Windows 的 .exe 文件。如果在 macOS 上打包,生成的文件只能在 macOS 上运行。

PyInstaller 有丰富的文档,提供了详细的使用说明和常见问题解答,你可以通过以下链接访问:

这些文档和资源能帮助你深入了解 PyInstaller 的使用方式,并解决在打包过程中可能遇到的问题。

3、WxPython跨平台开发框架中定制不同平台的 .spec文件

前面介绍了,我们推荐使用修改配置.spec文件的方式生成打包文件,并且可以通过定制不同平台的.spec文件,以便实现更好的处理,避免冲突。

对于不同平台的图标处理,我们可以使用代码来判断,.spec文件本身可以编写python的代码的。

复制代码
import sys
import os
from pathlib import Path

if sys.platform == "win32":
    icon = "app/images/app.ico"
elif sys.platform == "darwin":
    icon = "app/images/app.icns"

另外我们的业务窗体是动态根据路径解析的,因此在打包的时候,会漏掉的,为了解决这个问题,需要手动把视图部分的模块加载到hidden-import集合中,如下所示。

为了避免手工填写出错和麻烦,使用python函数递归处理目录的视图模块。

复制代码
def collect_modules(directory):
    modules = []
    for root, dirs, files in os.walk(directory):
        for file in files:
            if file.endswith(".py") and file != "__init__.py":  # 排除 __init__.py 文件
                module_path = os.path.relpath(os.path.join(root, file), directory)
                module_name = module_path.replace(os.path.sep, ".").replace(".py", "")
                modules.append(module_name)
    return modules


# 使用动态加载目录下的模块方式
hiddenimports = collect_modules("app/views")
hiddenimports = [f"views.{module}" for module in hiddenimports]

这样在修改里面的变量即可。

复制代码
# Analysis: PyInstaller Analysis object
a = Analysis(
    ["app/main.py"],
    pathex=[],
    binaries=[],
    datas=[
        ("app/images/splash.png", "images"),
        ("app/.env", "."),
        ("app/settings.ini", "."),
    ],
    hiddenimports=hiddenimports,
    hookspath=[],
    hooksconfig={},
    runtime_hooks=[],
    excludes=[],
    noarchive=False,
    optimize=0,
)

1)WIndows平台的打包文件生成

然后指定EXE(用于Window的处理打包)

复制代码
# PYZ: PyInstaller PYZ object
pyz = PYZ(a.pure)

# EXE: PyInstaller EXE object
exe = EXE(
    pyz,
    a.scripts,
a.binaries,
a.datas,
    [],
    name="wxpython_project",
    debug=False,
    bootloader_ignore_signals=False,
    strip=False,
    upx=True,
    upx_exclude=[],
    runtime_tmpdir=None,
    console=False,  # True启用/False禁用命令行窗口
    onefile=False,  # <-- False取消、True使用 onefile 模式
    icon=icon,  # <-- 图标路径
    disable_windowed_traceback=False,
    argv_emulation=False,
    target_arch=None,
    codesign_identity=None,
    entitlements_file=None,
)

最后在dist目录上生成一个文件,如下所示。

本文件用于Window平台下打包整个项目,生成一个独立的exe文件,包含了所有的依赖和资源文件,文件运行后会在临时目录中解压出来一个文件夹,程序退出后,该文件夹自动移除。

临时目录一般在C:\Users\Administrator\AppData\Local\Temp。

如果我们想在Windows平台生成的dist目录中生成一个启动exe,和其他相关的Lib依赖库目录,那么我们可以适当调整下.spec文件,让它可以生成松散结构的文件目录包。

复制代码
# PYZ: PyInstaller PYZ object
pyz = PYZ(a.pure)

exe = EXE(
    pyz,
    a.scripts,
\[\],
exclude_binaries=True,
    name="wxpython_project",
    debug=False,
    bootloader_ignore_signals=False,
    strip=False,
    upx=True,
    console=False,  # True启用/False禁用命令行窗口
    icon=icon,  # <-- 图标路径
    disable_windowed_traceback=False,
    argv_emulation=False,
    target_arch=None,
    codesign_identity=None,
    entitlements_file=None,
)

# COLLECT: PyInstaller COLLECT object
coll = COLLECT(
    exe,
a.binaries,
a.datas,
    strip=False,
    upx=True,
    upx_exclude=[],
    name="main",
)

相当于之前在exe包中的a.binaries 和 a.datas从EXE 构造函数中移到了Collect的构造函数里面了。这样会生成下面的目录结构。

其中_internal目录包含程序的相关依赖包和文件资源。

如果我们需要使用第三方安装包制作工具(如SetupFactory ),那么整合这些文件即可实现安装程序的处理。

2)MacOs下的打包文件生成

如果在MacOS或者Linux下的打包处理,会有所不同。
在MacOS中,我们需要使用 BUNDLE 创建 macOS 应用包

复制代码
# 使用 BUNDLE 创建 macOS 应用包
app = BUNDLE(
    coll,
    name="wxpython_project.app",
    icon=icon,
    bundle_identifier="com.iqidi.wxpython_project",  # 推荐设置唯一的 bundle identifier
    info_plist={
        "NSPrincipalClass": "NSApplication",
        "NSHighResolutionCapable": "True",
    },
)

生成的 wxpython_project.app 应用程序捆绑包,实际上只是一个特殊的文件夹。

虽然macOS将其显示为一个应用程序,但如果你试图分享它,你实际上将分享数百个单独的文件。为了正确分发应用程序,我们需要某种方式将其打包成一个单一的文件。

如果你以前安装过macOS应用程序,通常情况下你会得到一个磁盘镜像 .dmg ,打开后会显示应用程序包,以及一个指向应用程序文件夹的链接。要安装该应用程序,你只需将其拖到目标上。

为了创建我们的磁盘镜像 ,我们将使用create-dmg工具。这是一个命令行工具,它提供了一个简单的方法来自动建立磁盘镜像。如果你使用Homebrew,你可以用以下命令安装 create-dmg。

复制代码
brew install create-dmg

create-dmg 是一个用于 macOS 的命令行工具,用于创建 .dmg (Disk Image) 文件,这些文件通常用于分发 macOS 应用程序。它简化了创建 .dmg 文件的过程,并允许你自定义磁盘映像的外观和行为。以下是 create-dmg 的一些主要功能和使用方法:

主要功能:

  1. 简单易用:通过命令行参数,快速创建 .dmg 文件。
  2. 自定义背景图片:可以为磁盘映像设置自定义背景图片。
  3. 应用程序放置位置:可以指定应用程序图标在磁盘映像中的位置。
  4. 图标大小和排列:自定义图标的大小和排列方式。
  5. 自动挂载和卸载:创建 .dmg 文件时自动挂载和卸载磁盘映像。

以下是一个简单的示例,用于创建一个 .dmg 文件:

复制代码
create-dmg 'path/to/your/app' 'path/to/output/directory'

常用参数:

create-dmg 提供了多种参数来定制 .dmg 文件。以下是一些常用参数:

  • --overwrite:如果输出目录已经存在相同名称的 .dmg 文件,使用此参数将其覆盖。
  • --background:指定 .dmg 文件的背景图片。
  • --icon:设置应用程序图标的位置,格式为 name:x,y,例如:--icon "YourAppName:150,150".
  • --icon-size:设置图标的大小,默认值为 80。
  • --window-size:设置 .dmg 窗口的大小,格式为 width,height,例如:--window-size 600,400.
  • --title:设置 .dmg 窗口的标题。

以下是一个更复杂的示例,展示了如何使用多个参数来自定义 .dmg 文件:

复制代码
create-dmg 'path/to/your/app' 'path/to/output/directory' \
  --overwrite \
  --background 'path/to/background.png' \
  --icon 'YourAppName:150,150' \
  --icon-size 100 \
  --window-size 800,600 \
  --title 'YourAppName Installer'
相关推荐
伍华聪6 天前
WxPython跨平台开发框架之模块字段权限的管理
python开发
伍华聪7 天前
WxPython跨平台开发框架之动态菜单的管理和功能权限的控制
python开发
伍华聪9 天前
WxPython跨平台开发框架之前后端结合实现附件信息的上传及管理
python开发
伍华聪9 天前
WxPython跨平台开发框架之图标选择界面
python开发
伍华聪12 天前
WxPython跨平台开发框架之列表数据的通用打印处理
python开发
伍华聪13 天前
WxPython跨平台开发框架之复杂界面内容的分拆和重组处理
python开发
伍华聪1 个月前
WxPython跨平台开发框架之参数配置管理界面的设计和实现
python开发
伍华聪1 个月前
WxPython跨平台开发框架之表格数据导出到Excel并打开
python开发
伍华聪1 个月前
WxPython跨平台开发框架之用户选择和标签组件的设计
python开发