Packaging cmatrix with quilt (Local Build Tutorial)
Example Values Used in This Tutorial
This tutorial uses the following fake example values throughout. Replace them with your own real details when following along.
| Field | Example Value |
|---|---|
| Full Name | Rex Bytes |
[email protected] | |
| Launchpad Username | rexbytes |
| GPG Key ID | AABB1122CCDD3344 |
| Package | cmatrix 2.0 |
| PPA Version | 2.0-1~ppa1~rexbytes |
| Target Distribution | noble |
| Working Directory | ~/packaging/cmatrix-ppa |
| PPA | ppa:rexbytes/example-ppa |
In this tutorial, you’ll learn how to:
- Take an upstream tarball (cmatrix 2.0 from GitHub)
- Create minimal Debian packaging files by hand
- Use quilt to add a small patch
- Build a
.debpackage and test it locally - Understand the version string
2.0-1~ppa1~rexbytes
This assumes you’re on an Ubuntu-based system (example: Ubuntu Noble).
We are going to use the Ubuntu package cmatrix as our upstream package.
0. Getting the cmatrix source
You can start from either:
- The upstream cmatrix tarball from GitHub, or
- The Ubuntu/Debian source package via
apt source(after enablingdeb-src).
Both give you a cmatrix-2.0/ source tree to work in. Choose whichever matches what you want to learn.
0.1 Option 1: Upstream tarball (GitHub)
This is the “pure upstream” route we use in the main tutorial.
mkdir -p ~/packaging/cmatrix-ppa
cd ~/packaging/cmatrix-ppa
wget https://github.com/abishekvashok/cmatrix/archive/refs/tags/v2.0.tar.gz \
-O cmatrix_2.0.orig.tar.gz
tar -xzf cmatrix_2.0.orig.tar.gz
cd cmatrix-2.0
Code language: JavaScript (javascript)
After this:
cmatrix_2.0.orig.tar.gzis your upstream tarball.cmatrix-2.0/is the unpacked source directory where you’ll createdebian/.
0.2 Option 2: Source from Ubuntu (apt source)
If you’d rather start from Ubuntu’s existing packaging, you can fetch the source package instead.
0.2.1 Enable deb-src entries
Edit your APT sources:
- Do this using the GUI for your distro.
- Turn on the “source code repository” option.
Ubuntu Noble (24.04) and newer use the deb822 format by default. Your sources are in /etc/apt/sources.list.d/ubuntu.sources (not the old /etc/apt/sources.list). To enable source packages, add deb-src to the Types: line:
sudo nano /etc/apt/sources.list.d/ubuntu.sources
Code language: PHP (php)
Change:
Types: deb
Code language: HTTP (http)
to:
Types: deb deb-src
Code language: HTTP (http)
Note: Older Ubuntu releases and derivatives (like Linux Mint) may still use the traditional one-line format in
/etc/apt/sources.listor files under/etc/apt/sources.list.d/*.list. In that case, ensure you have matchingdebanddeb-srclines:
deb http://archive.ubuntu.com/ubuntu noble main restricted universe multiverse
deb-src http://archive.ubuntu.com/ubuntu noble main restricted universe multiverse
Code language: JavaScript (javascript)
Save and exit, then update:
sudo apt update
If you’re using a PPA and want its source too:
sudo add-apt-repository -s ppa:rexbytes/example-ppa
sudo apt update
Important: You do need to manually run the above command for PPAs. It adds a
deb-srcline for the PPA as well.
0.2.2 Fetch the cmatrix source
mkdir -p ~/packaging/cmatrix-ppa
cd ~/packaging/cmatrix-ppa
apt source cmatrix
Code language: JavaScript (javascript)
This will download and unpack the source, giving you something like:
cmatrix-2.0/— source tree (already contains adebian/directory)cmatrix_2.0.orig.tar.gzcmatrix_2.0-<rev>.debian.tar.xzcmatrix_2.0-<rev>.dsc
Then:
cd cmatrix-2.0
Code language: CSS (css)
Important: Using
apt sourcemeans there may already be an existingdebian/directory created by Ubuntu packagers. Delete (or rename) the existingdebian/directory — you’ll recreate it from scratch in this tutorial. Renaming it (e.g.mv debian debian.orig) lets you refer back to the original packaging if needed.
mv debian debian.orig
Code language: CSS (css)
1. Install required tools
Install the packaging tools (including quilt) and build dependencies:
sudo apt update
sudo apt install devscripts build-essential debhelper quilt \
autoconf automake libncurses-dev \
dput gnupg
Note: On Ubuntu Noble and newer, the old
libncurses5-devandlibncursesw5-devpackages have been replaced bylibncurses-dev, which covers both narrow and wide character support.gnupgis usually pre-installed on Ubuntu but is listed here for completeness — you’ll need it for signing in tutorial 03.
2. Prepare a working directory and download cmatrix
If you already followed Section 0 above, you should have
~/packaging/cmatrix-ppa/cmatrix-2.0ready. Skip to Section 3.
If you skipped Section 0 and want the quick path, use the upstream GitHub tarball:
mkdir -p ~/packaging/cmatrix-ppa
cd ~/packaging/cmatrix-ppa
wget https://github.com/abishekvashok/cmatrix/archive/refs/tags/v2.0.tar.gz \
-O cmatrix_2.0.orig.tar.gz
tar -xzf cmatrix_2.0.orig.tar.gz
cd cmatrix-2.0
Code language: JavaScript (javascript)
Note: The underscore in
cmatrix_2.0.orig.tar.gzis important for Debian naming conventions (<package>_<upstream-version>.orig.tar.gz).
3. Create the debian/ directory
All packaging files live in a directory called debian inside the source tree.
mkdir debian
We’ll now create several files manually:
debian/controldebian/rulesdebian/changelogdebian/copyrightdebian/patches/*(for quilt)
4. Create debian/control
This file declares metadata about the package and build dependencies.
nano debian/control
Insert:
Source: cmatrix
Section: misc
Priority: optional
Maintainer: Rex Bytes <[email protected]>
Build-Depends: debhelper-compat (= 13), autoconf, automake, libncurses-dev
Standards-Version: 4.7.0
Homepage: https://github.com/abishekvashok/cmatrix
Package: cmatrix
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: Terminal-based "The Matrix" effect
CMatrix simulates the digital rain from "The Matrix" inside your terminal.
Code language: HTTP (http)
- Source: name of the source package.
- Build-Depends: tools and libraries needed to build. The
debhelper-compat (= 13)entry is a virtual package that tells debhelper which compatibility level to use — level 13 is the current recommended default. This replaces the olderdebian/compatfile. - Package: the binary package name (the
.deb). - Depends:
${shlibs:Depends},${misc:Depends}— automatically generated deps.
Save and exit.
5. Create debian/rules
This is a makefile that tells debhelper how to build and install the package.
nano debian/rules
Insert:
#!/usr/bin/make -f
%:
dh $@
override_dh_auto_configure:
autoreconf -i
./configure --prefix=/usr
override_dh_auto_install:
make DESTDIR=$(CURDIR)/debian/cmatrix install
Code language: PHP (php)
dh $@calls the appropriate debhelper command for each step (build, install, clean, etc.).override_dh_auto_configurerunsautoreconfand./configurewith/usras the prefix.override_dh_auto_installinstalls into a temporary tree underdebian/cmatrix, not your real filesystem.
Make it executable:
chmod +x debian/rules
Important:
debian/rulesis a Makefile. Indented lines must use a real tab character, not spaces. If you copy-paste from a web page, your editor may convert tabs to spaces — this will cause build failures withmissing separator. Innano, pressTabto insert a literal tab. Invim, tabs are the default.
6. Create debian/changelog
We’ll write a minimal changelog entry by hand (no dch).
nano debian/changelog
Insert:
cmatrix (2.0-1~ppa1~rexbytes) noble; urgency=medium
* Initial PPA build with custom Debian packaging.
-- Rex Bytes <[email protected]> Wed, 26 Nov 2025 12:00:00 +0000
Code language: HTML, XML (xml)
2.0-1~ppa1~rexbytesis the package version. We’ll explain it in detail near the end.nobleis the target distribution (e.g. Ubuntu Noble).- The last line is your signature line: name, email, date, and time.
Important: The trailing line format is strict: one space, two dashes, one space,
Name <email>, then two spaces before the RFC 2822 date. Getting the spacing wrong will causedpkg-sourceto reject the changelog. This is the most common gotcha when writing the changelog by hand — usingdch(covered in section 14) avoids this entirely.
7. Create debian/copyright
This tells Debian/Ubuntu about licensing and copyright terms.
nano debian/copyright
Insert (based on the Debian copyright file for cmatrix):
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: CMatrix
Source: https://github.com/abishekvashok/cmatrix
Files: *
Copyright: 1999-2017 Chris Allegretta
2017-2019 Abishek V Ashok <[email protected]>
License: GPL-3+
Files: debian/*
Copyright: 2025 Rex Bytes <rexbytes@example.com>
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 package 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/>.
Comment:
On Debian systems, the complete text of the GNU General
Public License version 3 can be found in "/usr/share/common-licenses/GPL-3".
Code language: PHP (php)
8. Create debian/source/format
This file tells dpkg-source which source package format to use. Without it, dpkg-source defaults to the legacy format 1.0 and emits a warning.
mkdir -p debian/source
echo '3.0 (quilt)' > debian/source/format
Code language: PHP (php)
Format 3.0 (quilt) is the modern standard. It stores the upstream tarball separately from your Debian changes and uses quilt to manage patches.
9. Prepare quilt for patches
Create the patches directory and an (initially empty) series file:
mkdir -p debian/patches
touch debian/patches/series
For this shell session, set quilt environment variables (so it uses debian/patches):
export QUILT_PATCHES=debian/patches
export QUILT_SERIES=series
Code language: JavaScript (javascript)
10. Create a quilt patch
We’ll add a small patch that modifies the version output, for example to add a “Packaged By” line.
10.1 Start a new patch
quilt new add-debian-tag-to-version-output.patch
Code language: JavaScript (javascript)
This creates a new patch entry and marks it as “current” for quilt.
10.2 Tell quilt which file you’re editing
quilt add cmatrix.c
Code language: CSS (css)
This tells quilt to track changes in cmatrix.c for this patch.
10.3 Edit the source
Open cmatrix.c and modify the version() function to print your tag:
nano cmatrix.c
Code language: CSS (css)
Find the version(void) function and add a line:
void version(void) {
printf("CMatrix version %s (compiled %s, %s)\n",
VERSION, __TIME__, __DATE__);
printf("Email: [email protected]\n");
printf("Web: https://github.com/abishekvashok/cmatrix\n");
printf(" Packaged By: Rex Bytes - As part of a packaging tutorial.\n");
}
Code language: JavaScript (javascript)
Save and exit.
10.4 Refresh the patch
Tell quilt to record the differences into the patch file:
quilt refresh
You can inspect the generated patch:
cat debian/patches/add-debian-tag-to-version-output.patch
It should look similar to:
Index: cmatrix-2.0/cmatrix.c
===================================================================
--- cmatrix-2.0.orig/cmatrix.c
+++ cmatrix-2.0/cmatrix.c
@@ -152,6 +152,7 @@ void version(void) {
VERSION, __TIME__, __DATE__);
printf("Email: [email protected]\n");
printf("Web: https://github.com/abishekvashok/cmatrix\n");
+ printf(" Packaged By: Rex Bytes - As part of a packaging tutorial.\n");
}
Code language: JavaScript (javascript)
At this point, your debian/patches/series file should contain the patch name:
cat debian/patches/series
Expected content:
add-debian-tag-to-version-output.patch
Code language: CSS (css)
11. Build the package
Go back to the top of the source tree (if you’re not already there):
cd ~/packaging/cmatrix-ppa/cmatrix-2.0
Code language: JavaScript (javascript)
First, unapply any quilt patches. With 3.0 (quilt) format, dpkg-source will re-apply patches during the build — if they’re still applied, the build can fail or produce warnings:
quilt pop -a
Build the package (no signing, local build):
dpkg-buildpackage -us -uc
-us= do not sign source.-uc= do not sign the.changesfile.
Note:
dpkg-buildpackagedoes not runlintianautomatically (that is a feature ofdebuild). After the build finishes, runlintianyourself to check for packaging issues:
lintian ../cmatrix_2.0-1~ppa1~rexbytes_amd64.changes
You may see warnings about missing man pages or other minor policy issues — these don’t block the build and are normal for tutorial packages. To see detailed explanations of any warnings, add the --info flag.
If everything succeeds, you’ll have .deb and related files in ~/packaging/cmatrix-ppa.
Troubleshooting common build failures
| Symptom | Likely cause | Fix |
|---|---|---|
missing separator in debian/rules | Spaces instead of tabs | Re-indent with real tab characters |
cannot find -lncurses or missing curses.h | Missing build dependency | sudo apt install libncurses-dev |
autoreconf: command not found | Missing autotools | sudo apt install autoconf automake |
patch ... does not apply | Quilt patches still applied or modified source | Run quilt pop -a before building, or check your patch matches the source |
dpkg-source: error: aborting due to unexpected upstream changes | You edited source files directly instead of through quilt | Undo direct edits, use quilt push, quilt add, edit, quilt refresh |
12. Install and test the package
Go up one directory and install the freshly built .deb:
cd ..
sudo dpkg -i cmatrix_2.0-1~ppa1~rexbytes_amd64.deb
Code language: CSS (css)
Note: The
.debfilename includes your system’s architecture (e.g.amd64,arm64). Adjust the filename to match whatdpkg-buildpackageactually produced — you can check withls *.deb.
Now test the version output:
cmatrix -V
Expected output (similar to):
CMatrix version 2.0 (compiled 12:00:00, Nov 26 2025)
Email: abishekvashok@gmail.com
Web: https://github.com/abishekvashok/cmatrix
Packaged By: Rex Bytes - As part of a packaging tutorial.
Code language: CSS (css)
13. Understanding the version: 2.0-1~ppa1~rexbytes
Debian version format:
[epoch:]upstream-version[-debian-revision]
Code language: CSS (css)
For your package:
- Upstream version:
2.0 - Debian revision:
1~ppa1~rexbytes
Breakdown:
| Part | Meaning |
|---|---|
2.0 | The upstream project version (cmatrix 2.0). |
-1 | The first Debian packaging revision for this upstream version. If someone changes the packaging, they’d bump this to -2, -3, etc. |
~ppa1 | ppa1 = “first PPA build”. The leading ~ makes this version sort older than 2.0-1. So 2.0-1~ppa1 < 2.0-1. If Ubuntu later publishes 2.0-1 officially, apt will upgrade users from your PPA package to the official one. |
~rexbytes | A label indicating which PPA/repo this build is from. Keeps the overall version below 2.0-1, but distinguishes it from other PPA builds. |
In short:
2.0-1~ppa1~rexbytes= cmatrix 2.0, first Debian-style packaging revision, first PPA build, from “rexbytes”, always considered older than the official2.0-1package.
14. Bonus: Using dch to manage the changelog
In this tutorial, we wrote debian/changelog by hand to understand the format. In real packaging work, you’ll usually use the dch tool (from devscripts) to edit it safely.
dch can:
- Create a new
debian/changelog - Bump the Debian revision (
-1→-2, etc.) - Set the version explicitly
- Add new changelog entries with your name, email, and the current date
14.1 Tell dch who you are
dch gets your name and email from environment variables (preferred) or, if those aren’t set, from git config / other fallbacks.
For packaging, set explicit Debian identity variables:
export DEBFULLNAME="Rex Bytes"
export DEBEMAIL="[email protected]"
Code language: JavaScript (javascript)
You can put these in ~/.bashrc (or ~/.zshrc, etc.) so they’re always set:
echo 'export DEBFULLNAME="Rex Bytes"' >> ~/.bashrc
echo 'export DEBEMAIL="[email protected]"' >> ~/.bashrc
source ~/.bashrc
Code language: PHP (php)
From now on, dch will create changelog trailer lines like:
-- Rex Bytes <[email protected]> Fri, 05 Dec 2025 12:34:56 +0000
Code language: HTML, XML (xml)
14.2 Creating a changelog with dch
If debian/changelog doesn’t exist yet, you can create it with:
dch --create -v 2.0-1~ppa1~rexbytes --package cmatrix -D noble
Code language: CSS (css)
dch will:
- Open an editor with a template entry
- Use your
DEBFULLNAME/DEBEMAIL - Fill in the version and date
Edit the bullet points, save, and quit. dch will write a proper changelog stanza for you.
Important: Without
-D noble,dchdefaults the distribution toUNRELEASED. Launchpad rejects uploads withUNRELEASED— you must set it to an active Ubuntu series likenoble.
14.3 Bumping the version for a new PPA build
Suppose you’ve already uploaded 2.0-1~ppa1~rexbytes and now want a second PPA build, e.g. 2.0-1~ppa2~rexbytes:
dch -v 2.0-1~ppa2~rexbytes "Second PPA build: tweak packaging."
Code language: JavaScript (javascript)
This will:
- Add a new changelog entry at the top
- Set the new version to
2.0-1~ppa2~rexbytes - Use your configured name and email
- Update the date automatically
14.4 Auto-incrementing Debian revisions
If you’re doing classic Debian-style revisions (2.0-1, 2.0-2, 2.0-3, …), you can let dch increment the revision for you:
dch -i "Bump Debian revision after packaging changes."
Code language: JavaScript (javascript)
-i tells dch to:
- Look at the current version (e.g.
2.0-1) - Bump the Debian revision (
-1→-2) - Add a new changelog entry with that incremented version
Linux PPA Packaging — All Parts
- 1 Key Management for Launchpad (GPG + SSH)
- 2 Packaging cmatrix with quilt (Local Build Tutorial) You are here
- 3 Uploading cmatrix to a PPA (PPA Upload Tutorial)
- 4 Packaging Your Own Software for a PPA (From Scratch)
