Pyinstaller打包Pyd文件到exe(update)
前言
去年写了一篇文章,就是使用 Pyinstaller 编译 pyd 文件到 exe 中的,只不过上次是记录了解决问题的过程,并没有详细记录打包的过程和原理,这次正好借用新项目来记录下。
项目介绍
项目中用 Python 开发了一款数据采集工具,部署端为 Windows 服务器,为了在服务器上直接运行,需要将程序打包为 exe 格式。为了保护源代码并且加快程序的运行速度,使用 Cython 编译项目各个模块,使用 Pyinstaller 将模块打包为 exe 文件。
项目结构
项目所有代码均为异步,使用到了 asyncio 和一个异步的 opc client,和 PLC 进行交互,项目结构为:
1 | D:\AQ |
其中,main.py
为启动文件,aq 为一个 Python 包,所有的业务逻辑都在 aq 包中,只需要将包中所有文件编译为 pyd 文件,之后使用 Pyinstaller 打包即可。
打包思路
打包思路为:通过 Cython 编译 aq 文件夹中所有的文件为 pyd 文件,然后删除对应的 py 文件,在 import 时就可以直接导入 pyd 了。然后使用 Pyinstaller 打包所有的文件为 exe,使用 --hidden-import
参数添加依赖项,使用 --add-data
参数添加所有的 pyd 文件到程序中,最后进行清理工作。
这里涉及到一个问题就是:Pyinstaller 会自动分析 py 文件,然后将需要导入的依赖自动导入到程序中去,但是由于我们已经将 py 文件编译为 pyd 文件了,所以 Pyinstaller 无法分析编译后的二进制 pyd 文件,导致不能自动导入依赖到程序中。
解决此问题的方法就是我们需要使用 --hidden-import
参数来手动指定所有的依赖。
编译脚本
编译脚本(setup.py)为:
1 | from distutils.core import setup |
打包脚本
打包脚本(build2pyd.bat)为:
1 | python setup.py build_ext --inplace |
打包流程
- 先运行 setup.py,编译所有的 py 文件为 pyd 文件
- 然后新建一个临时文件夹, 将所有的 pyd 文件移动到临时文件夹中
- 删除原有文件夹中所有的 c 文件,重命名 aq 文件夹为一个其他名字,然后执行打包脚本
- 在打包时 Pyinstaller 会根据 main.py 中的 import 信息自动去对应文件夹导入 py 文件,为了防止 py 文件被导入需要将 aq 文件夹重命名。
- 打包时比较重要的两个参数为
--hidden-import
和--add-data
,第一个参数用来导入依赖项,因为 py 文件被打包为 pyd 文件了,Pyinstaller 无法判断 pyd 文件中导入了什么其他依赖,所以默认不会导入 pyd 所需要的依赖,需要使用--hidden-import
参数手动导入对应依赖。第二个参数用来将编译好的 pyd 文件添加到打包的文件中,并且将 temp 重命名为 aq,因为 main.py 中所有内容原本就是从 aq 包中导入的,无论包中是 py 文件还是 pyd 文件,包名要保持相同。 - 删除一些无用的文件,将文件夹的名字恢复为 aq,结束脚本。
持续集成
以上过程可以通过持续集成系统变成完全的自动化流程,这里我使用 GitHub Actions 来实现自动编译和打包过程,配置文件如下:
1 | name: build Python Package |
参考官方文档可以很快写出此配置文件,仅供参考。
这里比较特殊的是 Cython 依赖,由于目前最新版本的 Cython 不支持项目中用到的
iscoroutinefunction
函数,详细信息可以看这里,这里需要自己编译安装 Cython 依赖。
总结
打包过程到这里就结束了,总结下整体的流程,其实就两个,编译和打包,编译基本上一条命令就可以搞定,打包的问题稍微多一点,如果有问题的话可以看看我之前的一篇文章。
参考链接
https://blog.d77.xyz/archives/75cf9cb3.html
本文章首发于个人博客 LLLibra146’s blog
本文作者:LLLibra146
更多文章请关注:
版权声明:本博客所有文章除特别声明外,均采用 © BY-NC-ND 许可协议。非商用转载请注明出处!严禁商业转载!
本文链接:
https://blog.d77.xyz/archives/118d44fa.html