使用dlopen()动态加载共享对象

6

我正在开发一个普通的X11应用程序。

默认情况下,我的应用程序只需要libX11.so和标准的gcc C和数学库。该应用程序可以通过Xfixes、Xrender和ALSA音频系统来扩展功能。然而,这些(Xfixes、Xrender和ALSA)功能是可选的。

为了实现这种行为,我使用了运行时加载,即将libXfixes、libXrender和libasound dlopen()化。

因此,在这些库缺失的情况下,该应用程序仍能正常工作。

现在我的问题是:在调用dlopen()时应使用哪个库名称?

我观察到这些名称在不同的发行版之间有所不同。
例如,在openSUSE 11上,它们被命名为以下名称:

  • libXfixes.so
  • libXrender.so
  • libasound.so

然而,在Ubuntu上,名称附带有版本号,就像这样:

  • libXfixes.so.3
  • libXrender.so.1
  • libasound.so.2
所以,尝试在Ubuntu上打开“libXfixes.so”会失败,尽管该库显然存在,但它只附有版本号。那么我的应用程序应该如何处理?
我应该让我的应用程序手动扫描/usr/lib/,看看我们有哪些库,然后选择一个合适的库吗?还是谁有更好的建议?

还可以在这里查看回复: https://dev59.com/8XDYa4cB1Zd3GeqPEtEF - AjayKumarBasuthkar
2个回答

2

你应该使用库的SONAME进行dlopen。你可以通过使用readelf -d [libname]来查看。

例如,在我的一台Fedora Linux机器上,C库的SONAME是libc.so.6。

.so名称到.so.6名称的符号链接不能保证存在。这些符号链接仅用于编译软件,并且通常不会安装在没有开发包的系统上。

无论如何,您都不希望最终加载具有不同编号的版本,因为编号更改表示主要API差异。


大多数库都是向后兼容的,这意味着具有更高 soname 的库应该可以工作。假设您编写了一个程序,它 dlopen libc.so.6。然后 libc 开发人员进行了重大更新并发布了 libc.so.7。现在,您的程序将不必要地中断,因为 soname 不匹配。 - Björn Lindqvist
1
@BjörnLindqvist:不,大多数库都不向后兼容。你从哪里得到这个想法的?如果它们是兼容的,那么它们就不会改变主版本号。GNU libc现在已经使用6版本很长时间了。 - Zan Lynx
你可以包含 <gnu/lib-names.h> 并使用提供的宏来加载各种 glibc 共享库。其他软件包可能会执行类似的操作,以提供要加载的库名称。请参阅 "man dlopen" 以获取示例。 - Carlos O'Donell

-1
从我所了解的情况来看,你只需要像这样使用dlopen()函数打开"libXfixes.so",它很可能是一个指向最新文件"libXfixes.so.3"的符号链接。
$ file /usr/lib/libalpm.so
/usr/lib/libalpm.so: symbolic link to `libalpm.so.4.0.3'

快速查看我的"/usr/lib/",几乎每个库文件都是通过符号链接指向它最新的".X"版本文件,我相信其他发行版也是这么做的。
只有当你需要特定版本的库时,你才会显式地命名版本,例如"libXfixes.so.2"。

还可以在这里查看回复: https://dev59.com/8XDYa4cB1Zd3GeqPEtEF - AjayKumarBasuthkar
1
你不应该dlopen裸so名称,这仅由开发包提供,在生产部署系统上不会存在。 - Carlos O'Donell

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