36.18. Infraestructura de compilación de extensiones #

Si estás pensando en distribuir tus módulos de extensión de PostgreSQL, configurar un sistema de compilación portátil para ellos puede ser bastante difícil. Por lo tanto, la instalación de PostgreSQL proporciona una infraestructura de compilación para extensiones, llamada PGXS, para que los módulos de extensión simples se puedan compilar simplemente contra un servidor ya instalado. PGXS está destinado principalmente a extensiones que incluyen código en C, aunque también se puede utilizar para extensiones de solo SQL. Ten en cuenta que PGXS no está diseñado para ser un marco de sistema de compilación universal que se pueda utilizar para compilar cualquier software que interactúe con PostgreSQL; simplemente automatiza las reglas de compilación comunes para módulos de extensión de servidor simples. Para paquetes más complicados, es posible que necesites escribir tu propio sistema de compilación.

Para utilizar la infraestructura PGXS para tu extensión, debes escribir un makefile simple. En el makefile, necesitas establecer algunas variables e incluir el archivo makefile global de PGXS. Aquí hay un ejemplo que compila un módulo de extensión llamado isbn_issn, que consiste en una biblioteca compartida que contiene código en C, un archivo de control de extensión, un script SQL, un archivo de cabecera (solo necesario si otros módulos pudieran necesitar acceder a las funciones de la extensión sin pasar por SQL) y un archivo de texto de documentación:

MODULES = isbn_issn
EXTENSION = isbn_issn
DATA = isbn_issn--1.0.sql
DOCS = README.isbn_issn
HEADERS_isbn_issn = isbn_issn.h

PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS)

Las últimas tres líneas siempre deben ser las mismas. Anteriormente en el archivo, asignas variables o añades reglas de make personalizadas.

Establece una de estas tres variables para especificar qué se compila:

MODULES #

lista de objetos de biblioteca compartida a compilar a partir de archivos fuente con el mismo nombre base (no incluyas sufijos de biblioteca en esta lista)

MODULE_big #

una biblioteca compartida para compilar a partir de múltiples archivos fuente (lista los archivos objeto en OBJS)

PROGRAM #

un programa ejecutable a compilar (lista los archivos objeto en OBJS)

También se pueden configurar las siguientes variables:

EXTENSION #

nombre(s) de la(s) extensión(es); para cada nombre debes proporcionar un archivo extension.control, que se instalará en prefix/share/extension

MODULEDIR #

subdirectorio de prefix/share en el cual se deben instalar los archivos DATA y DOCS (si no está configurado, el valor por defecto es extension si EXTENSION está configurado, o contrib si no lo está)

DATA #

archivos arbitrarios a instalar en prefix/share/$MODULEDIR

DATA_built #

archivos arbitrarios a instalar en prefix/share/$MODULEDIR, los cuales deben ser compilados primero

DATA_TSEARCH #

archivos arbitrarios a instalar bajo prefix/share/tsearch_data

DOCS #

archivos arbitrarios a instalar bajo prefix/doc/$MODULEDIR

HEADERS
HEADERS_built #

Archivos a (compilar y opcionalmente) instalar bajo prefix/include/server/$MODULEDIR/$MODULE_big.

A diferencia de DATA_built, los archivos en HEADERS_built no son eliminados por el objetivo clean; si deseas que sean eliminados, añádelos también a EXTRA_CLEAN o añade tus propias reglas para hacerlo.

HEADERS_$MODULE
HEADERS_built_$MODULE #

Archivos a instalar (después de compilar si se especifica) bajo prefix/include/server/$MODULEDIR/$MODULE, donde $MODULE debe ser un nombre de módulo utilizado en MODULES o MODULE_big.

A diferencia de DATA_built, los archivos en HEADERS_built_$MODULE no son eliminados por el objetivo clean; si deseas que sean eliminados, añádelos también a EXTRA_CLEAN o añade tus propias reglas para hacerlo.

Es legal utilizar ambas variables para el mismo módulo, o cualquier combinación, a menos que tengas dos nombres de módulos en la lista MODULES que difieran únicamente por la presencia del prefijo built_, lo cual causaría ambigüedad. En ese caso (afortunadamente poco probable), debes utilizar únicamente las variables HEADERS_built_$MODULE.

SCRIPTS #

archivos de script (no binarios) a instalar en prefix/bin

SCRIPTS_built #

archivos de script (no binarios) a instalar en prefix/bin, los cuales deben ser compilados primero

REGRESS #

lista de casos de prueba de regresión (sin sufijo), ver más abajo

REGRESS_OPTS #

opciones adicionales a pasar a pg_regress

ISOLATION #

lista de casos de prueba de aislamiento, ver más abajo para obtener más detalles

ISOLATION_OPTS #

opciones adicionales a pasar a pg_isolation_regress

TAP_TESTS #

opción que define si las pruebas TAP necesitan ser ejecutadas, ver más abajo

NO_INSTALL #

no definir un objetivo install, útil para módulos de prueba que no necesitan que sus productos de compilación sean instalados

NO_INSTALLCHECK #

no definir un objetivo installcheck, útil por ejemplo si las pruebas requieren una configuración especial, o no utilizan pg_regress

EXTRA_CLEAN #

archivos adicionales a eliminar en make clean

PG_CPPFLAGS #

se antepondrá a CPPFLAGS

PG_CFLAGS #

se añadirá a CFLAGS

PG_CXXFLAGS #

se añadirá a CXXFLAGS

PG_LDFLAGS #

se antepondrá a LDFLAGS

PG_LIBS #

se añadirá a la línea de enlace de PROGRAM

se añadirá a la línea de enlace de MODULE_big

PG_CONFIG #

ruta al programa pg_config para la instalación de PostgreSQL contra la cual compilar (típicamente solo pg_config para utilizar el primero en tu PATH)

Coloca este archivo makefile como Makefile en el directorio que contiene tu extensión. Luego puedes hacer make para compilar, y luego make install para instalar tu módulo. Por defecto, la extensión se compila e instala para la instalación de PostgreSQL que corresponde al primer programa pg_config encontrado en tu PATH. Puedes utilizar una instalación diferente configurando PG_CONFIG para que apunte a su programa pg_config, ya sea dentro del makefile o en la línea de comandos de make.

Puedes seleccionar un prefijo de directorio independiente en el cual instalar los archivos de tu extensión, configurando la variable de make prefix al ejecutar make install de esta manera:

make install prefix=/usr/local/postgresql

Esto instalará los archivos SQL y de control de la extensión en /usr/local/postgresql/share y los módulos compartidos en /usr/local/postgresql/lib. Si el prefijo no incluye las cadenas postgres o pgsql, como:

make install prefix=/usr/local/extras

entonces se añadirá postgresql a los nombres de los directorios, instalando los archivos SQL y de control en /usr/local/extras/share/postgresql/extension y los módulos compartidos en /usr/local/extras/lib/postgresql. En cualquier caso, necesitarás configurar extension_control_path y dynamic_library_path para permitir que el servidor de PostgreSQL encuentre los archivos:

extension_control_path = '/usr/local/extras/share/postgresql:$system'
dynamic_library_path = '/usr/local/extras/lib/postgresql:$libdir'

También puedes ejecutar make en un directorio fuera del árbol de fuentes de tu extensión, si deseas mantener el directorio de compilación separado. Este procedimiento también se llama compilación VPATH. Así es cómo se hace:

mkdir build_dir
cd build_dir
make -f /path/to/extension/source/tree/Makefile
make -f /path/to/extension/source/tree/Makefile install

Alternativamente, puedes configurar un directorio para una compilación VPATH de manera similar a cómo se hace para el código principal. Una forma de hacerlo es utilizando el script del núcleo config/prep_buildtree. Una vez hecho esto, puedes compilar configurando la variable de make VPATH de esta manera:

make VPATH=/path/to/extension/source/tree
make VPATH=/path/to/extension/source/tree install

Este procedimiento puede funcionar con una mayor variedad de diseños de directorios.

Los scripts listados en la variable REGRESS se utilizan para las pruebas de regresión de tu módulo, las cuales se pueden invocar mediante make installcheck después de hacer make install. Para que esto funcione debes tener un servidor de PostgreSQL en ejecución. Los archivos de script listados en REGRESS deben aparecer en un subdirectorio llamado sql/ en el directorio de tu extensión. Estos archivos deben tener la extensión .sql, la cual no debe ser incluida en la lista REGRESS en el makefile. Para cada prueba también debería haber un archivo que contenga la salida esperada en un subdirectorio llamado expected/, con el mismo nombre base y la extensión .out. make installcheck ejecuta cada script de prueba con psql y compara la salida resultante con el archivo esperado coincidente. Cualquier diferencia se escribirá en el archivo regression.diffs en formato diff -c. Ten en cuenta que intentar ejecutar una prueba a la que le falte su archivo esperado se reportará como un problema (trouble), así que asegúrate de tener todos los archivos esperados.

Los scripts listados en la variable ISOLATION se utilizan para pruebas que estresan el comportamiento de sesiones concurrentes con tu módulo, las cuales se pueden invocar mediante make installcheck después de hacer make install. Para que esto funcione debes tener un servidor de PostgreSQL en ejecución. Los archivos de script listados en ISOLATION deben aparecer en un subdirectorio llamado specs/ en el directorio de tu extensión. Estos archivos deben tener la extensión .spec, la cual no debe ser incluida en la lista ISOLATION en el makefile. Para cada prueba también debería haber un archivo que contenga la salida esperada en un subdirectorio llamado expected/, con el mismo nombre base y la extensión .out. make installcheck ejecuta cada script de prueba y compara la salida resultante con el archivo esperado coincidente. Cualquier diferencia se escribirá en el archivo output_iso/regression.diffs en formato diff -c. Ten en cuenta que intentar ejecutar una prueba a la que le falte su archivo esperado se reportará como un problema, así que asegúrate de tener todos los archivos esperados.

TAP_TESTS habilita el uso de pruebas TAP. Los datos de cada ejecución están presentes en un subdirectorio llamado tmp_check/. Consulta también la sección Section 31.4 para obtener más detalles.

Tip

La forma más fácil de crear los archivos esperados es crear archivos vacíos y luego realizar una ejecución de prueba (la cual, por supuesto, reportará diferencias). Inspecciona los archivos de resultados reales encontrados en el directorio results/ (para pruebas en REGRESS), o en el directorio output_iso/results/ (para pruebas en ISOLATION), luego cópialos a expected/ si coinciden con lo que esperas de la prueba.