使用PyInstaller构建Cython编译的Python代码

26 投票
2 回答
17841 浏览
提问于 2025-04-18 11:50

我正在尝试用 PyInstaller 来构建一个包含多个文件的 Python 代码。为此,我先用 Cython 编译了代码,然后用生成的 .so 文件来替代 .py 文件。

假设第一个文件是 main.py,而引入的文件是 file_a.pyfile_b.py,经过 Cython 编译后,我得到了 file_a.sofile_b.so

当我把 main.pyfile_a.sofile_b.so 放在一个文件夹里,并通过 "python main.py" 来运行时,它是可以正常工作的。

但是,当我用 PyInstaller 打包后,尝试运行生成的可执行文件时,它会因为在 file_afile_b 中的引入而报错。

这个问题怎么解决呢?一种解决方案是把所有标准模块都在 main.py 中引入,这样是可以的。但如果我不想改动我的代码,还有什么解决办法呢?

2 个回答

3

如果有人在找快速解决办法,这里有个小窍门。

我遇到过同样的问题,找到了一种简单粗暴的方法来解决。问题在于,pyinstaller没有把运行你程序所需的库添加到生成的.exe文件里。

你只需要在你的main.py文件中导入所有需要的库(还有.so文件)。main.py就是那个调用file_a.py和file_b.py的文件。举个例子,假设file_a.py使用了opencv库(也就是cv2),而file_b.py使用了matplotlib库。那么在你的main.py文件中,你也需要导入cv2和matplotlib。简单来说,你在file_a.py和file_b.py中导入的东西,main.py中也要导入。这告诉pyinstaller你的程序需要这些库,然后它就会把这些库包含进生成的exe文件里。

30

我帮你搞定这个了。

请看看这个链接:用Pyinstaller打包Cython扩展

快速入门:

git clone https://github.com/prologic/pyinstaller-cython-bundling.git
cd pyinstaller-cython-bundling
./dist/build.sh

这样可以生成一个静态的可执行文件:

$ du -h dist/hello
4.2M    dist/hello
$ ldd dist/hello
    not a dynamic executable

并且会输出:

$ ./dist/hello 
Hello World!
FooBar

简单来说,这个过程就是创建一个简单的 setup.py 文件,用来构建扩展 file_a.sofile_b.so,然后使用 pyinstaller 把这些扩展和应用打包成一个单独的可执行文件。

示例 setup.py 文件:

from glob import glob
from setuptools import setup
from Cython.Build import cythonize


setup(
    name="test",
    scripts=glob("bin/*"),
    ext_modules=cythonize("lib/*.pyx")
)

构建扩展的过程:

$ python setup.py develop

打包应用的过程:

$ pyinstaller -r file_a.so,dll,file_a.so -r file_b.so,dll,file_b.so -F ./bin/hello

撰写回答