我用C编写了一个简单的程序,并在Ubuntu上使用GCC进行编译。 这个文件会在另一台机器上工作吗?
有几个级别/来源的二进制不兼容。
通常情况下,如果你在另一台机器上运行一个二进制文件,使用不同版本的“相同操作系统”(不管那意味着什么),那么它将运行良好。 完全。 问题不在于代码不工作,而在于缺少代码:二进制文件所依赖的操作系统位在目标机器上不存在。 这是一个找不到代码运行的代码,而不是运行代码(这可能是完全不错的,直到它试图使用丢失的位)。
所以,你的Ubuntu gcc的二进制文件很可能会运行在任何不比编译机器大的Linux系统上。 它依赖于二进制从OS和系统库所依赖的功能。
很少有二进制文件没有外部依赖。 在输出上使用ldd
检查依赖关系。 最有可能导致问题的是libgcc依赖项。 libc和朋友改变很少,所以几乎不会造成兼容性的困难。 GCC经常变化,所以会限制你的二进制文件运行的目标机器。
一般的规则是:使用您想要运行的最古老的发行版作为您的生成器。 因此,使用RHEL 2构建机器,您将能够在任何不老的系统上运行二进制文件(有一些例外)。 这是一个简单的通用指南。 如果你需要很多发行版本的二进制兼容性,静态链接到libstdc ++(如果你使用C ++)是一个很好的选择。 静态链接到libgcc是危险的,除非你真的知道你在做什么,否则不要试图尝试。
最后请注意,在其他UNIX平台上,库兼容性要简单得多。 这只是Linux,这是一个很痛苦的事情。 在AIX 6(例如)或SunOS 5.8或HP-UX 11.00上编译的任何东西,或者在所有更高版本上都没有问题的情况下运行。 这个环境是同质的,它们可以在系统库中传递一堆遗留下来的信息,以确保旧版本中的每个符号都可以在最新版本上使用,而且具有相同的语义。
这只是机器代码,所以你可能会认为二进制文件应该在其他操作系统上工作。 他们不会。 一个很大的原因是系统调用:当你需要从内核中调用某些东西(这对大多数不重要的功能是必须的)时,你必须知道如何“与内核进行交谈”。 也就是说,你做了一个系统调用,并告诉操作系统,“做的事情,你知道的”。
系统调用的数字取决于内核。 所以,Solaris二进制文件可以从Linux上运行,除此之外,这个工作几乎停止了。
事实上,有些操作系统支持其他内核的系统调用。 FreeBSD知道linux系统调用,当你告诉它“做这件事情”时,它会检查ELF头部中的一个标志,并且如果ELF被标记为linux,则对linux系统调用号码执行适当的操作。 整齐。 (当然,你也需要在linux库中链接…但是,一个静态链接的linux二进制文件在FreeBSD中运行良好,没有外部的。)
二进制不是“只是一个二进制”; 它包含了一个完整的元数据负载,在内核可以运行之前被内核解释。 大部分的二进制代码和数据都是连接器信息。 但是,即使是没有任何外部依赖的东西也必须被内核解析。
一些内核可以理解多种二进制格式,例如PE,ELF或a.out(已过时)。 Linux二进制文件将永远不会在Windows上运行,即使它们没有进行任何系统调用(这样的二进制文件不能干净地退出,但为了举例…)。 这是因为MS不会将ELF支持添加到他们的内核中:描述如何加载和启动的代码包装器不能被Windows读取,因此它内部的代码将不会运行:Windows doesn不知道文件的哪些位是偶数的!
a.out
( .o
)文件适用于类Unix操作系统的机器。 (由@Nicholas Wilson给出的OS的细节)
.o
包含.c
文件中提到的所有库。 被调用函数的一个副本从库中复制,并与.c
文件中给出的代码一起生成.o
文件。
再次编译.o
文件以获取可执行文件。
.o
文件的使用是,如果您正在处理一个大的项目,每个部门都有自己的源文件( .c
)并需要制作一个可执行文件。 你可以通过编译.c
文件来得到它。 编译后你会得到.o
文件。 现在,您可以将所有这些.o
文件合并为一个可执行文件。