在 Linux 中为所有 x86 机器创建通用二进制文件
我正在尝试编译一个开源项目的二进制文件,以便我们的用户不必自己编译它。
我注意到在一台 32 位 ubuntu 计算机“A”上创建的一些二进制文件无法在 32 位计算机“B”上运行,并报告了有关缺少 .so 文件的错误。
但是,如果我在机器“B”上从头开始编译,那么所有错误都会消失。
在目标机器上编译代码是否有任何原因可以使这些错误消失?我只运行了“./configure”和“make”,而不是“make-install”,所以这不像我让这些 .so 文件全局可用。
编译器是否检测到系统库中缺少 .so 文件,并在这种情况下将静态库链接到可执行文件中?
Ubuntu 如何编译其软件包以便 i386 软件包在所有 x86 机器上运行?
Im trying to compile a binary of an open-source project so that our users do not have to compile it themselves.
I've noticed that some binaries created on one 32-bit ubuntu machine "A" don't work on 32-bit machine "B", with errors regarding missing .so files being reported.
However, if I compile from scratch on machine "B", then all the errors are gone.
Could there be any reason why compiling the code on the target machine makes these errors go away? I only ran "./configure" and "make" - not "make-install", So its not like I made these .so files available globally.
Could it be that the compiler detects there are .so files missing from the system library and in this case links a static library into the executable?
How does Ubuntu compile its packages so that an i386 package runs on all x86 machines?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我想这个问题被称为“二进制兼容性”(堆栈溢出上有一个标签专门针对这些问题)。当您在一台机器上链接二进制文件时,周围的环境会影响该二进制文件,并且在另一台机器上运行后,它仍然会尝试找到与其编译时相似的环境。
在这种情况下,对不同环境的容忍称为二进制兼容性。
它是如何工作的?
这里的关键点是,即使您在不同机器上为链接器指定相同选项,您仍然可能会得到不同 > 二进制文件。例如,如果您使用
-lfoo
将二进制文件链接到共享库,则您构建的计算机上的foo
的确切版本(例如,libfoo.so.5
)被硬编码到二进制文件中。当它在机器B
上运行时,它可能只包含libfoo.so.4
,并且二进制文件将拒绝运行,因为它需要缺少libfoo.so。 5.so文件。这就是为什么重新编译有用,没有它就不起作用。
Ubuntu 软件包(以及任何其他发行版的软件包)全部在(彼此)相同的环境中编译。这就是为什么它们安装得很好。发行商注意到每个下一个版本都与以前的版本向后兼容。
我应该做什么?
如果您想让您的软件与不同的发行版兼容,这比您想象的要容易。首先,尝试在尽可能最旧的发行版上编译您的应用程序。正如我之前提到的,由于现代发行版通常是向后兼容的,因此您的软件很可能在较新的发行版上运行而不会出现问题。
要更彻底地检查生成的包并获得有关兼容性的更多建议,您可以从我们的免费 Linux应用程序检查器工具。您可能还对打包 Linux 软件的通用技巧感兴趣。
I guess the issue is called "binary compatibility" (there's a tag on stack overflow devoted to these problems). When you link a binary on a machine, the surrounding environment affects the binary, and, having been run on another machine, it still tries to find the environment similar to the one it was compiled in.
Tolerance to different environments in this case is called binary compatibility.
How does it work?
The key point here is that, even if you specify the same options to linker on different machines, you may still get different binaries. For example, if you link your binary against a shared library with
-lfoo
, the exact version offoo
you have on the machine you build on (for example,libfoo.so.5
) is hardcoded into the binary. When it's run on machineB
, it may only containlibfoo.so.4
, and the binary will refuse to run because it needs the missinglibfoo.so.5
so file. That's why recompilation helps, and without it it doesn't work.Ubuntu packages—and these of any other distribution—are all compiled in the same environment (of each other). That's why they install well. And distribution vendors watch that each next version is backwards-compatible with previous ones.
What should I do?
If you want to make your software compatible with different distributions, it's easier than you thought. First, try to compile your application at the oldest distribution possible. Since, as I mentioned before, modern distributions are usually backwards compatible, your soft will, most likely, run on newer distros without problem.
To check the resultant package more thoroughly and get more advice about compatibility, you may from our free Linux Application Checker tool. You might also be interested in generic tips for packaging Linux soft.
如果您在一台机器上编译代码,那么在该机器上执行该程序时,您很可能不会收到任何有关缺少库的错误。在配置运行期间,检测到所有需要的库(这是配置、自动工具等存在的主要原因),并将适当的标志(例如 -lsomelib 和 -I/some/include/patch)写入 makefile 并传递给编译器和链接器。
如果您将该可执行文件复制到另一台机器,该机器的库可能版本错误或根本丢失,因此它可能无法运行。
配置脚本通常不会构建静态二进制文件,除非您明确告诉它这样做。
Ubuntu 软件包不会在所有 x86 机器上运行。但是包管理器会进行依赖项解析,以确保没有错误的库或缺少库,否则拒绝安装包。如果无论是否缺少依赖项都强制安装,您可能会再次遇到缺少库的相同问题。
如果您想确保您的包能够在任何计算机上运行,只需将其静态链接即可。
如果足以让它在特定发行版(例如Ubuntu)上运行,您可以自己创建一个包。这需要更多的努力。
If you compile code on a machine, you will most likely not get any errors regarding missing libs if you execute the program on this machine. During the configure run all needed libraries are detected (this is the main reason configure, autotools etc. exist) and appropriate flags, like -lsomelib and -I/some/include/patch are written to the makefile and passed to the compiler and linker.
I you copy that executable to another machine that machine may have the libs in a wrong version or missing at all, so it may not run.
The configure script will usually not build static binaries, unless you explicitly told it to do so.
Ubuntu packages will not run on all x86 machines. But the package manager does a dependency resolution to make sure there are no wrong libraries or libraries missing, and refuses to install a package otherwise. If you force the install regardless of missing dependencies you might run in the same problems with missing libs again.
If you want to make sure that your package is able to on any machine, just link it static.
If it is sufficient to have it run on a specific distro (e. g. Ubuntu), you can create a package by yourself. This requires some more effort.
您可以使用 Ermine 等项目来创建包含共享库的动态链接本机二进制文件的发行版。
除此之外,您可以静态编译代码。这需要您获取整个依赖关系树的源代码,对其进行编译,并在构建代码时引用这些已编译的二进制文件。您无法针对其他共享库(.so 文件)编译静态二进制文件。这可能是一个真正的痛苦,特别是如果您的依赖项有自己的依赖项。
You can use a project like Ermine to create distributions of dynamically linked native binaries with the shared libraries included.
Outside of that, you could compile your code static. This would require that you obtain the source code for your entire dependency tree, compile them, and reference those compiled binaries when you build your code. You cannot compile static binaries against other shared libraries (.so files). This can be a real pain, especially if your dependencies have their own dependencies.
您可以尝试使用相对路径作为库搜索路径(在 Windows 中由自 DOS 时代以来的标准)。将
$ORIGIN
标志与链接器一起使用。这个博客很好地描述了完整的方法 (存档版本)。
Instead of the error prone
LD_LIBRARY_PATH
approach (which also requires user interaction) or static linking (not always possible or prohibited by GPL) you can try to use a relative path as library search path (offered in windows by standard since DOS times). Use the$ORIGIN
flag with the linker.The complete approach is nicely described in this blog (archived version).