Rolling your own Debian packages (part 2)

Posted by bdf on Sat 21 Jan 2006 at 17:18

In the first part of this text, we introduced the principal concepts of Debian package building. We're now ready to build an example package of a simple command line program.

I picked svnyoungest, a small auxiliary program to report the latest revision of a Subversion repository. You can find the source tarball of svnyoungest here. To interface directly with the Subversion library, it is written in C, but you can package programs from any development environment.

The source code is provided with a Makefile (no configure script though) that accepts these standard targets: all (the default), clean, distclean and install.

Generating the debian subdir

The first step is to create a debian subdir with packaging information. Probably the easiest approach is to use dh_make to generate one from a standard template. The package providing this command is called dh-make (with hyphen, not underscore).

apt-get install dh-make 

dh_make requires the source directory to be named according to the common pattern packagename-version. So once we have the source available in svnyoungest-0.1, we can issue the dh_make command with appropriate options: -n indicates a native package (i.e. that is packaged by the original author), which is slightly simpler for demonstration purposes, -s indicates a single binary and -e sets the maintainer e-mail address to be used:

~/svnyoungest-0.1$ find .
.
./svnyoungest.1
./svnyoungest.c
./Makefile
./README
~/svnyoungest-0.1$ dh_make -n -s -e bruno@defraine.net
Maintainer name : Bruno De Fraine
Email-Address   : bruno@defraine.net 
Date            : Tue, 20 Dec 2005 10:28:12 +0100
Package Name    : svnyoungest
Version         : 0.1
License         : blank
Type of Package : Single
Hit  to confirm: 
Done. Please edit the files in the debian/ subdirectory now. You should also
check that the svnyoungest Makefiles install into $DESTDIR and not in / .
~/svnyoungest-0.1$ rm debian/*.ex debian/*.EX
~/svnyoungest-0.1$ find debian/
debian/
debian/changelog
debian/compat
debian/dirs
debian/README.Debian
debian/copyright
debian/control
debian/rules
debian/docs
debian/README
~/svnyoungest-0.1$ rm debian/README debian/README.Debian

Notice that the standard template used by dh_make contains a number of example files (extensions .ex or .EX). These files illustrate features for advanced packages (such as helper scripts, cron jobs, installation dialogs,...) and can be handy if your package needs them. In this case however, they would make the presentation needlessly complex, so I chose to remove them for the time being (they can easily be recreated by issuing dh_make with the -a switch). The template also provides a README and README.Debian file. I chose to delete both of them, respectively because my original source already contains a README document, and because I don't have additional Debian-specific remarks. This leaves us with an uncluttered debian subdir.

Editing control files

The first file to edit is probably the main debian/control file. The format and contents of this file should look familiar if you know the output of apt-cache show, and you can always find additional info in the deb-control(5) manpage. Note that the first and second parts refer to the source and binary packages respectively. In this case, it is straightforward to fill in the fields set up by the template:

Source: svnyoungest
Section: devel
Priority: optional
Maintainer: Bruno De Fraine 
Build-Depends: debhelper (>= 4.0.0), libapr0-dev, libsvn0-dev
Standards-Version: 3.6.1

Package: svnyoungest
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: report the youngest revision of a svn repository path
 svnyoungest is a small tool to report the youngest revision of a path in
 a Subversion (svn) repository. It is similar to ''svnlook youngest'', but
 works on the client side.
 

Since the generated debian/rules file invokes a number of debhelper tools, dh_make already included a build dependency for them. As the svnyoungest program uses functionality from the APR and svn libraries, I added their development packages. Other than that, I only had to provide a description text for the package.

Notice that there is no version number in the control file. This is because it can be extracted from another mandatory file: debian/changelog. This file contains an entry for each released version and is later installed as /usr/share/doc/packagename/changelog.Debian.gz. dh_make did already set up debian/changelog to document the initial release, so we don't need to edit it now. If you need to update it for a subsequent releases, I recommend using the debchange helper (also from the devscripts package), since the file format is rather stringent.

A third mandatory file is debian/copyright. Its format is not stipulated, but it should contain the license restrictions under which the software is distributed. It is installed with the documentation of the package. In this example, I just copy the license section from the README file.

Editing the debian/rules script

Once we have the control data in place, it is the easiest to take a trial-and-error approach. dh_make already generated a debian/rules file for us, and before we edit anything, we try if it responds as expected to the standard targets:

~/svnyoungest-0.1$ fakeroot debian/rules clean
(... invokes make clean; no errors ...)

Although the target clean does not produce an error, there is a small mismatch to be aware of: in the underlying Makefile, a complete clean is referred to as distclean, not clean (the latter one only deletes intermediate files). So in this case, we need to invoke make distclean. This can be easily corrected by changing the actions of the clean target in debian/rules:

        # Add here commands to clean up after the build process.
        -$(MAKE) distclean

We can then rerun the clean target and try the other consecutive targets:

~/svnyoungest-0.1$ fakeroot debian/rules clean
(... invokes make distclean; no errors ...)
~/svnyoungest-0.1$ debian/rules build
(... invokes make; no errors ...)
~/svnyoungest-0.1$ fakeroot debian/rules binary
(... invokes make install ...)
install: cannot create regular file `/usr/local/bin/svnyoungest': Permission denied
(...)

We notice that there is an error during the binary target: the underlying make install tries to install to /usr/local instead of the temporary directory where we build the installation tree. It is not difficult to see why: debian/rules passes in this path as the DESTDIR variable, whereas the Makefile expects a variable PREFIX. Here's how we correct the relevant part of the binary target in debian/rules:

    # Add here commands to install the package into debian/svnyoungest.
    $(MAKE) install PREFIX=$(CURDIR)/debian/svnyoungest/usr

We then retry building the binary package. After this succeeds, we can check the generated installation tree in the temporary directory (created by default under debian/packagename).

~/svnyoungest-0.1$ fakeroot debian/rules binary
(... invokes make install; no errors ...)
~/svnyoungest-0.1$ find debian/svnyoungest
debian/svnyoungest
debian/svnyoungest/usr
debian/svnyoungest/usr/bin
debian/svnyoungest/usr/bin/svnyoungest
debian/svnyoungest/usr/sbin
debian/svnyoungest/usr/man
debian/svnyoungest/usr/man/man1
debian/svnyoungest/usr/man/man1/svnyoungest.1.gz
debian/svnyoungest/usr/share
debian/svnyoungest/usr/share/doc
debian/svnyoungest/usr/share/doc/svnyoungest
debian/svnyoungest/usr/share/doc/svnyoungest/README
debian/svnyoungest/usr/share/doc/svnyoungest/copyright
debian/svnyoungest/usr/share/doc/svnyoungest/changelog.gz
debian/svnyoungest/DEBIAN
debian/svnyoungest/DEBIAN/md5sums
debian/svnyoungest/DEBIAN/control
~/svnyoungest-0.1$ cat debian/svnyoungest/DEBIAN/control      
Package: svnyoungest
Version: 0.1
Section: devel
Priority: optional
Architecture: i386
Depends: libapr0 (>= 2.0.54), libc6 (>= 2.3.2.ds1-21), libsvn0 (>= 1.1.4-2)
Installed-Size: 64
Maintainer: Bruno De Fraine 
Description: report the youngest revision of a svn repository path
 svnyoungest is a small tool to report the youngest revision of a path in
 a Subversion (svn) repository. It is similar to ''svnlook youngest'', but
 works on the client side.

This seems OK. Notice that the documentation is installed under the right location by the tools from debhelper. If something was omitted, we could have checked the debian/docs file and the dh_installdocs(1) manpage to see how to fix it. Similarly, we notice that the dependencies of the binary package have been provided by dh_shlibdeps.

Validating the package

We proceed by trying a complete debuild run. This will also run a package validator to verify the newly created package. We pass in the options -us -uc to turn off the package signing step.

~/svnyoungest-0.1$ debuild -us -uc
(... regular build output ...)
Now running lintian...
E: svnyoungest: FSSTND-dir-in-usr usr/man/
Finished running lintian.

Apparently, something is blatantly wrong with our package, because the package checker lintian reports an error. This normally signifies a violation of the Debian Policy, and we can find more info at the lintian website. A quick investigation of the policy reveals that the manpages should go into /usr/share/man instead of /usr/man. Of course, this error was quite obvious to advanced packagers, but I wanted to demonstrate the importance of validating a package. The mistake can be corrected in debian/rules, by passing in a special MANDIR value:

DESTDIR=$(CURDIR)/debian/svnyoungest

...

    # Add here commands to install the package into $(DESTDIR).
    $(MAKE) install PREFIX=$(DESTDIR)/usr MANDIR=$(DESTDIR)/usr/share/man

If we then re-invoke debuild, we notice that the package now passes the lintian check. We finally obtain the desired Debian package, both in source and binary form:

~/svnyoungest-0.1$ debuild -us -uc
(... regular build output ...)
Now running lintian...
Finished running lintian.
~/svnyoungest-0.1$ ls ../svnyoungest_0.1.*
../svnyoungest_0.1.dsc  ../svnyoungest_0.1.tar.gz
~/svnyoungest-0.1$ ls ../svnyoungest_0.1_i386.*
../svnyoungest_0.1_i386.build    ../svnyoungest_0.1_i386.deb
../svnyoungest_0.1_i386.changes

The resulting .deb file can be installed using dpkg -i.

Further Reading

More comprehensive information about creating Debian packages is available in the Debian New Maintainers' Guide and the Debian Developer's Reference.

If you would like to make your own .deb files downloadable by apt-get, check this article or this low-tech solution.

More advanced testing of packages can be done using pbuilder. Finally, this article describes how to integrate non-Debian packages with the standard reportbug tool.

 

 


Posted by tong (64.231.xx.xx) on Sun 22 Jan 2006 at 20:28
[ Send Message | View Weblogs ]
Nice article. Just a quick note, Building binary package can be much simpler than this, if you don't want to get into above details of preparing for a source package. A merely "checkinstall -D" would be enough for you to enjoy the beauty of Debian packaging system.


tong

[ Parent | Reply to this comment ]

Posted by Steve (82.41.xx.xx) on Sun 22 Jan 2006 at 21:13
[ Send Message | View Steve's Scratchpad | View Weblogs ]

We've covered checkinstall previously...

This guide is aimed more at people who want to understand the process, and do more complex things.

Steve

[ Parent | Reply to this comment ]

Posted by bdf (134.184.xx.xx) on Mon 23 Jan 2006 at 10:31
[ Send Message ]
checkinstall -D is great and very fast, but sometimes limited too: e.g. I don't think you can specify package dependencies. I tend to use checkinstall when I install external software that's not in Debian, mainly to have a uniform uninstall option with minimal effort. I only use those packages on my own system though. I think there are some cases where it's worth the (limited) extra trouble of creating a 'real' package:
  • you plan on distributing the packages
  • you package software you've written yourself
  • advanced options: e.g. when the program is a daemon

[ Parent | Reply to this comment ]

Posted by Anonymous (57.67.xx.xx) on Mon 23 Jan 2006 at 11:33
Hello bdf,

Very nice ;-)

I would just like to ask you if you know some reading to me to build a pkg ala glibc: i.e. including the tarball's src into the debian src tree + eventual patches in debian/patches + their list debian/patches/00list.

What should I change (i presume a few) to explode the tarball into some src tree, apply local patch, the rest should follow your advises?

TIA,
Joel

[ Parent | Reply to this comment ]

Posted by bdf (134.184.xx.xx) on Mon 23 Jan 2006 at 11:48
[ Send Message ]
Dear Joel,

I think you're talking about dpatch. This offers a clean way to store the debian-specific changes outside of the original source tree (so you can better follow upstream changes). I considered it too advanced for this tutorial where I focus on packaging your own software (and I don't know dpatch well enough myself, actually ;-).

Some pointers are the dpatch(1) manpage and the relevant sections in the Debian documentation like 1, 2 and 3.

Bye,
Bruno

[ Parent | Reply to this comment ]

Posted by Anonymous (57.67.xx.xx) on Mon 23 Jan 2006 at 17:31
Hello Bruno,

... I think you're talking about dpatch ...

No clue, but good starting point ;-)

... I focus on packaging your own software ...

oops, i understand it in a too generic way; but I trust I could follow same rules from src coming from outside ;)

... Some pointers are the dpatch(1) manpage ...

Ok i will start by this points.

Tx for your attention,
Joel

[ Parent | Reply to this comment ]

Posted by Anonymous (200.68.xx.xx) on Wed 14 Jun 2006 at 01:06
Hi, i am intrested in a kind of part3 of this, explaining the conffiles. I think it could be really usufull :)

[ Parent | Reply to this comment ]

Posted by AndreMoraes (161.148.xx.xx) on Wed 12 Jul 2006 at 12:49
[ Send Message ]
Hi Bruno, I'm running a brazilian portuguese site about Linux and FOSS and I'm a Kubuntu user and want ask you for permission to translate your articles on my website (http://www.linuxdailylog.com/). Is it possible? Thanks for great articles. André

[ Parent | Reply to this comment ]

Posted by Anonymous (67.49.xx.xx) on Mon 14 Aug 2006 at 05:05
Great article.

I'm a Debian newbie, and I just used the steps in this article to create a Debian package for the latest version of the newsreader Pan (version 0.107), which I then installed. This article was very helpful to me, and I'll probably use the same procedure to install a couple of other things from source in the near future.

The only glitch was I got several "segmentation fault" errors while I was trying to build the package, especially after running "debian/rules build" and then "debuild -us -uc". The weird thing was that these seg. fault errors always occurred at different steps, never in the same place twice. (By the way, this is a 233 MHz machine, very slow.) I ran a google search on this problem and found that excessive seg. fault errors are sometimes caused by hardware problems. I thought, "Hardware problem? Like maybe a slow-as-hell CPU getting over-worked by a long compile, and overheating and giving random errors?"

Anyway, during the "build" step, every time I got a seg. fault error, I just repeated "debian/rules build". This seemed to work OK, as every time I ran it again, the "build" command seemed to pick up where it got interrupted the previous time, and then ran normally. I had to repeat this "build" command 4 or 5 times, and it finally completed.

Running "debuild -us -uc" was trickier, because every time it got interrupted by a seg. fault, the next time I ran it, it would start again from the beginning. There was just no way it would ever complete, so I tried something different. I use conky to monitor my system here. I would start running debuild, and then watch conky's load meter and also watch conky's list of CPU-intensive jobs (with PIDs). After about 5 or 10 minutes of the CPU at full load, I would go into another xterm, and run a "kill -s STOP" on the PID that debuild was running. That suspended the debuild for a while, gave my CPU a break (and hopefully cooled it off), and I would wait another 10 or 15 minutes or so, and then run a "kill -s CONT" on the same PID, to get debuild to resume. I repeated this process, I don't know, 10 or 15 times. This took a few hours (I was watching the 1983 "Scarface" while I was doing this; excellent flick to accompany linux-admin activities, haha). Doing it this way, I avoided all errors, and I eventually got a package that I was able to sucessfully install. Pan itself runs with no problems now. I just got done configuring Pan a few minutes ago.

Thanks again! I am also grateful to Debian for dumbing their OS down enough that dumb yokels like me are able to get by on it. I'm liking it more and more all the time. Just wait till I install it on a REAL machine!

LONG LIVE DEBIAN GNU/LINUX AND PACINO/DE PALMA/STONE!!!

[ Parent | Reply to this comment ]

Posted by Anonymous (118.96.xx.xx) on Fri 11 Jun 2010 at 18:25
Thank you, that is what i need.

[ Parent | Reply to this comment ]

Posted by Anonymous (91.75.xx.xx) on Mon 21 Nov 2011 at 16:18
I have a question about building Debian packages:

During the installation, I would like the package to check for available diskspace and only proceed if there is enough space. I would like this to happen during re-install as well.

I tried adding bash code to do the check in prerm file with exit 1 if the check fails, but the installer went ahead and ran the remaining files(preinst,postinst etc) and I ended up with a broke installation!

Thanks.

[ Parent | Reply to this comment ]

Posted by Anonymous (72.211.xx.xx) on Sat 25 Feb 2012 at 01:05
Thanks for this excellent guide!

Newer dh_make produces a bare-bones debian/rules file. In order to fix up the rules file for recent versions, append something like this instead of what was given above (note that this doesn't fix up the distclean target):

override_dh_auto_install:
dh_auto_install -- PREFIX=$(CURDIR)/debian/svnyoungest/usr MANDIR=$(CURDIR)/debian/svnyoungest/usr/share/man

For more information: www.debian.org/doc/manuals/maint-guide/dreq.en.html#customrules

[ Parent | Reply to this comment ]

Sign In

Username:

Password:

[Register|Advanced]

 

Flattr

 

Current Poll

Which init system are you using in Debian?






( 1637 votes ~ 7 comments )

 

 

Related Links