A Minimum Complete Example of Debian Packaging and Launchpad PPA: hellodeb

April 24, 2022

There are many sites explaining how to create debian packages, but it seems to me none or only a few of them explains it at the very basic level.

The companion project of this post is hellodeb@github. I will explain how to generate the source package, architecture specific binary packages and an architecture independent binary package. Additionally, I will briefly mention uploading the source package to a launchpad PPA.

This post does not cover everything but it shows a minimum complete example, a hello world for Debian packaging, hellodeb. It does not use anything other than the basic tools provided in dpkg-dev package, particularly it neither uses dh_make nor debuild.

The main reference for this post is Debian Policy Manual, and the other sources are the manual pages of the tools used.

I am using Ubuntu 20.04 for this post, and as you know, Ubuntu also uses Debian packaging.

hellodeb

My example project hellodeb contains:

  • a C source file (hellodeb.c)
  • a manual page (hellodeb.1)

It also contains debian directory which includes the meta-data for packaging.

Additionally, there are a few bash scripts:

  • build-package.sh: runs dpkg-buildpackage with the provided build type (source, binary etc.) and other arguments which are directly passed to dpkg-buildpackage
  • build-source.sh: runs dpkg-source --build .
  • clean.sh: removes all generated files and returns the directory to initial state
  • test.sh: used to check the build in a CI, not used in this post

The reason I have these scripts is that before running the package build, they clean the directory, create a new build directory and copy the debian directory and source files there and runs dpkg-buildpackage and dpkg-source under that directory.

The files in hellodeb repository might have a slightly different content than what is shown in this post, because I fix or improve small issues while writing the post.

Debian Packages

There are two types of packages: source and binary.

Source packages are built from the original source code (e.g. of a program). Then the build rules file (a Makefile) is run which is expected to generate binary packages. This process is controlled with some additional (meta-data) files.

By the use of meta data, (maintainer) scripts and tools, Debian packaging handles the installation, removal and dependencies of packages.

There are different source package formats, and in this post 3.0 (quilt) is used. In this format, a source package contains three files:

  • original source, orig.tar.xz
  • debian source (meta-data), debian.tar.xz
  • source control, dsc

Binary package contains a single file:

  • debian binary package, deb

In addition to these files, there are two more files.

  • build record, buildinfo
  • upload control, changes

My understanding is that both the source and binary packages of a project are supposed to be built. Maybe it is possible and it sounds like it should be possible to build only one, but the tools assume you have the source code and you are going to build source package first and then the binary package(s) -the reason I say this might be more clear later-.

Multiple binary packages do not mean one binary package for each architecture (i386, amd64 etc.). Each binary package can consist of different things from the same source code such as the core or common files, documentation, examples etc. For example, all packages of tomcat9:

$ apt-cache search tomcat9 | cut -f1 -d' '

libtomcat9-embed-java
libtomcat9-java
tomcat9
tomcat9-admin
tomcat9-common
tomcat9-docs
tomcat9-examples
tomcat9-user

are built from the same source package called tomcat9. When you want to get the sources of, for example, tomcat9-admin, it redirects you to the correct source package:

$ apt source tomcat9-admin

Reading package lists... Done
Picking 'tomcat9' as source package instead of 'tomcat9-admin'

...<output continues>...

dpkg

Debian packaging tools, dpkg suite, are inter-connected. You can use dpkg with some options, which runs dpkg-deb to build a binary package. You can also use dpkg-buildpackage and let it execute various steps, run various tools in dpkg suite, depending on what you requested. On its manual page, there is a short summary of all the steps dpkg-buildpackage takes, it is a good reference. Also, dpkg-buildpackage is a Perl script like other similar tools in dpkg suite. You can look at the source code of these scripts when needed.

If you want to build only a source package, without any other files and without signing them, you can use dpkg-source directly, however in all other cases dpkg-buildpackage is the best choice, which also calls dpkg-source to build the source package.

dpkg comes with the base installation of Ubuntu, but you need to install dpkg-dev package to generate packages.

A (package) build triggered by dpkg-buildpackage can be one of the following (provided with --build option):

  • source: builds only the source package
  • any: builds architecture specific binary packages e.g. amd64
  • all: builds architecture independent binary packages e.g. documentation, pure Java or Python
  • binary: an alias for any and all, thus all possible binary packages
  • full: an alias for source and binary, thus all possible packages

The options any and all have also a meaning for Architecture (meta-data) of a package. any is used as a wildcard to mean any architecture the OS is supposed to run (this really means many many architectures), whereas all is used for documentation and with platform independent code like Java and it means this package is architecture independent (it runs on all architectures without modification). I checked a few packages and it seems to me some packages are using any as a shortcut when they support a number of architectures (but probably not all). On the other hand, some packages are NOT using any and explicitly state the supported architectures (e.g. amd64 armhf arm64 i386 mips mips64).

As mentioned before, the process of running dpkg-buildpackage --build=source and dpkg-source --build . is not the same. dpkg-source only builds the source package, whereas dpkg-buildpackage can run checks and do other things like generating buildinfo and changes and signing the files.

dpkg-source and dpkg-buildpackage is run in a directory with source code and debian folder but they generate the packages in the parent directory. In some versions of source format, the directory should have a particular name, but for 3.0 (quilt) there is no such constraint, so I am simply using the name build.

Process

I first assumed source and binary packages are/can be created independently. This is correct to some extent (they are not created simultaneously) but -I think- the implied process is a bit different then what I thought, so it was a little confusing for me.

It seems the assumption is that (being a packager) you first get the original source files and then add debian directory and meta-data files including the rules file to build packages. The dpkg tools are run in such a way, it generates first the source package and then all other binary packages in a single run.

So the source and the binary package build processes are intermixed. Another proof of this is the debian/control file, which has to have at least two paragraphs (sections), one for source and other for binary package. This means, a source package always has a binary package and vice versa. So the implied process naturally makes sense.

For the demonstration purpose, I also provide debian directory in the hellodeb project. However, build scripts build-source.sh and build-package.sh create a correctly named and versioned original source tarball and create a directory with the debian directory and copies the source files also there, in effect they imitate the procedure I described above.

Source Package (with dpkg-source)

The meta data for source packages stay under the folder debian. You must have at least debian/changelog and debian/control.

The directory names can be a bit confusing. Source packages use debian whereas binary packages use DEBIAN for the meta data directory. You will see this in Debian Policy Manual and other places, it is not a typo.

debian/changelog describes the changes. However, the more important thing is it sets the name (hellodeb), version (1.0-4) and distribution of the package. When distribution name is UNRELEASED, it means this package build is not targeted for a particular distribution (e.g. focal for Ubuntu 20.04), so it does not need to be signed. This file changelog has a very rigid structure.

$ cat debian/changelog

hellodeb (1.0-4) UNRELEASED; urgency=low

  * Initial release.

 -- Mete Balci <metebalci@gmail.com>  Tue, 12 Apr 2022 10:21:28 +0000

The version may include both the upstream/original version of the code and also the Debian revision (due to packaging). Above, 1.0 is the upstream version, and 4 is the Debian revision. It is a good idea to have a Debian revision, because you may make a mistake during packaging and you may not be able to upload the exact same version again, so you can just change the Debian revision.

The next file is debian/control, so called source package control file. This file contains fields (name and value pairs) grouped in paragraphs (sections) separated by an empty line. First paragraph contains information about the source package. The second and other paragraphs are about the binary packages. This file has to have at least two paragraphs.

$ cat debian/control

Source: hellodeb
Maintainer: Mete Balci <metebalci@gmail.com>
Standards-Version: 4.5.0
Priority: optional
Section: utils

Package: hellodeb
Architecture: amd64 arm64 armhf
Description: hello world for Debian packaging
 This is an hello program to demonstrate
 Debian packaging.

Package: hellodeb-doc
Architecture: all
Description: hellodeb documentation

Other than Priority and Section, all other fields above are mandatory. There is a source package (first), architecture specific binary package for three architectures (second) and an architecture independent package (third) for documentation. As you can see, each package can be named differently. It is OK to have the source and a binary package to have same name but naturally different binary packages should have different names (like hellodeb-doc above).

Priority and Section are recommended, and if not provided, a warning is issued. A detailed explanation about these fields can be found in the Debian Policy Manual. The Standards-Version field indicates the Debian Policy Manual version this file complies.

With only these two files (remove other things under debian if you want to try this with hellodeb), if you run build-source.sh which runs dpkg-source --build ., it generates the source package, but with a warning. The warning is about the format of source package which defaults to 1.0. The latest version of source packages is 3.0 and there are multiple alternatives or subtypes (see man dpkg-source for more information). This should be specified in debian/source/format file.

$ cat debian/source/format

3.0 (quilt)

If source format is 2.0 or newer, default compression of archive is xz. For 1.0, it is gzip (gz).

I first started using 3.0 (native) format but I think many packages use 3.0 (quilt) format so I also switched to that. Although the basics are the same or similar, there are some differences between them. The scripts build-source.sh and build-package.sh may not work for other formats.

When you also have the debian/source/format file, you can run build-source.sh:

$ ./build-source.sh 

hellodeb.c
hellodeb.1
dpkg-source: info: using source format '3.0 (quilt)'
dpkg-source: info: building hellodeb using existing ./hellodeb_1.0.orig.tar.xz
dpkg-source: info: building hellodeb in hellodeb_1.0-7.debian.tar.xz
dpkg-source: info: building hellodeb in hellodeb_1.0-7.dsc

The same result can also be achived with dpkg-buildpackage --build=source, and this is actually what is done at first when dpkg-buildpackage is run to build the binary packages. However, you cannot run dpkg-buildpackage only with these files, because it is checking the files required for building the binary packages as well.

The generated dsc file is also a control file, which contains information about the packages e.g. packages that can be built, checksums of source.tar.xz file.

$ cat hellodeb_1.0-7.dsc 

Format: 3.0 (quilt)
Source: hellodeb
Binary: hellodeb, hellodeb-doc
Architecture: amd64 arm64 armhf all
Version: 1.0-7
Maintainer: Mete Balci <metebalci@gmail.com>
Standards-Version: 4.5.0
Package-List:
 hellodeb deb utils optional arch=amd64,arm64,armhf
 hellodeb-doc deb utils optional arch=all
Checksums-Sha1:
 93a7c60ecd983d6edc4acd6a63d8d3bfa200a70a 432 hellodeb_1.0.orig.tar.xz
 cd5594120dcea179b81bc8143c1b2c4391135cc2 1472 hellodeb_1.0-7.debian.tar.xz
Checksums-Sha256:
 085592fbda0cf0475242e6a43278e97f9fc491bdb976e794d573fd938cf949af 432 hellodeb_1.0.orig.tar.xz
 d9b23f56c1f905b0c55ff1c92aa35cae1d1c811051c7b36f15aabdbe56452ae7 1472 hellodeb_1.0-7.debian.tar.xz
Files:
 5bbaabb2e7d782425c5e66830e0bc805 432 hellodeb_1.0.orig.tar.xz
 92b587958d619a4c3c880ee61c459b8f 1472 hellodeb_1.0-7.debian.tar.xz

The .orig.tar.xz file contains the source code:

$ tar tvf hellodeb_1.0.orig.tar.xz | awk '{print $NF}'

hellodeb.c
hellodeb.1

and debian.tar.xz file contains only the debian directory with meta-data files.

$ tar tvf hellodeb_1.0-7.debian.tar.xz | awk '{print $NF}'

debian/
debian/changelog
debian/control
debian/copyright
debian/rules
debian/source/
debian/source/format

It seems dpkg-source does not generate any warning, but the copyright information is also a must. This is given in debian/copyright file. In order to make it machine readable, it also has a simple structure:

$ cat debian/copyright

Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: hellodeb
Upstream-Contact: info@metebalci.com
Source: https://github.com/metebalci/hellodeb

Files: *
Copyright: 2022 Mete Balci
License: GPL-3

License: GPL-3
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.
 .
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 .
 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <https://www.gnu.org/licenses/>.

It is possible to specify different copyrights for different files, but above all the files (*) have the same GPL-3 copyright.

Signing Key

If you already know about PGP and have a key that you can use, skip this section. If not, you need to have a local PGP key to sign packages. The steps below are enough to have a working example, but probably not good enough for a professional use.

  • create a key with gpg --full-gen-key, I select RSA and RSA (default), 4096 bits and key does not expire options.
  • send the key to Ubuntu keyserver with gpg --keyserver keyserver.ubuntu.com --send-keys <fingerprint>. You can see the fingerprint with gpg --list-keys, it is the long hexadecimal string.

If you want to use a Launchpad PPA, you need to add the fingerprint of this key to Launchpad and verify it. You have to wait for some minutes before adding the fingerprint to Launchpad.

  • enter the fingerprint of the key to your Launchpad OpenPGP keys section, the same fingerprint format requested (groups of 4 digits, separated by spaces) can be printed with gpg --fingerprint.
  • when the verification e-mail arrives, run gpg and paste the PGP MESSAGE part, this will show a URL that you need to open in a browser, and this completes the Launchpad OpenPGP key setup.

Signed Source Package (with dpkg-buildpackage)

Another way to build the source package is using dpkg-buildpackage with --build=source option. However, by default, it wants to sign the files unless disturbution name is UNRELEASED, so you need to create the signing key first. If you want to run dpkg-buildpackage but do not want it to sign the files, you can use --no-sign option.

Also, although it is not very necessary for a source package, debian/rules file has to be present for this to work. Either use the one in hellodeb repository, or just create an empty file if you want to try this. You can see on the output below, its clean target is called before calling dpkg-source.

At the beginning of the post, I showed debian/changelog stating distribution name as UNRELEASED. Now, I am using the version in the repository and distribution name is focal (Ubuntu 20.04). If you keep it as UNRELEASED, dpkg-buildpackage will run and say this package is UNRELEASED so no need to sign the files.

$ ./build-package.sh source

hellodeb.c
hellodeb.1
dpkg-buildpackage: info: source package hellodeb
dpkg-buildpackage: info: source version 1.0-8
dpkg-buildpackage: info: source distribution focal
dpkg-buildpackage: info: source changed by Mete Balci <metebalci@gmail.com>
 dpkg-source --before-build .
 fakeroot debian/rules clean
rm -f hellodeb
rm -f hellodeb.1.gz
rm -rf debian/tmp
 dpkg-source -b .
dpkg-source: info: using source format '3.0 (quilt)'
dpkg-source: info: building hellodeb using existing ./hellodeb_1.0.orig.tar.xz
dpkg-source: info: building hellodeb in hellodeb_1.0-8.debian.tar.xz
dpkg-source: info: building hellodeb in hellodeb_1.0-8.dsc
 dpkg-genbuildinfo --build=source
 dpkg-genchanges --build=source >../hellodeb_1.0-8_source.changes
dpkg-genchanges: info: not including original source code in upload
 dpkg-source --after-build .
dpkg-buildpackage: info: binary and diff upload (original source NOT included)
 signfile hellodeb_1.0-8.dsc

 signfile hellodeb_1.0-8_source.buildinfo

 signfile hellodeb_1.0-8_source.changes

Pay attention to the line with (original source NOT included) output. By default, if the upstream version of this build (1.0 in 1.0-7) in debian/changelog is the same as the last change (1.0 in 1.0-6), the source (orig.tar.xz) is not included in this source package build, because the assumption is at least a previous version of the source package has this source.

As you have seen above, buildinfo and changes files are also produced in addition to dsc file. dsc file is produced by dpkg-source but buildinfo and changes are produced by dpkg-genbuildinfo and dpkg-genchanges tools and these are only run when dpkg-buildpackage is used.

buildinfo file is just a record of some information like dependencies of the system that has built this package.

changes file is called upload control file. Basically the files listed in changes are uploaded for example to Launchpad. So this file decides if the original source (orig.tar.xz) is included or not.

As you can on the last lines of the output above, dsc, buildinfo and changes files are signed.

Because Launchpad requires only the source package, at this point you can upload this signed source package to a Launchpad PPA. However, you probably want to test it first, so you will create the binary packages anyway. So I will explain binary packages first and then upload the source package to my Launchpad PPA.

Binary Packages

Until now, I showed running dpkg-source and dpkg-buildpackage --build=source. All other options for --build involve building one or more binary packages. The only extra file that is required is a proper debian/rules which is a Makefile and a set of three targets of this Makefile is called depending on the value of --build option. If the option is:

  • full (or if it is omitted): clean, build and binary targets are run.
  • all: clean, build-indep and binary-indep
  • any: clean, build-arch and binary-arch
  • binary: clean, build and binary
  • source: as a reminder, only clean target is called for source

The difference between full and binary is that full also builds the source packages, but only the clean target of debian/rules file is used.

For the sake of completeness, I should mention, even if the source package build is not requested, dpkg-buildpackage still calls dpkg-source with --before-build at the very start of any execution and --after-build just before signing the files. These call source format (debian/source/format) specific actions like applying patches.

As you have realized, clean and a different set of 2 targets are run anytime dpkg-buildpackage is invoked. It is totally up to you, how you write this rules file, and there are helper utilities to simplify this but I am not going to use any such helper in this post.

In many projects, the project has its own Makefile, so rules can invoke the actual Makefile. In this post, I am not using any other Makefile, so my rules file actually builds hellodeb.c. It is expected the binary executables are stripped from unnecessary information, so it is usually done after the build. The man page hellodeb.1 does not require any compilation, it is simply compressed and copied.

There are two additional tools that are used when building binary packages. These are called from rules explicitly. First is dpkg-gencontrol, which generates the binary package control file at DEBIAN/control. The other is dpkg-deb, which actually creates the binary package from a directory. By default, the target directory is debian/tmp, so it is also used in this post.

It is a bit confusing all the directories, so I summarize again:

  • The source code is under hellodeb_1.0
  • The source package meta-data directory is hellodeb_1.0/debian
  • dpkg-gencontrol creates binary package control file at hellodeb_1.0/debian/tmp/DEBIAN
  • The folder hellodeb_1.0/debian/tmp is used to build the binary package by dpkg-deb, so the binary files to be installed/copied to the target system is under this hellodeb_1.0/debian/tmp folder e.g. hellodeb_1.0/debian/tmp/usr/bin/hellodeb which is copied to /usr/bin/hellodeb in the target system.
  • When building multiple packages (e.g. hellodeb and hellodeb-doc), naturally you need to have a clean debian/tmp folder to start with.

Lets build binary (both any and all) packages:

$ ./build-package.sh binary

mete@lemur:~/hellodeb$ ./build-package.sh binary
hellodeb.c
hellodeb.1
dpkg-buildpackage: info: source package hellodeb
dpkg-buildpackage: info: source version 1.0-8
dpkg-buildpackage: info: source distribution focal
dpkg-buildpackage: info: source changed by Mete Balci <metebalci@gmail.com>
dpkg-buildpackage: info: host architecture amd64
 dpkg-source --before-build .
 fakeroot debian/rules clean
rm -f hellodeb
rm -f hellodeb.1.gz
rm -rf debian/tmp
 debian/rules build
x86_64-linux-gnu-gcc `dpkg-buildflags --get CFLAGS` -Wall -o hellodeb hellodeb.c
gzip -c hellodeb.1 > hellodeb.1.gz
 fakeroot debian/rules binary
rm -rf debian/tmp
mkdir -p debian/tmp/DEBIAN
dpkg-gencontrol -phellodeb
mkdir -p debian/tmp/usr/bin
cp hellodeb debian/tmp/usr/bin
strip --strip-unneeded --remove-section=.comment --remove-section=.note debian/tmp/usr/bin/hellodeb
dpkg-deb --build debian/tmp ../hellodeb_1.0-8_amd64.deb
dpkg-deb: building package 'hellodeb' in '../hellodeb_1.0-8_amd64.deb'.
rm -rf debian/tmp
mkdir -p debian/tmp/DEBIAN
dpkg-gencontrol -phellodeb-doc
mkdir -p debian/tmp/usr/share/man/man1
cp hellodeb.1.gz debian/tmp/usr/share/man/man1
dpkg-deb --build debian/tmp ../hellodeb-doc_1.0-8_all.deb
dpkg-deb: building package 'hellodeb-doc' in '../hellodeb-doc_1.0-8_all.deb'.
 dpkg-genbuildinfo --build=binary
 dpkg-genchanges --build=binary >../hellodeb_1.0-8_amd64.changes
dpkg-genchanges: info: binary-only upload (no source code included)
 dpkg-source --after-build .
dpkg-buildpackage: info: binary-only upload (no source included)
 signfile hellodeb_1.0-8_amd64.buildinfo

 signfile hellodeb_1.0-8_amd64.changes

If you follow the output messages carefully, you can see everything I have described above (any a little bit more).

Because I did not ask for the source package, no dsc file is generated (dpkg-source is not run). However, buildinfo and changes files are generated and signed.

At this point, you can go back to Deconstruction of a Full Package Build, and all should make sense.

Personal Package Archive on Launchpad

Now I have the source and binary packages but how to distribute them. It is possible to store these in a directory like a local repository but it is not very useful. There are two options: one is to use Launchpad to create a Personal package archive and upload the (source) package there (and Launchpad builds the binary packages), and the second is to create a Debian repository that can be accessed with http. PPA does not require any extra effort, but creating a Debian repository requires a web server etc.

For a PPA, Launchpad only accepts source packages, the binary packages are created by the launchpad after uploading the source package. Since there are many PPAs and many packages, and some are more important than others, there is a prioritized build queue, and it might take a while for a package to be available. You can select which architectures to build the architecture specific binary packages (like amd64, arm64) and the architecture independent “all” package is built in one architecture only (I believe at the moment it is always amd64), and copied to other architectures for distribution (since it is architecture independent, it should not matter where it is built).

The architecture of hellodeb binary package is amd64, arm64 and armhf and the architecture of hellodeb-doc binary package is all. At the moment, Launchpad runs dpkg-buildpackage with --build:

  • any (meaning architecture specific binary packages) for arm64 and armhf
  • binary (meaning both architecture specific and independent binary packages) for amd64

so arm64 and armhf architectures build only the hellodeb package, but amd64 builds also the hellodeb-doc package. To remind, build type of any runs clean, build-arch and binary-arch targets of debian/rules and build type of binary runs clean, build and binary targets (and not build-arch and build-indep separately). This is not very clear and I did not see this information in any documentation yet, so you need to be careful with your debian/rules file, all targets should do what they are supposed to do.

Before uploading the source package to your PPA, you naturally need to create an account, create a PPA and verify the OpenPGP key, as I briefly mentioned before.

An additional tool, dput, is needed to upload the source package, from dput package. I also installed lintian, which is a tool that checks the package for common errors.

After installing dput, I created the configuration file ~/.dput.cf:

$ cat ~/.dput.cf 

[hellodeb]
fqdn = ppa.launchpad.net
method = ftp
incoming = ~metebalci/ubuntu/hellodeb/
login = anonymous
allow_unsigned_uploads = 0
run_lintian = 1

After building the source package by ./build_package source, it can be uploaded with dput. The second argument hellodeb in this command refers to the section name [hellodeb] in the configuration file, that is how it finds the name of the server to upload, method, the name of the PPA etc.

$ dput hellodeb hellodeb_1.0-8_source.changes

Checking signature on .changes
gpg: /home/mete/hellodeb/hellodeb_1.0-8_source.changes: Valid signature from C8DFA32F5BC52C01
Checking signature on .dsc
gpg: /home/mete/hellodeb/hellodeb_1.0-8.dsc: Valid signature from C8DFA32F5BC52C01
Package is now being checked with lintian.
Uploading to hellodeb (via ftp to ppa.launchpad.net):
  Uploading hellodeb_1.0-8.dsc: done.
  Uploading hellodeb_1.0-8.debian.tar.xz: done.
  Uploading hellodeb_1.0-8_source.buildinfo: done.
  Uploading hellodeb_1.0-8_source.changes: done.
Successfully uploaded packages.

As mentioned before, original source (orig.tar.xz) is not included in changes so it is not uploaded.

The PPA can be added to the system with sudo add-apt-repository ppa:metebalci/hellodeb. After a sudo apt update, hellodeb package can be seen:

$ apt-cache search hellodeb
hellodeb - hello world for Debian packaging
hellodeb-doc - hellodeb documentation

Lets install and try the program:

$ sudo apt install hellodeb hellodeb-doc

Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following NEW packages will be installed:
  hellodeb hellodeb-doc
0 upgraded, 2 newly installed, 0 to remove and 0 not upgraded.
Need to get 3,352 B of archives.
After this operation, 4,096 B of additional disk space will be used.
Get:1 http://ppa.launchpad.net/metebalci/hellodeb/ubuntu focal/main amd64 hellodeb amd64 1.0-8 [2,292 B]
Get:2 http://ppa.launchpad.net/metebalci/hellodeb/ubuntu focal/main amd64 hellodeb-doc all 1.0-8 [1,060 B]
Fetched 3,352 B in 0s (39.8 kB/s)  
Selecting previously unselected package hellodeb.
(Reading database ... 146030 files and directories currently installed.)
Preparing to unpack .../hellodeb_1.0-8_amd64.deb ...
Unpacking hellodeb (1.0-8) ...
Selecting previously unselected package hellodeb-doc.
Preparing to unpack .../hellodeb-doc_1.0-8_all.deb ...
Unpacking hellodeb-doc (1.0-8) ...
Setting up hellodeb (1.0-8) ...
Setting up hellodeb-doc (1.0-8) ...
Processing triggers for man-db (2.9.1-1) ...

Everything installed and works as expected. You can also see the man page with man hellodeb.

$ which hellodeb
/usr/bin/hellodeb

$ hellodeb
hello deb

Deconstruction of a Full Package Build

Below is the output of a full package build, where each number step corresponds the number step in the manual page of dpkg-buildpackage and the first word terminated by : (if any) is the hook name (e.g. init) called within dpkg-buildpackage. After this post, almost all of the output should make sense now.

build-package.sh script prepares the versioned directory and runs dpkg-buildpackage --build=full.

$ ./build-package.sh full

1- init: prepares the build environment, checks if debian/rules is present and calls dpkg-source for --before-build

hellodeb.c
hellodeb.1
dpkg-buildpackage: info: source package hellodeb
dpkg-buildpackage: info: source version 1.0-7
dpkg-buildpackage: info: source distribution focal
dpkg-buildpackage: info: source changed by Mete Balci <metebalci@gmail.com>
dpkg-buildpackage: info: host architecture amd64

 dpkg-source --before-build .

2- dependencies are checked here but I dont have any dependencies so there is nothing displayed

3- preclean: calls debian/rules for clean

 fakeroot debian/rules clean
rm -f hellodeb
rm -f hellodeb.1.gz
rm -rf debian/tmp

4- source: calls dpkg-source to build the source package

 dpkg-source -b .
dpkg-source: info: using source format '3.0 (quilt)'
dpkg-source: info: building hellodeb using existing ./hellodeb_1.0.orig.tar.gz
dpkg-source: info: building hellodeb in hellodeb_1.0-7.debian.tar.xz
dpkg-source: info: building hellodeb in hellodeb_1.0-7.dsc

5- build: calls debian/rules for build and then binary

 debian/rules build
x86_64-linux-gnu-gcc `dpkg-buildflags --get CFLAGS` -Wall -o hellodeb hellodeb.c
gzip -c hellodeb.1 > hellodeb.1.gz

 fakeroot debian/rules binary
rm -rf debian/tmp
mkdir -p debian/tmp/DEBIAN
dpkg-gencontrol -phellodeb
mkdir -p debian/tmp/usr/bin
cp hellodeb debian/tmp/usr/bin
strip --strip-unneeded --remove-section=.comment --remove-section=.note debian/tmp/usr/bin/hellodeb
dpkg-deb --build debian/tmp ../hellodeb_1.0-7_amd64.deb
dpkg-deb: building package 'hellodeb' in '../hellodeb_1.0-7_amd64.deb'.
rm -rf debian/tmp
mkdir -p debian/tmp/DEBIAN
dpkg-gencontrol -phellodeb-doc
mkdir -p debian/tmp/usr/share/man/man1
cp hellodeb.1.gz debian/tmp/usr/share/man/man1
dpkg-deb --build debian/tmp ../hellodeb-doc_1.0-7_all.deb
dpkg-deb: building package 'hellodeb-doc' in '../hellodeb-doc_1.0-7_all.deb'.

6- buildinfo: calls dpkg-genbuildinfo to generate buildinfo build record file

 dpkg-genbuildinfo --build=full

7- changes: calls dpkg-genchanges to generate changes upload control file

 dpkg-genchanges --build=full >../hellodeb_1.0-7_amd64.changes
dpkg-genchanges: info: not including original source code in upload

8- postclean: since --post-clean is not specified, nothing is done

9- calls dpkg-source for --after-build, and also describes the build

 dpkg-source --after-build .
dpkg-buildpackage: info: binary and diff upload (original source NOT included)

10- check: since no check command (DEB_CHECK_COMMAND) is specified, nothing is done

11- sign: calls gpg to sign dsc, buildinfo and changes files

 signfile hellodeb_1.0-7.dsc

 signfile hellodeb_1.0-7_amd64.buildinfo

 signfile hellodeb_1.0-7_amd64.changes

12- done:

What is Missing in This Tutorial

  • maintainer scripts
  • creating a Debian repository
  • dh_make, debuild