事实上,Linux 上的 -static gcc 标志现在不起作用。让我引用 GNU libc 常见问题解答:
2.22。即使是静态链接的程序也需要一些我无法接受的共享库。我能做些什么? {AJ} NSS(有关详细信息,只需键入 `info libc "Name Service Switch"')在没有共享库的情况下将无法正常工作。 NSS 允许通过更改一个配置文件 (/etc/nsswitch.conf) 来使用不同的服务(例如 NIS、文件、db、hesiod),而无需重新链接任何程序。唯一的缺点是现在静态库需要访问共享库。这由 GNU C 库透明地处理。一种解决方案是使用 --enable-static-nss 配置 glibc。在这种情况下,您可以创建一个仅使用服务 dns 和文件的静态二进制文件(为此更改 /etc/nsswitch.conf)。您需要明确链接所有这些服务。例如: gcc -static test-netdb.c -o test-netdb \ -Wl,--start-group -lc -lnss_files -lnss_dns -lresolv -Wl,--end-group 这种方法的问题是你'必须将每个使用 NSS 例程的静态程序与所有这些库链接起来。 {UD} 事实上,不能再说使用此选项编译的 libc 正在使用 NSS。没有开关了。因此强烈建议不要使用 --enable-static-nss,因为这会使系统上程序的行为不一致。
关于这个事实,现在是否有任何合理的方法可以在 Linux 上创建功能齐全的静态构建,或者静态链接在 Linux 上完全死了?我的意思是静态构建:
行为与动态构建完全相同(行为不一致的静态nss是邪恶的!);
适用于 glibc 环境和 Linux 版本的合理变化;
我认为这很烦人,并且我认为将某个功能称为“无用”是傲慢的,因为它在处理某些用例时存在问题。 glibc 方法的最大问题是它对系统库(gconv 和 nss)的路径进行硬编码,因此当人们尝试在不同于构建它的 Linux 发行版上运行静态二进制文件时,它会中断。
无论如何,您可以通过将 GCONV_PATH 设置为指向适当的位置来解决 gconv 问题,这使我可以获取在 Ubuntu 上构建的二进制文件并在 Red Hat 上运行它们。
静态链接又回来了!
Linus Torvalds 支持静态链接,并对 Linux 发行版中的静态链接数量表示担忧(另请参阅此讨论)。
许多(大多数?)Go 编程语言可执行文件是静态链接的。增加的可移植性和向后兼容性是它们流行的原因之一。
增加的可移植性和向后兼容性是它们流行的原因之一。
其他编程语言也有类似的努力使静态链接变得非常容易,例如:Haskell(我正在努力)Zig(详见此处)
Haskell(我正在努力)
之字(详情见这里)
可配置的 Linux 发行版 / 包集,如 NixOS / nixpkgs 使得静态链接大部分包成为可能(例如,它的 pkgsStatic 包集可以提供各种静态链接的可执行文件)。
静态链接可以在链接时更好地消除未使用的代码,从而使可执行文件更小。
像 musl 这样的 libcs 使静态链接变得简单而正确。
一些大型软件行业的领导者同意这一点。例如,Google 正在编写针对静态链接的新 libc(“支持静态非 PIE 和静态 PIE 链接”、“我们目前不打算投资 [in] 动态加载和链接支持”)。
关于这个事实,现在是否有任何合理的方法可以在 Linux 上创建功能齐全的静态构建,或者静态链接在 Linux 上完全死了?
我不知道在哪里可以找到历史参考,但是是的,static linking 在 GNU 系统上已死。 (我相信它在从 libc4/libc5 到 libc6/glibc 2.x 的过渡期间死了。)
鉴于以下情况,该功能被认为是无用的:
安全漏洞。静态链接的应用程序甚至不支持升级 libc。如果应用程序链接到包含 lib 漏洞的系统上,那么它将在静态链接的可执行文件中永久存在。
代码膨胀。如果许多静态链接的应用程序在同一个系统上运行,标准库就不会被重用,因为每个应用程序都包含在它自己的所有内容的副本中。 (尝试 du -sh /usr/lib 以了解问题的严重程度。)
尝试挖掘 10-15 年前的 LKML 和 glibc 邮件列表档案。我很确定很久以前我在 LKML 上看到过一些相关的东西。
glibc
的 eglibc
分支使静态链接至少再次成为可能,但如果您想实际使用静态链接而没有巨大的二进制文件和像 nss 这样的错误/问题,您可能需要使用不同的 libc执行。
execve
之前到自执行之后 main
的第一行所经过的时间。对于除了 libc 之外没有共享库的普通程序,静态链接自执行所需的时间减少了大约 50%,并且时间在几十或几百微秒的范围内,具体取决于机器速度。加入一些共享库,您可以轻松地将其减少 90%。您将 O(n) 时间与 O(1) 时间进行比较,因此无论每个库的成本有多小,您都可以任意接近 100%,但实际上只需要很少的时间。
mmap
开销也足以让它在许多库中变得重要。对于小型库mmap
,时间将占主导地位,但对于大型(尤其是 C++)库,重定位时间,包括需要修补的每个数据/GOT 页面中的需求分页,是主要因素。
静态链接在 Linux 世界中似乎并不受欢迎。这是我的看法。
没有看到静态链接吸引力的人通常在内核和较低级别的操作系统领域工作。许多 *nix 库开发人员一生都在处理不可避免的问题,试图将一百个不断变化的库链接在一起,这是他们每天都在做的任务。如果您想了解他们擅长的后空翻,请查看自动工具。
但不应期望其他所有人将大部分时间都花在这上面。静态链接将使您远离库流失的缓冲。开发人员可以根据软件的时间表升级她的软件的依赖项,而不是在新的库版本出现时被迫这样做。这对于具有复杂用户界面的面向用户的应用程序非常重要,这些应用程序需要控制它们不可避免地依赖的许多低级库的流量。这就是为什么我将永远是静态链接的粉丝。如果您可以静态链接交叉编译的可移植 C 和 C++ 代码,那么您几乎可以将世界变成您的牡蛎,因为您可以更快地将复杂的软件交付给世界上各种不断增长的设备。
从其他角度来看,那里有很多不同意的地方,开源软件允许所有这些都很好。
仅仅因为您必须动态链接到 NSS 服务并不意味着您不能静态链接到任何其他库。常见问题解答的所有内容是,即使是“静态”链接的程序也有一些动态链接的库。这并不是说静态链接“不可能”或“不起作用”。
添加其他答案:
由于其他答案中所述的原因,不建议将其用于大多数 Linux 发行版,但实际上有一些发行版专门用于运行静态链接的二进制文件:
斯塔里
睡眠
淀粉Linux
彩虹桥
从斯塔利描述:
static linux 是基于为每个任务和每个静态链接的工具(包括一些 X 客户端,例如 st、surf、dwm、dmenu)手工选择的最佳工具集合,它还通过避免 glibc 和其他臃肿的 GNU 库(早期实验表明,静态链接的二进制文件通常比动态链接的 glibc 对应的文件小!!!)。请注意,这与 Ulrich Drepper 对静态链接的估计完全相反。由于静态链接的二进制文件启动速度更快的附带好处,该分发还以性能提升为目标。
静态链接也有助于减少依赖。
您可以在 this question about static vs dynamic linking 中阅读有关它的更多信息。
libc
更新不太灵活。但是我总是可以随时为我的(完全)静态链接的程序提供一个新的二进制文件到现场的设备。