通过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
我有一个 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 模块捆绑在一起(例如
您需要使用 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