我在这个假设的例子中有一个名为Super的项目,其中包含一组内置于.so
的{{1}}个文件。在运行时,规范配置文件告诉Super使用其/home/whatever/super/
名称加载哪些插件。这是在Ubuntu 16.04上。
示例插件:
.so
/home/whatever/super/magic.so
/home/whatever/super/wow.so
我已设置/home/whatever/super/awesome.so
:
LD_LIBRARY_PATH
在Super中,我使用export LD_LIBRARY_PATH=/home/whatever/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
的子目录中搜索.so
文件?我显然不想将/usr/lib/x86_64-linux-gnu
文件的完整路径硬编码到我的C ++代码中。
最后,这是一个很好的方法,可以放置插件和加载方法吗?
答案 0 :(得分:2)
我担心Glibc不会处理dlopen
中的相对文件路径(以及其他功能)。 Here你可以看到任何斜杠导致它将文件名视为绝对值,而不是在标准路径中搜索它。)
我认为最好的解决方案是将绝对插件路径传递给dlopen
。可能还要求Glibc维护人员更好地诊断此类错误。
答案 1 :(得分:1)
看起来常见的方法是对插件目录(或插件.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
的别名。< / p>
无论哪种方式,您都可以使用dlopen
构建一个不需要LD搜索的完整路径。只需将配置的字符串连接到插件文件名即可。两种CMake变量替换方法并不重要。为了完整起见,我只是投入了${}
和@@
替代方案。