【问题标题】:Simple Cython file causes redefinition errors when using cpdef使用 cpdef 时简单的 Cython 文件会导致重新定义错误
【发布时间】:2021-09-13 23:58:23
【问题描述】:

我有一个简单的 cython *.pyx 文件,它会导致一堆重新定义错误,我不明白为什么。如果我将“cpdef”更改为“cdef”,它编译得很好,但不会导出这些函数,我希望它们被导出。有人可以解释为什么这会失败,或者我在这里做错了什么吗?

core.pyx:

cdef extern from "module.h":
    cpdef double radians(double degrees)
    cpdef double degrees(double radians)

模块.h:

#ifndef MODULE_H
#define MODULE_H
double radians(double degrees);
double degrees(double radians);
#endif

module.c:

#include "module.h"

double radians(double degrees)
{
    return degrees * (M_PI / 180.0);
}

double degrees(double radians)
{
    return radians * (180.0 / M_PI);
}

错误:

$ python3 setup.py build
running build
running build_ext
building 'core' extension
x86_64-linux-gnu-gcc -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -g -fwrapv -O2 -g -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -fPIC -Iinclude -I/usr/include/python3.8 -c src/core.c -o build/temp.linux-x86_64-3.8/src/core.o
src/core.c:1294:13: error: redefinition of ‘__pyx_doc_11cfunc_dot_to_py_36__Pyx_CFunc_double____double___to_py_wrap’
 1294 | static char __pyx_doc_11cfunc_dot_to_py_36__Pyx_CFunc_double____double___to_py_wrap[] = "wrap(radians: float) -> float";
      |             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/core.c:1146:13: note: previous definition of ‘__pyx_doc_11cfunc_dot_to_py_36__Pyx_CFunc_double____double___to_py_wrap’ was here
 1146 | static char __pyx_doc_11cfunc_dot_to_py_36__Pyx_CFunc_double____double___to_py_wrap[] = "wrap(degrees: float) -> float";
      |             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/core.c:1295:20: error: redefinition of ‘__pyx_mdef_11cfunc_dot_to_py_36__Pyx_CFunc_double____double___to_py_1wrap’
 1295 | static PyMethodDef __pyx_mdef_11cfunc_dot_to_py_36__Pyx_CFunc_double____double___to_py_1wrap = {"wrap", (PyCFunction)__pyx_pw_11cfunc_dot_to_py_36__Pyx_CFunc_double____double___to_py_1wrap, METH_O, __pyx_doc_11cfunc_dot_to_py_36__Pyx_CFunc_double____double___to_py_wrap};
      |                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/core.c:1147:20: note: previous definition of ‘__pyx_mdef_11cfunc_dot_to_py_36__Pyx_CFunc_double____double___to_py_1wrap’ was here
 1147 | static PyMethodDef __pyx_mdef_11cfunc_dot_to_py_36__Pyx_CFunc_double____double___to_py_1wrap = {"wrap", (PyCFunction)__pyx_pw_11cfunc_dot_to_py_36__Pyx_CFunc_double____double___to_py_1wrap, METH_O, __pyx_doc_11cfunc_dot_to_py_36__Pyx_CFunc_double____double___to_py_wrap};
      |                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/core.c:1296:18: error: redefinition of ‘__pyx_pw_11cfunc_dot_to_py_36__Pyx_CFunc_double____double___to_py_1wrap’
 1296 | static PyObject *__pyx_pw_11cfunc_dot_to_py_36__Pyx_CFunc_double____double___to_py_1wrap(PyObject *__pyx_self, PyObject *__pyx_arg_radians) {
      |                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/core.c:1148:18: note: previous definition of ‘__pyx_pw_11cfunc_dot_to_py_36__Pyx_CFunc_double____double___to_py_1wrap’ was here
 1148 | static PyObject *__pyx_pw_11cfunc_dot_to_py_36__Pyx_CFunc_double____double___to_py_1wrap(PyObject *__pyx_self, PyObject *__pyx_arg_degrees) {
      |                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/core.c:1317:18: error: redefinition of ‘__pyx_pf_11cfunc_dot_to_py_36__Pyx_CFunc_double____double___to_py_wrap’
 1317 | static PyObject *__pyx_pf_11cfunc_dot_to_py_36__Pyx_CFunc_double____double___to_py_wrap(PyObject *__pyx_self, double __pyx_v_radians) {
      |                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/core.c:1169:18: note: previous definition of ‘__pyx_pf_11cfunc_dot_to_py_36__Pyx_CFunc_double____double___to_py_wrap’ was here
 1169 | static PyObject *__pyx_pf_11cfunc_dot_to_py_36__Pyx_CFunc_double____double___to_py_wrap(PyObject *__pyx_self, double __pyx_v_degrees) {
      |                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/core.c:1370:18: error: redefinition of ‘__Pyx_CFunc_double____double___to_py’
 1370 | static PyObject *__Pyx_CFunc_double____double___to_py(double (*__pyx_v_f)(double)) {
      |                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/core.c:1222:18: note: previous definition of ‘__Pyx_CFunc_double____double___to_py’ was here
 1222 | static PyObject *__Pyx_CFunc_double____double___to_py(double (*__pyx_v_f)(double)) {
      |                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/core.c:1317:18: warning: ‘__pyx_pf_11cfunc_dot_to_py_36__Pyx_CFunc_double____double___to_py_wrap’ defined but not used [-Wunused-function]
 1317 | static PyObject *__pyx_pf_11cfunc_dot_to_py_36__Pyx_CFunc_double____double___to_py_wrap(PyObject *__pyx_self, double __pyx_v_radians) {
      |                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/core.c:1296:18: warning: ‘__pyx_pw_11cfunc_dot_to_py_36__Pyx_CFunc_double____double___to_py_1wrap’ defined but not used [-Wunused-function]
 1296 | static PyObject *__pyx_pw_11cfunc_dot_to_py_36__Pyx_CFunc_double____double___to_py_1wrap(PyObject *__pyx_self, PyObject *__pyx_arg_radians) {
      |                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/core.c:1222:18: warning: ‘__Pyx_CFunc_double____double___to_py’ defined but not used [-Wunused-function]
 1222 | static PyObject *__Pyx_CFunc_double____double___to_py(double (*__pyx_v_f)(double)) {
      |                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: command 'x86_64-linux-gnu-gcc' failed with exit status 1

【问题讨论】:

  • 我还没有完成 Cython,但你不好奇你如何使用相同的标识符作为倒数函数的参数吗?我想知道这是否让编译器感到困惑。
  • 这对我来说似乎是一个错误。检查您使用的是最新版本的 Cython,如果不能修复,请在错误跟踪器上报告。
  • 我不知道,可以直接使用cpdef...但是有相应的文档部分:cython.readthedocs.io/en/latest/src/tutorial/…
  • 看起来好像对两个变量使用了相同的名称__pyx_doc_11cfunc_dot_to_py_36__Pyx_CFunc_double____double___to_py_wrap。这个特性似乎只适用于一个函数,或者函数应该有不同的签名。
  • 我同意这似乎是一个错误。我用 0.29.14、0.29.23 和 3.0a7 进行了尝试。他们都表现出这种行为。将提交罚单。谢谢!

标签: python cython


【解决方案1】:

正如 DavidW 所指出的,这可能是一个错误。看起来,生成的 C 代码中使用的变量名称仅采用变量类型而不采用函数名称,因此 __pyx_doc_11cfunc_dot_to_py_36__Pyx_CFunc_double____double___to_py_wrap 被定义了两次:一次用于 radians,一次用于 degrees

因此,暂时您应该使用解决方法。一种是给双类型不同的名称,例如:

%%cython -a  --verbose
cdef extern from *:
    """
    //some dummy implementations
    double radians(double degrees)
    {
        return degrees * (1.0 / 180.0);
    }

    int degrees(double radians)
    {
        return radians * (180.0 / 1.0);
    }
    """
    ctypedef double double1 "double"
    cpdef double degrees(double radians)
    cpdef double1 radians(double degrees)

这里我们使用cname-trick,Cython 将用“double”替换“double1”。

但这看起来不像是更大规模/长期的明智解决方案。我会改用更冗长但不那么令人费解的方法(考虑到在 extern (here documentation) 中使用 cpdef 反正不是很常见):

%%cython -a

cdef extern from *:
    """
    // code as above
    ...
    """
    double c_degrees "degrees"(double radians)
    double c_radians "radians"(double degrees)
    
cpdef double degrees(double radians):
    return c_degrees(radians)
cpdef double radians(double degrees):
    return c_radians(degrees)

再次,cname-trick 用于区分 cpdef 和在 Cython 代码中包装函数的 cname。

【讨论】:

  • 显然,你甚至可以这样做,它有效:cpdef double radians "radians"(double degree)
猜你喜欢
  • 2015-04-06
  • 2020-09-11
  • 2011-07-17
  • 1970-01-01
  • 1970-01-01
  • 2020-02-21
  • 2013-07-12
  • 1970-01-01
相关资源
最近更新 更多