使用cython编译所需的外部模块

10 投票
4 回答
6456 浏览
提问于 2025-04-17 23:20

我正在Linux上使用Cython构建一个独立的可执行文件。

我有以下代码:

import psycopg2 as pg

conn = pg.connect('dbname=**** user=**** password=****')
cur = conn.cursor()
cur.execute('SELECT version()')
print(cur.fetchone())

问题是,当机器上没有安装Python包psycopg2时,会抛出以下异常:

Traceback (most recent call last):
File "test.py", line 2, in init test (test.c:872)
    import psycopg2 as pg
ImportError: No module named 'psycopg2'

我在构建时使用了--embed这个Cython选项。

我该如何让Cython也编译这个特定的包呢?

4 个回答

0

过了很久,我偶然看到了这个问题,因为我之前也遇到过类似的情况。我的解决办法是把缺少的模块加到PyInstaller里,使用 --hidden-imports 这个选项。

所以

python3 -m PyInstaller --onefile <your.py> --hidden-import=<missed module>

这样做不会用cython来编译模块。不过,这也不是你问题中的要求。

4

Nuitka 是你需要的工具。

你把你的 Python 应用程序给它,它会做很多聪明的事情,然后输出一个可执行文件或者扩展模块。

现在,Nuitka 是一个很好的替代 Python 解释器的工具,它可以编译 CPython 2.6、2.7,和 3.2、3.3、3.4 所有的语法结构。它会把 Python 代码转换成 C++ 程序,然后使用 "libpython" 来执行,和 CPython 的执行方式非常相似。

它的运行速度比 CPython 快一些,但目前还没有实现所有可能的优化。不过在 pystone 测试中,它的速度提升了 258%,这已经是个不错的开始(这个数据来自版本 0.3.11)。

5

--embed的意思是把Python解释器嵌入到你的可执行文件里。这并不意味着你可以完全不依赖Python。它的作用可能和你想的有些不同。听起来你更需要像py2exe、py2app或者pyfreeze这样的工具。

5

根据我的经验,从多个 Python 文件(包括你自己的文件或像 psycopg2 这样的依赖库)创建一个独立的可执行文件并不是那么简单。

我会尝试几种方法:

第一种是使用 cython_freeze,具体可以查看这个链接 https://github.com/cython/cython/tree/master/Demos/freeze。不过我自己没有用过,所以不能多说。

第二种是使用 pyinstaller 来创建这样的可执行文件。它可以把 .py 或 .pyc 文件作为输入,连同 Python 解释器和所需的依赖库一起打包成一个可执行文件,这样你就不需要在目标机器上安装任何东西。不过要注意,你的代码会以解释的方式运行,别人可以很容易地反编译和查看你的代码。

如果你真的需要编译(cythonize)你的代码,可以先用 cythonize() 编译,然后用 setup() 构建你的扩展,最后像上面说的那样运行 pyinstaller(要确保它找不到 .py 或 .pyc 文件,只找到 .pyd 或 .so 扩展名)来生成独立的可执行文件。在这两种情况下,pyinstaller 会收集你所有的依赖库并把它们嵌入到可执行文件中(即使失败了,你也可以告诉 pyinstaller 用 hidden_imports 来嵌入它们)。

当然还有其他方法,比如 py2exe,但几个月前我研究和尝试了几种技术后,发现 pyinstaller 是对我来说最好的选择。我在 Windows、Linux 和 Mac 上都能顺利进行这个过程,变化不大。

编辑:我没注意到这个例子是 Python 3 的。现在 pyinstaller 只支持 2.x 版本。

撰写回答