我有一个要从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
有什么办法可以使单个共享库解决方案正常工作?
答案 0 :(得分:2)
关于将多个Cython模块捆绑在一起(例如1,2),存在许多类似的问题,因为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