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.

2008-05-02

Emacs is a text editor

[ Context: Steve Yegge wrote a blog post about why XEmacs should role over and die. While I agree with his main point, I disagree about his vision of the future for Emacs. ]

I know it is controversial point of view, but see it this way: Emacs is really a lousy OS with only cooperative multitasking. And as a platform, Emacs is a joke compared to the Common Lisp environments. However, as a text editor it is brilliant. And the brilliance doesn't mean it is better editor for a specific kind of text (say programming) than any more specialized editor (say a specialized IDE). The brilliance is that it treats everything as text, and gives a uniform interface to editing (or browsing) the various kind of text. When Emacs is best, it conforms to a matrix similar to the major modes (one for each kind of text) and the minor modes (one for each functionality), where the functionality is adapted to each kind of text.

This view of Emacs, as an application rather than as a platform, is why I say: Please don't add multi-language support to Emacs.. Yes, people like to write applications in their preferred language. But people shouldn't write applications in Emacs. They should extend Emacs. To extend something, you have to read and understand the existing code.

Today, if I encounter a bug or "missing feature" in Emacs, I have to know one, or at most two, languages to fix it. Emacs Lisp in most cases, perhaps C if it is something more fundamental.

During the time I have used Emacs the "cool extension language" have switched between APL, Snobol, Icon, Rexx, Awk, Turing, Perl, Tcl, Python, Java, JavaScript, PHP, Ruby, and more. Had Emacs been multi-lingual, there would have been packages contributed in all of these languages. Adding a new row or column to the matrix of functionality would mean knowing how to play nice with code in all of these languages, and likely debug it as well.

In practice, it would likely mean that I'd have the choice between using the Python based LaTeX mode with one set of functionality, or the Perl based LaTeX mode with another set of functionality, because the programmers had different preferences. Yes, there can be multiple packages with similar functionality all written in Emacs Lisp as well. I know, when I maintained AUCTeX, I stole liberally code from Vortex and CMUTeX whenever users suggested features from those packages. All being written in Emacs Lisp and distributed under the GPL made it easy.

Lisp is a good choice for an extension language for a long lived application mostly because of its age and lack of syntax. The lack of syntax means less to learn, and also mean that whatever its popularity elsewhere, it will always have a niche in computer science research.

If you want to make Emacs more OS like, I'd much prefer true multitasking.