lubuntu-packaging-guide/lubuntu-packaging-guide.rst

377 lines
19 KiB
ReStructuredText

==============================
Packaging Software for Lubuntu
==============================
This document provides information about how to to create and maintain the
Debian packages that comprise the core of Lubuntu. We'll go over how to set up
your system for packaging, basic packaging concepts, best practices for
Lubuntu's packages, and advice for what to do and not do in order to make your
life as a packager easier.
Copyright and Licensing
-----------------------
The text of this document may be used under the terms of the CC-BY-SA 4.0
license. The copyright info for this document is as follows:
* Copyright (c) 2025 Aaron Rainbolt <arraybolt3@ubuntu.com>.
.. NOTE::
If you make a substantial contribution to this document, you should add
your own copyright info to the above list.
High-level overview of a Debian "package"
-----------------------------------------
There are two distinct kinds of packages in Debian, *binary packages* and
*source packages*. Binary packages are the packages you actually install on
your system. For the most part, you won't need to worry about the details of
how they work internally. Source packages are bundles of source code with
Debian packaging metadata. This metadata describes (among other things) how to
build the package, and where the files it installs should go. *Building* a
source package will create one or more binary packages, along with some other
files that we'll describe as we go.
To get an idea of how source packages are structured, we'll start with a
fairly simple package, ``lxqt-about``::
aaron@pkg-builder:~/lubuntu-dev/lxqt-about$ tree
.
├── aboutdialog
│   ...
├── AUTHORS
├── CHANGELOG
├── CMakeLists.txt
├── COPYING
├── debian
│   ├── changelog
│   ├── control
│   ├── copyright
│   ├── docs
│   ├── ...
│   ├── ...
│   ├── lxqt-about.install
│   ├── lxqt-about-l10n.install
│   ├── lxqt-about.lintian-overrides
│   ├── rules
│   ├── ...
│   ├── source
│   │   ├── format
│   │   └── options
│   ├── upstream
│   │   ├── metadata
│   │   └── signing-key.asc
│   └── watch
├── languages
├── main.cpp
├── README.md
├── resources
│   ...
├── translations
│   ...
└── translatorsinfo
...
(The contents of the ``aboutdialog``, ``translations``, and
``translatorsinfo`` dirs are omitted for brevity, and a few irrelevant files
from the ``debian`` directory have been hidden for clarity.)
If you look at `the lxqt-about Git repo
<https://github.com/lxqt/lxqt-about>`__, you'll see that this looks very
similar to the lxqt-about source code repository. The primary difference is
there is a ``debian`` directory here, with a number of files in it. This
``debian`` directory contains all the instructions necessary to take code, and
turn it into Debian binary packages.
We won't go into the details about what these files contain quite yet, but we
will briefly cover what each one does.
* ``changelog``: As one would expect, this contains a record of all changes
made to the package over time. It also specifies the version number of the
package, the version of Ubuntu (or Debian) the package is intended for, and
the identity of the person or people who made changes to the package.
* ``control``: This file defines critical information about the package,
including the names of the source package and each binary package, build and
runtime dependencies, what CPU each binary package is designed to run on,
and a description of each binary package.
* ``copyright``: This file contains copyright notices and authorship
information for (almost) every file in a source package. This is necessary
because many license agreements require or encourage a software distributor
(like Ubuntu) to include copyright notices, license text, and authorship
information for software they distribute. Thanks to the somewhat complex
nature of software licensing, this can be tricky and tedious to maintain,
but it is necessary.
* ``docs``: This file isn't present in all packages. When it is present, it
specifies files that should be installed in a subdirectory of
``/usr/share/doc`` for the user to reference later if they care to.
* ``lxqt-about.install``: This file contains information about what files
should be placed in the ``lxqt-about`` binary package. There are some simple
source packages that don't need a ``.install`` file for a binary package,
but those are rare.
* ``lxqt-about-l10n.install``: This file serves the same purpose as
``lxqt-about.install``, but for the ``lxqt-about-l10n`` binary package. (As
you can probably guess, the ``lxqt-about`` source package builds two binary
packages, named ``lxqt-about`` and ``lxqt-about-l10n``.)
* ``lxqt-about.lintian-overrides``: This file is used to silence
false-positive warnings from Lintian, a package checking tool that we'll
discuss later.
* ``rules``: This is a Makefile that provides the instructions for building
the source code of the source package into binaries. Previously this file
was rather large and complicated (and with some more advanced packages it's
still large and complicated), but thanks to some of Debian's more modern
tooling it is a lot easier to work with than it was in the past.
* ``source/format``: This file contains a string indicating what "format" the
package is in. We'll cover formats later.
* ``source/options``: You can usually ignore this file. It contains some
configuration for the ``dpkg-source`` tool, which you will very rarely have
to work with.
* ``upstream/metadata``: This file contains some basic information about the
source package's *upstream*, i.e. the entity that actually wrote the
software you are now packaging for Debian. It's good to know how to work
with these files, but you won't have to touch them very often.
* ``watch``: This file is used to locate, download, and sometimes repack
source code from upstream. It's rare that you'll have to change this file,
and it is usually very painful to work with it, but nonetheless it's good to
understand how to work with it.
Most of the simpler packages you'll work with (including the entire LXQt
stack) will have a ``debian`` directory that more-or-less follows this
structure. More complicated packages may feature a substantially different
package structure, but for now we won't worry about those.
The above is mainly meant to be a teaser of what you'll be working with as a
packager. Before we get into the details of packaging and how it works though,
you should have a good environment for packaging set up. That's what we'll
cover in the next few sections, starting with setting up PGP keys.
PGP keys in Ubuntu development
------------------------------
One critical tool you'll use as an Ubuntu packager is PGP. Put simply, PGP is
a powerful tool used to prove that you take responsibility for some data (i.e.
a Debian package), and to ensure confidential data you send to someone can
only be read by them. This is useful, because as a packager, you will
frequently be uploading packages to Launchpad, and you need to prove that you
are the one doing the uploads for them to be accepted. Rarely, you will also
run into instances where someone has to send you confidential data.
Using PGP effectively requires some understanding of how it works, so we'll
start with an overview of how PGP does what it does.
Overview of PGP concepts
^^^^^^^^^^^^^^^^^^^^^^^^
PGP is a system for encrypting and signing arbitrary data using public key
cryptography. The basic idea behind PGP is that:
* Each PGP user has two keys, a public key and a private key. The public key
is uploaded to a *keyserver* where others can download it, while the private
key is kept secret and is only accessible by the key's owner.
* Any PGP user can use the public key to *encrypt* data. Only the key owner's
secret key can *decrypt* and read the data.
* The key owner can use their secret key to *sign* data, proving that they
claim responsibility for that data. Anyone can use the key owner's public
key to *verify* the signature.
* It is (in practice) impossible to decrypt data encrypted by the public key
without the corresponding private key. It is similarly impossible to create
a signature that can be verified with a public key, without the
corresponding private key. The reason things work this way is beyond the
scope of this guide, but basically PGP uses some clever math tricks to do
what it does. It's been proven to work over years of production use, so it's
very widely used.
Ubuntu uses PGP for several operations, including signing packages. Launchpad
requires that all packages are signed by the packager who claims
responsibility for them, before those packages can be uploaded. The signature
ensures that only authorized users can upload packages, and makes it so that
each package upload can be reliably traced back to the uploader.
Because of PGP's reliance on public keys for verification and encryption, it
is necessary to distribute the public key as widely as possible, so that
individuals can find it and use it to send you encrypted data or verify things
that you send. To facilitate this, there are several *keyservers*, which PGP
software can upload keys to and fetch keys from. PGP keyservers share public
keys with each other, so uploading a key to one keyserver is enough for users
of virtually any other server to fetch that key.
Preparing your PGP keys
^^^^^^^^^^^^^^^^^^^^^^^
.. NOTE::
Ubuntu has `PGP key recommendations
<https://documentation.ubuntu.com/project/contributors/setup/pgp-key-storage/>`__
for secure key storage. This overview is *not* fully compliant with these
recommendations, as the recommendations are non-mandatory, require special
hardware (in the form of a PGP-compatible USB hardware security key), and
are not easy to follow for first-time users. Once you have experience
generating PGP keys in general, you may choose to purchase a hardware
security key and configure it the way the Ubuntu PGP key recommendations
document.
Before you create a PGP key, there are a few recommendations you should
consider:
* If the laptop you intend to do development work on does not already use full
disk encryption, consider backing up your data and reinstalling the machine
with full disk encryption enabled. (This can be accomplished by using the
"Encrypt system" checkbox on the "Partitions" screen of Lubuntu's
installer.) This adds an extra layer of protection to the key.
* You **MUST** back up your key somewhere. If the key should become stolen or
compromised in the future, you will need a copy of it in order to revoke the
key and prevent it from being misused.
* If you are familiar with PGP key generation already, consider ignoring the
rest of this section and following the Ubuntu PGP key recommendations linked
above. These recommendations will have you generate a key in a known-good
environment and upload it to a hardware security key such as a Yubikey. This
provides much greater protection against key theft than the instructions
here.
The standard tool for PGP key management under Ubuntu is GNU Privacy Guard
(GnuPG, usually accessed using the ``gpg`` command). This tool should already
installed on your system. You can use it to generate keys, sign and encrypt
data, verify signatures, and decrypt data sent to you.
To generate a new PGP key using GPG, complete the following steps on your
physical system (do NOT do this in a packaging VM):
1. Open a terminal window (i.e. QTerminal).
2. Run ``gpg --full-generate-key``.
3. When prompted to select the kind of key you want, press ``Return`` to
accept the default of ``ECC (sign and encrypt)``.
4. When prompted to select which elliptic curve you want, press ``Return`` to
accept the default of ``Curve 25519``.
5. When prompted to specify how long the key should be valid, enter a
reasonable amount of time and press ``Return``. (The default, ``0``, will
result in the key never expiring. This is acceptable, however setting a key
expiration data will make you review your key storage practices every so
often, which you may find useful for staying secure.)
6. When asked if the provided expiration data is correct, press ``y``, then
press ``Return``.
7. When prompted for your real name, enter it and press ``Return``. (If you
have a pseudonym that is recognizable in the Ubuntu community, you may use
that instead. What's important is that the key and things you sign with
that key can be clearly traced back to you as an individual.)
8. When prompted for your email address, enter the same email address you use
for your Ubuntu One account and press ``Return``.
9. When prompted for a comment, press ``Return`` to accept the default (empty)
value. (If you intend on using this PGP key only for Ubuntu packaging, you
might consider adding a comment like "Ubuntu packaging key".)
10. When asked for confirmation of your choices, press ``o``, then press
``Return`` to accept your settings.
11. When prompted for a passphrase to protect your key, choose a strong
passphrase and enter it. Note that anyone who gains access to both your
key and its passphrase will be able to forge signatures in your name and
decrypt data sent to you, so it is of vital importance that this
passphrase be very secure. The easiest way to create a strong passphrase
is to pick six to eight random words and use those as your passphrase.
See `XKCD 936 <https://xkcd.com/936/>`__ (but note that four-word
passphrases like suggested in the comic are not very secure). After
entering the passphrase, click "OK" in the popup window.
12. After clicking "OK", wait for the key to be generated. You will see
something like this once the key has been generated::
pub ed25519 2025-11-04 [SC]
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
uid Your Name <name@example.com>
sub cv25519 2025-11-04 [E]
Congratulations, you have now generated a PGP key! You should immediately back
this key up to some "offline" storage (i.e. a storage device that won't be
actively connected to your computer most of the time; flash drives are good
for this). GnuPG saves all of its persistent data, including generated public
and private keys, in the directory ``~/.gnupg``. You can therefore copy this
entire directory to a backup drive to back up the key. This will also back up
any other PGP-related data that GnuPG is storing, such as imported public
keys.
Now that your key is generated and backed up, it's time to upload your public
key to a keyserver. This will of course allow users to verify things you sign
and encrypt data to you. More importantly for packaging though, uploading your
public key to a keyserver will let Launchpad discover it. This will allow you
to bind your key to your account in Launchpad, which will let you use that key
for package uploads later. Uploading a key is pretty simple::
gpg --keyserver keyserver.ubuntu.com --send-key name@example.com
(Replace ``name@example.com`` with the email address you specified when
generating the key.)
Your key is now on the Ubuntu keyserver. Now that you're done with that, it's
time to add the key to Launchpad. This is a bit tricky but not too difficult:
1. In a web browser, go to your user account page on Launchpad (for instance,
``https://launchpad.net/~example``).
2. Under the "User information" section, there is a subsection called "OpenPGP
keys". Click the pen icon next to this section.
3. Launchpad will require you to reauthenticate via Ubuntu One. Provide your
Launchpad account's username and password, click "Log in", then click "Yes,
log me in".
4. Open a terminal window (i.e., QTerminal), and type the command
``gpg --fingerprint | grep -C5 name@example.com``, replacing
``name@example.com`` with your email address. This will show some info
about your PGP key, including the fingerprint. The fingerprint will look
like ``xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx``, with
hexadecimal numbers in place of the "x" characters. Copy the fingerprint
to your clipboard (select it, then press Ctrl+Shift+C).
5. Back in your browser, you should be at the "Change your OpenPGP keys"
screen. Under the "Import an OpenPGP key" section, paste your fingerprint
into the "Fingerprint" field, then click "Import Key". This will cause
Launchpad to send you an email encrypted with your PGP public key, which
will contain an activation link you can use to confirm ownership of the
key.
6. You will receive an email with some instructions, and a block of text
starting with the string ``-----BEGIN PGP MESSAGE-----`` and ending with
the string ``-----END PGP MESSAGE-----``. Copy that block of text with
Ctrl+C.
7. Open a text editor (i.e. Featherpad), and paste the text in with Ctrl+V.
Then save the file to ``~/Documents/pgp-activate.txt``.
8. In a terminal window, run ``gpg --decrypt ~/Documents/pgp-activate.txt``.
Enter your key's passphrase when prompted. This will show you the link
needed to register your key with Launchpad. Copy the link (select it, then
press Ctrl+Shift+C).
9. Open a new tab in your browser, and paste the link into the address bar.
10. Click "Confirm" in the web page that appears.
Congratulations, your PGP key is now registered with Launchpad and is ready
for development use! With that out of the way, we can get to the fun part;
setting up your packaging environment.
Preparing a Debian packaging environment
----------------------------------------
There are a lot of different ways to set up a packaging environment, using
various different tools. The way documented here is a simplified version of my
packaging setup, which essentially uses a KVM-based VM running the latest
development release of Ubuntu, with ``sbuild`` as my primary build tool. This
method works well for me because:
* It uses a full installation of Ubuntu in a VM, rather than a container,
avoiding some of the numerous pitfalls of containers when it comes to
privileges, resource sharing, etc.
* KVM is more robust than much of the other virtualization software available
for Linux (in particular I've found VirtualBox to be problematic in some
instances).
* It avoids issues that often arise when trying to package for a newer version
of Ubuntu using an older version, while not requiring one to run that newer
version as their primary OS.
* It's fairly simple to get working and fairly easy to use.
* ``sbuild`` closely mimics how packages are actually built on Launchpad,
minimizing the chances of odd things happening because of your build
environment.
* It integrates several other packaging tools you should be using, such as
Lintian.
This method is not without disadvantages however:
* If you want to keep your PGP keys out of your VM (which is recommended), it
requires signing packages manually on the host prior to upload.
* Virtualization incurs some overhead, so it can be slower than other
solutions.
The steps are, roughly:
* Install your desired flavor of Ubuntu into a virtual machine.
* Create a shared folder for working on packages on both the VM and host.
* Install and configure packaging utilities.
* Test the system by building sample source and binary packages.