Packaging for dummies (1)
Packaging is one of the things I was trying to master several times. As always lack of condensed quick-start guides was putting me off. I do realize strict packaging rules exist for a reason but they're too complex to be thrown at beginners in introductory documents. That said I've finally shaved the yak and here's what you need to start packaging for Debian.
Case study
Packaging is important for several reasons I hopefully don't have to explain:
- it makes installing software easier for end users
- it enables dedicated software do the job of resolving and satisfying dependencies
- it is easier to record changes made by package and revert it
We'll focus on building package for Mongrel 2, which at the moment of writing is officially distributed only as a tarball. The process of manual building is rather simple thus well suited as an example.
Introduction to DEB packages
There are two types of packages:
- binary
Consists of a single file with .deb
extension and specific format that contains our software binaries, docs, etc. along with some metadata and install hooks.
- source
Consists of three files: package metadata in .dsc
, .orig.tar.gz
tarball with original software source and .diff.gz
that contains Debian-specific changes to original source
In the following process will also see some metadata and control files:
debian/control
-- serves as package metadata: lists dependencies, maintainer, description, etc.debian/rules
-- Makefile for building a packagedebian/changelog
-- changes between pacakges releasesdebian/patches/series
-- list of patches to be applied on original source treedebian/copyright
-- licensing information
One short note on package versioning rules:
package_version-revision_arch
This means our upstream mongrel2-1.7.5
becomes mongrel2_1.7.5-1_amd64
on 64-bit system. Given it's our first package revision, which clearly makes sense for the first package.
Building package
To assists with building, Debian community released several tools referred as packaging helpers. If you're starting a new package like here, just use dh. I assume you have a Debian or Ubuntu box, if not grab one with Vagrant.
Let's start with initial environment setup:
apt-get install build-essential debhelper dh-make
cat >> ~/.bashrc <<EOF
DEBEMAIL="your.email.address@example.org"
DEBFULLNAME="Firstname Lastname"
export DEBEMAIL DEBFULLNAME
EOF
. ~/.bashrc
Get a source tarball and convert it to Debian format, BSD licensed, single binary (single .deb) using helper:
mkdir mongrel2
cd mongrel2/
wget http://mongrel2.org/static/downloads/mongrel2-1.7.5.tar.bz2
tar -jxvf mongrel2-1.7.5.tar.bz2
cd mongrel2-1.7.5/
dh_make -c bsd -s -f ../mongrel2-1.7.5.tar.bz2
This produces ../mongrel2_1.7.5.orig.tar.bz2
(slightly renamed original source) and debian/
directory with metadata and control files mentioned above. Let's remove stuff we're not interested much in scope of this tutorial:
rm debian/*{.ex,.EX} debian/README.*
Let's start working with generated debian/control
:
#!control
Source: mongrel2
Section: unknown
Priority: extra
Maintainer: Firstname Lastname <your.email.address@example.org>
Build-Depends: debhelper (>= 8.0.0)
Standards-Version: 3.9.2
Homepage: <insert the upstream URL, if relevant>
Package: mongrel2
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: <insert up to 60 chars description>
<insert long description, indented with spaces>
You can find explanations of each of the these field in policy manual, but for now just fill in Homepage
, Description
. Most importantly we'll have to specify build and runtime dependencies (names of required packages from Debian repositories, optionally with versions). Finally we can edit Section
to assign our package to one of the sections and change Priority
to optional.
Target debian/control
may look like this:
#!control
Source: mongrel2
Section: httpd
Priority: optional
Maintainer: Firstname Lastname <your.email.address@example.org>
Build-Depends: debhelper (>= 8.0.0), sqlite3, libzmq1, libzmq-dev, libsqlite3-dev
Standards-Version: 3.9.2
Homepage: http://mongrel2.org
Package: mongrel2
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}, sqlite3, libzmq1
Description: Application, language and network architecture agnostic web server.
Mongrel2 is an application, language, and network architecture agnostic web
server that focuses on web applications using modern browser technologies.
It supports 17 languages and platforms, HTTP, Flash sockets, WebSockets,
Long Polling and many ways to deploy and hack on it.
Next we have to adjust debian/rules
which is responsible for building our software. By default it has following contents:
#!makefile
#!/usr/bin/make -f
%:
dh $@
If we wanted to build software that used autotools
we could have left it untouched. This tarball however ships with simpler build procedure that can be expressed in the following commands:
make all
make install
Fortunately dh
allows us to override it's hooks. Resulting debian/rules
looks like this:
#!makefile
#!/usr/bin/make -f
%:
dh $@
override_dh_auto_configure:
override_dh_auto_build:
$(MAKE) all
override_dh_auto_clean:
$(MAKE) clean
The process of building has some more restrictions though:
Makefile
must follow GNU conventions and support the$(DESTDIR)
variable- source must follow the Filesystem Hierarchy Standard
Mongrel's Makefile
violates second rule by installing it's binaries into /usr/local
. We have to fix this by recording our first patch. First fix the offending line then call another helper which compares modifications to original source:
sed -e 's/PREFIX?=\/usr\/local/PREFIX?=\/usr/' -i Makefile
dpkg-source --commit
Name a patch and provide relevant description of changes. In my case patchfile debian/patches/fhs_prefix.patch
was created with following contents:
#!diff
--- mongrel2-1.7.5.orig/Makefile
+++ mongrel2-1.7.5/Makefile
@@ -1,6 +1,6 @@ CFLAGS=-g -O2 -Wall -Wextra -Isrc -pthread -rdynamic -DNDEBUG $(OPTFLAGS) -D_FILE_OFFSET_BITS=64 LIBS=-lzmq -ldl -lsqlite3 $(OPTLIBS)
-PREFIX?=/usr/local
+PREFIX?=/usr
get_objs = $(addsuffix .o,$(basename $(wildcard $(1))))
You can verify that this patch is present in debian/patches/series
as a candidate for application.
Rest of files is easy to modify therefore I'll present only the final versions.
Final debian/changelog
:
mongrel2 (1.7.5-1) unstable; urgency=low
* Initial release
-- Firstname Lastname <your.email.address@example.org> Fri, 03 Aug 2012 12:52:05 +0000
Final debian/copyright
:
#!control
Format: http://dep.debian.net/deps/dep5
Upstream-Name: mongrel2
Source: <url://mongrel2.org>
Files: *
Copyright: 2010 Zed A. Shaw and Mongrel2 Project Contributors
License: BSD-3-Clause
Files: debian/*
Copyright: 2012 Firstname Lastname <your.email.address@example.org>
License: BSD-3-Clause
License: BSD-3-Clause
Redistribution and use in source and binary forms, with or without (...)
Now it's time to build that damn (unsigned) package!
sudo apt-get install libsqlite3-dev libzmq-dev libsqlite3
dpkg-buildpackage -b -uc -us -rfakeroot
Congratulations! You can grab your package from ../mongrel2_1.7.5-1_amd64.deb
and happily start using it.
Updating package
Let's say after some time you find out that your package is missing important dependency. For example someone uninstalled uuid-runtime
used by m2sh
for generating UUIDs and package manager didn't protest.
In such situation you just fix package dependencies or whatever the mistake is and update changelog entry with revision bump. Next just restart build:
dch -i "Added missing uuid-runtime dependency"
dpkg-buildpackage -b -uc -us -rfakeroot
Your updated package is now at ../mongrel2_1.7.5-2_amd64.deb
.
Further reading
This was just a starter. It gives you a working package but it's just a tip of the iceberg. I urge you to at least skim through maintainer's guide. If you'd like to learn more on the topic of Debian packaging follow also the links below:
- FAQ on basics of the Debian package management system
- extensive tutorial with many practical examples and debhelpers roundup
- policy requirements for the Debian distribution
Packaging for Ubuntu doesn't differ on basic level from Debian. They have though a slightly different workflow built around Launchpad and Bazaar. You can read on this topic in their guide.
What's next?
In next episode we'll go through RPM build process. Happy packaging!