【问题标题】:Cython: unable to call non static methods of shared libraryCython:无法调用共享库的非静态方法
【发布时间】:2018-03-21 08:18:16
【问题描述】:

我的问题很简单,我有一个用 CMake 编译的共享库,我想为它包含的一个 cpp 类和一个独立函数编写一个 python 包装器。

假设这个类是带有独立功能的

// 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我认为是由于 PyClass 对象内的指针 c_clazz 的初始化。

我知道我无法指定定义的位置,因为它是一个外部库,并且我已经在 setup.py 文件中指定了它的名称以及它的路径 extra_link_args

我在做什么(可能非常)错?

编辑:共享库是用g++ -shared -fPIC -c cppClass.cpp -o libcppClass.so编译的

编辑2:添加.h文件

编辑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/"]
                      )
                  ]
)

【问题讨论】:

  • 你是不是忘了给static_method加上int参数?
  • 只是忘记从我复制的 cpp 文件中删除它抱歉,如果我弄乱了参数,它将无法编译。
  • 我认为您需要在外部块中使用标题cppClass.h? (可能还将其路径添加到include_dirs
  • 您的设置看起来不错。你需要分析哪里出了问题。首先验证您的构建是否确实有效:将“-Wl,--no-undefined”添加到链接参数:现在链接器并不关心是否找到了所有符号,因此您只会在运行时看到缺失值。您还可以添加“-Wl,--verbose”以查看链接期间使用了哪些库。调用readelf -d cy_wrapper.so| grep NEEDED 看看mycustomlib 是否真的被标记为需要。使用LD_DEBUG=libs,files,symbols python -c "import cy_wrapper" 查看运行时出现的问题。
  • @ead 你说得对,mycustomlib 没有标记为需要,添加 -Wl,--no-undefined arg 显示了很多未定义的 PySomeFunc 和我的 standalone func 和我的 static 的引用方法。我不知道静态的,我可以在 python 中调用它并查看 c++ 输出。 @chrisb 我想避免使用它,因为我正在使用一个我不应该拥有源代码的共享库。

标签: python c++ python-3.x cython wrapper


【解决方案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"

【讨论】:

  • 我想避免这种解决方案,但我想这是我唯一的希望。感谢您的宝贵时间!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-20
  • 1970-01-01
  • 2023-03-27
  • 2013-03-20
  • 1970-01-01
相关资源
最近更新 更多