[英]Cython: Segmentation Fault Using API Embedding Cython to C
我试图在O'reilly Cython第8章之后将Cython代码嵌入到C中。我在Cython的文档中找到了这一段,但仍然不知道该怎么做:
如果想要使用这些函数的C代码是多个共享库或可执行文件的一部分,则需要在使用这些函数的每个共享库中调用import_modulename()函数。 如果在调用其中一个api调用时遇到分段错误(linux上的SIGSEGV)崩溃,这可能表明包含生成分段错误的api调用的共享库之前没有调用import_modulename()函数崩溃的api电话。
我在OS X上运行Python 3.4,Cython 0.23和GCC 5.源代码是transcendentals.pyx
和main.c
:
main.c
#include "transcendentals_api.h"
#include <math.h>
#include <stdio.h>
int main(int argc, char **argv)
{
Py_SetPythonHome(L"/Users/spacegoing/anaconda");
Py_Initialize();
import_transcendentals();
printf("pi**e: %f\n", pow(get_pi(), get_e()));
Py_Finalize();
return 0;
}
transcendentals.pyx
cdef api double get_pi():
return 3.1415926
cdef api double get_e():
print("calling get_e()")
return 2.718281828
我正在使用setup.py
和Makefile
编译这些文件:
setup.py
:
from distutils.core import setup
from distutils.extension import Extension
from Cython.Build import cythonize
setup(
ext_modules=cythonize([
Extension("transcendentals", ["transcendentals.pyx"])
])
)
Makefile
python-config=/Users/spacegoing/anaconda/bin/python3-config
ldflags:=$(shell $(python-config) --ldflags)
cflags:=$(shell $(python-config) --cflags)
a.out: main.c transcendentals.so
gcc-5 $(cflags) $(ldflags) transcendentals.c main.c
transcendentals.so: setup.py transcendentals.pyx
python setup.py build_ext --inplace
cython transcendentals.pyx
clean:
rm -r a.out a.out.dSYM build transcendentals.[ch] transcendentals.so transcendentals_api.h
但是,我来错误Segmentation fault: 11
。 有什么想法可以帮助吗? 谢谢!
在Makefile中有
transcendentals.so: setup.py transcendentals.pyx
python setup.py build_ext --inplace
除非python
引用/Users/spacegoing/anaconda/bin/python3
否则应该替换它,因为模块可能被编译为错误的python版本,因此无法加载。
在main.c中 ,调用import_transcendentals()
不检查返回值,即导入失败还是成功。 如果失败, get_pi()
和get_e()
指向无效的内存位置并尝试调用它们会导致分段错误。
此外,模块必须位于可以找到的位置。 似乎在嵌入时,不会搜索当前目录中的python模块。 可以更改PYTHONPATH
环境变量以包含transcendentals.so所在的目录。
以下是将代码嵌入C程序并回避导入问题的一种替代方法,因为模块代码链接到可执行文件。
实质上,缺少对PyInit_transcendentals()
的调用。
当cython函数被public
定义时,将生成文件transcendentals.h
cdef public api double get_pi():
...
cdef public api double get_e():
你的main.c应该有include指令
#include <Python.h>
#include "transcendentals.h"
然后在main
Py_Initialize();
PyInit_transcendentals();
应该没有#include "transcendentals_api.h"
而没有import_transcendentals()
第一个原因是根据文档
但是,请注意,您应该在给定的C文件中包含modulename.h或modulename_api.h,而不是两者,否则您可能会遇到冲突的双重定义。
第二个原因是,因为transcendentals.c与该计划有关
gcc $(cflags) $(ldflags) transcendentals.c main.c
没有理由导入transcendentals模块。 必须初始化模块, PyInit_transcendentals()
为Python 3执行此操作
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.