Cython:使用将Cython嵌入C的API的分段错误 [英] Cython: Segmentation Fault Using API Embedding Cython to C

查看:69
本文介绍了Cython:使用将Cython嵌入C的API的分段错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正尝试按照 O'reilly Cython的书将Cython代码嵌入到C中第8章。我在Cython的文档但仍然不知道该怎么办:

I'm trying to embed Cython code into C following O'reilly Cython book chapter 8. I found this paragraph on Cython's documentation but still don't know what should I do:


如果要使用这些功能的C代码是多个共享的一部分库或可执行文件,则需要在使用这些函数的每个共享库中调用import_modulename()函数。如果在调用以下api调用之一时因分段错误而崩溃(在Linux上为SIGSEGV),则可能表明包含正在生成分段错误的api调用的共享库未在之前调用import_modulename()函数

If the C code wanting to use these functions is part of more than one shared library or executable, then import_modulename() function needs to be called in each of the shared libraries which use these functions. If you crash with a segmentation fault (SIGSEGV on linux) when calling into one of these api calls, this is likely an indication that the shared library which contains the api call which is generating the segmentation fault does not call the import_modulename() function before the api call which crashes.

我正在OS X上运行Python 3.4,Cython 0.23和GCC5。源代码为 transcendentals.pyx main.c

I'm running Python 3.4, Cython 0.23 and GCC 5 on OS X. The source code are transcendentals.pyx and 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 编译这些文件:

I'm compiling those files using setup.py and 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

但是,我遇到错误分段错误:11 。有什么想法可以帮助您吗?谢谢!

However, I came to error Segmentation fault: 11. Any idea can help with this? Thanks!

推荐答案

在该Makefile中,有

In that Makefile there is

transcendentals.so: setup.py transcendentals.pyx
    python setup.py build_ext --inplace

除非 python 指的是 / Users / spacegoing / anaconda / bin / python3

main.c 中,调用<$ c替换了该模块,因为该模块可能是为错误的python版本编译的,因此无法加载。 $ c> import_transcendentals()不会检查返回值,即,导入是否成功。如果发生故障, get_pi() get_e()指向无效的内存位置,尝试调用它们会导致分段错误。

In main.c there is call import_transcendentals() that does not check the return value i.e. if the import fails or succeeds. In case of failure, get_pi() and get_e() point to invalid memory locations and trying to call them causes a segmentation fault.

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

Also, the module has to be located somewhere where it can be found. It seems that when embedding, the current directory is not searched for python modules. PYTHONPATH environment variable could be changed to include the directory where transcendentals.so is located.

以下是将代码嵌入C程序并回避导入问题的一种替代方法,因为模块代码已链接到可执行文件。

The following is an altenative way of embedding the code to the C program and sidesteps the import issues since the module code is linked to the executable.

本质上,这是一个调用缺少 PyInit_transcendentals()

Essentially, a call to PyInit_transcendentals() is missing.

文件 transcendentals.h 将在以下时间生成cython函数定义为 public

File transcendentals.h will be generated when the cython functions are defined public i.e.

cdef public api double get_pi():
...
cdef public api double get_e():

您的 main.c 应该具有include指令

Your main.c should have the include directives

#include <Python.h>
#include "transcendentals.h"

然后在 main中

Py_Initialize();
PyInit_transcendentals();

不应包含 #include transcendentals_api.h 且没有 import_transcendentals()

第一个原因是根据文档


但是,请注意,您应该在给定的C文件中包含modulename.h或
modulename_api.h,而不要同时包含两者,否则您可能会获得
双重定义冲突。

However, note that you should include either modulename.h or modulename_api.h in a given C file, not both, otherwise you may get conflicting dual definitions.

第二个原因是,由于 transcendentals.c 已链接到

The second reason is, that since transcendentals.c is linked to the program in

gcc $(cflags) $(ldflags) transcendentals.c main.c

没有理由导入先验模块。虽然必须初始化模块,但 PyInit_transcendentals()对于Python 3可以做到这一点

there is no reason to import transcendentals module. The module has to be initialized though, PyInit_transcendentals() does that for Python 3

这篇关于Cython:使用将Cython嵌入C的API的分段错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆