Debian Development

Published: Wed 28 February 2024
Updated: Wed 01 May 2024

This page records my daily commands used in packaging, building and maintaining a Debian package.

Basic workflow

If you want to update a package with a new upstream release:

gbp clone ...
gbp import-orig $UPSTREAM_TAR_URL
gbp export-orig  # if no .tar file
dh_make -i -p package_version -c custom --copyrightfile ../LICENSE.md
# Build with various tools

debsign ../.changes
dput 
  • https://blog.hosiet.me/blog/2016/09/15/make-debian-package-with-git-the-canonical-way/

License (copyright) checking

The output of this step is d/copyright. Some developers regard this step as the most boring and time-consuming process. But it's a must-have file in Debian packages, which are distributed directly or through the mirrors worldwide. Therefore, the package maintainer must ensure the license of all files are consistent, and compatible with DFSG.

There exist automation tools easing the borden of maintainers:

  • scan-copyrights: just simply run scan-copyrights
  • debmake: run debmake -c, or -cc with more detailing outputs, or -k to compare the source tree license information with the d/copyright file

Currently my personal license checking workflow is:

# generate basic license info, with file paths merged
scan-copyrights
# check the license
debmake -cc
debmake -k

Add patches

Use gbp pq to manage the source code patches:

gbp pq import
# step 1:
# modify the code here, note that all modifications can appear outside of d/
# each commit is regarded as a patch

# step 2:
# if everything is OK, apply the patch:
gbp pq export [--patch-numbers]
  • https://manpages.ubuntu.com/manpages/xenial/man1/gbp-pq.1.html

After accepted

Once your upload has been accepted by the FTP-master team, you should:

  • Tag the version and upload to Salsa: git tag -s $debian_version -m "msg" && git push --tags

Building environment

pbuilder

sudo pbuilder create --configfile ~/.pbuilderrc --distribution experimental \
    --basetgz /var/cache/pbuilder/base.experimental.tgz \
    --debootstrapopts --keyring=/usr/share/keyrings/debian-archive-keyring.gpg

Container

docker run -it -v sources.list:/etc/apt/sources.list \
    --name dd debian:unstable
# inside the container
mk-build-deps --install debian/control
debuild -- clean
debuild -us -uc -I -i

Release docker with podman as you like.

sbuild with mmdebstrap

# sudo apt install mmdebstrap apt-cacher-ng
sudo mkdir -p /srv/podman/apt-cacher-ng
sudo podman run --name apt-cacher-ng --init -d --restart=always \
     --publish 3142:3142 \
     --volume /srv/podman/apt-cacher-ng:/var/cache/apt-cacher-ng \
     sameersbn/apt-cacher-ng:3.7.4-20220421

mmdebstrap --variant=standard \
           --aptopt='Acquire::http { Proxy "http://127.0.0.1:3142"; }' \
           --verbose \
           unstable $HOME/.cache/sbuild/sid.standard.tgz \
           "http://mirrors.ustc.edu.cn/debian/ unstable"

# In the debianized source directory:
DEB_BUILD_OPTIONS="parallel=8" \
sbuild --chroot-mode=unshare \
       --chroot=$HOME/.cache/sbuild/sid.standard.tgz \
       --dist unstable \
       --chroot-setup-commands='chmod 777 /dev/shm'

# If experimental
SBUILD_CONFIG=$HOME/.experimental.sbuildrc DEB_BUILD_OPTIONS="parallel=8" \
sbuild --chroot-mode=unshare \
       --chroot=$HOME/.cache/sbuild/sid.standard.tgz \
       --dist experimental \
       --chroot-setup-commands='chmod 777 /dev/shm'

The extra content of ~/.experimental.sbuildrc is:

$extra_repositories = [ 'deb http://mirrors.ustc.edu.cn/debian/ experimental' ];
$build_dep_resolver = 'aptitude';

To log into the shell after build failure or before the build directory prune, add '%SBUILD_SHELL' as the value of the following commands:

  • --build-failed-commands, run if any error in the building process
  • --anything-failed-commands, run if any failure occurs
  • --chroot-cleanup-commands, after the build and test, just before the building directory to be pruned

References:

  • https://stephan.lachnit.xyz/posts/2023-02-08-debian-sbuild-mmdebstrap-apt-cacher-ng/
  • https://manpages.ubuntu.com/manpages/focal/en/man5/sbuild.conf.5.html
  • https://wiki.debian.org/sbuild#Enabling_experimental
  • https://manpages.debian.org/unstable/sbuild/sbuild.1.en.html

autopkgtest for runtime tests

Create the image for later runtime test:

PROXY_IP=$(sudo podman inspect -f '{{.NetworkSettings.IPAddress}}' ${container_id})
autopkgtest-build-podman -m http://mirrors.ustc.edu.cn/debian --vendor debian --release unstable -p http://${PROXY_IP}:3142

Note that rootless podman cannot obtain its IP address due to permission reason, so we should start the apt-cacher-ng service using rootful container, and tell the test base image autopkgtest/debian:unstable the proxy IP address.

After successfully building a package, invoke the regression tests with podman backend like this:

autopkgtest -B -s \
    ../python3-jupyter-cache_1.0.0-1\~exp1_all.deb \
    ../jupyter-cache_1.0.0-1\~exp1.dsc \
    -- podman autopkgtest/debian:unstable

You should define the test commands in d/test/control.

  • https://manpages.ubuntu.com/manpages/jammy/en/man1/autopkgtest-build-docker.1.html
  • https://salsa.debian.org/ci-team/autopkgtest/-/blob/master/doc/README.package-tests.rst

Note for ROCm packages, autopkgtest should be executed with GPU equipped.

Misc. commands

  • List the files contained in a .deb file:

    dpkg -c xxx.deb

  • Decompress the .deb file into a directory:

    dpkg -x xxx.deb ./yyy

  • Remove rpath header in the generated binaries:

    chrpath -d path/to/binary

    Note that Debian discourages the presence of rpath in the ELF files: https://wiki.debian.org/RpathIssue.

  • List package dependencies:

    dpkg -I xxx.deb, #or apt-rdepend xxx

links