【问题标题】:Loading Linux libraries at runtime在运行时加载 Linux 库
【发布时间】:2013-04-03 19:38:55
【问题描述】:

我认为 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 文件,对可能的情况进行一些检查循环 include 指令等导致的无限循环。真的没有更简单的方法来找出 *.so 的搜索路径吗?

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

感谢您的 cmets/解决方案!

【问题讨论】:

  • 您是否考虑过构建自己的共享库?这些可以与您需要的系统库动态链接,位于您期望它们所在的位置,并且您会知道它们的名称。
  • 另外,你可能想看看这个问题:stackoverflow.com/questions/2827181/…
  • @1:是的,这可能是一种解决方法,但是我必须将我的应用程序与随附的 *.so 文件一起分发。我希望在我的发行版中只有一个 ELF 二进制文件。
  • 您可以让您的应用程序成为免费软件 (GPLv3),并将打包的负担留给发行版...

标签: linux ld elf dlopen shared-libraries


【解决方案1】:

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

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

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

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

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

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

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

【讨论】:

  • 感谢您的澄清!我现在使用带有 dlopen() 的共享对象的 SONAME 来工作。
猜你喜欢
  • 2017-06-13
  • 1970-01-01
  • 2018-09-04
  • 2017-01-18
  • 1970-01-01
  • 2016-12-07
  • 1970-01-01
  • 2022-08-03
  • 1970-01-01
相关资源
最近更新 更多