大多数在线资料表明您可以静态链接 glibc,但不鼓励这样做;例如 centos 软件包回购:
glibc-static 包包含用于 -static 链接的 C 库静态库。你不需要这些,除非你静态链接,这是非常不鼓励的。
这些消息来源很少(或从不)说明为什么这是一个坏主意。
原文由 pzelasko 发布,翻译遵循 CC BY-SA 4.0 许可协议
大多数在线资料表明您可以静态链接 glibc,但不鼓励这样做;例如 centos 软件包回购:
glibc-static 包包含用于 -static 链接的 C 库静态库。你不需要这些,除非你静态链接,这是非常不鼓励的。
这些消息来源很少(或从不)说明为什么这是一个坏主意。
原文由 pzelasko 发布,翻译遵循 CC BY-SA 4.0 许可协议
程序/ glibc
接口由 POSIX、C 和 C++ 标准等标准化和记录。例如, fopen()
函数的行为符合 C 标准,而 pthread_mutex_lock()
POSIX。
glibc
/kernel 接口 未 标准化。 fopen()
在引擎盖下使用 open()
吗?还是使用 openat()
?或者是其他东西?明年用什么?你不知道。
如果 glibc
/kernel 接口发生更改,则使用任何更改但静态链接 glibc
的程序将不再工作。
15 多年前,出于这个原因,Solaris 删除了所有静态版本的 libc
。
使用 Solaris 10,您无法再构建静态可执行文件。并不是 ld(1) 不允许静态链接或使用存档,只是不再提供 libc.a,即 libc.so.1 的存档版本。这个库提供了用户空间和内核之间的接口,没有这个库就很难创建任何形式的应用程序。
一段时间以来,我们一直在警告用户不要进行静态链接,而针对 libc.a 的链接尤其成问题。每个 solaris 版本或更新(甚至一些补丁)都会导致某些针对 libc.a 构建的应用程序失败。问题是 libc 应该将应用程序与用户/内核边界隔离开来,这个边界可能会随着版本的不同而发生变化。
如果应用程序是针对 libc.a 构建的, 那么它所引用的任何内核接口都会从存档中提取并成为应用程序的一部分。因此,此应用程序只能在与所使用的内核接口同步的内核上运行。如果这些接口发生变化,应用程序将处于不稳定的状态。
…
编辑:
似乎严重高估了 Linux 内核接口的稳定性。有关详细信息,请参阅 Linux 内核 API 更改/添加。总结一下:
原文由 Andrew Henle 发布,翻译遵循 CC BY-SA 4.0 许可协议
3 回答2k 阅读✓ 已解决
2 回答3.9k 阅读✓ 已解决
2 回答3.2k 阅读✓ 已解决
1 回答3.2k 阅读✓ 已解决
1 回答2.7k 阅读✓ 已解决
3 回答3.4k 阅读
1 回答1.6k 阅读✓ 已解决
其他答案中给出的原因是正确的,但它们不是最重要的原因。
glibc 不应该被静态链接的最重要原因是它在内部广泛使用
dlopen
来加载 NSS( 名称服务切换)模块和iconv
转换。模块本身引用 C 库函数。如果主程序与 C 库动态链接,那没问题。但是如果主程序与 C 库静态链接,dlopen
必须去加载 C 库的 第二个副本 以满足模块的加载要求。这意味着您的“静态链接”程序仍然需要
libc.so.6
的副本出现在文件系统上,加上 NSS 或iconv
或任何模块本身,以及其他动态库模块可能需要,例如ld-linux.so.2
,libresolv.so.2
等。这不是人们在静态链接程序时通常想要的。这也意味着静态链接的程序在其地址空间中有两个 C 库副本,它们可能会争夺使用谁的
stdout
缓冲区,谁可以调用sbrk
一个非零参数,诸如此类。 glibc 内部有一堆防御性逻辑试图使这项工作发挥作用,但从未 保证 它会工作。您可能认为您的程序不需要担心这一点,因为它从不调用
getaddrinfo
或iconv
,但是语言环境支持在内部使用iconv
表示 任何stdio.h
函数 可能会触发对dlopen
的调用,并且您无法控制它,用户的环境变量设置可以。例如,如果您的程序 确实 调用了
iconv
,那么情况会变得更糟,尤其是当“静态链接”可执行文件构建在一个发行版上,然后复制到另一个发行版时。iconv
模块有时位于不同发行版的不同位置,因此在 Red Hat 发行版上构建的可执行文件可能无法在 Debian 上正常运行,这与人们想要静态链接的可执行文件。