简体   繁体   English

无法从共享库中删除共享库,只能从可执行文件中删除共享库

[英]Cannot dlopen a shared library from a shared library, only from executables

I have a C++ CMake project that has multiple sub-projects that I package into shared libraries. 我有一个C ++ CMake项目,它有多个子项目,我打包到共享库中。 Then, the project itself, which is an executable, links with all these shared libraries. 然后,项目本身(可执行文件)与所有这些共享库链接。 This is a project that is being ported from Windows to Ubuntu. 这是一个从Windows移植到Ubuntu的项目。 What I do is have the exectable, EXE, use a one subproject, Core, to open all other libraries. 我所做的是使用exectable,EXE,使用一个子项目Core来打开所有其他库。 Problem is that this isn't working on Linux. 问题是这不适用于Linux。

This is EXE: 这是EXE:

int main(int argc, char *argv[])
{
    core::plugin::PluginManager& wPluginManager = core::plugin::PluginManagerSingleton::Instance();
    wPluginManager.loadPlugin("libcore.so");
    wPluginManager.loadPlugin("libcontroller.so")
    wPluginManager.loadPlugin("libos.so")
    wPluginManager.loadPlugin("libnetwork.so")
    wPluginManager.loadPlugin("liblogger.so")
}

This is core::plugin::PluginManager::loadPlugin() : 这是core::plugin::PluginManager::loadPlugin()

bool PluginManager::loadPlugin(const boost::filesystem::path &iPlugin) {
    void* plugin_file = dlopen(plugin_file_name, RTLD_LAZY);
    std::cout << (plugin_file ? " success" : "failed") << std::endl;
    return true;
}

What happens is that libcore gets loaded properly, but then all other libraries fail with no no error message. 会发生什么是libcore正确加载,但所有其他库失败,没有错误消息。 I cannot find out why it's not working. 我无法找出它为什么不起作用。 However, when I do the same thing, but instead of having Core load the libraries, I simply do it in main and it works. 但是,当我做同样的事情,但不是让Core加载库,我只是在main中做它并且它工作。

Basically, I can load libraries from an exe , but I can't from other shared libraries. 基本上,我可以从exe加载库,但我不能从其他共享库加载。 What gives and how can I fix this? 给出了什么以及如何解决这个问题?

The most likely reason for dlopen from the main executable to succeed and for the exact same dlopen from libcore.so to fail is that the main executable has correct RUNPATH to find all the libraries, but libcore.so does not. 对于最可能的原因dlopen从主可执行成功和完全一样dlopenlibcore.so失败是主要的可执行文件具有正确RUNPATH找到所有的库,但libcore.so没有。

You can verify this with: 您可以通过以下方式验证:

readelf -d main-exe | grep R.*PATH
readelf -d libcore.so | grep R.PATH

If (as I suspect) main-exe has RUNPATH , and libcore.so doesn't, the right fix is to add -rpath=.... to the link line for libcore.so . 如果(我怀疑)main-exe有RUNPATH ,而libcore.so没有,正确的解决方法是将-rpath=....添加到libcore.so的链接行。

You can also gain a lot of insight into dynamic loader operation by using LD_DEBUG envrironment variable: 您还可以通过使用LD_DEBUG环境变量获得对动态加载程序操作的大量了解:

LD_DEBUG=libs ./main-exe

will tell you which directories the loader is searching for which libraries, and why. 将告诉您加载器正在搜索哪些目录库以及原因。

I cannot find out why it's not working 我无法找出它为什么不起作用

Yes, you can. 是的你可以。 You haven't spent nearly enough effort trying. 你没有花费足够的努力尝试。

Your very first step should be to print the value of dlerror() when dlopen fails. 你的第一步应该是在dlopen失败时打印dlerror()的值。 The next step is to use LD_DEBUG . 下一步是使用LD_DEBUG And if all that fails, you can actually debug the runtime loader itself -- it's open-source. 如果一切都失败了,你可以实际调试运行时加载器本身 - 它是开源的。

I managed to find a fix for this issue. 我设法找到了解决这个问题的方法。 I don't quite understand the inner workings nor the explanation of my solution, but it works. 我不太了解我的解决方案的内部工作原理和解释,但它确实有效。 If someone who has a better understanding than my very limited experience with shared libraries could comment on my answer with the real explanation, I'm sure it could help future viewers of this question. 如果有人比我对共享库的非常有限的经验有更好的理解,可以用真实的解释来评论我的答案,我相信它可以帮助未来的观众解决这个问题。

What I was currently doing is dlopen("libcore.so") . 我目前正在做的是dlopen("libcore.so") I simply changed it to an absolute path dlopen("/home/user/project/libcore.so") and it now works. 我只是将它改为绝对路径dlopen("/home/user/project/libcore.so") ,它现在可以工作了。 I have not yet tried with relative paths, but it appears we should always use relative or absolute paths instead of just the filename with dlopen . 我还没有试过相对路径,但看起来我们应该总是使用相对路径或绝对路径,而不仅仅是使用dlopen的文件名。

If absolute path was help, maybe problem is local dependencies of shared libraries. 如果绝对路径是帮助,可能问题是共享库的本地依赖性。 Another words, maybe libcontroller.so is depend from libos.so or other your library, but cannot find it. 换句话说,libcontroller.so可能依赖于libos.so或其他你的库,但找不到它。 Linux loader means that all shared libraries are placed in /lib, /usr/lib, etc. You need to specify path for find dynamic libraries with environment variable LD_LIBRARY_PATH. Linux加载器意味着所有共享库都放在/ lib,/ usr / lib等中。您需要为环境变量LD_LIBRARY_PATH指定查找动态库的路径。

Try to run your app this way: LD_LIBRARY_PATH=/path/to/your/executable/and/modules ./yourapp 尝试以这种方式运行您的应用程序:LD_LIBRARY_PATH = / path / to / your / executable /和/ modules ./yourapp

 bool PluginManager::loadPlugin(const boost::filesystem::path &iPlugin) { void* plugin_file = dlopen(plugin_file_name, RTLD_LAZY); std::cout << (plugin_file ? " success" : "failed") << std::endl; return true; } 

The flags to use with dlopen depend upon the distro. dlopen一起使用的标志取决于发行版。 I think Debian and derivatives use RTLD_GLOBAL | RTLD_LAZY 我认为Debian和衍生品使用RTLD_GLOBAL | RTLD_LAZY RTLD_GLOBAL | RTLD_LAZY , while Red Hat and derivatives use RTLD_GLOBAL . RTLD_GLOBAL | RTLD_LAZY ,而Red Hat和衍生产品使用RTLD_GLOBAL Or maybe it is vice-versa. 或者反之亦然。 And I seem to recall Android uses RTLD_LOCAL , too. 我似乎还记得Android也使用RTLD_LOCAL

You should just try both to simplify loading on different platforms: 您应该尝试两者来简化在不同平台上的加载:

bool PluginManager::loadPlugin(const boost::filesystem::path &iPlugin) {
    void* plugin_file = dlopen(plugin_file_name, RTLD_GLOBAL);
    if (!plugin_file) {
        plugin_file = dlopen(plugin_file_name, RTLD_GLOBAL | RTLD_LAZY);
    }
    const bool success = plugin_file != NULL;
    std::cout << (success ? "success" : "failed") << std::endl;
    return success ;
}

What happens is that libcore gets loaded properly, but then all other libraries fail with no no error message 会发生什么是libcore正确加载,但所有其他库失败,没有错误消息

This sounds a bit unusual. 这听起来有点不寻常。 It sounds like the additional libraries from the sub-projects are not in the linker path. 听起来子项目中的附加库不在链接器路径中。

You should ensure the additional libraries are in the linker path. 您应确保其他库位于链接器路径中。 Put them next to libcore.so in the filesystem since loading libcore.so seems to work as expected. 将它们放在文件系统中的libcore.so旁边,因为加载libcore.so似乎按预期工作。

If they are already next to libcore.so , then you need to provide more information, like the failure from loadPlugin , the RUNPATH used (if present) and the output of ldd . 如果它们已经在libcore.so旁边,那么您需要提供更多信息,例如loadPlugin的失败,使用的RUNPATH (如果存在)和ldd的输出。


but then all other libraries fail with no no error message. 但然后所有其他库失败,没有没有错误消息。 I cannot find out why it's not working. 我无法找出它为什么不起作用。

As @Paul stated in the comments, the way to check for a dlopen error is with dlerror . 正如@Paul在评论中所说,检查dlopen错误的方法是使用dlerror It is kind of a crappy way to do it since you can only get a text string and not an error code. 这是一种糟糕的方式,因为你只能获得文本字符串而不是错误代码。

The dlopen man page is at http://man7.org/linux/man-pages/man3/dlopen.3.html , and it says: dlopen手册页位于http://man7.org/linux/man-pages/man3/dlopen.3.html ,它说:

RETURN VALUE 返回值

On success, dlopen() and dlmopen() return a non-NULL handle for the loaded library. 成功时,dlopen()和dlmopen()为加载的库返回一个非NULL句柄。 On error (file could not be found, was not readable, had the wrong format, or caused errors during loading), these functions return NULL. 出错(无法找到文件,无法读取,格式错误或在加载过程中导致错误)时,这些函数将返回NULL。

On success, dlclose() returns 0; 成功时,dlclose()返回0; on error, it returns a nonzero value. 出错时,它返回非零值。

Errors from these functions can be diagnosed using dlerror(3). 可以使用dlerror(3)诊断这些函数的错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 C-共享库-dlopen,dlsym - C - Shared Library - dlopen, dlsym 将共享库与main()链接到仅提供处理程序功能的可执行文件 - Link shared library with main() to executables providing a handler function only 将链接共享库的符号提供给使用 dlopen 打开的共享库 - Providing symbol of linked shared library to shared library opened with dlopen 我可以使用dlopen从C ++使用C编译的共享库吗 - Can I use a shared library compiled by C from C++ using dlopen dynamic_cast从lt_dlopen(libtool)加载的共享库中的接口不起作用 - dynamic_cast an interface from a shared library which was loaded by lt_dlopen(libtool) doesn't work dlopen 成功(或至少似乎成功),但随后 dlsym 无法从共享库中检索符号 - dlopen succeeds (or at least seems to) but then dlsym fails to retrieve a symbol from a shared library 从共享库的导出 function 获取实例时 dlopen 分段错误错误 - dlopen Segmentation fault error when get a instance from shared library's exported function 使用dlopen动态加载共享库 - Loading shared library dynamically using dlopen CMake 没有创建可以访问我的共享库的可执行文件 - CMake is not creating executables with access to my shared library gcc链接共享库有效,但是同一共享库的dlopen失败 - gcc linking shared library works, but dlopen of the same shared lib fails
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM