python - Cython: Segmentation Fault Using API Embedding Cython to C 语言

标签 python cython

我正尝试在 O'reilly Cython book 之后将 Cython 代码嵌入到 C 中第 8 章。我在 Cython 的 documentation 上找到了这一段但还是不知道该怎么办:

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 和 GCC 5。源代码是 transcendentals.pyxmain.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;
}

先验数.pyx

cdef api double get_pi():
    return 3.1415926

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

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

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"])
    ])
)

生成文件

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() 的调用。

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

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()

第一个原因是根据文档

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 链接到

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

没有理由导入先验模块。尽管必须初始化模块,PyInit_transcendentals() 为 Python 3 执行此操作

关于python - Cython: Segmentation Fault Using API Embedding Cython to C 语言,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38026198/

相关文章:

python - 如何在python中找到两个字符串之间最长的公共(public)ENDING

python - 我想从点之间具有角度的点列表中创建相对于单个点的标题。有这个功能吗?

python - 字符串的所有分割的Cythonize列表

python - Cython - 在 for 循环中使用 "from"关键字

python - 如何使 Python Yaml 库以人性化的方式保存?

python - 如何为输出预测设置条件阈值?

Cython:将 void* 转换为 double 和反向转换

python - Cython 回调中的段错误

python - pygame.错误 : video system not initialized

python - 使用命令行参数通过 Cython 运行 python 代码