============================== 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 . .. 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 `__, 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 `__ 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 `__ (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 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.