当前位置: 首页 > news >正文

使用 GitHub Actions 和 Nuitka 实现 Python 应用(customtkinter ui库)的自动化跨平台打包

目录

  • 引言
  • 前置准备
  • 配置文件详解
  • 实现细节
  • CustomTkinter 打包注意事项
  • 完整配置示例
  • 常见问题

引言

在 Python 应用开发中,将源代码打包成可执行文件是一个常见需求。本文将详细介绍如何使用 GitHub Actions 和 Nuitka 实现自动化的跨平台打包流程,支持 Windows、Linux 和 macOS(包括 Intel 和 ARM 架构)。打包的过程中也是苦于找不到解决问题的文档,把自己的经历记录一下。

需要注意的是 windows 和 linux 的工作流我用了 Nuitka/Nuitka-Action 这个工作流的包,但是发现真的很慢,而且在打包macos老是报错。于是我把macos的工作流修改为我自己的 build.py 来实现。

下面主要是介绍我的流程,如果想要直接实现可以直接跳转到完整配置示例。当然 build.py 你不能直接使用,因为里面涉及到一些我自定义的配置,你需要甄别之后进行调整。然后配置 github action就可以实现自动化工作流。

前置准备

在开始之前,需要准备以下内容:

  1. Python 项目源代码
  2. requirements.txt 依赖文件
  3. GitHub 仓库
  4. 基本的 Python 开发环境

配置文件详解

本地构建脚本 (build.py)

首先,我们需要一个本地构建脚本来处理依赖检查和构建过程:

def check_and_install_dependencies():required_packages = {"customtkinter": "customtkinter","nuitka": "nuitka",}# ... 检查和安装依赖

这个脚本主要负责:

  • 检查和安装必要的依赖
  • 配置构建参数
  • 处理跨平台差异

GitHub Actions 工作流配置

.github/workflows/build.yml 中配置自动化构建流程:

name: Build Executableson:push:tags:- 'v*'  # 触发条件:创建新的版本标签

工作流包含四个主要任务:

  1. Windows 构建任务
build-windows:runs-on: windows-lateststeps:- uses: Nuitka/Nuitka-Action@main# ... Windows 特定配置
  1. Linux 构建任务
build-linux:runs-on: ubuntu-22.04steps:# ... Linux 特定配置
  1. macOS Intel 构建任务
build-macos-intel:runs-on: macos-latest# ... macOS Intel 特定配置
  1. macOS ARM 构建任务
build-macos-arm:runs-on: macos-15# ... macOS ARM 特定配置

实现细节

1. Nuitka 构建参数配置

关键的 Nuitka 构建参数包括:

  • --follow-imports: 跟踪并包含所有导入
  • --enable-plugin=tk-inter: 启用 Tkinter 支持
  • --include-package: 包含特定包
  • --include-data-dir: 包含数据目录
  • --macos-create-app-bundle: macOS 特定选项
  • --windows-console-mode: Windows 特定选项

2. 平台特定配置

Windows
windows-console-mode: disable
windows-icon-from-ico: src/assets/app_icon.ico
macOS
- name: Install Tcl/Tk Dependenciesrun: |brew install tcl-tkTCL_PATH=$(brew --prefix tcl-tk)
Linux
- name: Install System Dependenciesuses: awalsh128/cache-apt-pkgs-action@latestwith:packages: python3-tk tk-dev

3. 构建产物处理

使用 GitHub Actions 的 artifacts 功能保存构建结果:

- name: Upload artifactuses: actions/upload-artifact@v4with:name: CursorMagic-Platformpath: dist/*.app  # 或 .exe 等

CustomTkinter 打包注意事项

1. 必要的打包参数

使用 Nuitka 打包 CustomTkinter 应用时,需要特别注意以下参数:

- name: Build with Nuitkauses: Nuitka/Nuitka-Action@mainwith:nuitka-version: mainenable-plugins: tk-inter  # 必须启用 tk-inter 插件include-package: customtkinter  # 必须包含 customtkinter 包

2. 资源文件处理

CustomTkinter 的主题和样式文件需要正确打包:

  1. 主题文件

    • CustomTkinter 的主题文件位于包内的 assets 目录
    • 需要确保这些文件被正确包含在最终的可执行文件中
  2. 自定义资源

    • 如果使用了自定义主题或图标,需要使用 include-data-dir 确保资源文件被打包

3. 平台特定配置

Windows 平台
windows-console-mode: disable  # 禁用控制台窗口
standalone: true  # 确保所有依赖被打包
macOS 平台
macos-create-app-bundle: true  # 创建 .app 包
enable-plugins: tk-inter
onefile: false  # CustomTkinter 在 macOS 上不建议使用 onefile 模式

4. 依赖处理

  1. 版本控制

    # requirements.txt
    customtkinter==5.2.1  # 建议指定具体版本
    darkdetect>=0.7.1    # CustomTkinter 的依赖
    
  2. 依赖检查

    def check_dependencies():required = {"customtkinter": "customtkinter>=5.2.0","darkdetect": "darkdetect>=0.7.1"}# ... 检查依赖
    

5. 常见问题解决

  1. 主题加载失败

    • 症状:应用启动后显示默认 tkinter 样式
    • 解决:确保添加 --include-package=customtkinter 参数
  2. 图片资源丢失

    • 症状:自定义图标或图片无法显示
    • 解决:使用 --include-data-dir 指定资源目录
  3. 暗色模式问题

    • 症状:无法正确响应系统暗色模式
    • 解决:确保 darkdetect 包被正确打包
  4. macOS 特定问题

    - name: Fix macOS Permissionsif: runner.os == 'macOS'run: |chmod +x dist/*.app/Contents/MacOS/*
    

完整配置示例

这里提供一个实际的跨平台打包配置示例,包含本地构建脚本和 GitHub Actions 工作流配置。

本地构建脚本 (build.py)

import os
import sys
import subprocess
import pkg_resourcesdef check_and_install_dependencies():required_packages = {"customtkinter": "customtkinter","nuitka": "nuitka",}print("检查依赖项...")for package, pip_name in required_packages.items():try:pkg_resources.require(package)print(f"✓ {package} 已安装")except pkg_resources.DistributionNotFound:print(f"安装 {package}...")subprocess.check_call([sys.executable, "-m", "pip", "install", pip_name])def run_command(command):try:subprocess.run(command, shell=True, check=True)print(f"成功执行命令: {command}")except subprocess.CalledProcessError as e:print(f"命令执行失败: {command}")print(f"错误信息: {str(e)}")sys.exit(1)def main():print("开始构建过程...")# 设置输出目录和文件名output_dir = "dist"app_name = "CursorMagic"# 基础命令行选项base_options = ["--follow-imports",  # 跟踪导入"--enable-plugin=tk-inter",  # 启用 Tkinter 支持"--include-package=customtkinter",  # 包含 customtkinterf"--include-data-dir=src/utils/turnstilePatch=turnstilePatch",  # 包含数据目录f"--include-data-files=src/core/names-dataset.txt=names-dataset.txt",  # 包含具体的 txt 文件f"--include-data-dir=src/config=src/config",  # 包含配置目录"--warn-unusual-code",  # 警告不寻常的代码"--warn-implicit-exceptions",  # 警告隐式异常"--nofollow-import-to=tkinter.test",  # 排除测试模块"--nofollow-import-to=PIL.ImageQt",  # 排除 Qt 相关"--remove-output",  # 删除之前的输出f"--output-dir={output_dir}",  # 输出目录f'--output-file="{app_name}"',  # 输出文件名]# 根据操作系统添加特定选项if sys.platform == "darwin":  # macOStcl_path = os.getenv("TCL_PATH")if not tcl_path:try:tcl_path = subprocess.check_output(["brew", "--prefix", "tcl-tk"]).decode().strip()except:print("警告: 无法找到 Tcl/Tk 路径")sys.exit(1)base_options.extend(["--macos-create-app-bundle",  # 创建 macOS 应用包"--macos-app-icon=src/assets/app_icon.icns",  # 设置应用图标f"--macos-app-name={app_name}.app",  # 设置应用名称])elif sys.platform == "win32":  # Windowsbase_options.extend(["--standalone",  # 独立可执行文件"--mingw64",  # 使用 MinGW64"--windows-console-mode=disable",  # Windows 禁用控制台"--windows-icon-from-ico=src/assets/app_icon.ico",  # Windows 应用图标])nuitka_command = "python -m nuitka " + " ".join(base_options) + " " + "CursorMagic.py"run_command(nuitka_command)print("\n构建过程完成!")if __name__ == "__main__":main()

GitHub Actions 工作流配置 (.github/workflows/build.yml)

name: Build Executableson:push:tags:- 'v*'  # 添加标签触发条件,匹配 v1.0.0 这样的标签jobs:build-windows:runs-on: windows-lateststeps:- uses: actions/checkout@v4- name: Set up Pythonuses: actions/setup-python@v5with:python-version: '3.x'architecture: 'x64'cache: 'pip'cache-dependency-path: |**/requirements*.txt- name: Install Dependenciesrun: |pip install -r requirements.txt- name: Build Windows Executableuses: Nuitka/Nuitka-Action@mainwith:nuitka-version: mainscript-name: CursorMagic.pymode: onefileenable-plugins: tk-interinclude-package: customtkinterinclude-data-dir: |src/utils/turnstilePatch=turnstilePatchsrc/config=src/configinclude-data-files: src/core/names-dataset.txt=names-dataset.txtwindows-console-mode: disablewindows-icon-from-ico: src/assets/app_icon.icooutput-file: CursorMagic- name: Upload Windows artifactuses: actions/upload-artifact@v4with:name: CursorMagic-Windowspath: build/*.exeinclude-hidden-files: truebuild-linux:runs-on: ubuntu-22.04steps:- uses: actions/checkout@v4- name: Set up Pythonuses: actions/setup-python@v5with:python-version: '3.x'architecture: 'x64'cache: 'pip'cache-dependency-path: |**/requirements*.txt- name: Install System Dependenciesuses: awalsh128/cache-apt-pkgs-action@latestwith:packages: python3-tk tk-devversion: 1.0- name: Install Dependenciesrun: |pip install -r requirements.txt- name: Build Linux Executableuses: Nuitka/Nuitka-Action@mainwith:nuitka-version: mainscript-name: CursorMagic.pymode: onefileenable-plugins: tk-interinclude-package: customtkinterinclude-data-dir: |src/utils/turnstilePatch=turnstilePatchsrc/config=src/configinclude-data-files: src/core/names-dataset.txt=names-dataset.txtoutput-file: CursorMagic- name: Upload Linux artifactuses: actions/upload-artifact@v4with:name: CursorMagic-Linuxpath: build/CursorMagicinclude-hidden-files: truebuild-macos-intel:runs-on: macos-lateststeps:- uses: actions/checkout@v4- name: Set up Pythonuses: actions/setup-python@v5with:python-version: '3.11'architecture: 'x64'cache: 'pip'cache-dependency-path: |**/requirements*.txt- name: Install Tcl/Tk Dependenciesrun: |brew install tcl-tkTCL_PATH=$(brew --prefix tcl-tk)echo "TCL_PATH=$TCL_PATH" >> $GITHUB_ENVecho "LDFLAGS=-L$TCL_PATH/lib" >> $GITHUB_ENVecho "CPPFLAGS=-I$TCL_PATH/include" >> $GITHUB_ENVecho "PKG_CONFIG_PATH=$TCL_PATH/lib/pkgconfig" >> $GITHUB_ENVecho "Using Tcl/Tk from: $TCL_PATH"- name: Install Dependenciesrun: |pip install setuptoolspip install --upgrade nuitkapip install -r requirements.txtbrew install ccache- name: Clean Build Directoryrun: rm -rf build- name: Build with build.pyrun: python build.py- name: Upload MacOS Intel artifactuses: actions/upload-artifact@v4with:name: CursorMagic-MacOS-Intelpath: dist/*.appinclude-hidden-files: truebuild-macos-arm:runs-on: macos-15steps:- uses: actions/checkout@v4- name: Set up Pythonuses: actions/setup-python@v5with:python-version: '3.11'architecture: 'arm64'cache: 'pip'cache-dependency-path: |**/requirements*.txt- name: Install Tcl/Tk Dependenciesrun: |brew install tcl-tkTCL_PATH=$(brew --prefix tcl-tk)echo "TCL_PATH=$TCL_PATH" >> $GITHUB_ENVecho "LDFLAGS=-L$TCL_PATH/lib" >> $GITHUB_ENVecho "CPPFLAGS=-I$TCL_PATH/include" >> $GITHUB_ENVecho "PKG_CONFIG_PATH=$TCL_PATH/lib/pkgconfig" >> $GITHUB_ENVecho "Using Tcl/Tk from: $TCL_PATH"- name: Install Dependenciesrun: |pip install setuptoolspip install --upgrade nuitkapip install -r requirements.txtbrew install ccache- name: Clean Build Directoryrun: rm -rf build- name: Build with build.pyrun: python build.py- name: Upload MacOS ARM artifactuses: actions/upload-artifact@v4with:name: CursorMagic-MacOS-ARMpath: dist/*.appinclude-hidden-files: true

这个完整配置示例展示了:

  1. 本地构建脚本特点

    • 自动检查和安装依赖
    • 跨平台构建支持
    • 详细的构建选项配置
    • 错误处理和日志输出
  2. GitHub Actions 工作流特点

    • 支持四个平台的构建(Windows、Linux、macOS Intel、macOS ARM)
    • 完整的依赖安装配置
    • 构建缓存优化
    • 统一的构建产物处理
  3. 关键配置点

    • CustomTkinter 相关配置
    • 平台特定的依赖处理
    • 资源文件打包
    • 构建产物管理

常见问题

  1. 依赖问题

    • 确保 requirements.txt 完整且版本号正确
    • 使用 --include-package 包含所有必要的包
  2. TCL/TK 相关问题

    • macOS 需要正确配置 TCL_PATH
    • Linux 需要安装 python3-tk 和 tk-dev
  3. 路径问题

    • 使用相对路径
    • 正确配置 include-data-dirinclude-data-files
  4. 平台特定问题

    • Windows: 注意图标和控制台模式配置
    • macOS: 注意 ARM/Intel 架构差异内容已经更新完成,您可以查看完整的文档内容并进行必要的调整和修改。如果您有任何其他问题或需要进一步帮助,请随时告诉我。内容已经更新完成,您可以查看完整的文档内容并进行必要的调整和修改。如果您有任何其他问题或需要进一步帮助,请随时告诉我。
    • Linux: 注意系统依赖

结语

通过合理配置 GitHub Actions 和 Nuitka,我们可以实现 Python 应用的自动化跨平台打包。这不仅提高了开发效率,也确保了构建过程的一致性和可靠性。

参考资料

  • Nuitka 官方文档
  • GitHub Actions 文档
  • Python 打包指南

相关文章:

  • 状态管理最佳实践:Bloc架构实践
  • Android Jetpack Compose 状态管理解析:remember vs mutableStateOf,有啥不一样?为啥要一起用?
  • HTML表单与数据验证设计
  • 区块链预言机(Oracle)详解:如何打通链上与现实世界的关键桥梁?
  • 如何将自己封装的组件发布到npm上:详细教程
  • JavaScript学习教程,从入门到精通,DOM节点操作语法知识点及案例详解(21)
  • Android学习总结之APK打包流程
  • 使用Ingress发布应用程序
  • swift-12-Error处理、关联类型、assert、泛型_
  • ospf实验
  • 【HDFS入门】HDFS性能调优实战:压缩与编码技术深度解析
  • JavaScript中的Event事件对象详解
  • STL之vector基本操作
  • c语言中的原,反,补码
  • `Accelerate`库实现模型并行计算
  • STM32单片机入门学习——第42节: [12-2] BKP备份寄存器RTC实时时钟
  • QML动画--ParallelAnimation和SequentialAnimation
  • linux查看目录相关命令
  • SpringBoot启动后初始化的几种方式
  • 《关于加快推进虚拟电厂发展的指导意见》解读
  • 北京媒体锐评男子地铁辱骂他人:北京地铁永远欢迎沾着泥巴的普通劳动者
  • 京东:自21日起,所有超时20分钟以上的外卖订单全部免单
  • “30小时不够”,泽连斯基建议延长停火至30天
  • 智慧菜场团标试验:标准化的同时还能保留个性化吗?
  • 法官颁布紧急临时禁止令,中国留学生诉美国政府“首战胜利”
  • 中物联声明:反对美对华物流、海事和造船领域301调查措施