从 Python 调用 API 时dynamic_cast失败C++

dynamic_cast failure while calling C++ API from Python

本文关键字:cast 失败 C++ dynamic Python 调用 API      更新时间:2023-10-16

我正在尝试从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() 

问题:引擎类处于 libengine.so 状态,当它启动时,它会失败,因为内部dynamic_cast失败。引擎依次使用 dlopen(( 加载其他库。我在链接时搜索了网络以添加 RTDL_GLOBAL 和 -E 选项,但仍未解决。我应该在编译 python 本身时添加 -E 选项吗?引擎类在C++代码中使用时运行良好,而在 python 中使用时不起作用的原因是什么?

编辑 1:澄清 Cat++ 中的问题:libengine.so 还有许多其他类,在 Engine::init(( 内部使用 dynamic_cast<>。dynamic_cast中涉及的类根本不会暴露给 python。只有 Engine::init(( 被公开。

编辑 2:平台是Red Hat Linux,编译器是Intel

问题是如何以及何时加载动态库。 代码你在 engine_module.c 中显示引用Engine,所以库与 Engine将在任何初始化之前自动加载执行 engine_module.c 中的代码。 同样,使用 Engine将在加载包含Engine的库之前加载。 都其中将使用 Python 用于加载其的标志加载接口模块。 (RTDL_LOCAL是我的猜测。 您调用的任何dlopen稍后会发现模块已经加载,并忽略请求 - 包括忽略您可能拥有的任何dlopen选项通过。

我们解决这个问题的方法是创建一个特殊的加载器模块,它不包含对任何其他模块的直接引用。 蟒加载此模块,该模块实现initxxx函数。 这 initxxx函数显式加载所需的所有其他模块,在依赖关系确定的顺序。(如果 A 使用 B,B 将在 A 之前加载。当然是有RTDL_GLOBAL。 在您的情况下,这将是Engine使用的库,然后Engine 。 最后一个要加载的模块将是带有 Python 接口的那个;我们把蟒蛇静态对象的构造函数中的初始化代码,因此它将在加载对象时自动执行,但您也可以把它放在一个命名函数中,只要你得到这个的地址函数使用 dlsym ,而不是在任何声明中extern时尚。 重要的是确保所有库首先由显式dlopen加载,而不是由于之前加载的某些库中未定义的外部而隐式加载。

我最好的猜测是你试图将dynamic_cast应用于一些非多态类,这就是它失败的地方。请记住,dynamic_cast仅适用于至少具有一个虚拟方法(析构函数计数(的类。