当前位置: 首页 > 工具软件 > PyX > 使用案例 >

python导入pyx文件_使用cython从多个pyx文件制作可执行文件

章威
2023-12-01

我想从我的python源文件中创建一个unix可执行文件.

我有两个文件,p1.py和p2.py

p1.py: –

from p2 import test_func

print (test_func())

p2.py: –

def test_func():

return ('Test')

现在,我们可以看到p1.py依赖于p2.py.我想通过将两个文件组合在一起来制作可执行文件.我正在使用cython.

我将文件名分别更改为p1.pyx和p2.pyx.

现在,我可以使用cython使文件可执行,

cython p1.pyx --embed

它将生成一个名为p1.c的C源文件.接下来我们可以使用gcc使其可执行,

gcc -Os -I /usr/include/python3.5m -o test p1.c -lpython3.5m -lpthread -lm -lutil -ldl

但是如何将两个文件合并为一个可执行文件?

解决方法:

有一些循环你必须跳过才能使它工作.

首先,您必须意识到生成的可执行文件是一个非常纤薄的层,它将整个工作委托给(即调用函数)pythonX.Ym.so.调用时可以看到这种依赖关系

ldd test

...

libpythonX.Ym.so.1.0 => not found

...

因此,要运行该程序,您需要将LD_LIBRARY_PATH显示到libpythonX.Ym.so的位置,或者使用–rpath选项构建exe,否则在测试动态加载程序启动时将抛出类似于

/test: error while loading shared libraries: libpythonX.Ym.so.1.0: cannot open shared object file: No such file or directory

通用构建命令如下所示:

gcc -fPIC -o test p1.c -I -L -Wl,-rpath= -lpython3.6m

生成的可执行测试的行为与它是python-interpreter的行为完全相同.这意味着现在,测试将失败,因为它将找不到模块p2.

一个简单的解决方案是将p2模块进行cython化(cythonize p2.pyx -i),你将获得所需的行为 – 但是,你必须分发生成的共享对象p2.so以及test.

将两个扩展名捆绑成一个可执行文件很容易 – 只需将两个cythonized c文件传递给gcc即可:

# creates p1.c:

cython --empbed p1.pyx

# creates p2.c:

cython p2.pyx

gcc ... -o test p1.c p2.c ...

但现在出现了一个新的(或旧的)问题:生成的测试可执行文件不能再次找到模块p2,因为python-path上没有p2.py且没有p2.so.

关于这个问题,有两个类似的SO问题,here和here.在你的情况下,建议的解决方案有点矫枉过正,这里足以初始化p2模块,然后在p1.pyx文件中导入它以使其工作:

# making init-function from other modules accessible:

cdef extern object PyInit_p2();

#init/load p2-module manually

PyInit_p2() #Cython handles error, i.e. if NULL returned

# actually using already cached imported module

# no search in python path needed

from p2 import test_func

print(test_func())

在导入模块之前调用模块的init函数(实际上模块不会第二次真正导入,只在缓存中查找),如果模块之间存在循环依赖关系,也可以工作.例如,如果模块p2导入模块p3,它将轮流导入p2.

由于Cython 0.29,Cython使用默认的Python> = 3.5进行多阶段初始化,因此调用PyInit_p2是不够的(参见例如this SO-post).要关闭此多阶段初始化-DCYTHON_PEP489_MULTI_PHASE_INIT = 0应该传递给gcc或类似于其他编译器.

一句警告:如果我们将PyInit_p2()声明为

from cpython cimport PyObject

cdef extern PyObject *PyInit_p2();

PyInit_p2(); # TODO: error handling if NULL is returned

Cython将不再处理错误和我们的责任.代替

PyObject *__pyx_t_1 = NULL;

__pyx_t_1 = PyInit_p2(); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4, __pyx_L1_error)

__Pyx_GOTREF(__pyx_t_1);

__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;

为object-version生成,生成的代码变为:

(void)(PyInit_p2());

即没有错误检查!

另一方面使用

cdef extern from *:

"""

PyObject *PyInit_p2(void);

"""

object PyInit_p2()

将无法使用g – 必须将extern C添加到声明中.

标签:python,cython,cythonize

 类似资料: