Cython: неопределенный символ в общем объекте - PullRequest
0 голосов
/ 17 мая 2018

Я импортирую код c ++ в проект Python, все, кажется, компилируется очень хорошо, однако при импорте моего .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

Я не понимаю, что я здесь пропустил, я не думаю, что предупреждение - это проблема чтения этого вопроса

Ответы [ 2 ]

0 голосов
/ 17 мая 2018

Что, наконец, помогло мне, изменило

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

на:

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

с просмотра этой страницы в документации по Cython

Почему это работает, а не иначе, я не уверен, однако

0 голосов
/ 17 мая 2018

Ваша проблема - искажение имени.Однако есть две причины, по которым он не работает.

Первый

Язык C без именования используется по умолчанию для AGCython.pyx, то есть он ожидаетсимвол с именем 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(...)
...