377 lines
19 KiB
ReStructuredText
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.
|