首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Cython:用API将Cython嵌入到C中分割故障

Cython:用API将Cython嵌入到C中分割故障
EN

Stack Overflow用户
提问于 2016-06-25 07:42:51
回答 1查看 1.7K关注 0票数 7

O‘’reilly书第8章之后,我尝试将Cython代码嵌入到C中。我在Cython的文档上找到了这段代码,但仍然不知道该怎么做:

如果想使用这些函数的C代码是多个共享库或可执行文件的一部分,那么需要在使用这些函数的每个共享库中调用import_modulename()函数。如果在调用这些api调用时出现分段错误(linux上的SIGSEGV)崩溃,这很可能表明包含生成分段错误的api调用的共享库在崩溃的api调用之前不会调用import_modulename()函数。

我在OS上运行Python3.4、Cython0.23和GCC 5。源代码是transcendentals.pyxmain.c

main.c

代码语言:javascript
复制
#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

代码语言:javascript
复制
cdef api double get_pi():
    return 3.1415926

cdef api double get_e():
    print("calling get_e()")
    return 2.718281828

我正在使用setup.pyMakefile编译这些文件

setup.py

代码语言:javascript
复制
from distutils.core import setup
from distutils.extension import Extension
from Cython.Build import cythonize

setup(
    ext_modules=cythonize([
        Extension("transcendentals", ["transcendentals.pyx"])
    ])
)

Makefile

代码语言:javascript
复制
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。有什么能帮上忙的吗?谢谢!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-06-25 12:38:42

在那个Makefile中

代码语言:javascript
复制
transcendentals.so: setup.py transcendentals.pyx
    python setup.py build_ext --inplace

除非python引用/Users/spacegoing/anaconda/bin/python3,否则应该替换它,因为模块可能被编译成错误的/Users/spacegoing/anaconda/bin/python3版本,因此无法加载。

在main.c中,调用import_transcendentals()不检查返回值,即导入失败或成功。如果失败,get_pi()get_e()指向无效的内存位置,并试图调用它们将导致分段错误。

此外,模块必须位于可以找到它的地方。在嵌入时,似乎没有搜索当前目录中的python模块。可以将PYTHONPATH环境变量更改为包含transcendentals.so所在的目录。

下面是将代码嵌入C程序并避免导入问题的一种扩展方式,因为模块代码是链接到可执行文件的。

从本质上说,对PyInit_transcendentals()的调用是缺失的。

当定义cython函数时,将生成public文件,即:

代码语言:javascript
复制
cdef public api double get_pi():
...
cdef public api double get_e():

您的main.c应该有包含指令

代码语言:javascript
复制
#include <Python.h>
#include "transcendentals.h"

然后在main

代码语言:javascript
复制
Py_Initialize();
PyInit_transcendentals();

不应该有#include "transcendentals_api.h"import_transcendentals()

第一个原因是根据文件

但是,请注意,您应该在给定的C文件中包含Modename.h或modulename_api.h,而不是两者都包含,否则可能会得到相互矛盾的双重定义。

第二个原因是,由于超越性.c与

代码语言:javascript
复制
gcc $(cflags) $(ldflags) transcendentals.c main.c

没有理由导入transcendentals模块。虽然必须初始化模块,但是PyInit_transcendentals()为Python3做了这些工作。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38026198

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档