我认为 Linux 中的一个主要设计缺陷是在以二进制而不是源代码形式分发程序时的共享对象 hell 。
这是我的具体问题:我想以 ELF 二进制形式发布一个 Linux 程序,该程序应该在尽可能多的发行版上运行,因此我的强制依赖项尽可能低:在任何情况下都需要的唯一库是 libpthread、libX11、librt和 libm(当然还有 glibc)。当我使用 gcc 构建我的程序时,我正在动态链接这些库。
但是,我的程序还应该支持 ALSA(声音接口(interface))、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 程序真的那么复杂吗!做我想做的事有某种标准吗?还是我注定要以骇人听闻的方式做到这一点?
感谢您的意见/解决方案!
最佳答案
就系统的创建者而言,这不是设计缺陷;这是一个优势——它鼓励您以源代码形式分发程序。哦,你想卖你的软件?抱歉,这不是 Linux 优化的用例。
是的,这称为外部库版本控制。阅读它 here 。从该描述中可以清楚地看出,如果您在通常会给您 libXcursor.so.1
作为运行时引用的系统上使用 header 编译二进制文件,那么您唯一兼容的共享库是 libXcursor.so.1
,并且尝试 dlopen
libXcursor.so.0.2000
将导致不可预测崩溃。
任何提供 libXcursor.so
但不提供 libXcursor.so.1
的系统要么是损坏的安装,要么与您的二进制文件不兼容。
您不应该尝试使用它们的完整路径 dlopen 任何这些库。只需调用 dlopen("libXcursor.so.1", RTLD_GLOBAL);
,运行时加载器就会在系统适当的位置搜索库。
关于linux - 在运行时加载 Linux 库,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/15951672/