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 avai开发者_JAVA百科lable 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?
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 of foo
you have on the machine you build on (for example, libfoo.so.5
) is hardcoded into the binary. When it's run on machine B
, it may only contain libfoo.so.4
, and the binary will refuse to run because it needs the missing libfoo.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.
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.
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.
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).
精彩评论