我试图从python调用C ++ API。以下是伪形式的代码。
class Engine { // Singleton Class which does a heavy duty work
public:
static Engine* getEngine();
bool init();
private:
static Engine* m_instance;
Engine();
};
// Following the code to wrap the call to engine to call from python
// Its only a simplified form
//engine_module.c
#include <Engine.h>
PyObject* initengine() {
Engine* e = Engine::getInstance();
e->init();
// return the Py_BuildValue ...
}
PyObject* initengine_module() {
//... init the module
}
// Python code
import engine_module
status = engine_module.init()
问题: Engine类在libengine.so中,并且当它内部失败时,因为内部dynamic_cast失败。 Engine依次使用dlopen()加载其他库。我搜索网络时添加了RTDL_GLOBAL和-E选项,但链接仍未解决。我应该在编译python时添加-E选项吗? 当在C ++代码中使用Engine类时,它可以正常工作,并且在python中使用时不起作用的原因是什么?
编辑1: 澄清Cat ++的问题: libengine.so还有许多其他类,它们在Engine :: init()内部使用dynamic_cast&lt;&gt;。 dynamic_cast中涉及的类根本不会暴露给python。只暴露了Engine :: init()。
编辑2: 该平台是Red Hat Linux,编译器是Intel
答案 0 :(得分:1)
问题是如何以及何时加载动态库。代码
你在engine_module.c中显示引用Engine
,所以库有
在任何初始化之前,{em}将自动加载Engine
执行engine_module.c
中的代码。同样,使用的任何库
在加载Engine
的库之前,将加载Engine
。所有
其中将使用Python用于加载它的标志加载
接口模块。 (RTDL_LOCAL
是我的猜测。)你调用的任何dlopen
稍后会发现该模块已经被加载,并忽略了
请求 - 包括忽略您可能拥有的任何dlopen
选项
过去了。
我们解决这个问题的方法是创建一个特殊的加载器模块
包含 no 对任何其他模块的直接引用。蟒蛇
加载此模块,该模块实现initxxx
功能。该
initxxx
函数显式加载所需的所有其他模块
依赖确定的顺序。 (如果A使用B,B将在A之前加载。)
当然是RTDL_GLOBAL
。在你的情况下,这将是
Engine
使用的库,然后是Engine
。要加载的最后一个模块
将是具有Python接口的那个;我们把Python
初始化代码在静态对象的构造函数中,所以它会
在加载对象时自动执行,但您也可以
把它放在一个命名函数中,只要你得到它的地址
函数使用dlsym
,而不是在其中声明extern
时尚。重要的是确保所有库首先由显式dlopen
加载,而不是由于先前加载的某个库中未定义的外部而隐式地加载。
答案 1 :(得分:0)
我最好的猜测是,您正在尝试将dynamic_cast
应用于某些非多态类,而这是失败的地方。请记住,dynamic_cast
仅适用于具有至少一个虚方法(析构函数计数)的类。