pze*_*sko 36 c c++ linker glibc static-linking
在线上的大多数资源都指出您可以静态链接glibc,但不建议这样做。例如centos软件包repo:
The glibc-static package contains the C library static libraries
for -static linking. You don't need these, unless you link statically,
which is highly discouraged.
Run Code Online (Sandbox Code Playgroud)
这些消息来源很少(或从来没有)说过为什么这不是一个好主意。
zwo*_*wol 26
其他答案中给出的原因是正确的,但不是最重要的原因。
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
对用户的环境变量的调用,而您却无法对此进行控制设置呢。
程序/glibc
接口由 POSIX、C 和 C++ 标准等标准化并记录在案。例如,该fopen()
函数的行为符合 C 标准和pthread_mutex_lock()
POSIX。
该glibc
/内核接口没有标准化。是否在引擎盖下fopen()
使用open()
?或者它使用openat()
?或者是其他东西?明年用什么?你不知道。
如果glibc
/kernel 接口发生变化,使用任何更改但静态链接的程序glibc
将不再工作。
15 多年前,libc
出于这个原因,Solaris 删除了所有静态版本。
使用 Solaris 10,您无法再构建静态可执行文件。不是 ld(1) 不允许静态链接或使用存档,只是不再提供 libc.a,即 libc.so.1 的存档版本。这个库提供了用户空间和内核之间的接口,没有这个库就很难创建任何形式的应用程序。
一段时间以来,我们一直在警告用户不要进行静态链接,而针对 libc.a 的链接尤其成问题。每个solaris 版本或更新(甚至一些补丁)都会导致一些针对libc.a 构建的应用程序失败。问题是 libc 应该将应用程序与用户/内核边界隔离,该边界可以在不同版本之间发生变化。
如果应用程序是针对 libc.a 构建的,那么它引用的任何内核接口都将从存档中提取并成为应用程序的一部分。因此,此应用程序只能在与所使用的内核接口同步的内核上运行。如果这些接口发生变化,应用程序就会处于不稳定的状态。
...
编辑:
似乎严重高估了 Linux 内核接口的稳定性。有关详细信息,请参阅Linux 内核 API 更改/添加。总结一下: