summaryrefslogtreecommitdiffstats
path: root/pg_buildext
diff options
context:
space:
mode:
Diffstat (limited to '')
-rwxr-xr-xpg_buildext503
-rw-r--r--pg_buildext.pod358
2 files changed, 861 insertions, 0 deletions
diff --git a/pg_buildext b/pg_buildext
new file mode 100755
index 0000000..304e8a1
--- /dev/null
+++ b/pg_buildext
@@ -0,0 +1,503 @@
+#!/bin/bash
+#
+# build a PostgreSQL module based on PGXS for given list of supported major
+# versions
+#
+# (C) 2010 Dimitri Fontaine <dfontaine@hi-media.com>
+# (C) 2011-2023 Christoph Berg <myon@debian.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+set -eu
+
+die() {
+ echo "$(basename $0): error: $*" >&2
+ exit 1
+}
+
+VENVARGS=""
+MAKEVARS=""
+while getopts "c:i:m:o:s" opt ; do
+ case $opt in
+ c|i|o) VENVARGS="$VENVARGS -$opt $OPTARG" ;;
+ m) MAKEVARS="$OPTARG" ;;
+ s) VENVARGS="$VENVARGS -$opt" ;;
+ *) exit 1 ;;
+ esac
+done
+# shift away args
+shift $(($OPTIND - 1))
+
+# positional arguments: action [srcdir] [target [opt]]
+[ "${1:-}" ] || die "no action given"
+action="$1"
+shift
+
+if [ -d "${1:-}" ] && [ "${2:-}" ]; then # optional: source directory
+ srcdir="${1:-}"
+ [ "$srcdir" = "." ] && srcdir="$PWD"
+ shift
+else
+ srcdir="$PWD"
+fi
+target="${1:-}"
+opt="${2:-}"
+
+prepare_env() {
+ local version=$1
+ vtarget=`echo $target | sed -e "s:%v:$version:g"`
+ pgc="/usr/lib/postgresql/$version/bin/pg_config"
+ [ -e "$pgc" ] || die "$pgc does not exist"
+ if [ "${CFLAGS:-}" ]; then
+ export COPT="$CFLAGS"
+ fi
+}
+
+configure() {
+ prepare_env $1
+ confopts=`echo $opt | sed -e "s:%v:$1:g"`
+
+ mkdir -p $vtarget
+ ( echo "calling configure in $vtarget" &&
+ cd $vtarget && $srcdir/configure $confopts PG_CONFIG="$pgc" VPATH="$srcdir" ) || return $?
+}
+
+build() {
+ prepare_env $1
+ if [ "$opt" ]; then
+ cflags="$(echo $opt | sed -e "s:%v:$1:g")"
+ export COPT="${COPT:+$COPT }$cflags"
+ fi
+
+ mkdir -p $vtarget
+ # if a Makefile was created by configure, use it, else the top level Makefile
+ [ -f $vtarget/Makefile ] || makefile="-f $srcdir/Makefile"
+ make -C $vtarget ${makefile:-} PG_CONFIG="$pgc" VPATH="$srcdir" USE_PGXS=1 $MAKEVARS || return $?
+}
+
+substvars() {
+ version="$1"
+ package="$2"
+
+ depends="postgresql-$version"
+ if [ -d "debian/$package/usr/lib/postgresql/$version/lib/bitcode" ]; then
+ pg_provides=$(dpkg-query --show --showformat='${Provides}' postgresql-$version | grep -o 'postgresql-[0-9]*-jit-llvm (= [0-9.]*')
+ llvm_version=${pg_provides#*= }
+ if [ "$llvm_version" ]; then # skip if server version doesn't have the Provides yet
+ depends="$depends, postgresql-$version-jit-llvm (>= $llvm_version)"
+ fi
+ fi
+ echo "postgresql:Depends=$depends" >> "debian/$package.substvars"
+
+ if ! grep -q postgresql:Depends debian/control; then # compat: add to misc:Depends
+ if grep -q ^misc:Depends "debian/$package.substvars"; then
+ sed -i -e "s/^misc:Depends=/misc:Depends=$depends, /" "debian/$package.substvars"
+ else
+ echo "misc:Depends=$depends" >> "debian/$package.substvars"
+ fi
+ fi
+}
+
+install() {
+ prepare_env $1
+ package=`echo $opt | sed -e "s:%v:$1:g"`
+
+ mkdir -p $vtarget
+ # if a Makefile was created by configure, use it, else the top level Makefile
+ [ -f $vtarget/Makefile ] || makefile="-f $srcdir/Makefile"
+ make -C $vtarget ${makefile:-} install DESTDIR="$PWD/debian/$package" PG_CONFIG="$pgc" VPATH="$srcdir" USE_PGXS=1 $MAKEVARS || return $?
+ substvars "$1" "$package"
+}
+
+clean() {
+ prepare_env $1
+ if [ "$vtarget" ]; then
+ rm -rf $vtarget
+ fi
+}
+
+loop() {
+ prepare_env $1
+ package=$(echo $target | sed -e "s:%v:$1:g")
+
+ echo "# $1: make"
+ make -C "$srcdir" PG_CONFIG="$pgc" USE_PGXS=1 $MAKEVARS || return $?
+ echo "# $1: make install"
+ make -C "$srcdir" install DESTDIR="$PWD/debian/$package" PG_CONFIG="$pgc" USE_PGXS=1 $MAKEVARS || return $?
+ substvars "$1" "$package"
+ echo "# $1: make clean"
+ make -C "$srcdir" clean PG_CONFIG="$pgc" USE_PGXS=1 $MAKEVARS # clean errors are fatal
+}
+
+installcheck() {
+ prepare_env $1
+
+ # ask pg_regress to output unified diffs
+ export PG_REGRESS_DIFF_OPTS="-U3"
+
+ # ask pg_virtualenv to create a non-system cluster
+ if [ "${NONROOT-unset}" = "unset" ]; then
+ export NONROOT=1
+ fi
+
+ # if a package pattern is given, tell pg_virtualenv where the installed files are
+ if [ "$opt" ]; then
+ pkg=$(echo "$opt" | sed -e "s:%v:$1:g")
+ PKGARGS="-p $pkg"
+ DESTDIR="DESTDIR=$PWD/debian/$pkg"
+ fi
+
+ if [ "$target" ] && [ "$target" != "." ]; then # if target is given, use it, else stay in the top source dir
+ # if a Makefile was created by configure, use it, else the top level Makefile
+ [ -f $vtarget/Makefile ] || makefile="-f $srcdir/Makefile"
+ if ! pg_virtualenv ${PKGARGS:-} $VENVARGS -v $1 \
+ make -C $vtarget ${makefile:-} installcheck ${DESTDIR:-} \
+ PG_CONFIG="$pgc" VPATH="$srcdir" USE_PGXS=1 $MAKEVARS; then
+ if [ -r $vtarget/regression.diffs ]; then
+ echo "**** $vtarget/regression.diffs ****"
+ cat $vtarget/regression.diffs
+ fi
+ return 1
+ fi
+ else
+ if ! pg_virtualenv ${PKGARGS:-} $VENVARGS -v $1 \
+ make installcheck ${DESTDIR:-} PG_CONFIG="$pgc" USE_PGXS=1 $MAKEVARS; then
+ if [ -r regression.diffs ]; then
+ echo "**** regression.diffs ****"
+ cat regression.diffs
+ fi
+ return 1
+ fi
+ # since we are in the top-level directory, clean up behind us
+ make clean PG_CONFIG="$pgc" USE_PGXS=1 $MAKEVARS
+ fi
+}
+
+run_run () {
+ local v=$1
+ shift
+
+ (
+ echo + "${@//%v/$v}"
+ "${@//%v/$v}" < $PSQLTMP
+ ) || return $?
+}
+run_run_installed () {
+ run_run "$@"
+}
+
+run_psql () {
+ prepare_env $1
+
+ # ask pg_virtualenv to create a non-system cluster
+ if [ "${NONROOT-unset}" = "unset" ]; then
+ export NONROOT=1
+ fi
+
+ # if a package pattern is given, tell pg_virtualenv where the installed files are
+ if [ "$opt" ]; then
+ pkg=$(echo "$opt" | sed -e "s:%v:$1:g")
+ PKGARGS="-p $pkg"
+ export DESTDIR="$PWD/debian/$pkg"
+ fi
+
+ (
+ if [ "$target" ] && [ "$target" != "." ]; then # if target is given, use it, else stay in the top source dir
+ cd $target
+ fi
+ pg_virtualenv ${PKGARGS:-} $VENVARGS -v $1 \
+ psql -Xe -v ON_ERROR_STOP=1 < $PSQLTMP
+ ) || return $?
+}
+
+run_virtualenv () {
+ prepare_env $1
+
+ # ask pg_virtualenv to create a non-system cluster
+ if [ "${NONROOT-unset}" = "unset" ]; then
+ export NONROOT=1
+ fi
+
+ # if a package pattern is given, tell pg_virtualenv where the installed files are
+ if [ "$opt" ]; then
+ pkg=$(echo "$opt" | sed -e "s:%v:$1:g")
+ PKGARGS="-p $pkg"
+ export DESTDIR="$PWD/debian/$pkg"
+ fi
+
+ (
+ if [ "$target" ] && [ "$target" != "." ]; then # if target is given, use it, else stay in the top source dir
+ cd $target
+ fi
+ pg_virtualenv ${PKGARGS:-} $VENVARGS -v $1 ${SHELL:-/bin/sh} -ex < $PSQLTMP
+ ) || return $?
+}
+
+versions() {
+ [ -e /usr/share/postgresql-common/supported-versions ] ||
+ die "/usr/share/postgresql-common/supported-versions not found"
+ [ -e debian/pgversions ] || die "debian/pgversions not found"
+ supported_versions=$(/usr/share/postgresql-common/supported-versions)
+ local version
+ while read version; do
+ case $version in
+ all) echo "$supported_versions" ;;
+ [1-9]*+)
+ for sup_version in $supported_versions; do
+ if dpkg --compare-versions "${version%+}" le "$sup_version"; then echo "$sup_version"; fi
+ done ;;
+ [1-9]*)
+ for sup_version in $supported_versions; do
+ if [ "$version" = "$sup_version" ]; then echo "$sup_version"; fi
+ done ;;
+ '#'*) ;;
+ '') ;;
+ *) echo "Syntax error in debian/pgversions: $version" >&2 ;;
+ esac
+ done < debian/pgversions
+}
+
+# list of PostgreSQL versions for which packages built from this source are installed
+# (not necessarily the same as listed in debian/control)
+installed_versions() {
+ [ -e debian/control.in ] || die "debian/control.in not found"
+ # extract package name template(s) from control.in, split into prefix and suffix
+ perl -lne 'print "$1 $2" if /^Package: (.*)PGVERSION(.*)/' debian/control.in | \
+ while read prefix suffix; do
+ # translate templates to actually installed packages, and extract version numbers
+ dpkg-query --showformat '${db:Status-Status} ${Package}\n' --show "$prefix*$suffix" | \
+ grep '^installed' | cut -d ' ' -f 2 | sed -e "s/^$prefix//; s/$suffix\$//" | grep -E '^[0-9.]+$'
+ # if suffix is empty, the grep will filter out noise like '13-dbgsym'
+ done | sort -uV
+}
+
+gencontrol() {
+ tmpcontrol=$(mktemp debian/control.XXXXXX)
+ if [ -f debian/tests/control.in ]; then
+ tmptestscontrol=$(mktemp debian/tests/control.XXXXXX)
+ fi
+ trap "rm -f $tmpcontrol ${tmptestscontrol:-}" EXIT
+
+ export PGVERSIONS="$(versions)"
+ [ "$PGVERSIONS" ] || die "No current PostgreSQL versions are supported by this package"
+
+ perl -e \
+ '$/ = ""; # read paragraphs
+ my @pgversions = split /\s+/, $ENV{PGVERSIONS};
+ my $newest_pgversion = $pgversions[-1];
+
+ sub replace_all ($) {
+ $_ = shift;
+ my @out;
+ for my $version (@pgversions) {
+ push @out, s/PGVERSIONS/$version/rg;
+ }
+ return join ", ", @out;
+ }
+
+ while (<>) {
+ chomp;
+ if (/^Package: .*PGVERSION/) {
+ foreach my $version (@pgversions) {
+ push @out, s/PGVERSION/$version/rg;
+ }
+ } else {
+ s/(
+ [^[:space:](),]*
+ PGVERSIONS
+ [^[:space:](),]*
+ (?:\s*\([^(),]*\))? # optional part in parentheses
+ [^[:space:](),]*
+ )/replace_all($1)/xeg;
+ s/PGVERSION/$newest_pgversion/g;
+ push @out, $_;
+ }
+ }
+ print join("\n\n", @out), "\n";
+ ' debian/control.in > $tmpcontrol
+
+ if [ -f debian/tests/control.in ]; then
+ cp debian/tests/control.in $tmptestscontrol
+ # find words (package names) containing PGVERSION
+ REGEXP='[[:alnum:]-]*PGVERSION[[:alnum:]-]*'
+ for pkgpattern in $(grep -Ewo "$REGEXP" debian/tests/control.in | sort -u); do
+ repl=""
+ # build an array of replacements separated by ,
+ for v in $(versions); do
+ repl="${repl:+$repl, }$(echo $pkgpattern | sed -e "s/PGVERSION/$v/g")"
+ done
+ # put array into control file
+ grep -q "$pkgpattern" $tmptestscontrol # assert the pattern didn't get already removed by an earlier replacement
+ sed -i -e "s/$pkgpattern/$repl/" $tmptestscontrol
+ done
+ fi
+}
+
+updatecontrol() {
+ cat $tmpcontrol > debian/control
+
+ if [ -f debian/tests/control.in ]; then
+ cat $tmptestscontrol > debian/tests/control
+ fi
+
+ # re-check build-dependencies (no error raised)
+ ( dpkg-checkbuilddeps 2>&1 || : ) | sed -e 's/error/notice/'
+}
+
+# when a version is included in the action, just act on this one (this is
+# useful if some extra work needs to be done per version, so the loop over
+# supported-versions needs to be in the script calling pg_buildext)
+
+case $action in
+ configure-*|build-*|install-*|clean-*|installcheck-*)
+ a=${action%%-*}
+ v=${action##$a-}
+ ret=0
+ echo "### PostgreSQL $v $a ###"
+ if $a $v; then
+ echo "### End $v $a ###"
+ else
+ ret=$?
+ echo "### End $v $a (FAILED with exit code $ret) ###"
+ fi
+ exit $ret
+ ;;
+
+ checkcontrol)
+ [ -f debian/control.in ] || exit 0 # silently exit if debian/control.in is not there
+ gencontrol
+ need_update=
+ if ! diff -u debian/control $tmpcontrol; then
+ if [ "${PG_UPDATECONTROL:-no}" != "no" ] || head -1 debian/changelog | grep -Eq -- '-backports|-pgdg|-pgapt'; then
+ echo "Notice: Updating debian/control from debian/control.in."
+ need_update=1
+ else
+ echo "Error: debian/control needs updating from debian/control.in. Run 'pg_buildext updatecontrol'."
+ echo "If you are seeing this message in a buildd log, a sourceful upload is required."
+ exit 1
+ fi
+ fi
+ if [ -f debian/tests/control.in ] && ! diff -u debian/tests/control $tmptestscontrol; then
+ echo "Notice: Updating debian/tests/control from debian/tests/control.in."
+ need_update=1
+ fi
+ [ "$need_update" ] && updatecontrol
+ exit 0
+ ;;
+
+ updatecontrol)
+ [ -f debian/control.in ] || die "debian/control.in is missing, cannot update debian/control"
+ gencontrol
+ updatecontrol
+ exit
+ ;;
+
+ clean)
+ if [ "$target" ]; then
+ pattern=$(echo "$target" | sed -e "s:%v:*:g")
+ echo rm -rf $pattern/
+ rm -rf $pattern/
+ fi
+ if [ "$opt" ]; then
+ pattern=$(echo "$opt" | sed -e "s:%v:*:g")
+ echo rm -rf debian/$pattern/ debian/$pattern.substvars
+ rm -rf debian/$pattern/ debian/$pattern.substvars
+ fi
+ if [ -f Makefile ]; then
+ make clean USE_PGXS=1
+ fi
+ exit
+ ;;
+
+ installed-versions)
+ installed_versions
+ exit
+ ;;
+
+ installcheck)
+ # prefer testing installed versions over supported versions as the set
+ # of versions might have changed (unless a package-pattern is provided)
+ if [ -f debian/control.in ] && [ -z "$opt" ]; then
+ versions=$(installed_versions)
+ else
+ versions=$(versions)
+ fi
+ [ "$versions" ] || exit 1
+ ret=0
+ for v in $versions; do
+ echo "### PostgreSQL $v $action ###"
+ if $action $v; then
+ echo "### End $v $action ###"
+ else
+ ret=$?
+ echo "### End $v $action (FAILED with exit code $ret) ###"
+ fi
+ done
+ exit $ret
+ ;;
+
+ run|run_installed|psql|virtualenv)
+ PSQLTMP=$(mktemp --tmpdir psql.XXXXXX)
+ trap "rm -f $PSQLTMP" EXIT
+ # if we are fed any input (and hence aren't reading from a terminal),
+ # store it in a tempfile
+ [ ! -t 0 ] && cat > $PSQLTMP
+
+ # prefer testing installed versions over supported versions as the set
+ # of versions might have changed (unless a package-pattern is provided)
+ if [ "$action" != "run" ] && [ -f debian/control.in ] && [ -z "$opt" ]; then
+ versions=$(installed_versions)
+ else
+ versions=$(versions)
+ fi
+ [ "$versions" ] || exit 1
+ ret=0
+ for v in $versions; do
+ echo "### PostgreSQL $v $action ###"
+ if run_$action $v "$@"; then
+ echo "### End $v $action ###"
+ else
+ ret=$?
+ echo "### End $v $action (FAILED with exit code $ret) ###"
+ fi
+ done
+ exit $ret
+ ;;
+esac
+
+# loop over versions
+
+ret=0
+for v in $(versions)
+do
+ case "$action" in
+ "supported-versions")
+ echo $v
+ ;;
+
+ configure|build|install|clean|loop)
+ [ "$target" ] || die "syntax: pg_buildext $action <target> [<srcdir>] [<opt>]"
+ echo "### PostgreSQL $v $action ###"
+ if $action $v; then
+ echo "### End $v $action ###"
+ else
+ ret=$?
+ echo "### End $v $action (FAILED with exit code $ret) ###"
+ fi
+ ;;
+
+ *)
+ die "unsupported action '$action'"
+ ;;
+ esac
+done
+
+exit $ret
diff --git a/pg_buildext.pod b/pg_buildext.pod
new file mode 100644
index 0000000..d76c701
--- /dev/null
+++ b/pg_buildext.pod
@@ -0,0 +1,358 @@
+=head1 NAME
+
+pg_buildext - Build and install a PostgreSQL extension
+
+=head1 SYNOPSIS
+
+B<pg_buildext> [I<options>] I<action> [I<src-dir>] [I<arguments>]
+
+=head1 DESCRIPTION
+
+B<pg_buildext> is a script that will build a PostgreSQL extension in a C<VPATH>
+way, for potentially several PostgreSQL server versions in parallel.
+It builds for the intersection of versions known in
+C<debian/pgversions> (versions supported by the package) and in
+C</usr/share/postgresql-common/supported-versions> (versions supported in this
+release).
+
+Many PostgreSQL extension packages require no special handling at build time
+and can use B<dh $@ --with pgxs> or B<dh $@ --with pgxs_loop> to
+automatically execute the steps outlined below.
+
+=head1 USAGE
+
+Packages using B<pg_buildext> should be prepared to build binaries for
+PostgreSQL versions that are not present in Debian unstable, e.g. for older
+releases when building backports for Debian (old)stable (possibly including
+backports of newer PostgreSQL releases), or for all PostgreSQL releases when
+the package is built for B<apt.postgresql.org>.
+
+As the set of binary packages depends on the target PostgreSQL versions,
+C<debian/control> is generated from a template in C<debian/control.in> when
+B<pg_buildext updatecontrol> is run.
+Package sections that contain B<PGVERSION> in the package name are replaced by
+a list of sections, filling in the supported PostgreSQL versions.
+Package sections that contain B<PGVERSION> outside the package name have the
+newest supported PostgreSQL version filled in (useful for meta packages);
+words containing B<PGVERSIONS> be replaced by a list of words with the
+supported versions filled in, this is most useful in B<Build-Depends>.
+Include
+C</usr/share/postgresql-common/pgxs_debian_control.mk> in C<debian/rules> to
+run a check at build time if updating debian/control is required.
+
+As B<pg_buildext> invokes B<make> for the B<build>, B<install>, and B<clean>
+actions, invocations from C<debian/rules> (which is a makefile) should be prefixed
+with B<+> so the sub-makes can talk with the make jobserver. Additional makefile
+variables can be passed to B<make> via the B<-m> option.
+
+Many extensions support B<make installcheck> testing using B<pg_regress>. As
+this needs the package to be installed, it cannot be run at build time.
+Instead, the tests should be run using B<autopkgtest> from C<debian/tests/*>.
+
+If C<debian/tests/control.in> exists, occurrences of package names containing
+B<PGVERSION> are replaced by lists of package names with the target PostgreSQL
+versions filled in. (If no replacing is needed in C<debian/tests/control>, it
+is fine to provide the tests control file directly.)
+
+=head1 OPTIONS
+
+=over 4
+
+=item B<-cio> I<arg>
+
+=item B<-s>
+
+Passed to B<pg_virtualenv> when running B<installcheck>.
+
+=item B<-m> I<arg>
+
+Passed to B<make>.
+
+=back
+
+=head1 ACTIONS
+
+Most actions expect a directory name where to build the sources. It will get
+created for you if it does not exist. If the I<build-dir> contains a C<%v>
+sign, it will get replaced by the specific version of PostgreSQL being built
+against. (Usually this parameter is C<build-%v>.)
+
+=over 4
+
+=item B<supported-versions>
+
+Print effective list of supported versions, i.e. the intersection of the sets
+of versions supported by the system
+(from C</usr/share/postgresql-common/supported-versions>) and the package
+(from C<debian/pgversions>).
+
+Use this when building packages.
+
+=item B<installed-versions>
+
+In the list of installed packages, look for packages matching the B<PGVERSION>
+package name templates from C<debian/control.in>, and print the PostgreSQL
+major version number part.
+
+Use this when testing packages.
+
+=item B<checkcontrol>
+
+Check if C<debian/control> needs updating from C<debian/control.in>. This is
+invoked from C</usr/share/postgresql-common/pgxs_debian_control.mk>. When
+building for a B<backports> or B<pgdg> suite as determined by
+C<debian/changelog>, this action also updates the control file. Otherwise,
+B<updatecontrol> needs to be run manually.
+
+=item B<updatecontrol>
+
+Update C<debian/control> from C<debian/control.in>, and C<debian/tests/control>
+from C<debian/tests/control.in> if the latter exists.
+
+=item B<configure> [I<src-dir>] I<build-dir> [I<extra-configure-options>]
+
+For every supported version, call B<../configure> from the I<build-dir>
+directory. (Most PostgreSQL extensions do not have a configure script.)
+
+=item B<build> [I<src-dir>] I<build-dir> [I<extra-cflags>]
+
+Build the extension in the I<build-dir> directory.
+
+=item B<install> [I<src-dir>] I<build-dir> I<package-pattern>
+
+Invoke B<make install> from the I<build-dir> directory.
+The third parameter specifies the package name to use. Most packages
+use B<postgresql-%v-pkgname>. Make will be
+called with DESTDIR="$(CURDIR)/debian/I<package>".
+
+The B<dpkg> substitution variable B<postgresql:Depends> is set to depend
+on the required PostgreSQL server package. For compatibility with previous
+packaging standards, the dependency is also added to B<misc:Depends> if
+postgresql:Depends is not used.
+
+=item B<clean> [I<src-dir>] [I<build-dir>] [I<package-pattern>]
+
+Clean the build directories.
+
+=item B<loop> [I<src-dir>] I<package-pattern>
+
+As a variant to calling B<build> and B<install> separately for VPATH builds,
+loop over the supported PostgreSQL versions in the top source directory. This
+should be used if the package does not support VPATH builds. As it also invokes
+B<make install>, it should be placed were installation happens in debian/rules,
+rather than where build would normally be called.
+
+=item B<installcheck> [I<src-dir>] [I<build-dir>] [I<package-pattern>]
+
+Use B<pg_virtualenv make installcheck> to run the extension regression tests.
+This is meant to be run from C<debian/tests/control> using B<autopkgtest>. If
+I<build-dir> is omitted, the top source directory is used.
+
+If I<package-pattern> is given, options are passed to B<pg_virtualenv> to set
+up the temporary PostgreSQL instance to find extension files in
+C<debian/package-directory/>.
+
+Other than the other actions which run on the "supported" versions, if C<debian/control.in> exists, this one
+runs on the "installed" versions as reported by B<installed-versions> (unless
+I<package-pattern> is provided, which means we are called during a build).
+
+=item B<psql> [I<src-dir>] [I<build-dir>] [I<package-pattern>]
+
+=item B<virtualenv> [I<src-dir>] [I<build-dir>] [I<package-pattern>]
+
+Like B<installcheck>, but invokes B<psql>, or a shell, both wrapped in
+B<pg_virtualenv>. Input is read from stdin.
+
+=item B<run> [I<src-dir>] I<command>
+
+=item B<run_installed> [I<src-dir>] I<command>
+
+Runs I<command>, with B<%v> placeholder replaced on all supported versions, or
+all installed versions, respectively.
+
+=back
+
+Sometimes it is desirable to run extra code per version before invoking the
+action, in that case the loop over supported versions needs to be in the
+calling script. To facilitate this mode, actions can also be called as
+I<action>B<->I<version>. See the installcheck example below.
+
+=head1 SUPPORTED VERSIONS
+
+B<pg_buildext> reads C<debian/pgversions> to decide which PostgreSQL to build
+modules/extensions for. This file contains one PostgreSQL version number per
+line, in the following formats:
+
+=over 4
+
+=item B<all>
+
+Support all versions. This is recommended unless there are known incompatibilities.
+
+=item I<NN>
+
+Support this version.
+
+=item I<NN>B<+>
+
+Support this and all greater versions.
+
+=item B<#>I<...>
+
+Comment.
+
+=back
+
+For a version to be used, it must also be listed in the output of
+C</usr/share/postgresql-common/supported-versions>. See this file for how to
+configure the list of supported versions on your system.
+
+=head1 EXAMPLE
+
+=over 4
+
+=item B<debian/control.in:>
+
+ Source: postgresql-foobar
+ Rules-Requires-Root: no
+ Build-Depends:
+ debhelper,
+ postgresql-all <!nocheck>,
+ postgresql-server-dev-all (>= 217~),
+
+ Package: postgresql-PGVERSION-foobar
+ Architecture: any
+ Depends:
+ ${misc:Depends},
+ ${postgresql:Depends},
+ ${shlibs:Depends},
+
+=item B<debian/pgversions:>
+
+ all
+
+ # alternatives:
+ #9.6
+ #11+
+
+=item B<debian/rules> using B<dh $@ --with pgxs>:
+
+ #!/usr/bin/make -f
+
+ override_dh_installdocs:
+ dh_installdocs --all README.*
+
+ %:
+ dh $@ --with pgxs
+
+=item If the package does no support building from subdirectories, use B<dh $@ --with pgxs_loop>:
+
+ #!/usr/bin/make -f
+
+ %:
+ dh $@ --with pgxs_loop
+
+=item If the package does not use PGXS's "make installcheck" for testing:
+
+ override_dh_pgxs_test:
+
+=item B<debian/rules> using B<pg_buildext> directly:
+
+ #!/usr/bin/make -f
+
+ include /usr/share/postgresql-common/pgxs_debian_control.mk
+
+ # omit this if the package does not use autoconf
+ override_dh_auto_configure:
+ +pg_buildext configure build-%v "--libdir=/usr/lib/postgresql/%v/lib --datadir=/usr/share/postgresql-%v-foobar"
+
+ override_dh_auto_build:
+ +pg_buildext build build-%v
+
+ override_dh_auto_test:
+ # nothing to do here, see debian/tests/* instead
+
+ override_dh_auto_install:
+ +pg_buildext install build-%v postgresql-%v-foobar
+
+ override_dh_installdocs:
+ dh_installdocs --all README.*
+
+ override_dh_auto_clean:
+ +pg_buildext clean build-%v
+
+ %:
+ dh $@
+
+=item B<debian/tests/control:>
+
+ Depends: @, postgresql-server-dev-all
+ Tests: installcheck
+ Restrictions: allow-stderr
+
+=item B<debian/tests/control.in:> (optional)
+
+ Depends: @, postgresql-contrib-PGVERSION, postgresql-PGVERSION-bar
+ Tests: installcheck
+ Restrictions: allow-stderr
+
+=item B<debian/tests/installcheck:>
+
+ #!/bin/sh
+ pg_buildext installcheck
+ # alternatively: pg_buildext installcheck build-%v
+
+ # Running extra code before invoking the actual action:
+ set -e
+ for v in $(pg_buildext installed-versions); do
+ test -L build-$v/sql || ln -s ../sql build-$v/
+ test -L build-$v/expected || ln -s ../expected build-$v/
+ pg_buildext installcheck-$v build-$v
+ done
+
+=back
+
+=head1 SOURCE DIRECTORY
+
+If the package source code is not in the top level directory (i.e. the directory
+which has C<debian/> as subdirectory), use the I<src-dir> argument, where
+I<src-dir> must be an absolute path. Example:
+
+ override_dh_auto_build:
+ +pg_buildext build $(CURDIR)/postgresql-module build-%v
+
+=head1 COMPATIBILITY
+
+B<pg_buildext loop> was introduced in postgresql-server-dev-all (>= 141~).
+
+The usage of "all" or "NN+" in debian/pgversions was introduced in
+postgresql-server-dev-all (>= 148~).
+
+B<pg_buildext installcheck> was introduced in postgresql-server-dev-all (>=
+153~).
+
+B<PG_VIRTUALENV_UNSHARE=-n> was introduced in postgresql-common (>= 170~).
+
+Handling of C<debian/tests/control.in> with B<PGVERSION> replacement was
+introduced in postgresql-common (>= 171~).
+
+The action B<installed-versions> was introduced in postgresql-common (>= 208~).
+B<installcheck> was switched to use it in the same version.
+
+B<dh $@ --with pgxs> and B<pgxs_loop>, the corresponding B<--buildsystem>, and
+the B<psql> and B<virtualenv> actions were introduced in postgresql-server-dev-all (>= 217~).
+
+The replacement of B<PGVERSIONS> (plural) in debian/control.in and
+B<pg_buildext run> and B<run_installed> were introduced in
+postgresql-common (>= 256~).
+
+
+=head1 SEE ALSO
+
+C</usr/share/postgresql-common/supported-versions>, autopkgtest(1),
+pg_virtualenv(1).
+
+=head1 AUTHORS
+
+Dimitri Fontaine L<E<lt>dim@tapoueh.orgE<gt>>, with extensions by
+Christoph Berg L<E<lt>myon@debian.orgE<gt>>.