我正在制作一个非常简单的程序,使用c ++进行linux使用,我想知道是否可以制作一个包含所有依赖项的大二进制文件,这些依赖项可以在任何Linux系统上运行。
如果我的理解是正确的,那么任何编译器都会将源代码转换为机器指令,但由于通常可以在不同程序中重用代码的公共部分,因此大多数程序依赖于其他库。
但是如果我有所有依赖项的源代码,我应该能够以不需要系统的任何方式编译二进制文件吗?我能在32位系统上运行64位系统编译的东西吗?
答案 0 :(得分:5)
简而言之:也许吧。
答案越长越好:
这取决于。例如,您不能在32位系统上运行64位二进制文件,这几乎不可能。是的,它是相同的处理器系列,但64位系统中的寄存器数量是原来的两倍,寄存器也是两倍。什么是32位处理器“回馈”处理器硬件中不存在的那些位和寄存器的值?它只是平淡无济。一些指令也完全改变了意义,因此系统确实需要对编译的代码“正确”,否则它将无法正常工作 - 幸运的是,如果不正确,Linux将检查这个并且明确拒绝。
您可以在64位系统上构建32位二进制文件(假设您已为64位和32位安装了所有正确的库等)。
同样,如果你试图在x86处理器上运行ARM代码,或者在ARM处理器上运行MIPS代码,它就没有机会工作,因为实际的指令是完全不同的(或者它们会违反某些专利) /版权或类似,因为几乎在所有情况下处理器指令集都包含“受保护的知识产权”部分 - 所以设计师必须确保他们不做“与其他人的设计相同”)。就像32位和64位一样,你根本就没有机会在这里运行错误的二进制文件,它只是不起作用。
有时,存在细微差别,例如ARM代码可以使用“硬”或“软”浮点编译。如果代码是为硬浮点编译的,并且OS中没有正确的支持,那么它将不会运行二进制文件。更糟糕的是,如果你在x86上编译SSE指令,并尝试在非SSE处理器上运行,代码就会崩溃[除非你专门构建代码来“检查SSE,如果不存在则显示错误”]。 / p>
因此,如果你有一个通过上述标准的二进制文件,Linux系统往往会在版本之间稍微改变一下,不同的发行版会有微妙的“修复”来改变事物。大多数情况下,这些都是完全良性的(它们修复了一些在测试过程中发现的一些模糊不清的角落案例,但一般的非角落案例行为是“正常的”)。但是,如果你从Linux 2.2版本升级到Linux版本3.15,那么两个版本之间会有一些实质性的差异,而旧版本的二进制文件很可能与新版本不兼容(而且几乎可以肯定是相反) - 很难确切知道哪些版本是不兼容的。在接近的版本中,只要您没有专门依赖仅存在于一个中的某些功能(毕竟,新内容不时添加到Linux内核中),它应该可以正常工作。答案是“也许”。
注意,上面也是你的C和C ++运行时的实现,所以如果你有一个使用Linux内核特性X的“新”C或C ++运行时库,并尝试在旧内核上运行它,之前功能X已实现(或在C或C ++运行时尝试使用它的情况下正常工作)。
静态链接确实是减少不同版本依赖性的好方法。这是让你的二进制文件变得庞大的好方法,这可能会阻止人们下载它。
使代码开源是解决此问题的更好方法,然后您只需分发源代码和“最低要求”列表,并让其他人处理它需要重新编译。
答案 1 :(得分:2)
在实践中,它取决于“足够简单”。如果您正在使用C ++ 11,您很快就会发现C ++ 11库依赖于现代libc版本。反过来,那些只发布现代Linux发行版。我不知道任何“长期支持”Linux发行版,今天(2014年6月)附带libc支持GCC 4.8
答案 2 :(得分:0)
简短的回答是否定的,至少没有严重的黑客攻击。
不同的Linux发行版在用户空间和内核之间可能有不同的粘合代码。对于即时,似乎没有从ubuntu构建的依赖的hello世界不能在CentOS下执行。
编辑:感谢您的评论。我重新验证了这一点,原因是使用32位VM。很抱歉引起混淆。但是,如上所述,经验法则是,即使是相同的Linux发行版也可能有时会破坏兼容性以便部署bugfix,所以结论就是这样。