4

我认为 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 文件也可以使用某种包含指令,这意味着我必须解析更多的 .conf 文件,对由循环包含指令引起的可能的无限循环进行一些检查等等。真的没有更简单的方法来找出 *.so 的搜索路径吗?

所以,我的实际问题是:难道没有更方便、更简单的方式来实现我想做的事情吗?创建一个具有一些可选依赖项(如 ALSA、GTK、libXcursor)的 Linux 程序真的那么复杂吗……但没有它也应该可以工作!做我想做的事有某种标准吗?还是我注定要以骇人听闻的方式去做?

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

4

1 回答 1

2

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

就系统的创建者而言,这不是设计缺陷。这是一个优势——它鼓励您以源代码形式分发程序。哦,你想卖你的软件?抱歉,这不是 Linux 优化的用例。

库命名约定:共享对象通常不是简单地称为“libXcursor.so”,而是具有某种版本扩展名,如“libXcursor.so.1”,甚至是“libXcursor.so.0.2000”等非常有趣的东西。

是的,这称为外部库版本控制。在这里阅读。从该描述中应该可以清楚地看出,如果您在通常会给您libXcursor.so.1作为运行时参考的系统上使用标头编译二进制文件,那么您唯一兼容的共享库是libXcursor.so.1,并且尝试dlopen libXcursor.so.0.2000将导致不可预知的崩溃。

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

库搜索路径:到底我应该在哪里查找 *.so 文件?

应该尝试使用它们的完整路径打开这些库中的任何一个。只需调用,运行时加载程序就会在系统适当的位置dlopen("libXcursor.so.1", RTLD_GLOBAL);搜索库。

于 2013-04-14T21:29:43.720 回答