使用 dlopen() 引用共享库插件的正确方法是什么?
What is the proper way to reference shared library plugins with dlopen()?
我有一个项目,在这个假设的例子中叫做Super,其中包含一组内置于/home/whatever/super/
中的.so
文件。在运行时,规范配置文件会告诉 Super 使用其.so
名称加载哪些插件。这是在 Ubuntu 16.04 上。
示例插件:
/home/whatever/super/magic.so
/home/whatever/super/wow.so
/home/whatever/super/awesome.so
我设置了LD_LIBRARY_PATH
:
export LD_LIBRARY_PATH=/home/whatever/super
在 Super 中,我使用dlopen()
加载模块:
std::string filename = "magic.so"
dlopen(filename.c_str(), RTLD_LAZY)
在这一点上,一切正常。现在我正在尝试打包我的项目,这意味着将内容移动到正确的系统目录。我现在已切换到使用/usr/lib/x86_64-linux-gnu/super/
作为插件的基本路径,如下所示:
/usr/lib/x86_64-linux-gnu/super/magic.so
/usr/lib/x86_64-linux-gnu/super/wow.so
/usr/lib/x86_64-linux-gnu/super/awesome.so
我也清除了LD_LIBRARY_PATH
.我将dlopen()
代码更新为如下所示:
std::string filename = "super/magic.so"
dlopen(filename.c_str(), RTLD_LAZY)
不幸的是,系统无法加载我的模块。我收到此错误:
Cannot load library: super/magic.so: cannot open shared object file: No such file or directory
我确认/etc/ld.so.conf.d/x86_64-linux-gnu.conf
存在并包含:
# Multiarch support
/lib/x86_64-linux-gnu
/usr/lib/x86_64-linux-gnu
我做错了什么?我已经确认/usr/lib/x86_64-linux-gnu/super/magic.so
存在。为什么加载程序不在/usr/lib/x86_64-linux-gnu
的子目录中搜索.so
文件?我显然不想将.so
文件的完整路径硬编码到我的C++代码中。
最后,这是放置插件和加载方法的好方法吗?
恐怕 Glibc 不会处理dlopen
中的相对文件路径(可能还有其他函数)。在这里你可以看到任何斜杠都会导致它把文件名视为绝对的,这不会在标准路径中搜索它)。
我认为最好的解决方案是将绝对插件路径传递给dlopen
。可能还会要求 Glibc 维护者对此类错误进行更好的诊断。
看起来常见的方法是对插件目录(或插件.so
文件本身)的完整路径进行编码,然后在编译时或运行时存储该路径,而不是依靠 LD 组件来查找子目录。
编译时
您可以使用 CMake 进程来确定插件模块的安装目录,并在编译之前将该目录写入文件,如 Remmina 中所示:
config.h.in
内的行:
#define REMMINA_PLUGINDIR "${REMMINA_PLUGINDIR}"
CMakeLists.txt
内的行数:
if(NOT REMMINA_PLUGINDIR)
set(REMMINA_PLUGINDIR "${CMAKE_INSTALL_FULL_LIBDIR}/remmina/plugins")
endif()
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_SOURCE_DIR}/config.h)
运行
对于运行时解决方案,CMake 可以将安装路径写入与软件一起安装的配置文件中。例如:
super.conf.in
内的行:
PLUGIN_PATH "@SUPER_PLUGINDIR@"
CMakeLists.txt
内的行数:
if(NOT SUPER_PLUGINDIR)
set(SUPER_PLUGINDIR "${CMAKE_INSTALL_FULL_LIBDIR}/super")
endif()
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/super.conf.in
${CMAKE_CURRENT_BINARY_DIR}/super.conf
@ONLY)
install(
FILES ${CMAKE_CURRENT_BINARY_DIR}/super.conf
DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
在我的 Ubuntu 16.04 系统上,CMAKE_INSTALL_LIBDIR
是lib/x86_64-linux-gnu
的别名,CMAKE_INSTALL_FULL_LIBDIR
是创建安装在系统根目录的软件包时/usr/lib/x86_64-linux-gnu
的别名。
无论哪种方式,您都可以使用不需要 LD 搜索的dlopen
构建完整路径。只需将配置的字符串连接到插件文件名即可。两种CMake变量替换方法并不重要。我只是投入了${}
并@@
完整的替代方案。
- 为不同配置设置MSVC_RUNTIME_LIBRARY的正确方法是什么
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 实现无开销push_back的最佳方法是什么
- C++从另一个类访问公共静态向量的正确方法是什么
- 在 c++ 中拥有一组结构的正确方法是什么?
- 通过JNI传递数据数组的最快方法是什么
- 用常见虚拟函数实现的任意组合来实现派生类的正确方法是什么
- 使用不同的CRT将新的C++代码与旧的(二进制)组件隔离开来的最佳方法是什么
- 当无法使用模板和宏时,生成类型变体C++代码的最简单方法是什么?
- 在另一个类视图中添加最多2个图表的正确方法是什么
- 在C++中样板"冷/never_inline"错误处理技术的最佳方法是什么?
- 在 c++ 中对类中的 c 字符串动态数组进行排序的最佳方法是什么?
- 在C++中包含原型文件的正确方法是什么?
- 在 OpenCV C++ 中估计基本矩阵之前对相应点进行归一化的正确方法是什么?
- 在PostgreSQL中根据它们的ID选择大量行的最快方法是什么?
- 在OSX上使用CMake将Adobe的XMP工具包构建为共享库的最简单方法是什么?
- 将一系列整数放入类的最佳方法是什么?
- 从长整整转换为uint64_t的推荐方法是什么?
- 将此布尔值传递给此函数的最有效方法是什么?
- 通过比较C++中的行在 txt 文件中搜索的最简单方法是什么?