How to Compile on Linux to Share with All Distributions

How do I compile on linux to share with all distributions?

The statement: "ELF file OS ABI invalid", means that the Application Binary Interface is non compatible between binaries used (i.e. one is trying to mix host and target binaries, which may not work as expected). The e_ident[EI_OSABI] byte of the ELF header contains the operating system/ABI identification. Your Fedora system is setting this to ELFOSABI_LINUX (3) while your friend's CentOS system is setting it to ELFOSABI_SYSV (ELFOSABI_NONE or 0).

You may be able to compile the FreeBSD brandelf utility (brandelf.c) and use it to set the OSABI to ELFOSABI_SYSV (brandelf -f 0 <file> or brandelf -t SVR4 <file>.

I am not aware of any gcc flags for specifying this value at compile/link time. I believe that the version of binutils used by gcc on your Fedora system is responsible for setting the OSABI to Linux. It is my understanding that the linker only specifies the ABI if a STT_GNU_IFUNC symbol ends up in the output file (see ifunc.txt at http://groups.google.com/group/generic-abi for details on STT_GNU_IFUNC).


The readelf(1) command can be used to retrieve and display the ABI information stored in the ELF header (readelf -h <file>).


This similar question may also be of interest.

Compiling for many linux distributions

  • You can generally produce 64 and 32 bit binaries on a 64 bit machine with relative ease - i.e. the distribution usually has the proper support in its compiler packages and you can actually test your build. Note that the OS needs to be 64 bit too, not just the CPU.

  • Static binaries generally run everywhere, provided adequate support from the kernel and CPU - keep an eye on your compiler options to ensure this. They are your best bet for compatibility. Shared libraries can be an issue. To deal with this, binaries linked with shared libraries can be bundled with those libraries and run with a loader script if necessary.

  • You should at least target Debian/Ubuntu with dpkg packages, Redhad/Fedora/Mandriva with RPM and SUSE/OpenSUSE with RPM again (I mention these two RPM cases separately because you might need to produce separate packages for these "families" of distributions). You should also provide a .tar.bz2 or a .run installer for the rest.

  • You can have a look at the options provided by e.g. Oracle for Java and VirtualBox to see how they provide their software.

Compile C++ for all linux distributions

% gcc -o foo foo.c -static

the resulting binary should work on most distros, given that it runs on the same architecture (64bit, 32bit, arm, mips etc).

the main point is: since you do not know what can be found on the target systems in advance, you have to bundle everything you can into either the binary you are shipping or in some kind of "chrooted" environment where you deploy external libs as well (stuff that can't be linked statically) and then have some kind of a wrapper to use your deployed libs instead of the system libs.

Is it possible to compile a C/C++ source code that executes in all Linux distributions without recompilation?

No, you can't compile an executable the executes in all Linux distributions. However, you can compile an executable that works on most distributions that people will tend to care about.

  1. Compile 32-bit. Compile for the minimum CPU level you're willing to support.

  2. Build your own version of glibc. Use the --enable-kernel option to set the minimum kernel version you're willing to support.

  3. Compile all other libraries you plan to use yourself. Use the headers from your glibc build and your chosen CPU/compiler flags.

  4. Link statically.

  5. For anything you couldn't link to statically (for example, if you need access to the system's default name resolution or you need PAM), you have to design your own helper process and API. Release the source to the helper process and let them (or your installer) compile it.

  6. Test thoroughly on all the platforms you need to support.

You may need to tweak some libraries if they call functions that cannot work with this mechanism. That includes dlopen, gethostbyname, iconv_open, and so on. (These kinds of functions fundamentally rely on dynamic linking. See step 5 above. You will get a warning when you link for these.)

Also, time zones tend to break if you're not careful because your code may not understand the system's zone format or zone file locations. (You will get no warning for these. It just won't work.)

Most people who do this are building with the minimum supported CPU being a Pentium 4 and the minimum supported kernel version being 2.6.0.

Building linux binaries for multiple platforms

You may try to focus on a few major platforms rather than individual distributions. What I mean by that is to build on what I call the "foundational distros" (Debian and RedHat) and hope for the best on the others.

Most likely, Debian binaries (that are statically linked) will run just fine on Ubuntu and Mint and other Debian derived distributions. RedHat binaries will probably run on Centos, Scientific Linux and SuSE Linux. If you care about less popular distros (Say you have a lot of customers running some uncommon Linux), and neither your Debian or RedHat executable works on them or can be made to work somehow, then setup a VM of that distro and build one executable specifically for that flavor.

I've taken this approach in the past and it has worked well.

C++ Executable distribution strategy

You might give this technique a try.



Related Topics



Leave a reply



Submit