在运行时加载Linux库

时间:2013-04-11 14:39:40

标签: linux ld elf dlopen shared-libraries

我认为Linux中的一个主要设计缺陷是以二进制而不是源代码形式分发程序时的共享对象。

这是我的具体问题:我希望以ELF二进制形式发布一个Linux程序,该程序应该在尽可能多的发行版上运行,因此我的强制依赖项尽可能低:在任何情况下所需的唯一库是libpthread, libX11,librt和libm(当然还有glibc)。当我使用gcc构建我的程序时,我正在动态地链接这些库。

但是,我的程序还应该支持ALSA(声音接口),Xcursor,Xfixes和Xxf86vm扩展以及GTK。但是这些只应在用户系统上可用的情况下使用,否则我的程序仍应运行但功能有限。例如,如果没有GTK,我的程序将回退到终端模式。因为我的程序仍然可以在没有ALSA,Xcursor,Xfixes等的情况下运行。我无法动态链接这些库,因为如果其中一个库不存在,程序将根本无法启动。

所以我需要手动检查库是否存在,然后使用dlopen()逐个打开它们,并使用dlsym()导入必要的函数符号。然而,这会导致各种各样的问题:

1)库命名约定: 共享对象通常不是简单地称为“libXcursor.so”,而是具有某种版本扩展名,如“libXcursor.so.1”,甚至是非常有趣的东西,如“libXcursor.so.0.2000”。这些扩展似乎因系统而异。那么在调用dlopen()时我应该选择哪一个?在这里使用硬编码名称似乎是一个非常糟糕的主意,因为名称因系统而异。因此,我想到的唯一解决方法是扫描整个库路径并查找以“libXcursor.so”前缀开头的文件名,然后进行一些自定义版本匹配。但我怎么知道他们真的兼容?

2)图书馆搜索路径:我应该在哪里寻找* .so文件?这在系统与系统之间也是不同的。有一些默认路径,如/ usr / lib和/ lib,但* .so文件也可以在许多其他路径中。所以我必须打开/etc/ld.so.conf并解析它以找出所有库搜索路径。这不是一件容易的事,因为/etc/ld.so.conf文件也可以使用某种 include 指令,这意味着我必须解析更多.conf文件,对可能做一些检查由循环包含指令等引起的无限循环。是否真的没有更简单的方法来找出* .so的搜索路径?

所以,我的实际问题是:是不是有更方便,更少的hackish方式来实现我想做的事情?创建一个具有ALSA,GTK,libXcursor等可选依赖项的Linux程序真的很复杂......但是没有它也应该工作!做我想做的事情有某种标准吗?或者我注定要以hackish的方式去做?

感谢您的意见/解决方案!

1 个答案:

答案 0 :(得分:2)

  

我认为Linux中的一个主要设计缺陷是以二进制而不是源代码形式分发程序时的共享对象。

就系统的创造者而言,这不是一个设计缺陷;它是一个优势 - 它鼓励您以源代码形式分发程序。哦,你想出售你的软件?对不起,这不是Linux针对的优化用例。

  

库命名约定:共享对象通常不被简单地称为" libXcursor.so"但有一些版本扩展,如" libXcursor.so.1"甚至是非常有趣的事情,比如" libXcursor.so.0.2000"。

是的,这称为外部库版本控制。阅读它here。从该描述中可以清楚地看出,如果您使用通常会将libXcursor.so.1作为运行时引用的系统上的标头编译二进制文件,则与您兼容的 only 共享库是libXcursor.so.1,并尝试dlopen libXcursor.so.0.2000会导致无法预料的崩溃。

提供libXcursor.so但不是libXcursor.so.1的任何系统都是安装损坏,或者与您的二进制文件不兼容。

  

图书馆搜索路径:我应该在哪里查找* .so文件?

不应该尝试使用完整路径来删除任何这些库。只需调用dlopen("libXcursor.so.1", RTLD_GLOBAL);,运行时加载程序将在系统相应的位置搜索库。