通过C ++调用具有多个pyx文件的cython库

时间:2018-10-04 11:54:45

标签: python cython

我有一个要从C ++应用程序调用的python项目。我想将所有python源捆绑在一起在一个共享库中,并将c ++应用程序链接到该库。现在,我的cython setup.py为每个python源创建一个*.so,这非常不方便。

这是setup.py文件:

from distutils.core import setup
from distutils.extension import Extension
from Cython.Build import cythonize

sourcefiles = ['project_interface.pyx', 'impl_file1.pyx']

setup(
    ext_modules = cythonize(sourcefiles)
)

project_interface.pyx:

# distutils: language = c++

import impl_file1

cdef public void HelloWorld():
    print "Calling Hello World"
    impl_file1.helloworld_func()

impl_file1.pyx:

def helloworld_func():
    print 'Hello World'

我试图修改setup.py以将所有python代码捆绑在一个库中,如下所示:

setup(
      ext_modules = cythonize([Extension("my_project", sourcefiles, language='c++')])
)

不幸的是,当执行void HelloWorld()时,应用程序无法再归档impl_file1了。我得到了:

Calling Hello World
NameError: name 'impl_file1' is not defined
Exception NameError: "name 'impl_file1' is not defined" in 'project_interface.HelloWorld' ignored

驱动此操作的c ++程序是:

#include <Python.h>
#include "project_interface.h"

int main(int argc, const char** argv){
    Py_Initialize();
    initproject_interface();
    HelloWorld();
    Py_Finalize();


    return 0;
}

使用多个*.so文件进行编译时,此应用程序可以正常工作。

在两种情况下,编译都非常简单:

python setup.py build_ext --inplace
mv my_project.so libmy_project.so
g++ main.cpp -o main `python2-config --cflags --ldflags` -L. -lmy_project

有什么办法可以使单个共享库解决方案正常工作?

2 个答案:

答案 0 :(得分:2)

关于将多个Cython模块捆绑在一起(例如12),存在许多类似的问题,因为Python使用文件路径来处理模块,因此这实际上并不可行。但是,这个问题并不完全相同,因为您是从C ++调用它的,这为您提供了一个额外的选择。

您需要对Python使用C API函数PyImport_AppendInittab来将impl_file1视为内置模块,以便它不会在路径中搜索要导入的文件。首先提供导入函数的声明(因为您不会从头文件中获得该声明):

extern "C" {
// PyObject* PyInit_impl_file1(); // Python 3
void initimpl_file1(); // Python 2
}

然后在main之前的Py_Initialize中,添加:

PyImport_AppendInittab("impl_file1", initimpl_file1); // change the name for Python 3

答案 1 :(得分:1)

对我来说(在稍微不同的情况下,但我没想到会有什么不同)@DavidW的解决方案需要进行一些调整。这是我的设置:

foo.pyx

cdef extern from "Python.h":
    int PyImport_AppendInittab(const char *name, object (*initfunc)())


cdef extern from *:
    """
    PyObject *PyInit_bar(void);
    """
    object PyInit_bar()

PyImport_AppendInittab("bar", PyInit_bar)

import bar  # HERE The error happens

bar.pyx

print("bar imported")

setup.py

from distutils.core import setup
from distutils.extension import Extension
from Cython.Build import cythonize

sourcefiles = ['foo.pyx', 'bar.pyx']


setup(
    ext_modules = cythonize([Extension("foo", sourcefiles)])
)

现在用python setup.py build_ext -i构建后,会导致错误:

import foo
ImportError: 'bar' is not a built-in module

来自here。要变通,我必须将名称“ bar”添加到sys.builtin_module_names

...
import sys
sys.builtin_module_names = list(sys.builtin_module_names)+["bar"]
import bar