通过c++调用带有多个pyx文件的cython库

Calling a cython library with multiple pyx files through c++

我有一个 python 项目,我想从 C++ 应用程序调用它。我想将所有 python 源捆绑在一个共享库中,并将 link 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

有没有办法让单一共享库解决方案起作用?

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

您需要使用 C API 函数 PyImport_AppendInittab 到 Python 将 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

对我来说(在稍微不同的情况下,但我没想到会有所不同)@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