ali

Distributing Linux binaries

In Uncategorized on July 21, 2010 at 7:26 pm

In this post I will talk about how to distribute binary applications on Linux. My target is to describe how to distribute a binary that will run on as many distributions as possible, without relying on a package manager such as RPM.

Assumptions:

  • Compiling on Linux for x86 or x86-64
  • Not using processor specific instructions
  • Not using any "special" kernel services
  • Targeting a "close enough" C library1

Instruction Set

Make sure to compile with a specific -march and perhaps -mfpmath option.

Kernel

The C library you’re using will depend on a specific kernel version, or hopefully a kernel family.

A major change in the kernel (such as the switch from LinuxThreads to NPTL) will break your application.

You can find out the kernel ABI you’re linking against2:

$ eu-readelf -n /lib/libc-2.3.2.so

Note segment of 32 bytes at offset 0x00000134:
  Owner          Data size  Type
  GNU                   16  VERSION
    OS: Linux, ABI: 2.2.5

Dynamic Libraries

You can either link statically, or distribute the shared libraries along your tools.

Reasons for distributing shared libraries:

  • Some times a library’s license will prevent you from linking statically.
  • If you have many binaries, then by distributing shared libraries, you can save space.
  • If you have many binaries, then dynamic linking will make better use of memory.
  • You can update an application by updating the shared library.

Distributing Shared Libraries

Either rely on a package manager to make sure you have the right libraries, or distribute everything except the C library.

When distributing shared libraries, your application is usually laid out as follows:

Directory Purpose
app/ Top level application directory. This should contain a README, a LICENSE, and a ChangeLog.
app/bin/ Contains binaries.
app/lib/ Contains shared libraries.

Shell Scripts

For the executable appexe, you would create two files:

  1. app/bin/appexe.bin — The actual ELF executable.
  2. app/bin/appexe — A shell script that runs appexe.bin

The shell script will set the environment variable LD_LIBRARY_PATH before invoking the real executable.

Case Study: Chrome

Google’s Chrome is distributed on Linux using shared libraries and a shell script.

  • The file /usr/bin/google-chrome is a symlink to the shell script /opt/google/chrome/google-chrome.
  • The shell script invoke /opt/google/chrome/chrome

The chrome binary links against a lot of libraries, but includes only libffmpegsumo.so and libgcflashplayer.so. They distribute RPMs, and rely on the package manager to ensure that the right versions of libraries are installed.

The script:

  1. Figures out the executable name.
  2. Adds the parent directory (/opt/google/chrome) to $PATH
  3. Adds the parent directory to $LD_LIBRARY_PATH
  4. Exports some chrome-specific environment variables.
  5. Launches the chrome binary (exec -a "$0" "$PROGDIR/chrome" "$@").

Using RPATH

The ELF format allows each executable to specify a shared library directory.

You can use the $ORIGIN keyword3 instead of specifying the absolute path:

g++ -c -o main.o main.cpp
g++ -Wl,--rpath=\$ORIGIN/../lib -z origin -o main main.o

This way, if your executable is located in app/bin/, then the linker will look in app/lib/ for libraries.

apgcc

The apgcc tool is a wrapper around gcc. It use rpath (specifying $ORIGIN) and some other tricks to help you create portable applications.

Linking Statically

  • Be sure to use the -Bstatic option of the linker instead of using -static. This way, you select which libraries to link with statically.
  • Remember that you can’t statically link with LGPL’d libraries (such as glibc) without following some conditions4.
  • Remember that libstc++ is licensed under the GPL. However, there is an exception that allows static linking as long as you haven’t modified the toolchain5.
  • Some toolchains don’t provide a static version of libgcc_s.so.

1. glibc uses ELF symbol versioning. Still, it could be that you use a symbol that was added later on, and isn’t present in an older glibc. Or, your target system could be using a different C library!

2. Also see LD_ASSUME_KERNEL

3. For a discussion of rpath, see this page. For information on $ORIGIN, see this page or this page.

4. See terms of the LGPL.

5. See the libstdc++ license.

Advertisements
%d bloggers like this: