GCC静态库链接与动态链接对比

3

我的构建环境是CentOS 5。我有一个名为libcunit的第三方库。我使用autotools安装它,生成了libcunit.alibcunit.so两个文件。我有自己的应用程序,链接了一堆共享库。 libcunit.a在当前目录中,而libcunit.so和其他共享库在/usr/local/lib/中。当我编译时:

gcc -o test test.c -L. libcunit.a -L/usr/local/lib -labc -lyz

我遇到了一个链接错误:

libcunit.a(Util.o): In function `CU_trim_left':
Util.c:(.text+0x346): undefined reference to `__ctype_b'
libcunit.a(Util.o): In function `CU_trim_right':
Util.c:(.text+0x3fd): undefined reference to `__ctype_b'

但是当我使用 .so 编译时,如下所示:

gcc -o test test.c -L/usr/local/lib -lcunit -labc -lyz

这段代码编译和运行都很好。

但是,当与libcunit.a静态链接时,为什么会出现错误?

2个回答

6
为什么使用静态链接 libcunit.a 时会出现错误?
问题在于你的 libcunit.a 是在一个古老的 Linux 系统上构建的,依赖于已经从 libc 中删除的符号(这些符号在 glibc-2.2 中使用,并且在 10 多年前从 glibc-2.3 中删除)。更准确地说,这些符号已经被隐藏了。它们对于旧二进制文件(如 libcunit.so)进行动态链接是可用的,但是新代码不能静态链接到它们(您无法创建一个新的可执行文件或共享库来引用它们)。
你可以这样观察:
readelf -Ws /lib/x86_64-linux-gnu/libc.so.6 | egrep '\W__ctype_b\W'
   769: 00000000003b9130     8 OBJECT  GLOBAL DEFAULT   31 __ctype_b@GLIBC_2.2.5

readelf -Ws /usr/lib/x86_64-linux-gnu/libc.a | egrep '\W__ctype_b\W'
# no output

嗨,我正在从源代码编译cunit项目(http://cunit.sourceforge.net/)。我没有得到预编译的二进制文件。我使用autotools进行安装。还有一个问题,libc.a没有ctype_b符号。但是我没有要求将libc静态链接到我的测试应用程序。因此它应该动态链接到libc.so.6,对吗? - bala1486

3
没有注意到在你的情况下实际上发现了libcunit.a,链接问题实际上在CUnit库本身中。Employed Russian是绝对正确的,他不是在谈论预编译二进制文件。我们知道你自己构建了它。然而,CUinit本身似乎依赖于从glibc中的符号,这个符号不再适用于静态链接。因此,你只有两个选择:
  1. 向CUnit的开发者提交报告,并请求他们解决该问题;
  2. 使用动态链接。
尽管如此,我仍然推荐你的静态链接样式。-L.通常是一个不好的做法。CUnit是第三方库,不应该放置在包含你项目源文件的目录中。它应该像动态版本一样安装,即你在/usr/local/lib中拥有libcunit.so。如果你在CUnit的配置阶段向Autotools提供了prefix,那么Autotools会正确安装所有内容。因此,如果你想与CUnit进行静态链接,请考虑采用以下形式:
gcc -o test test.c -L/usr/local/lib -Wl,-Bstatic -lcunit -Wl,-Bdynamic -labc -lyz

这个答案是不正确的,问题与库的顺序没有任何关系 - Employed Russian
@Employed Russian:您认为我的回答解决了“库排序”问题吗?建议的命令行只是复制粘贴OP的命令行,并添加/编辑了一些标志,但未更改链接顺序。 - Alexander Shukaev
如果您直接列出libcunit.a(如OP所做),则不需要使用-Wl,-Bstatic - Employed Russian

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