使用PyInstaller构建Cython编译的Python代码
我正在尝试用 PyInstaller
来构建一个包含多个文件的 Python 代码。为此,我先用 Cython
编译了代码,然后用生成的 .so
文件来替代 .py
文件。
假设第一个文件是 main.py
,而引入的文件是 file_a.py
和 file_b.py
,经过 Cython 编译后,我得到了 file_a.so
和 file_b.so
。
当我把 main.py
、file_a.so
和 file_b.so
放在一个文件夹里,并通过 "python main.py"
来运行时,它是可以正常工作的。
但是,当我用 PyInstaller
打包后,尝试运行生成的可执行文件时,它会因为在 file_a
和 file_b
中的引入而报错。
这个问题怎么解决呢?一种解决方案是把所有标准模块都在 main.py
中引入,这样是可以的。但如果我不想改动我的代码,还有什么解决办法呢?
2 个回答
如果有人在找快速解决办法,这里有个小窍门。
我遇到过同样的问题,找到了一种简单粗暴的方法来解决。问题在于,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文件里。
我帮你搞定这个了。
请看看这个链接:用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.so
和 file_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