如何使用dlopen动态加载库文件

3
在我正在工作的项目中,我们提供了动态加载其他功能的可能性。为此,我们使用dlopen。
为了找到这些库,我们有一个称为模块路径的东西。我们有一个默认路径,在其中共享库(很多共享库都被装载)。
目前我们有两个默认路径:首先在构建目录中查找共享库,然后在安装目录中查找。这是因为也应该可以在不安装的情况下运行应用程序(因此在这种情况下需要首先查找构建目录)。
现在问题是,如果用户从源代码构建应用程序并使用make install进行安装,则默认情况下会加载她的构建目录中的库。这将导致崩溃。所以它只有在用户之后删除或重命名构建目录时才能正常工作。
现在的问题是:是否有诀窍(无论是通过C ++还是通过构建系统)来知道应用程序是否已安装。问题是功能是在共享库中实现的,并且寻找模块的实现方式也必须适用于链接到我们的库的其他应用程序(因此我们不能依赖可执行文件的路径)。我们使用CMake作为构建系统。
为使情况更加困难,解决方案必须在Windows、Linux和Mac OS X上工作。
编辑:
我进一步调查了一下,发现问题更为复杂。以下是情况:
有一个小的可执行文件a
此外还有一个“主”库main.so
然后有一个动态加载的库lib.so lib.so链接到main.so
问题是,lib.so在其rpath中具有对构建目录中main.so的绝对路径。感谢@MSalters的提示,我现在能够制作一个黑客程序来确保加载正确版本的lib.so(安装目录中的版本),但由于它在rpath中具有构建路径,它加载错误的main.so(因此实际上存在两个副本的main.so在内存中-这会搞乱事情)。
有没有办法从库中删除对构建路径的引用?我尝试了与rpath相关的所有cmake选项,但都没有成功。

难道修复崩溃不是更容易的选择吗? - MSalters
问题在于,加载的库也链接到主库。由于构建目录中的库具有指向构建目录中的库的完整路径,而安装的库具有相对路径,因此两者都会被加载。然后就会出现冲突(或更具体地说:单例未在库的第二个副本中初始化)。 - Markus Pilman
那个(加载第二个库)听起来像是你可以很容易地检测到的东西。这不就是你问题的答案吗? - MSalters
2个回答

1

你不能检查可执行文件本身的位置吗?如果它在构建目录中,请使用构建库 - 如果它在安装中,请使用安装库?

getcwd() 在所有这些平台上都有等效物,但可能不是你想要的 - 这取决于你如何运行可执行文件。

获取进程位置是系统特定的,我认为,但包装起来应该不太难。


我也考虑过这个问题。但问题在于,我们有一个库,如果另一个可执行文件链接到该库(例如我们用于测试的另一个可执行文件),它就无法正常工作了。 - Markus Pilman

0
已安装的版本不应该在rpath中有构建目录。
您可能希望链接两次(一次用于构建版本,一次用于安装版本)。通常,在*nix系统上,安装的二进制文件具有某些静态路径,它尝试查找插件。您可以定义一些环境变量(或命令行参数)以在构建执行中重载它(并使用包装器脚本在构建环境中设置它)。
检查一些项目如何解决此问题(例如Firefox)。
我对Windows系统不太了解,但我认为标准的做法是在可执行文件所在的同一目录中搜索插件。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接