RTLD_LOCAL and dynamic_cast on Linux
RTLD_LOCAL and dynamic_cast on Linux
我们有一个插件,它由应用程序中的几个共享库构成,我们需要在应用程序运行时更新这些库。出于性能原因,我们在卸载旧插件之前加载并开始使用新插件,并且只有当所有线程都使用旧插件完成时,我们才会卸载它。由于新插件和旧插件的库具有相同的符号,因此我们使用RTLD_LOCAL
dlopen()
。如果我们不意外地从内部函数调用新插件到旧插件中的符号。
插件的一个库dynamic_cast()
插件的另一个库创建的对象。这适用于HP-UX,AIX,Solaris和Windows,但不适用于Linux。据我所知,这是因为所有这些操作系统(编译器)都使用类的名称来比较类型(在dynamic_cast()
中),但 Linux 使用名称字符串地址来进行比较(以提高性能),并且由于每个库都有自己的 type_info
对象(因为它加载了 RTLD_LOCAL
),地址是不同的,因此相等的类型似乎不等于dynamic_cast()
。
有没有办法执行以下操作之一:
- 仅加载
type_info
对象,就像提供了RTLD_GLOBAL
一样。 - 使编译器使用类名比较而不是
type_info
地址来比较类型。
?我们使用的编译器是:
$ icpc -V
Intel(R) C++ Intel(R) 64 Compiler XE for applications running on Intel(R) 64, Version 12.0.0.084 Build 20101006
Copyright (C) 1985-2010 Intel Corporation. All rights reserved.
好的,我们最终做的是解决这个问题。
我们在类中添加了要dynamic_cast()
两个静态函数:
static MyClass* doNew();
static MyClass* doDynCast(MyBase*);
这些是在cpp文件中实现的,该文件将new
,dynamic_cast()
和type_info
对象保存在同一个库中,从而使dynamic_cast()
变通解决此问题。
对于我们的具体情况,这个解决方案已经足够了,但如果有人有更通用的解决方案,它将受到欢迎。
我们发现的另一个选择是将类的所有实现放在 cpp 文件中,这使得typeinfo
符号仅存在于一个库中,而所有其他库仅引用它。这会导致成功的dynamic_cast()
。
不幸的是,由于type_info结构是创建它们的库的本地弱符号,因此很难使dynamic_cast
工作。但是,您可以尝试操作类 vtable(和 type_info)实例化的位置;在 GCC 上,这可以通过确保类中的第一个非内联函数(按定义顺序)仅在公共共享依赖项库中定义来完成。如果您的类没有非内联函数,请创建一个虚拟函数来强制生成此类。但是请注意,我还没有对此进行测试,因此不能保证它会起作用。此外,这依赖于编译器;我不知道英特尔的编译器是做什么的。
当然,你可以使用类名来实现你自己的替代动态转换机制;有许多库也这样做,比如Qt的qobject_cast。
- VS2019 - Sudo Remote Debugging on Linux with Cmake project
- SFML 交叉编译 for Windows on Linux.
- OpenAL C++ on Linux
- Valgrind on codeblocks (linux)
- CMake FindJNI issue on linux
- pthread_self on Linux
- std::vector sort() on Linux?
- Building OpenCV 2.4.11 on Linux with `libopencv_ffmpeg.so`
- 在Linux上使用QT,有没有办法禁用"Always on Top"?
- 在 Windows for Linux on Intel 上编译C++库
- 计算"copying a binary file in c++ on linux"消耗时间的最佳方法是什么?
- C++ [[gnu::visibility( "default" )]] vs __declspec(dllexport) on Windows 和 Linux
- XRE_InitEmbedding2 SIGSEGV on Linux with XULRunner 15
- boost::mutex::timed_lock not on Linux
- Netbeans C/C++ on Linux "step in to" Linux C 运行时代码?
- gdb fork() exec on Linux
- flock-ing a C++ ifstream on Linux (GCC 4.6)
- C++ GetModuleBase on linux
- _vscwprintf on Mac OS X/Linux
- RTLD_LOCAL and dynamic_cast on Linux