Linux 程序是否像 Windows 程序一样可移植?
Are Linux programs as portable as Windows programs?
也许这是一个愚蠢的问题,但这是从人们四处交谈中学到的问题之一,如果专业人士正确描述了情况,我会很高兴。
谈到标准台式计算机,我看到 Windows 程序尽可能便携。我可以用静态库链接编译任何 32 位软件,然后将该软件放在闪存驱动器上,它可以在世界上任何 32 位或 64 位计算机上运行。我有超过 10 年的程序,它们仍然可以正常工作。
现在我也在编程 linux,但是我在做 linux 程序时脑子里没有那个画面。我总是有一个画面,它应该在必须使用该程序的每个系统中编译。一位同事告诉我,在两台 linux 计算机之间盲目地在两台计算机上 运行 相同的软件是错误的。但是...我在 Windows 上使用我的静态可执行文件执行此操作。我可以在 linux 两次内完成吗?
总结一下我的问题:像人们在 Windows 上所做的那样,在 linux 上创建可移植软件有哪些限制?当然,假设目标计算机除了某个任意版本的 glibc 之外根本没有任何库。在我心目中的模型中,所有库 都应该 是静态的。
在 Windows 平台上使用 C 编译器编译的程序依赖于 Windows 平台。然后您可以在另一台 Windows 计算机上尝试 运行 这个程序,它可能 运行 没问题。但是对于 Linux 程序来说完全一样。
您将无法将该程序复制到 Unix 机器上并 运行 它。
根据您编写程序的方式,很可能可以在 MAC 或 linux PC 上重新编译在 Windows 机器上开发的程序源。但反过来也是如此。
例如,这个 C 程序:
#include <stdio.h>
int main() {
printf("Hello World!");
}
如果为每个平台重新编译,会 运行 Windows、MAC 和 linux 以及实际上很多平台。
Windows 操作系统之间存在差异,这意味着在 Windows 7 上编写的程序不会 运行 在 Windows 8 上编写。这取决于程序.
至于静态链接与动态链接的问题,是的,静态链接可以使您的程序更有可能 运行 在具有相同操作系统的系统上,因为函数库当然已经存在于可执行文件。但是静态链接不会使您的程序可移植到不同的操作系统。 Windows 上的 C 运行time 库对 unix 上 运行 的程序没有用处。系统的界面非常不同。
我最初在 Windows 98 上写了一个语音处理程序,后来我将它移植到 Windows NT4 和后来的 Windows 2000。我不得不为每个新的代码更改代码操作系统。这与图书馆无关。其中一些是因为该功能的实现在不同操作系统之间发生了变化。 Windows 9X 是与 Windows NT 完全不同的代码库。有时是因为错误在 OS 的更高版本中得到了修复。所以你永远无法确定。基本上,您必须在部署的每个新平台上进行测试。
我假设您的问题是关于 Linux 版本之间的应用程序可移植性。
Linux 版本之间存在不同类型的 API/ABI 不兼容性。最常见的可以影响静态可执行文件的是:
libc 版本。 (例如,您的应用程序依赖于特定于 glibc 的功能,但主机具有非常旧的版本或具有另一个 C 库(newlib、bionic 等))
架构。 (例如系统没有 32 位 libc,在 ARM 上你关心像 soft/hard float 这样的东西,应用程序可能使用 SSE2/AVX2 但内核不知道如何在上下文切换后保留寄存器)
系统Calls/Hardware支持。这通常是新内核 API (inotify/old dnotify) 之类的东西。旧内核也不知道 IPv6、USB3.0。一些旧的内核 API 将来可能会被删除。
一些极不可能的可能性:
- 可执行格式。 (例如,您的应用是 ELF,但系统只知道 a.out)
- 资源限制。 (例如,没有 PAE 的 32 位内核无法映射您的 40GB 文件)
而这只是基础知识。我什至不想开始使用 Xorg 或任何接近 OpenGL 的问题。
在 Linux 世界中,二进制兼容性被认为不如源代码兼容性重要,因为 Linux 周围的大部分生态系统都是开源的。即使二进制兼容性中断,您仍然可以 运行 旧程序再次编译后。在 Windows 生态系统中,这是不可能的:大多数软件都是封闭源代码,因此用户将依赖软件供应商来更新软件以获得新的 OS 版本。由于这基本上不会发生,Windows 非常重视维护二进制级别的反向兼容,以至于 20 岁的二进制文件通常仍然可以 运行。
Linux 有一个名为 Linux Standard Base (LSB) 的规范,它试图提供稳定的应用程序编程接口 (API) 以实现源兼容性和更有限的应用程序二进制接口 ( ABI) 以实现二进制兼容性。它基于 POSIX 和单一 Unix 规范。但是,大多数 Linux 发行版并未完全实现 LSB。与 Debian 和 Ubuntu 相关的发行版相比,与 Red Hat 相关的发行版似乎更接近它。
所以不幸的是,Linux 生态系统并没有硬性保证不同发行版之间或不同版本之间的二进制兼容性。但在实践中,存在一定程度的兼容性。特别是,个别发行版可能会提供更强的兼容性保证。在特定发行版的一个安装上编译的二进制文件可以在该版本的任何安装上使用,前提是它们具有相同的架构——Linux 上的大多数包管理器都使用带有此类预编译二进制文件的包。但请注意,这些包通常是在具有严格控制的依赖项的参考安装上编译的。
在某些情况下,可以跨越架构、可执行格式和 OS ABI 的界限。例如。 WINE 接口层实现了 Windows'“可移植可执行文件”格式,并重新实现了 Windows ABI 的重要部分,导致有限的 Windows→Linux 二进制兼容性。只能通过使用模拟器来跨越架构边界(例如,即使使用相同的 OS 版本,也不能在 AMD64 系统上使用为 SPARC 编译的软件)。
x86 二进制文件在 AMD64 架构上的兼容性是一个特例。 AMD64 指令集经过专门设计,可向后兼容 x64(这就是它如此成功的原因)。操作系统仍然需要在 AMD64 系统(64 位)上为 运行ning x86 二进制文件(具有 32 位指针)提供特殊的内核级支持,但所有重要的操作系统都提供这种支持。
也许这是一个愚蠢的问题,但这是从人们四处交谈中学到的问题之一,如果专业人士正确描述了情况,我会很高兴。
谈到标准台式计算机,我看到 Windows 程序尽可能便携。我可以用静态库链接编译任何 32 位软件,然后将该软件放在闪存驱动器上,它可以在世界上任何 32 位或 64 位计算机上运行。我有超过 10 年的程序,它们仍然可以正常工作。
现在我也在编程 linux,但是我在做 linux 程序时脑子里没有那个画面。我总是有一个画面,它应该在必须使用该程序的每个系统中编译。一位同事告诉我,在两台 linux 计算机之间盲目地在两台计算机上 运行 相同的软件是错误的。但是...我在 Windows 上使用我的静态可执行文件执行此操作。我可以在 linux 两次内完成吗?
总结一下我的问题:像人们在 Windows 上所做的那样,在 linux 上创建可移植软件有哪些限制?当然,假设目标计算机除了某个任意版本的 glibc 之外根本没有任何库。在我心目中的模型中,所有库 都应该 是静态的。
在 Windows 平台上使用 C 编译器编译的程序依赖于 Windows 平台。然后您可以在另一台 Windows 计算机上尝试 运行 这个程序,它可能 运行 没问题。但是对于 Linux 程序来说完全一样。
您将无法将该程序复制到 Unix 机器上并 运行 它。
根据您编写程序的方式,很可能可以在 MAC 或 linux PC 上重新编译在 Windows 机器上开发的程序源。但反过来也是如此。
例如,这个 C 程序:
#include <stdio.h>
int main() {
printf("Hello World!");
}
如果为每个平台重新编译,会 运行 Windows、MAC 和 linux 以及实际上很多平台。
Windows 操作系统之间存在差异,这意味着在 Windows 7 上编写的程序不会 运行 在 Windows 8 上编写。这取决于程序.
至于静态链接与动态链接的问题,是的,静态链接可以使您的程序更有可能 运行 在具有相同操作系统的系统上,因为函数库当然已经存在于可执行文件。但是静态链接不会使您的程序可移植到不同的操作系统。 Windows 上的 C 运行time 库对 unix 上 运行 的程序没有用处。系统的界面非常不同。
我最初在 Windows 98 上写了一个语音处理程序,后来我将它移植到 Windows NT4 和后来的 Windows 2000。我不得不为每个新的代码更改代码操作系统。这与图书馆无关。其中一些是因为该功能的实现在不同操作系统之间发生了变化。 Windows 9X 是与 Windows NT 完全不同的代码库。有时是因为错误在 OS 的更高版本中得到了修复。所以你永远无法确定。基本上,您必须在部署的每个新平台上进行测试。
我假设您的问题是关于 Linux 版本之间的应用程序可移植性。
Linux 版本之间存在不同类型的 API/ABI 不兼容性。最常见的可以影响静态可执行文件的是:
libc 版本。 (例如,您的应用程序依赖于特定于 glibc 的功能,但主机具有非常旧的版本或具有另一个 C 库(newlib、bionic 等))
架构。 (例如系统没有 32 位 libc,在 ARM 上你关心像 soft/hard float 这样的东西,应用程序可能使用 SSE2/AVX2 但内核不知道如何在上下文切换后保留寄存器)
系统Calls/Hardware支持。这通常是新内核 API (inotify/old dnotify) 之类的东西。旧内核也不知道 IPv6、USB3.0。一些旧的内核 API 将来可能会被删除。
一些极不可能的可能性:
- 可执行格式。 (例如,您的应用是 ELF,但系统只知道 a.out)
- 资源限制。 (例如,没有 PAE 的 32 位内核无法映射您的 40GB 文件)
而这只是基础知识。我什至不想开始使用 Xorg 或任何接近 OpenGL 的问题。
在 Linux 世界中,二进制兼容性被认为不如源代码兼容性重要,因为 Linux 周围的大部分生态系统都是开源的。即使二进制兼容性中断,您仍然可以 运行 旧程序再次编译后。在 Windows 生态系统中,这是不可能的:大多数软件都是封闭源代码,因此用户将依赖软件供应商来更新软件以获得新的 OS 版本。由于这基本上不会发生,Windows 非常重视维护二进制级别的反向兼容,以至于 20 岁的二进制文件通常仍然可以 运行。
Linux 有一个名为 Linux Standard Base (LSB) 的规范,它试图提供稳定的应用程序编程接口 (API) 以实现源兼容性和更有限的应用程序二进制接口 ( ABI) 以实现二进制兼容性。它基于 POSIX 和单一 Unix 规范。但是,大多数 Linux 发行版并未完全实现 LSB。与 Debian 和 Ubuntu 相关的发行版相比,与 Red Hat 相关的发行版似乎更接近它。
所以不幸的是,Linux 生态系统并没有硬性保证不同发行版之间或不同版本之间的二进制兼容性。但在实践中,存在一定程度的兼容性。特别是,个别发行版可能会提供更强的兼容性保证。在特定发行版的一个安装上编译的二进制文件可以在该版本的任何安装上使用,前提是它们具有相同的架构——Linux 上的大多数包管理器都使用带有此类预编译二进制文件的包。但请注意,这些包通常是在具有严格控制的依赖项的参考安装上编译的。
在某些情况下,可以跨越架构、可执行格式和 OS ABI 的界限。例如。 WINE 接口层实现了 Windows'“可移植可执行文件”格式,并重新实现了 Windows ABI 的重要部分,导致有限的 Windows→Linux 二进制兼容性。只能通过使用模拟器来跨越架构边界(例如,即使使用相同的 OS 版本,也不能在 AMD64 系统上使用为 SPARC 编译的软件)。
x86 二进制文件在 AMD64 架构上的兼容性是一个特例。 AMD64 指令集经过专门设计,可向后兼容 x64(这就是它如此成功的原因)。操作系统仍然需要在 AMD64 系统(64 位)上为 运行ning x86 二进制文件(具有 32 位指针)提供特殊的内核级支持,但所有重要的操作系统都提供这种支持。