Build PostgreSQL Extensions for Every Supported Server Version
pg_buildext builds a PostgreSQL extension against every server version your package supports. Allow 20 to 30 minutes for a small extension if the source and packaging skeleton already exist, then stage each build in its own Debian package directory. The examples describe postgresql-common 257build1.1 installed on this machine.
The route
Jump straight to the step you need, or tick off Done means at the end.
- 1. Check the effective PostgreSQL versions
- 2. Declare the package's supported versions
- 3. Generate control files from the template
- 4. Configure and build with VPATH directories
- 5. Install into versioned package staging directories
- 6. Clean and test in the right environment
- 7. Handle non-standard source layouts
- 8. Verify the package workflow
- You need: a Debian source package directory containing
debian/, a working extension source tree,postgresql-common, the relevant PostgreSQL server development packages, and the usual Debian packaging tools. - It will not touch: a running PostgreSQL server. These commands build package files under
debian/only.
1. Check the effective PostgreSQL versions
pg_buildext takes the intersection of two lists: the versions declared by debian/pgversions and the versions in /usr/share/postgresql-common/supported-versions. Start at the top level of the source package and ask for the result:
$ pg_buildext supported-versions
16
Your output may differ. This machine currently reports PostgreSQL 16, so the examples that loop over versions run once here. The command requires debian/pgversions to exist; a missing file is a packaging error, not a reason to guess a version.
Checkpoint
Keep this output. It is the list that build, install and clean actions will use.
2. Declare the package's supported versions
Create debian/pgversions with one entry per line:
allrequests every system-supported version.NNselects one major version.NN+selects that version and newer ones.- Lines starting with
#are comments.
all
# Keep these examples as comments until you have a reason to limit support.
# 15
# 15+
all is normally the least surprising choice when the extension has no known incompatibility. It does not override the system list: a version missing from supported-versions is still excluded. For a narrow compatibility range, use explicit version lines and rerun pg_buildext supported-versions before building.
3. Generate control files from the template
Put PGVERSION in package names in debian/control.in, and PGVERSIONS in a dependency field where a space-separated list of versioned packages is needed. A package template can look like this:
Source: postgresql-foobar
Build-Depends: debhelper, postgresql-all <!nocheck>,
postgresql-server-dev-all (>= 217~)
Package: postgresql-PGVERSION-foobar
Architecture: any
Depends: ${misc:Depends}, ${postgresql:Depends}, ${shlibs:Depends}
Generate debian/control with:
$ pg_buildext updatecontrol
This expands every package section containing PGVERSION. A PGVERSION elsewhere in a section is replaced by the newest supported version, and PGVERSIONS expands to the supported version list. If debian/tests/control.in exists, the same replacement runs there too.
Add this line to debian/rules so a build can detect that generated control files have gone stale:
include /usr/share/postgresql-common/pgxs_debian_control.mk
For backports and PGDG suites, checkcontrol can update the control file as part of its suite-specific behaviour. On other builds, run updatecontrol yourself and review the diff before packaging.
Checkpoint
Inspect the generated package names and dependencies. Do not continue with a stale debian/control: the binary package set follows that file.
4. Configure and build with VPATH directories
For an extension with an autoconf configure script, call the action from debian/rules with a separate directory for each PostgreSQL version. The %v marker is replaced by the version:
override_dh_auto_configure:
+pg_buildext configure build-%v "--libdir=/usr/lib/postgresql/%v/lib"
override_dh_auto_build:
+pg_buildext build build-%v
The leading + matters: it lets the sub-make talk to the parent make jobserver. Most PGXS extensions do not need a configure action at all, so leave that override out when the source has no configure script.
The optional -m option passes extra make variables to these actions. For example, pg_buildext -m V=1 build build-%v turns on a make variable the extension's own makefile expects. Do not treat -m as a compiler flag: it is appended to the make invocation, nothing more.
5. Install into versioned package staging directories
Install each VPATH build into the package named by the third argument:
override_dh_auto_install:
+pg_buildext install build-%v postgresql-%v-foobar
For each supported version, pg_buildext runs make install with a DESTDIR under debian/. The %v in the package pattern becomes the actual major version. It also writes the required server dependency to debian/<package>.substvars, using postgresql:Depends when the control file declares it, and falling back to the older misc:Depends path when needed.
Warning
This is the point where package contents actually change. Review the staged files and package names before a full package build. Do not replace DESTDIR with a system path, and do not run the makefile as root to install straight into /usr.
6. Clean and test in the right environment
Add a clean action matching the build directory:
override_dh_auto_clean:
+pg_buildext clean build-%v
The installcheck action is not an ordinary build test. It uses pg_virtualenv and is meant for autopkgtest, run after the extension package is installed into the test environment:
Depends: @, postgresql-server-dev-all
Tests: installcheck
Restrictions: allow-stderr
#!/bin/sh
pg_buildext installcheck
If tests need an explicit build directory, use pg_buildext installcheck build-%v. A package pattern can also point the temporary PostgreSQL instance at files below debian/<package>/.
Warning
Never point a service-disrupting test at a production cluster from this action. pg_virtualenv exists precisely so you don't have to.
For interactive SQL or a shell inside that temporary environment, use the related psql and virtualenv actions. They read their input from standard input, so only feed them commands whose state changes are fine inside a throwaway cluster.
7. Handle non-standard source layouts
If the extension source sits below the package root, pass its absolute path before the build directory:
override_dh_auto_build:
+pg_buildext build $(CURDIR)/postgresql-module build-%v
The source directory argument must be absolute. The build directory can still contain %v; the source tree itself is shared through VPATH, so version-specific generated files stay separated.
8. Verify the package workflow
Run these checks from the package root:
$ pg_buildext supported-versions
16
$ test -f debian/control
$ grep -E '^Package: postgresql-[0-9]+-foobar$' debian/control
Package: postgresql-16-foobar
$ find debian -maxdepth 2 -type d -name 'postgresql-*-foobar' -print
The final command should show a staging directory once installation has run. Exact paths and output depend on the extension. If installed-versions reports that debian/control.in is missing, that just means the action cannot infer installed package versions here; it is meant for test environments whose control template contains PGVERSION. Treat a configure, make or test failure as a real failure, not as evidence that another PostgreSQL version should be invented.
Recovery
To undo a generated build, run pg_buildext clean build-%v and remove only the generated control files, preserving any deliberate packaging edits. Do not use a broad recursive delete in the package root. Keep the original extension source and reviewed templates until the package has rebuilt successfully.
Done means
- Versions declared and confirmed.
debian/pgversionsstates the intended support range andsupported-versionsconfirms the effective list. - Control files regenerated.
debian/controland any test control file came from reviewed templates. - Builds are versioned. Each build uses a
build-%vdirectory, with a leading+indebian/rules. - Installs stay scoped. Installation populates only the matching
debian/package staging directory and records PostgreSQL dependencies. - Tests run in a throwaway cluster. Regression tests go through
autopkgtestandpg_virtualenv, never a production cluster. - Staged output reviewed. Package names and files were checked before any publication or install.