Packaging PostgreSQL Extensions for Debian ========================================== January 2024, Christoph Berg Debian ships many PostgreSQL applications and extensions as packages. I often get asked by developers how they would get their programs packaged, and ended up writing the same reply over and over. This is a write-up intended as a more thorough answer. # Anatomy of Debian packages Debian knows two sorts of packages: "source" packages and "binary" packages. The latter type is the `.deb` files that get installed using apt or dpkg. The first type is what this article is mostly about. For both sorts of packages, there is an unpacked form and a packed form. ## Binary packages Packed binary packages are a single `.deb` file: ``` $ ls -al postgresql-16-unit_7.7-1_amd64.deb -rw-r--r-- 1 myon myon 136740 Jan 12 14:13 postgresql-16-unit_7.7-1_amd64.deb $ dpkg-deb -I postgresql-16-unit_7.7-1_amd64.deb new Debian package, version 2.0. size 136740 bytes: control archive=1332 bytes. 643 bytes, 15 lines control 2046 bytes, 25 lines md5sums Package: postgresql-16-unit Source: postgresql-unit Version: 7.7-1 Architecture: amd64 Maintainer: Christoph Berg Installed-Size: 500 Depends: postgresql-16, postgresql-16-jit-llvm (>= 16), libc6 (>= 2.14) Section: database Priority: optional Homepage: https://github.com/df7cb/postgresql-unit Description: SI Units for PostgreSQL postgresql-unit implements a PostgreSQL datatype for SI units, plus byte. The base units can be combined to named and unnamed derived units using operators defined in the PostgreSQL type system. SI prefixes are used for input and output, and quantities can be converted to arbitrary scale. $ dpkg-deb -c postgresql-16-unit_7.7-1_amd64.deb drwxr-xr-x root/root 0 2023-01-06 16:34 ./ drwxr-xr-x root/root 0 2023-01-06 16:34 ./usr/ drwxr-xr-x root/root 0 2023-01-06 16:34 ./usr/share/ drwxr-xr-x root/root 0 2023-01-06 16:34 ./usr/share/doc/ drwxr-xr-x root/root 0 2023-01-06 16:34 ./usr/share/doc/postgresql-16-unit/ -rw-r--r-- root/root 267 2023-01-06 16:34 ./usr/share/doc/postgresql-16-unit/NEWS.Debian.gz -rw-r--r-- root/root 7202 2023-01-06 16:34 ./usr/share/doc/postgresql-16-unit/README.md.gz -rw-r--r-- root/root 977 2023-01-06 16:34 ./usr/share/doc/postgresql-16-unit/changelog.Debian.gz -rw-r--r-- root/root 868 2023-01-06 16:34 ./usr/share/doc/postgresql-16-unit/copyright drwxr-xr-x root/root 0 2023-01-06 16:34 ./usr/share/postgresql/ drwxr-xr-x root/root 0 2023-01-06 16:34 ./usr/share/postgresql/16/ drwxr-xr-x root/root 0 2023-01-06 16:34 ./usr/share/postgresql/16/extension/ -rw-r--r-- root/root 19259 2023-01-06 16:34 ./usr/share/postgresql/16/extension/unit--7.sql -rw-r--r-- root/root 244 2023-01-06 16:34 ./usr/share/postgresql/16/extension/unit.control ... ``` The unpacked binary package is of course the files being installed on the system. ## Source packages Unpacked source packages consist of the original upstream source code, with a `debian/` directory added. ``` postgresql-unit/ ├── debian/ │   ├── changelog │   ├── control │   ├── control.in │   ├── copyright │   ├── gitlab-ci.yml │   ├── NEWS │   ├── pgversions │   ├── rules* │   ├── source/ │   │   └── format │   ├── tests/ │   │   ├── control │   │   └── installcheck* │   ├── upstream/ │   │   └── metadata │   └── watch ├── Makefile ├── NEWS.md ├── README.md ├── unit--7.sql.in ├── unit.c └── unit.control ``` Most packages are maintained in Git, which tracks this unpacked source package form. (Either with or without the original upstream source, more on that later.) Packed source packages are actually a set of files: ``` -rw-rw-r-- 1 myon myon 3848 Jan 12 14:31 postgresql-unit_7.7-1.debian.tar.xz -rw-rw-r-- 1 myon myon 1100 Jan 12 14:31 postgresql-unit_7.7-1.dsc -rw-rw-r-- 1 myon myon 414114 Jan 12 14:12 postgresql-unit_7.7.orig.tar.gz ``` This transport format is used for uploading to the Debian archive and for retrieving the source code using `apt source`. (It is not stored in Git.) The `.orig.tar.gz` is the original source tarball as distributed by upstream, either as download from the upstream homepage, or for projects hosted on GitHub, often a tarball automatically generated by GitHub from an upstream Git tag. The `.debiar.tar.xz` file contains the `debian/` directory. The `.dsc` file is a descriptor that contains pointers to the other files in the source package, and more meta information. ``` $ cat postgresql-unit_7.7-1.dsc Format: 3.0 (quilt) Source: postgresql-unit Binary: postgresql-16-unit Architecture: any Version: 7.7-1 Maintainer: Christoph Berg Homepage: https://github.com/df7cb/postgresql-unit Standards-Version: 4.6.1 Vcs-Browser: https://github.com/df7cb/postgresql-unit Vcs-Git: https://github.com/df7cb/postgresql-unit.git Testsuite: autopkgtest Testsuite-Triggers: make Build-Depends: bison, debhelper-compat (= 13), flex, postgresql-server-dev-all (>= 217~) Package-List: postgresql-16-unit deb database optional arch=any Checksums-Sha1: c2f81968bfbe83fed49b084b737e3aba423bf15a 414114 postgresql-unit_7.7.orig.tar.gz b8a1917ddecb99b1441218bc74a0b7cb30752235 3848 postgresql-unit_7.7-1.debian.tar.xz Checksums-Sha256: 411d05beeb97e5a4abf17572bfcfbb5a68d98d1018918feff995f6ee3bb03e79 414114 postgresql-unit_7.7.orig.tar.gz 36e89c762e50ddf997b079703200c0df6967b4fe911bde8e9482d8e82dcb6a98 3848 postgresql-unit_7.7-1.debian.tar.xz Files: 33a22586c8b81564ba7e9c05f430ad40 414114 postgresql-unit_7.7.orig.tar.gz a0b31860b86c12c7173a78d6ecd525cb 3848 postgresql-unit_7.7-1.debian.tar.xz ``` ## Building the source package To get started with working with a Debian package, get the unpacked source package. This could mean invoking `apt source`, but most often checking out the packaging Git repository is the better option as it might contain changes that have not been uploaded yet. It also makes contributing changes easier. For packages, that are already part of Debian, the `debcheckout` tool can automate that (it uses the `Vcs-Git` field in the metadata). To build the packed source packed from the unpacked one, enter the package directory, and invoke `dpkg-buildpackage -S --no-sign`: ``` postgresql-unit $ dpkg-buildpackage -S --no-sign dpkg-buildpackage: info: source package postgresql-unit dpkg-buildpackage: info: source version 7.7-1 dpkg-buildpackage: info: source distribution unstable dpkg-buildpackage: info: source changed by Christoph Berg dpkg-source --before-build . debian/rules clean dh clean --with pgxs ... dpkg-source -b . dpkg-source: info: using source format '3.0 (quilt)' dpkg-source: info: building postgresql-unit using existing ./postgresql-unit_7.7.orig.tar.gz dpkg-source: info: building postgresql-unit in postgresql-unit_7.7-1.debian.tar.xz dpkg-source: info: building postgresql-unit in postgresql-unit_7.7-1.dsc dpkg-genbuildinfo --build=source -O../postgresql-unit_7.7-1_source.buildinfo dpkg-genchanges --build=source -O../postgresql-unit_7.7-1_source.changes dpkg-genchanges: info: including full source code in upload dpkg-source --after-build . dpkg-buildpackage: info: source-only upload (original source is included) ``` Note that the artifacts produced by `dpkg-buildpackage` are always in the *parent* directory of the working directory. To make room for that, I always create *two* levels of directory for my working copies, so a typical case looks like this: ``` postgresql-unit/ ├── postgresql-unit/ <--- most commands are invoked from here │   ├── debian/ │   │   ├── changelog │   │   ├── control │   │   ├── control.in │   │   ├── copyright │   │   ├── files │   │   ├── gitlab-ci.yml │   │   ├── NEWS │   │   ├── pgversions │   │   ├── rules* │   │   ├── source/ │   │   │   └── format │   │   ├── tests/ │   │   │   ├── control │   │   │   └── installcheck* │   │   ├── upstream/ │   │   │   └── metadata │   │   └── watch │   ├── Makefile │   ├── NEWS.md │   ├── powers.c │   ├── powers.h │   ├── README.md │   ├── unit--7.sql.in │   ├── unit.c │   └── unit.control ├── postgresql-16-unit_7.7-1_amd64.deb ├── postgresql-16-unit-dbgsym_7.7-1_amd64.deb ├── postgresql-unit_7.7-1_amd64.changes ├── postgresql-unit_7.7-1.debian.tar.xz ├── postgresql-unit_7.7-1.dsc └── postgresql-unit_7.7.orig.tar.gz ``` ## Building binary packages Binary packages are built using `dpkg-buildpackage --no-sign`. ``` dpkg-buildpackage --no-sign dpkg-buildpackage: info: source package postgresql-unit dpkg-buildpackage: info: source version 7.7-1 dpkg-buildpackage: info: source distribution unstable dpkg-buildpackage: info: source changed by Christoph Berg dpkg-buildpackage: info: host architecture amd64 dpkg-source --before-build . debian/rules clean dh clean --with pgxs ... dpkg-source -b . dpkg-source: info: using source format '3.0 (quilt)' dpkg-source: info: building postgresql-unit using existing ./postgresql-unit_7.7.orig.tar.gz dpkg-source: info: building postgresql-unit in postgresql-unit_7.7-1.debian.tar.xz dpkg-source: info: building postgresql-unit in postgresql-unit_7.7-1.dsc debian/rules binary dh binary --with pgxs dh_update_autotools_config dh_autoreconf dh_auto_configure dh_auto_build --buildsystem=pgxs pg_buildext build build-%v ### PostgreSQL 16 build ### make[1]: Entering directory '/home/myon/projects/postgresql/postgresql-unit/postgresql-unit/build-16' gcc -Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Werror=vla -Wendif-labels -Wmissing-format-attribute -Wimplicit-fallthrough=3 -Wcast-function-type -Wshadow=compatible-local -Wformat-security -fno-strict-aliasing -fwrapv -fexcess-precision=standard -Wno-format-truncation -Wno-stringop-truncation -g -g -O2 -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fno-omit-frame-pointer -g -O2 -ffile-prefix-map=/home/myon/projects/postgresql/postgresql-unit/postgresql-unit=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fPIC -fvisibility=hidden -ffp-contract=off -I. -I/home/myon/postgresql/postgresql-unit/postgresql-unit -I/usr/include/postgresql/16/server -I/usr/include/postgresql/internal -Wdate-time -D_FORTIFY_SOURCE=2 -D_GNU_SOURCE -I/usr/include/libxml2 -c -o unit.o /home/myon/postgresql/postgresql-unit/postgresql-unit/unit.c ... ### End 16 build ### create-stamp debian/debhelper-build-stamp dh_prep dh_auto_install --buildsystem=pgxs --destdir=debian/postgresql-16-unit/ pg_buildext install build-%v postgresql-%v-unit ### PostgreSQL 16 install ### make[1]: Entering directory '/home/myon/projects/postgresql/postgresql-unit/postgresql-unit/build-16' /usr/bin/install -c -m 755 unit.so '/home/myon/postgresql/postgresql-unit/postgresql-unit/debian/postgresql-16-unit/usr/lib/postgresql/16/lib/unit.so' ... ### End 16 install ### debian/rules override_dh_installdocs make[1]: Entering directory '/home/myon/projects/postgresql/postgresql-unit/postgresql-unit' dh_installdocs --all README.* make[1]: Leaving directory '/home/myon/projects/postgresql/postgresql-unit/postgresql-unit' dh_installchangelogs dh_perl dh_link debian/rules override_dh_pgxs_test make[1]: Entering directory '/home/myon/projects/postgresql/postgresql-unit/postgresql-unit' # defer testing to autopkgtest, the data tables are not in /usr/share/postgresql yet make[1]: Leaving directory '/home/myon/projects/postgresql/postgresql-unit/postgresql-unit' dh_strip_nondeterminism dh_compress dh_fixperms dh_missing dh_dwz -a dh_strip -a dh_makeshlibs -a dh_shlibdeps -a dh_installdeb dh_gencontrol dh_md5sums dh_builddeb dpkg-deb: building package 'postgresql-16-unit' in '../postgresql-16-unit_7.7-1_amd64.deb'. dpkg-deb: building package 'postgresql-16-unit-dbgsym' in '../postgresql-16-unit-dbgsym_7.7-1_amd64.deb'. dpkg-genbuildinfo -O../postgresql-unit_7.7-1_amd64.buildinfo dpkg-genchanges -O../postgresql-unit_7.7-1_amd64.changes dpkg-genchanges: info: including full source code in upload dpkg-source --after-build . dpkg-buildpackage: info: full upload (original source is included) ``` Again, the resulting `.deb` files are placed in the parent directory. By default, this also builds the source. If this fails (often when there are files that differ from the tarball version, more on patches later), use `-b` to skip building the source: `dpkg-buildpackage -b --no-sign`. If building fails because of missing dependencies, install them using `apt build-dep .`. There are various front-end utilities to automate these building steps better (git-buildpackage, sbuild, pbuilder, debuild), but dpkg-buildpackage is just fine. ## The debian/ directory The `debian/` directory contains metadata and build instructions for the package. "Creating a Debian package" really means editing the files in this directory to make the package behave as desired. ### debian/control The control file contains one section for the source package, followed by one or more sections for binary packages. ``` $ cat debian/control Source: postgresql-unit Section: database Priority: optional Maintainer: Christoph Berg Build-Depends: bison, debhelper-compat (= 13), flex, postgresql-server-dev-all (>= 217~), Standards-Version: 4.6.1 Rules-Requires-Root: no Vcs-Git: https://github.com/df7cb/postgresql-unit.git Vcs-Browser: https://github.com/df7cb/postgresql-unit Homepage: https://github.com/df7cb/postgresql-unit Package: postgresql-16-unit Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends}, postgresql-16 Description: SI Units for PostgreSQL postgresql-unit implements a PostgreSQL datatype for SI units, plus byte. The base units can be combined to named and unnamed derived units using operators defined in the PostgreSQL type system. SI prefixes are used for input and output, and quantities can be converted to arbitrary scale. ``` (In the case of PostgreSQL extension packages, the control file is automatically generated from `debian/control.in`, see below. Normal packages do not have a control.in file.) ### debian/rules The rules file handles the actual binary package building steps, in Makefile syntax. Almost all packages today use a helper system called `debhelper` which consists of various building blocks called `dh_*` that handle the build steps. Historically, rules files would consist of long lists of `dh_*` steps (similar to the build output above), but there is a "sequencer" command `dh` that knows how to invoke the basic steps. Many packages that don't need any tweaking at that level have a very short `debian/rules` file. (Make sure the indentation is a tab, not spaces!) ``` #!/usr/bin/make -f %: dh $@ ``` Or in the case of PostgreSQL extensions: ``` #!/usr/bin/make -f %: dh $@ --with pgxs ``` If any of the `dh_*` steps need changes, we can override them in the rules file by adding a `override_dh_*` target: ``` #!/usr/bin/make -f override_dh_installdocs: dh_installdocs --all README.* override_dh_pgxs_test: # defer testing to autopkgtest, the data tables are not in /usr/share/postgresql yet %: dh $@ --with pgxs ``` ### Build steps The most interesting build steps to hook into are: #### `dh_auto_configure` Autodetects the build system and runs `./configure`, `cmake` and the like with a set of default options. To add options, do: ``` override_dh_auto_configure: dh_auto_configure -- -DEXTRA_OPTION=foo --with-bar ``` #### `dh_auto_build` The main build step. If the automatically run command is wrong, just override it. ``` override_dh_auto_build: $(MAKE) -C some_sub_dir world ``` #### `dh_auto_install` Runs upstreams' `make install` or equivalent. The files are installed into `DESTDIR=debian/foo` (single-binary package) or `DESTDIR=debian/tmp` (multi-binary package). #### `dh_install` and `debian/foo.install` If there is more than one binary package, the files installed in `debian/tmp` need to be distributed to the individual binary packages. This is done by directory/file lists in `debian/*.install`. ### debian/source/format Should be verbatim this: ``` 3.0 (quilt) ``` (More on quilt and patches below.) ### debian/copyright Debian wants copyright information on *all* files in a package. For private package, this file can be omitted, but for anything official, this file has to list all the copyright holders, along with any copyright terms and license texts. ### debian/watch To get informed about new upstream versions, Debian runs a "watch" system that polls upstream download locations for new package versions. The `debian/watch` file tells the `uscan` tool where to look and (optionally) how to transform upstream's version naming scheme into a Debian-compatible one. ``` version=4 https://github.com/df7cb/postgresql-unit/tags .*/([0-9.]*).tar.gz ``` This is a simple example where `uscan` looks at some GitHub "tags" URL, parses the HTML, and recognizes all links pointing to .tar.gz files as new versions. The regexp part of the URL in parentheses is used as the version number. The `uscan` tool is part of the `devscripts` package which holds a bunch of utilities useful for packaging tasks. ## Patching the upstream source Debian packages are based on upstream tarballs, and `dpkg-buildpackage` does not like changed (or new) files (except in the `debian/` directory). Changes need to be done using patch files stored in the `debian/patches/` directory, and applied in the order listed in `debian/patches/series`. At package build time, support is built-in in dpkg-buildpackage. Patches can edited with whatever tool, with `quilt` being the easiest solution. (It's an optional package that likely isn't preinstalled.) `quilt` needs some configuration in `~/.quiltrc`: ``` QUILT_DIFF_OPTS="-p" QUILT_REFRESH_ARGS="-p ab --no-timestamps --no-index" QUILT_PATCHES=debian/patches ``` Some useful commands: * Apply all patches: `quilt push -a` * Unapply all patches: `quilt pop -a` * Create a new patch: `quilt new foo` * Add a file to a patch: `quilt add bar` (do this *before* changing the file!) * Add a file and edit it: `quilt edit bar` * Show current diff: `quilt diff` * Save a patch after editing: `quilt refresh` Suppose we want to fix something in the `unit.c` file: ``` $ quilt new unit-dllexport Patch unit-dllexport is now on top $ quilt add unit.c File unit.c added to patch unit-dllexport $ vi unit.c $ quilt diff | cat Index: postgresql-unit/unit.c =================================================================== --- postgresql-unit.orig/unit.c 2023-11-08 20:51:04.343207806 +0100 +++ postgresql-unit/unit.c 2024-01-12 16:10:23.143509535 +0100 @@ -136,7 +136,7 @@ unit_get_definitions(void) PG_MODULE_MAGIC; -void _PG_init(void); +void PGDLLEXPORT _PG_init(void); void _PG_init(void) $ quilt refresh Refreshed patch unit-dllexport ``` This creates the `debian/patches/` directory: ``` postgresql-unit/debian/patches/ ├── series └── unit-dllexport ``` At build-time, `dpkg-buildpackage` will then automatically apply and un-apply patches as needed. ## Tests Package tests are run in two flavors: at build-time and later independently on packages installed on some system. ### Build-time package tests If an upstream project has a test suite, it is recommended to run it at build time. In many cases, `dh_auto_test` will guess how to do that and no extra configuration is needed. If it guesses incorrectly, use `override_dh_auto_test` to provide a better command. ### Install-time package tests Next to tests at build-time, we can also run tests when the binary packages are installed on some actual system. This has the advantage that it runs when all files are in their final location, and can also interface with other packages and services that might not be available at build time. It can also run periodically to spot regression, while build-time tests would usually not be repeated. Debian's system to run these tests is `autopkgtest`. The TL;DR version of the documentation is this: In the `debian/tests/` directory, provide a command (usually a shell script) that exercises some package smoke test or more complex scenario. Register that test in `debian/tests/control`. ``` postgresql-unit/debian/tests/ ├── control └── installcheck* $ cat debian/tests/control Depends: @, make Tests: installcheck Restrictions: allow-stderr $ cat debian/tests/installcheck #!/bin/sh pg_buildext -i '--locale=C.UTF-8' installcheck ``` In `Depends` the `@` is a shorthand for all binary packages built from this source. Other packages that the tests needs (and that the binaries don't depend on) can be listed here. `Restrictions` declare tests properties. Examples are `allow-stderr` (don't consider stderr output to be a test failure) and `root-needed` (run test as root instead of an unprivileged user). In Debian, these tests are run automatically for QA, see https://ci.debian.net/. More details are in the autopkgtest package documentation in /usr/share/doc/autopkgtest/. # PostgreSQL extension packages Packages for PostgreSQL extensions work as described above, but since extensions have to be compiled for each PostgreSQL major version separately, things are a bit more complex. For Debian, the process is changed to still have one source package per upstream project, but to build separate binary packages for each PostgreSQL major version. The naming scheme is `postgresql-NN-foo`. (In case the upstream project is called `pg_foo`, make a judgment call if `postgresql-NN-pg-foo` or `postgresql-NN-foo` is better.) In Debian, only one PostgreSQL major version is supported at a time, but in the https://apt.postgresql.org/ repository, many major versions are supported in parallel (currently PostgreSQL 10 everything newer, even when 10 is already EOL). ## `debian/control.in` In order not to have to edit the list of binary packages built when a new PostgreSQL major version comes out, or when a source package is built both for Debian and for apt.postgresql.org, the `debian/control` file is generated from a template in `debian/control.in`. ``` $ cat debian/control.in Source: postgresql-unit Section: database Priority: optional Maintainer: Christoph Berg Build-Depends: bison, debhelper-compat (= 13), flex, postgresql-server-dev-all (>= 217~), Standards-Version: 4.6.2 Rules-Requires-Root: no Vcs-Git: https://github.com/df7cb/postgresql-unit.git Vcs-Browser: https://github.com/df7cb/postgresql-unit Homepage: https://github.com/df7cb/postgresql-unit Package: postgresql-PGVERSION-unit Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends}, ${postgresql:Depends} Description: SI Units for PostgreSQL postgresql-unit implements a PostgreSQL datatype for SI units, plus byte. The base units can be combined to named and unnamed derived units using operators defined in the PostgreSQL type system. SI prefixes are used for input and output, and quantities can be converted to arbitrary scale. ``` The section with the `PGVERSION` token is duplicated for each major version supported, with the version number filled in. ## `debian/pgversions` Not every package supports all PostgreSQL major versions. The `debian/pgversions` file is used to mark which versions are actually supported, so apt.postgresql.org can skip building the other version. Unless we know the exact versions supported, we should use `all`: ``` $ cat debian/pgversions all ``` If 14 or newer is supported: ``` $ cat debian/pgversions 14+ ``` ### Supported versions `debian/pgversions` lists the versions supported *by the package*. The other half of that system is the set of versions supported *by the system*. This list is configured in `/etc/postgresql-common/supported_versions` or by setting the `PG_SUPPORTED_VERSIONS` environment variable. (Set this variable to test building for other major versions.) The actual build process will use the intersection of these two lists. ## `pg_buildext` The process of building PostgreSQL extensions for several major versions is automated by the `pg_buildext` utility. It provides commands for the most common tasks. Package building: * `pg_buildext supported-versions` - print list of supported versions. Use this to loop over versions in `debian/rules`. * `pg_buildext build build-%v` - build in `build-%v` directory * `pg_buildext install build-%v postgresql-%v-unit` - invoke `make install` * `pg_buildext installcheck build-%v postgresql-%v-unit` - invoke `make installcheck` for build-time testing * `pg_buildext loop postgresql-%v-unit` - use instead of `build/install/installcheck` if the package doesn't support out-of-tree builds in subdirectories * `pg_buildext updatecontrol` - rebuild `debian/control` from `debian/control.in`. Run this manually when the set of supported versions has changed. This is not run automatically because the Debian packaging policy forbids changing the set of binary packages at build time. (In environments where this is not an issue, set `PG_UPDATECONTROL=yes`.) Package testing: * `pg_buildext installed-versions` - print list of installed versions. Use this to loop over versions in `debian/tests/*`. * `pg_buildext installcheck` - invoke `make installcheck` on installed packages ## `dh --with pgxs` A debhelper extension `pgxs` is provided that adds builds steps to the `dh` build sequence. ``` $ cat debian/rules #!/usr/bin/make -f %: dh $@ --with pgxs ``` If the package doesn't support out-of-tree builds, use `dh $@ --with pgxs_loop`. ``` dh_auto_build --buildsystem=pgxs pg_buildext build build-%v dh_auto_install --buildsystem=pgxs pg_buildext install build-%v postgresql-%v-unit dh_pgxs_test pg_buildext installcheck . build-%v postgresql-%v-unit ``` To override any of these steps, use `override_dh_auto_*` in `debian/rules`. ## Package template To get started with a new package, the `dh_make_pgxs` tool can generate a skeleton `debian/` directory: ``` $ dh_make_pgxs ``` If the auto-detected values are wrong, hit `^C` and add more command line parameters.