Cython:共享对象中的未定义符号

时间:2018-05-17 09:58:53

标签: c++ cython

我在python项目中导入c ++代码,一切似乎编译得很好但是在导入我的.pyx时得到:

from AGCython import *
ImportError: /path/to/shared/object/AGCython.cpython-36m-x86_64-linux-gnu.so: undefined symbol: c_Stat_GetMeanAndVariance_double

在我的AGCython.pyx中我有:

cdef extern void c_Stat_GetMeanAndVariance_double (double* array, int nSize, double* mean, double* var)

及其python包装器

def Stat_GetMeanAndVariance_double(np.ndarray[double, ndim=1, mode="c"] input not None):
    cdef int m #nSize
    m = input.shape[0]
    cdef double mean, var
    c_Stat_GetMeanAndVariance_double(&input[0], m, &mean, &var)
    return mean, var

这个cpp函数在AGc.cpp中定义:

#include "AGc.h"
void c_Stat_GetMeanAndVariance_double(const double *aData, const int nSize, double &mean, double &var)
{
    // Special case, small vector
    if (nSize<=1)
    {
        var= 0;
        if (nSize)
            mean= *aData;
        else
            mean= 0;
        return;
    }

    double s, ssqr;
    Stat_GetSums_double(aData, nSize, s, ssqr);

    mean= s/nSize;
    var= Stat_GetVariance(s, ssqr, nSize);
    return;
}

和AGc.h包含:

void c_Stat_GetMeanAndVariance_double(const double *aData, const int nSize, double &mean, double &var);

我的编译脚本是这样的:

from distutils.core import setup
from Cython.Build import cythonize
from distutils.extension import Extension
import numpy


sourcefiles = ['AGCython.pyx', 'AGc.cpp']

extensions = [Extension("AGCython", sourcefiles)]

setup(
    ext_modules = cythonize(extensions, annotate=True)
)

这导致了这个gcc调用:

gcc -pthread -B /home/ludvig/anaconda3/compiler_compat -Wl,--sysroot=/ -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -fPIC -I/home/ludvig/anaconda3/include/python3.6m -c AGc.cpp -o build/temp.linux-x86_64-3.6/AGc.o
cc1plus: warning: command line option ‘-Wstrict-prototypes’ is valid for C/ObjC but not for C++
g++ -pthread -shared -B /home/ludvig/anaconda3/compiler_compat -L/home/ludvig/anaconda3/lib -Wl,-rpath=/home/ludvig/anaconda3/lib -Wl,--no-as-needed -Wl,--sysroot=/ build/temp.linux-x86_64-3.6/AGCython.o build/temp.linux-x86_64-3.6/AGc.o -o /path/to/my/project/AGCython.cpython-36m-x86_64-linux-gnu.so

我不明白我在这里错过了什么,我不认为警告是阅读this问题的问题

2 个答案:

答案 0 :(得分:2)

你的问题是名字错误。然而,有两个原因导致它无法正常工作。

首先

AGCython.pyx默认使用没有名称修改的C语言,即它希望该符号的名称为c_Stat_GetMeanAndVariance_double

附加文件是*.cpp,因此gcc决定将其编译为C ++ - 源代码,这意味着相应符号名称中的名称修改变为_Z32c_Stat_GetMeanAndVariance_doublePKdiRdS1_。因此,在查找非损坏名称时,加载程序在运行时失败。

有不同的方法可以修复它,但如果您计划使用c ++,最简单的方法是将language='c++'添加到您的设置中:

extensions = [Extension("AGCython", 
                        sourcefiles,
                        language='c++')]

第二次

您将导出的函数声明为:

cdef extern void c_Stat_GetMeanAndVariance_double (...)

它是从cython转换为

__ PYX_EXTERN_C DL_IMPORT(void)c_Stat_GetMeanAndVariance_double(...);

__PYX_EXTERN_C是以下的定义:

#ifndef __PYX_EXTERN_C
  #ifdef __cplusplus
    #define __PYX_EXTERN_C extern "C"
  #else
    #define __PYX_EXTERN_C extern
  #endif
#endif

这意味着它关闭了C ++的名称错位。为了避免这种情况,您需要在标题中包含函数,通常这样做:

cdef extern from "AGc.h":
    void c_Stat_GetMeanAndVariance_double(...)

答案 1 :(得分:1)

最终我的诀窍是改变

cdef extern from "AGc.h":
    void c_Stat_GetMeanAndVariance_double(const double* aData, const int nSize, double &mean, double &var)

成:

type EmailFilter = Email => Boolean

val minimumSize: Int => EmailFilter = n => email => email.text.size >= n

查看error disappears

为什么这种方法有效,而不是我不确定的其他方式