我认为
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的搜索路径?
所以,我的实际问题是:是不是有更方便,更少的hackish方式来实现我想做的事情?创建一个具有ALSA,GTK,libXcursor等可选依赖项的Linux程序真的很复杂……但是没有它也应该工作!做我想做的事情有某种标准吗?或者我注定要以hackish的方式做到这一点?
感谢您的意见/解决方案!
最佳答案
I think a major design flaw in Linux is the shared object hell when it comes to distributing programs in binary instead of source code form.
就系统的创造者而言,这不是一个设计缺陷;这是一个优势 – 它鼓励您以源代码形式分发程序.哦,你想出售你的软件?对不起,这不是Linux优化的用例.
Library naming conventions: Shared objects often aren’t simply called “libXcursor.so” but have some kind of version extension like “libXcursor.so.1” or even really funny things like “libXcursor.so.0.2000”.
是的,这称为外部库版本控制.阅读它here.从该描述中应该清楚,如果您使用通常为libXcursor.so.1作为运行时引用的系统上的头文件编译二进制文件,那么您唯一兼容的共享库是libXcursor. so.1,并尝试dlopen libXcursor.so.0.2000将导致不可预测的崩溃.
任何提供libXcursor.so而不是libXcursor.so.1的系统都是破坏的安装,或者与二进制文件不兼容.
Library search paths: Where should I look for the *.so files after all?
您不应该尝试使用它们的完整路径来删除任何这些库.只需调用dlopen(“libXcursor.so.1”,RTLD_GLOBAL);,运行时加载程序将在系统适当的位置搜索库.