TL;DR
This post will walk you through creating a debian package from a simple hello world C program using debuild
.
Setup
On a debian-based system, install the following programs:
$ sudo apt-get install devscripts build-essential lintian
The debuild
tool
debuild is a convenient wrapper around dpkg-buildpackage, fakeroot, lintian, and debsign. It handles all the packaging linting, and signing for us. Let’s use it to package a simple “helloworld” program.
Our “Hello World” program
It consists of the source file main.c
:
#include <stdio.h>
int main (int argc, char *argv[]) {
printf("Hi\n");
return 0;
}
And a Makefile
:
helloworld:
gcc main.c -o helloworld
install: helloworld
install -m 0755 helloworld /usr/local/bin
Building and Testing
Let’s make sure everything works before we package it up.
Run make
to build the program. This should create a helloworld
binary you can execute by running ./helloworld
.
You should see “Hi” printed to the screen.
Then, try installing the binary: run sudo make install
and now helloworld
should be in /usr/local/bin
.
Remove our test binary before continuing:
$ sudo rm -rf /usr/local/bin/helloworld
Packaging our program
Note: debuild
will make use of symlinks in it’s build process, so if you are using a Virtualbox or VMware Shared folder to build your package, it will not work.
Now that we’ve verified everything works, let’s create a debian package for it:
1. Create a debian/
folder
This is where all of our debian specific packaging files will go.
2. Create a debian/control
file
This file describes your package using debian control fields. Below we have defined a binary package and a corresponding source package (from which the binary package can be repackaged):
Source: helloworld
Maintainer: Julio Capote <julio@packagecloud.io>
Build-Depends: debhelper (>= 8.0.0)
Standards-Version: 3.9.3
Section: utils
Package: helloworld
Priority: extra
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: a simple helloworld package
Just prints "Hi", it's very useful.
3. Create a debian/changelog
file
This file tracks all the changes to the package. You need a minimum of one entry to build a package.
The syntax of this file is tricky, so while you can create this file by hand, it’s recommended to use the debchange tool, or dch
.
To initially create the changelog, type:
$ dch -i --create
This will bring up your $EDITOR
and let you edit the fields. Make sure you change UNRELEASED
to unstable
. Check out the dch
man page and the debian changelog policy for more details.
helloworld (0.0.1) unstable; urgency=low
* Initial release.
-- Julio Capote <julio@packagecloud.io> Sun, 07 Jun 2015 22:07:56 -0700
4. Create a debian/rules
file
This file tells debian specifically how to build your package. The most basic implementation just passes all calls to the original Makefile
created above:
Note: Make sure you use hard tabs here, since it uses the same format as Makefile
#!/usr/bin/make -f
%:
dh $@
5. Create a debian/copyright
file
To pass lintian, you need a copyright file (however, it can be blank). Ours can be very simple:
Copyright 2015, Computology LLC.
6. Run debuild
to build your package.
$ debuild -us -uc
Error!
If you were following along, you’ll notice the package doesn’t build and returns the following error:
install: cannot create regular file `/usr/local/bin/helloworld': Permission denied
This is because debuild
ran make install
and failed because it did not have permissions to write to /usr/local/bin/
(hardcoded in our Makefile
above).
As you can imagine, most software will not package cleanly out of the box for reasons like the above. In such cases, a more specific debian/rules
file will be needed. Let’s override the install
directive of our Makefile
during packaging in our debian/rules
file:
#!/usr/bin/make -f
%:
dh $@
override_dh_auto_install:
install -D -m 0755 helloworld $$(pwd)/debian/helloworld/usr/local/bin/helloworld
Now run debuild -us -uc
again and the package should build successfully. To see your built package, navigate backwards into the parent directory of the source folder. You should see:
helloworld_0.0.1_amd64.build # build log file
helloworld_0.0.1_amd64.changes # changelog and checksums
helloworld_0.0.1_amd64.deb # binary package
helloworld_0.0.1.dsc # source package
helloworld_0.0.1.tar.gz # original source directory
Sign your package with GPG and debsign
Refer to our other post on this topic: GPG signing debian packages with debsign.
Conclusion
Creating debian packages gives you full control over how a program is compiled and the specific version being packaged. Uploading those packages to packagecloud lets you easily distribute them to all of your machines, exactly how you built it.