将应用程序链接到libbz2.so.1而不是libbz2.so.1.0

6

这是我当前的情况:

我想在Linux上分发一个二进制应用程序,可以在几个发行版上运行(不是所有的,目前只关注主要的,为了本次讨论的重点,我们将专注于Ubuntu和Fedora)。所涉及的应用程序链接到libbz2以完成某些工作。一个简单的“Hello World”将说明这种情况:

/* main.cpp */
#include <iostream>

int main(int argc, char* argv[])
{
  std::cout << "Hello World!\n";
  return 0;
}

该应用程序是这样构建的:

g++ -lbz2 -o test.bin main.cpp

我的构建系统在Ubuntu上。当我使用ldd对生成的二进制文件进行检查时,它会列出libbz2.so.1.0作为运行时依赖项。但是当我将该应用程序带到Fedora机器上时,该应用程序无法运行,并且ldd显示找不到libbz2.so.1.0。Fedora仅有libbz2.so.1和libbz2.so.1.0.4,但没有libbz2.so.1.0。
Red Hat的Bugzilla数据库显示,这种行为不是一个错误,而是一种特性。我实际上不需要libbz2.so.1.0,如果能简单地链接到libbz2.so.1就可以了,但我还没有弄清楚如何做到这一点。
我看到这里之前有一个类似的问题被提出(链接),但是被接受的答案(您可以在链接器命令行上传递实际的.so文件而不是-l)似乎不起作用。我尝试使用以下命令进行构建:
g++ /lib/libbz2.so.1 -o test.bin main.cpp

然而,ldd仍然提到该应用程序依赖于libbz2.so.1.0,尽管我已经将完整名称传递给了g++。

现在的问题是,在Ubuntu上是否有一种方法可以构建该应用程序,使其仅依赖于libbz2.so.1而不是libbz2.so.1.0

谢谢。

2个回答

5
这是一些背景说明,解释了链接的内容。在ELF平台上,你传递的-L和-l标志只能在链接时找到二进制文件。如果链接器确定需要某个库,它会在该二进制文件中生成对SONAME的引用,而不管它被称为什么。例如: $ objdump -p /lib64/libbz2.so.1 | grep SONAME SONAME libbz2.so.1
因此,无论libbz2被命名为什么,这都将显示为一个依赖项。再举个例子: $ ln -s /lib64/libbz2.so.1 libblah.so $ g++ t.C -L. -l blah
你似乎已经链接到了libblah,但由于二进制文件中的SONAME很重要,所以你的依赖关系仍然是libbz2.so.1。 $ ldd a.out | grep bz2 libbz2.so.1 => /lib64/libbz2.so.1 (0x00002b3d1a000000)
除了静态技巧(可能会以有趣的方式破坏事物)之外,没有简单的方法可以摆脱混乱(理想情况下,库将进行良好的符号版本控制,就像glibc一样,从不或很少更改其SONAME)。

使用以下命令可以更好地示例:cp /lib64/libbz2.so.1 libblah.so而不是使用 ln 命令(如果有人认为 ld 以某种方式将名称追踪到 libbz2.so.1)。 - Jaro

3

为什么不直接进行静态链接呢?

我过去在Ubuntu上进行构建并在RHEL上部署时,使用静态构建就可以完美运行。


扶额...因为那太明显了。由于某种原因,我认为bzip2将被许可为LGPL,禁止静态链接,但似乎它是BSD,允许这样做...那么就进行静态链接吧。谢谢。 - Fred
1
没问题。但是为什么你认为LGPL对你链接的方式有任何规定呢?你可以使用静态或动态链接与LGPL和GPL代码--您的限制在于如何分发您的应用程序等,以及是否必须提供源代码。这完全独立于您的构建过程。 - Dirk Eddelbuettel
3
好的,我应该更加准确些。LGPL 禁止将静态链接用于专有应用程序。至于那些寻找完整答案的人,如果你想在某些库中进行静态链接,并与其他一些库进行动态链接,下面是如何操作:使用以下命令:g++ -Wl,-Bstatic -lbz2 -Wl,-Bdynamic -lotherlib -o test.bin main.cpp - Fred

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接