Cython: не удается вызвать нестатические методы общей библиотеки


Моя задача довольно проста, у меня есть общая библиотека, скомпилированная с CMake, и я хочу написать оболочку python для одного класса cpp, который он содержит, и отдельную функцию.

Предположим, что класс является этим с автономной функцией

// cppClass.cpp
void standalone() 
{ 
    printf("I am not alone\n"); 
}
int cppClass::not_static_method(int value)
{
    printf("I am not static\n");
    return value;
}
cppClass* cppClass::static_method()
{
    cppClass* c = new cppClass();
    if (!c) { return NULL; }
    return c;
}

// cppClass.h
#ifndef __CPPCLASS_H__
#define __CPPCLASS_H__
void standalone();
class cppClass
{
public:
    int not_static_method(int value);
    static cppClass* static_method();
};
#endif

Поэтому я объявляю его в моем файле .pxd и пишу небольшой класс-обертку в моем файле .pyx:

# .pxd
cdef extern:
    cdef cppclass cppClass:
        int not_static_method(int value)
        @staticmethod
        cppClass* static_method()
    cdef void standalone()
# .pyx
cdef class PyClass:
    cdef cppClass* c_clazz
    def __cinit__(self):
        self.c_clazz = cppClass.static_method()
    def NotStatic(self, value):
        standalone()
        return self.c_clazz.not_static_method(value)

Проблема в том, что после компиляции я могу инициализировать объект PyClass, но вызов метода NotStatic последнего объекта вызывает undefined symbol: standalone и когда я комментирую вызов этой функции, он вызывает segmentation fault, который, как я думаю, вызван инициализацией указателя c_clazz внутри объекта PyClass.

Я понял, что не могу указать, где находятся определения, поскольку это библиотека extern, и я уже указал ее имя в файле setup.py, а также ее путь как extra_link_args.

Что я делаю (возможно, крайне) неправильно?

Edit: общая библиотека компилируется с помощью g++ -shared -fPIC -c cppClass.cpp -o libcppClass.so

Правка 2: добавлено .h файл

Edit 3: я не упомянул, почему я хочу использовать общую библиотеку, потому что нестатический метод использует некоторое определение в файлах CUDA, скомпилированных в общую библиотеку.

Правка 4: Мой установочный файл

# setup.py
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext

setup(
    cmdclass = {"build_ext": build_ext},
    ext_modules = [
            Extension("cy_wrapper",
                      sources=["cy_wrapper.pyx"],
                      libraries=["mycustomlib"],
                      language="c++",
                      extra_compile_args=["-O3", "-Wall", "-std=c++11"],
                      extra_link_args=["-L/absolute/path/to/libmycustomlib.so/directory/"]
                      )
                  ]
)
1   3  

1 ответ:

Проверка кода, сгенерированного Cython (cy_wrapper.cpp), показывает, что функция standalone объявляется как

__PYX_EXTERN_C DL_IMPORT(void) standalone(void);

То есть

extern "C" void standalone(void);

, который не определен в cppClass.h (проблема искажения имени C++).

Также cppClass несколько отличается в сгенерированном файле

struct cppClass;
struct cppClass {
    virtual int not_static_method(int);
    static cppClass *static_method(void);
    virtual ~cppClass() { }
};

То есть не так, как определено в cppClass.h. Определения должны соответствовать или могут быть проблемы, такие как ошибки сегментации.

Я бы рекомендовал включить файл заголовка в .pxd файл, т. е.

cdef extern from "cppClass.h"