2016-03-10

Distribute a single executable as a .deb file

Distributing your Linux binary as a .deb file.

Say you have a binary build on a Debian based system (like Ubuntu) that you want to distribute directly to your users as a ".deb" file to be nice. Perhaps together with some support files. Can't be so hard, right?

Skip to the second section for the cookbook on how to do it.

Why is creating a .deb package so hard?

The good news is: Creating a .deb package is not so hard.

Say your executable is called 'daisy', it is build for amd64, the version is 5.23, your makefile may contain something like this:


rm -rf tmp
mkdir -p tmp/usr/bin
cp amd64/bin/daisy tmp/usr/bin
mkdir tmp/DEBIAN
cp control tmp/DEBIAN
fakeroot dpkg-deb --build tmp daisy_5.23_amd64.deb
You can put any support files needed under 'tmp/usr/share' or 'tmp/usr/lib', or maybe just everything under 'tmp/opt'. Check out the File Hierarchy Standard for what goes where.

The 'control' file is a simple text file, which might look like

Package: daisy
Version: 5.23
Architecture: amd64
Maintainer: Per Abrahamsen <per.abrahamsen@mail.invalid>
Installed-Size: 8000
Depends: libc6 (>= 2.14), libcxsparse3.1.2, libgcc1 (>= 1:4.1.1), libstdc++6 (>= 5.2)
Homepage: http://daisy.ku.dk
Description: Simulated plant production and environmental effects.
Automatically generating the Version field and the Installed-Size file is trivial (use du for the later).

The bad news is: Generating the Depends field is not easy.

'ldd' and 'readelf -d' can be used to generate a list of shared library dependencies, but how to translate them to Debian versions is not clear.

The good news is: There are tools for this.

'dh_shlibsdeps' and 'dpkg-shlibsdeps' specifically.

The bad news is: The tools are not stand alone.

If you try to google information about them you get into a maze of 'dh_make', upstream source tarballs, 'quilt', Debian Policies, source requirements, and Debians automated multi-architecture build system.

All great if you want to be a Debian maintainer, and prepare someones else software for inclusion into the Debian distribution.

Not so great if you just want to distribute your little program directly to non-technical users, without involving Debian at all. 

The good news is: Only a tiny part of all this is needed.

How to distribute your executable as a .deb file

First you need a directory 'debian' (not DEBIAN) with two files 'control' (related to, but different from DEBIAN/control) and 'changelog'. These names are hardcoded by the build tools. The content is static though, so I suggest you add them to your source repository. 

The content of 'debian/control':
Source: daisy
Priority: optional
Maintainer: Per Abrahamsen <per.abrahamsen@mail.invalid>
Homepage: http://daisy.ku.dk
Package: daisy
Architecture: amd64
Depends: ${shlibs:Depends}
Description: Simulated plant production and environmental effects.
Change 'daisy' to your program (or package) name as well as the Maintainer, Homepage, and Description fields. 

The way we are building the .deb file, the content of the 'debian/changelog' file doesn't matter, but the tools insist it exists and follow a very strict syntax, so just create it with the following content:

daisy (0.0) UNRELEASED; urgency=low
  * Dummy
 -- Foo Bar <Foo@Bar.invalid>  1 Jan 1970 00:00:00 +0000

The two tools are used for building the final 'DEBIAN/control' field by default assume all the files for the '.deb' package will be placed under 'debian/tmp' so we will do that as well. I.e. the generated control file will be 'debian/tmp/DEBIAN/control'.

We will use the following tools 'dpkg-shlibdeps', 'dpkg-gencontrol', 'fakeroot', and 'dpkg-deb'. Make sure to install them (with apt-get) before proceeding.

A sample Makefile rule for generating the '.deb' file can then be:
debian-setup:
@if [ "X$(TAG)" = "X" ]; then echo "*** No tag ***"; exit 1; fi
rm -rf debian/tmp
mkdir -p debian/tmp/usr/bin
mkdir cp 
amd64/bin/daisy tmp/usr/bin
# cp any support files as well.
mkdir debian/tmp/DEBIAN
dpkg-shlibdeps debian/tmp/usr/bin/daisy
dpkg-gencontrol -USource -UPriority -v$(TAG)
(cd debian && fakeroot dpkg-deb --build tmp daisy_$(TAG)_amd64.deb)
invoked like 'make debian-setup TAG=5.23'.

Some details about the four programs:
  • 'dpkg-shlibdeps' generates 'debian/substvars' conatining the dependencies we want.
  • 'dpkg-gencontrol' merges 'debian/control' and 'debian/substvars' into 'debian/tmp/DEBIAN/control'.
  • 'fakeroot' pretends all files are owned by root, avoids a warning when the user installs the package.
  • 'dpkg-deb' actually builds the final file.

No comments: