1. Overview
A Debian package is the simplest and most efficient way of distributing software in Debian-based distributions. It takes care of managing dependencies and provides a good interface for install/upgrade/uninstall operations.
The official way of creating a package involves a lot of steps and processes. In this tutorial, we’ll look at a simpler way of creating these packages. However, the official way of package creation is ideal and recommended for production purposes.
2. Preparing the Files
2.1. Structure of .deb Package
In Debian-based distributions, one of the ways we install applications is by downloading the .deb package file and using dpkg command to install it. This “deb package” is an archive of binaries and configuration files associated with a software application. All the files inside the archive are kept in a specific folder structure.
During installation, in the target machine, the binaries and configuration files go into a similar folder structure from the root folder.
2.2. Application Related Files
Let’s look at an example to understand more clearly. First, we create a working folder for the build:
bluelake@pacific:~/Documents/deb/build$ mkdir test
Please note the path – we’ll be changing the folder as and when we progress through this exercise.
Then, we prepare files for our application. To keep things simple, let’s have two files:
- test.sh executable
- test.conf configuration file
For these files, we’ll keep the contents as below for this exercise:
bluelake@pacific:~/Documents/deb/build/test$ cat test.conf
NAME=Test
bluelake@pacific:~/Documents/deb/build/test$ cat test.sh
#!/bin/bash
. test.conf
echo "Hi $NAME"
We know that the executable files in Debian are kept in the /bin folder and the configuration files in the /etc folder. Following the convention, we’ll keep the test.sh file in the /bin folder and test.conf in the /etc folder.
Hence, we create two folders, bin and etc, in our current directory:
bluelake@pacific:~/Documents/deb/build/test$ mkdir {bin,etc}
bluelake@pacific:~/Documents/deb/build/test$ ls
bin etc test.conf test.sh
Now, let’s move the executable and configuration files to their respective folders:
bluelake@pacific:~/Documents/deb/build/test$ mv test.conf etc/
bluelake@pacific:~/Documents/deb/build/test$ mv test.sh bin/
bluelake@pacific:~/Documents/deb/build/test$ ls
bin etc
With this, we’ve placed our files in a folder structure that would be the same once it’s installed in the target machine.
2.3. The control File
Finally, we need a control file that contains the metadata for the package. This is a text file with fields and descriptions. The supported fields are:
- Package (Required): Name of package
- Version (Required): Version of the package
- Maintainer (Required): Name and email of maintainer
- Architecture (Required): Supported target machine architecture
- Description (Required): Short description of the package
- Section: Package classification like admin, database, kernel, utils
- Priority: Whether the package is optional or required
- Essential: Whether the package is always required
- Depends: List other dependent packages like libc6 (>= 2.2.4-4)
- Homepage: URL of the website associated with the package
- Package-Type: Indicate the types, like deb or udeb, for example
As mentioned above, some fields are required and others are optional.
Using this information, let’s create a control file with the required fields and some of the recommended fields. This file goes under a folder named DEBIAN:
bluelake@pacific:~/Documents/deb/build/test$ ls
bin DEBIAN etc
bluelake@pacific:~/Documents/deb/build/test$ cat DEBIAN/control
Package: test
Version: 1.0-1
Section: utils
Priority: optional
Architecture: all
Maintainer: Baeldung <[email protected]>
Description: This is a test application
for packaging
3. Building the Package
With that, we’re ready to build our package. And for that, we can use the dpkg-deb command:
bluelake@pacific:~/Documents/deb/build$ dpkg-deb --root-owner-group --build test
dpkg-deb: building package 'test' in 'test.deb'.
bluelake@pacific:~/Documents/deb/build$ ls
test test.deb
As we can see, a test.deb file is created successfully. With that, we are almost ready with our package.
4. Verify the Package
4.1. Check Contents
Once the package is created, we can verify if the files are present in it by running the dpkg command:
bluelake@pacific:~/Documents/deb/build$ dpkg -c test.deb
drwxr-xr-x thinkpalm/thinkpalm 0 2021-12-23 12:09 ./
drwxr-xr-x thinkpalm/thinkpalm 0 2021-12-23 11:30 ./bin/
-rwxr-xr-x thinkpalm/thinkpalm 40 2021-12-23 11:15 ./bin/test.sh
drwxr-xr-x thinkpalm/thinkpalm 0 2021-12-23 11:30 ./etc/
-rw-r--r-- thinkpalm/thinkpalm 10 2021-12-23 11:15 ./etc/test.conf
From the results, we see that it contains the files we have added in their expected paths.
4.2. Linting
In order to further comply with the Debian packaging conventions, we can lint the package. For this, we use the tool called lintian.
Let’s see how we can use this tool:
bluelake@pacific:~/Documents/deb/build$ lintian test.deb
E: test: debian-changelog-file-missing
E: test: file-in-etc-not-marked-as-conffile etc/test.conf
E: test: no-copyright-file
W: test: script-with-language-extension bin/test.sh
W: test: binary-without-manpage bin/test.sh
After running the command, we can see some errors marked as E and warnings marked as W.
Let’s check how we can fix these, one by one.
Changelog File Missing:
To fix this error, we can add a changelog file:
bluelake@pacific:~/Documents/deb/build$ cat changelog.Debian
test (1.0-2) stable; urgency=low
[ Baeldung ]
* Changes to installer
-- Baeldung <[email protected]> Thu, 23 Dec 2021 11:30:00 +0100
test (1.0-1) stable; urgency=low
[ Baeldung ]
* Wonderful program to print the name ;)
-- Baeldung <[email protected]> Thu, 23 Dec 2021 11:00:00 +0100
bluelake@pacific:~/Documents/deb/build$ gzip --best -n changelog.Debian
bluelake@pacific:~/Documents/deb/build$ mkdir -p test/usr/share/doc/test
bluelake@pacific:~/Documents/deb/build$ cp changelog.Debian.gz test/usr/share/doc/test/
Marking File as Conf File:
In order to fix this error, we can add a conffile in the DEBIAN folder:
bluelake@pacific:~/Documents/deb/build$ cat test/DEBIAN/conffiles
/etc/test.conf
Adding Copyright File:
To fix this one, we can add a copyright file:
bluelake@pacific:~/Documents/deb/build$ cat test/usr/share/doc/test/copyright
test
Copyright: 2020 Baeldung <[email protected]>
2020-12-23
The entire code base may be distributed under the terms of the GNU General
Public License (GPL), which appears immediately below. Alternatively, all
of the source code as any code derived from that code may instead be
distributed under the GNU Lesser General Public License (LGPL), at the
choice of the distributor. The complete text of the LGPL appears at the
bottom of this file.
See /usr/share/common-licenses/(GPL|LGPL)
Removing Extension for Binary File:
Let’s remove the extension for the script file to fix this error:
bluelake@pacific:~/Documents/deb/build$ mv test/bin/test.sh test/bin/test
Adding Man Entry for Binary:
Let’s add a man file to fix this error:
bluelake@pacific:~/Documents/deb/build$ cat test.1
.\" Hey, EMACS: -*- nroff -*-
.\" (C) Copyright 2020 Baeldung <[email protected]>
.\"
.TH TEST 1
.SH NAME
test \- test application
.SH SYNOPSIS
.B test.sh
.SH DESCRIPTION
The
.B test
prints the name.
.SH SEE ALSO
.BR echo (1).
.SH AUTHORS
The
.B test
script was written by
Baeldung <[email protected]>
.PP
This document was written by Baeldung <[email protected]> for Debian.
bluelake@pacific:~/Documents/deb/build$ gzip --best -n test.1
bluelake@pacific:~/Documents/deb/build$ ls
build.sh changelog.Debian.gz changelog.gz test test_1.0-1.deb test.1.gz
bluelake@pacific:~/Documents/deb/build$ mkdir -p test/usr/share/man/man1
bluelake@pacific:~/Documents/deb/build$ cp test.1.gz test/usr/share/man/man1/
The final folder structure would be:
bluelake@pacific:~/Documents/deb/build$ tree test
test
├── bin
│ └── test
├── DEBIAN
│ ├── conffiles
│ └── control
├── etc
│ └── test.conf
└── usr
└── share
├── doc
│ └── test
│ ├── changelog.Debian.gz
│ └── copyright
└── man
└── man1
└── test.1.gz
9 directories, 7 files
Let’s build this again:
bluelake@pacific:~/Documents/deb/build$ dpkg-deb --root-owner-group --build test
dpkg-deb: building package 'test' in 'test.deb'.
bluelake@pacific:~/Documents/deb/build$ mv test.deb test_1.0-2.deb
bluelake@pacific:~/Documents/deb/build$ lintian test_1.0-2.deb
bluelake@pacific:~/Documents/deb/build$
Now, we can see all the errors and warnings are fixed.
5. Conclusion
In this tutorial, we went through the process of creating a deb package with minimum steps. We hope this will be a good starting point for learning to create Debian packages.