如果我在 ubuntu 中静态链接一个可执行文件,该可执行文件是否有可能在其他发行版(如 mint os)中不起作用?或软呢帽?我知道处理器类型会受到影响,但除此之外还有什么我需要注意的吗?对不起,如果这是一个愚蠢的问题。谢谢你的帮助
8 回答
有一些极端情况,但在大多数情况下,您应该使用静态链接保持良好状态。想到的就是libnss。这个特定的库基本上不可能静态链接,因为它的工作方式(权限、身份验证、安全任务)。不过,只要 glibc 版本相似,您就应该可以解决这个问题。
如果您的程序需要使用内核的细微功能(例如卷管理器),那么您有非常小的机会让您的程序在各个发行版之间以静态链接方式工作,因为内核接口可能会略有变化。
大多数典型的应用程序,甚至讨论可移植性的那种应用程序,如网络服务、gui 应用程序、语言工具(如编译器/解释器)都不会有任何问题。
如果您在一台计算机上静态链接一个程序,然后将其移动到另一台系统基本上以相同方式运行的计算机,那么它应该可以正常工作。这就是静态链接的意义所在;程序不依赖其他文件 - 它完全是独立的,所以只要它可以运行,它就会以与它在其“主机”系统上相同的方式运行。
这与动态链接形成对比,其中程序在运行时合并其他文件(库)的元素。如果您将动态链接的程序移动到另一个系统,其中它所依赖的库不同(或不存在),它将无法工作。
在大多数情况下,您的可执行文件可以正常工作。只要您的可执行文件不依赖于任何不寻常的东西来运行,就不会有问题。(而且,如果它确实取决于存在的异常情况,那么即使您动态链接也会遇到同样的问题。)
为了不同 UNIX 环境之间的兼容性,静态链接通常比动态链接更安全,只要使用相同的 CPU。
要使静态链接的二进制文件失败,再次假设相同的处理器架构,您将不得不在使用 a.out 二进制格式的系统上进行链接之类的操作,并尝试在运行 ELF 的系统上执行它,在这种情况下,动态链接版本同样会失败。
那么为什么人们不经常静态链接呢?两个原因:
- 它使可执行文件更大,有时更大,并且
- 如果库中的错误已修复,您必须重新链接程序才能访问错误修复。如果在库中修复了严重的安全错误,您必须重新链接并重新分发您的 exe。
On the contrary. Whatever your chances are of getting a binary to work across distributions or even OSes, those chances are maximized by static linking. Static linking makes an executable self-contained in terms of libraries. It can still go wrong if it tries to read a file that's not there on another system.
For even better chances of portability, try linking against dietlibc or some other libc. An article at Linux Journal mentions some candidates. A smaller, simpler libc is less likely to depend on things in the filesystem that differ from distro to distro.
这里有两个兼容性问题:库版本和库库存。
你没有说你正在使用什么库。
如果您没有“-l”选项,那么唯一的“库”就是 glibc 本身,它用作内核的接口。Glibc 版本向上兼容。如果您在 glibc 2.x 系统上链接,您可以在 glibc 2.y 上运行,因为 y > x。开发商对此做出了坚定的承诺。
如果你有 -l 选项,静态链接总是安全的。如果您是动态链接的,则必须确保 (1) 库存在于目标系统上,并且 (2) 具有兼容的版本。您的里程可能会因目标发行版是否具有您需要的内容而异。
只要您可以保证它只会在类似硬件上的类似操作系统版本上执行,如果它是静态链接的,您的程序就可以正常工作。因此,如果您为 2.6 Linux 构建并静态链接,您将可以在(几乎)所有 2.6 Linux 发行版上运行。
请注意,您不能静态链接 GLIBC 的某些部分,因此如果您使用它们,则无论如何都必须动态链接。在我调查时,从内存中,名称服务 (nss) 部分需要动态链接。
您不能静态链接(比如说)Linux 的程序,然后期望它在 BSD 或 Windows 上运行。BSD 和 Unix 不像 Linux 那样呈现或处理它们的系统调用。我撒了一个小谎,因为 BSD 有一个可以启用的 Linux 仿真层,但开箱即用它不会工作。
出于上述原因,我会避免静态链接某些东西,除非你绝对必须。
话虽如此,它应该适用于相同架构的任何其他类似内核(即,如果您在运行 linux 2.4.x 的机器上静态链接,加载程序 VDSO 在 linux 2.6 上将有所不同,VDSO 是虚拟动态共享对象,内核向每个包含加载程序代码的进程公开的共享对象)。
其他陷阱包括 /etc 中的内容不是您想的那样,日志位于不同的位置,系统实用程序不存在或不同(ubuntu 使用 update-rc.d,RHEL 使用 chkconfig)等。
有时你别无选择。我正在编写一个程序,该程序与 LVM2 的基于字符串的 cmdlib 接口进行对话,以支持使用 execv().. 低,我需要支持的 30% 的发行版不包含该库,并且无法获取它。因此,在生成二进制包时,我必须链接到静态对象。
如果您使用 glibc,您可以确信 getpwnam() 和朋友之类的东西仍然可以工作.. 只需确保观看任何硬编码路径(更好的是,让它们在运行时可配置)
不,它不会工作。分配独立性的静态链接是旧 Unix 时代的概念,不推荐使用。事实上,无论如何,你不能像静态库那样使用尽可能多的库。
遵循 Linux Standard Base 方式,这是您获得尽可能多的跨发行版可移植性的唯一机会。
如果您为 FreeBSD 和 Solaris 编程,LSB 也可以正常工作。