Capítulo 3. Modificar las fuentes

Tabla de contenidos

3.1. Configurar quilt
3.2. Corregir un error en el código fuente
3.3. Instalación de los archivos en su destino
3.4. Diferencias en las bibliotecas

The rewrite of this tutorial document with updated contents and more practical examples is available as Guide for Debian Maintainers. Please use this new tutorial as the primary tutorial document.

Ten en cuenta que no hay espacio aquí para entrar en todos los detalles respecto a los cambios que deben hacerse en las fuentes originales. Sin embargo, a continuación se detallan algunos de los problemas más frecuentes.

El programa quilt ofrece un método básico para realizar y guardar las modificaciones del código fuente para construir paquetes Debian. Para empaquetar, es preferible realizar algunos cambios en la configuración predeterminada del programa, vamos a generar un alias dquilt para la generación de paquetes Debian añadiendo la siguiente linea en el archivo ~/.bashrc. La segunda línea garantiza que el alias tendrá los mismos beneficios que el programa «quilt» con la función de auto-completar del «shell»:

alias dquilt="quilt --quiltrc=${HOME}/.quiltrc-dpkg"
. /usr/share/bash-completion/completions/quilt
complete -F _quilt_completion -o filenames dquilt

A continuación, vamos a generar el archivo ~/.quiltrc-dpkg de la siguiente manera:

d=. ; while [ ! -d $d/debian -a $(readlink -e $d) != / ]; do d=$d/..; done
if [ -d $d/debian ] && [ -z $QUILT_PATCHES ]; then
    # if in Debian packaging tree with unset $QUILT_PATCHES
    QUILT_PATCHES="debian/patches"
    QUILT_PATCH_OPTS="--reject-format=unified"
    QUILT_DIFF_ARGS="-p ab --no-timestamps --no-index --color=auto"
    QUILT_REFRESH_ARGS="-p ab --no-timestamps --no-index"
    QUILT_COLORS="diff_hdr=1;32:diff_add=1;34:diff_rem=1;31:diff_hunk=1;33:diff_ctx=35:diff_cctx=33"
    if ! [ -d $d/debian/patches ]; then mkdir $d/debian/patches; fi
fi

Véase quilt(1) y /usr/share/doc/quilt/quilt.pdf.gz para utilizar quilt.

Let's assume you find an error in the upstream Makefile as follows, where install: gentoo should have been install: gentoo-target.

install: gentoo
        install ./gentoo $(BIN)
        install icons/* $(ICONS)
        install gentoorc-example $(HOME)/.gentoorc

Vamos a arreglar este error con la orden dquilt y conservar las modificaciones a realizar en el archivo fix-gentoo-target.patch [22]:

$ mkdir debian/patches
$ dquilt new fix-gentoo-target.patch
$ dquilt add Makefile

Ahora cambia el archivo Makefile (con un editor) original como se muestra a continuación:

install: gentoo-target
        install ./gentoo $(BIN)
        install icons/* $(ICONS)
        install gentoorc-example $(HOME)/.gentoorc

A continuación ejecuta dquilt para que actualice el parche generando el archivo debian/patches/fix-gentoo-target.patch y añade la descripción del parche como se describe en DEP-3: Patch Tagging Guidelines:

$ dquilt refresh
$ dquilt header -e
... describe el parche

Por lo general, los programas se instalan a sí mismos en el subdirectorio /usr/local. Pero los paquetes Debian no pueden utilizar este directorio ya que está reservado para el uso privado del administrador (o de los usuarios), sino que deben utilizar los directorios del sistema como /usr/bin según lo establecido por la normativa de jerarquía del sistema de archivos («Filesystem Hierarchy Standard» FHS).

Es frecuente la utilización de make(1) para la construcción automatizada del programa y la ejecución de la orden make install instala directamente el programa en la ubicación deseada ejecutando la sección install del archivo Makefile. En la construcción de los paquetes binarios de Debian, el sistema de construcción instala los programas en una reconstrucción de la estructura de directorios del programa en un directorio temporal en lugar de hacerlo en su destino real.

Estas dos diferencias entre la instalación del programa y el proceso de construcción del paquete es manejado en Debian de forma transparente por debhelper con las órdenes dh_auto_configure y dh_auto_install siempre que se cumplan los requisitos indicados a continuación:

  • El archivo Makefile debe seguir las convenciones GNU de forma que admita la variable $(DESTDIR) [23].

  • El código fuente sigue el estándar de la jerarquía del sistema de ficheros. («Filesystem Hierarchy Standard» o FHS).

Los programas que usan autoconf de GNU cumplen automáticamente con las convenciones GNU y su empaquetamiento es casi automático. Con estos requisitos y la heurística que aplica el paquete debhelper, se estima que funciona sobre el 90% de paquetes sin tener que realizar ningún cambio intrusivo en su sistema de construcción. El empaquetado no es tan complicado como puede parecer.

Si debes hacer cambios en el archivo Makefile, debes asegurarte que admite la variable $(DESTDIR). La variable $(DESTDIR) no está definida en el archivo y se añadirá en todas las rutas de directorios usadas en la instalación del programa. El guión de empaquetamiento establece el valor de la variable $(DESTDIR) al valor del directorio temporal de instalación del programa en el proceso de construcción del paquete.

El directorio temporal usado por la orden dh_auto_install es debian/nombre_de_paquete para paquetes con un binario [24]. El contenido completo del directorio temporal será instalado en el sistema del usuario cuando se instale el paquete, con la diferencia que con dpkg la instalación se realizará a partir del directorio raíz del sistema.

Aunque el programa se instale en el directorio debian/nombre_del_paquete será necesario que se comporte correctamente cuando se instale en el directorio raíz, esto es, cuando se instale usando el archivo .deb. Deberías evitar que el sistema de compilación incluya cadenas del tipo /home/mi/deb/nombre_del_paquete-versión/usr/share/nombre_del_paquete en los archivos del paquete.

Esta es la parte importante del archivo Makefile de gentoo [25]:

# ¿Dónde se colocaran los ejecutables con 'make install'?
BIN     = /usr/local/bin
# ¿Dónde se colocaran los iconos con 'make install'?
ICONS   = /usr/local/share/gentoo

We see that the files are set to install under /usr/local. As explained above, that directory hierarchy is reserved for local use on Debian, so change those paths as follows:

# ¿Dónde se colocaran los ejecutables con 'make install'?
BIN     = $(DESTDIR)/usr/bin
# ¿Dónde se colocaran los iconos con 'make install'?
ICONS   = $(DESTDIR)/usr/share/gentoo

La ubicación correcta de los binarios, iconos, documentación, etc, está especificada en el «Estándar de la jerarquía del sistema de ficheros». Te recomiendo que leas las secciones que podrían aplicarse a tu paquete.

Así pues, deberíamos instalar el binario en /usr/bin en lugar de /usr/local/bin y la página de manual en /usr/share/man/man1 en lugar de /usr/local/man/man1. No hemos mencionado ninguna página de manual en el Makefile de gentoo, pero la normativa de Debian requiere que cada programa debe tener una, así que haremos una más tarde y la instalaremos en /usr/share/man/man1.

Algunos programas no usan variables en el makefile para definir rutas como éstas. Esto significa que tendrás que editar algunos de los ficheros de código C para arreglarlos y que usen las rutas correctas. Pero, ¿dónde buscar?, y exactamente, ¿el qué? Puedes probar a encontrarlos usando:

$ grep -nr --include='*.[c|h]' -e 'usr/local/lib' .

grep buscará recursivamente en los subdirectorios y te indicará el nombre del fichero y la línea cuando encuentre una concordancia con la cadena.

Ahora edita esos ficheros y cambia en esas líneas usr/local/lib por usr/lib. Esto se puede hacer de forma automática como sigue:

$ sed -i -e 's#usr/local/lib#usr/lib#g' \
        $(find . -type f -name '*.[c|h]')

Si deseas confirmar cada sustitución, puedes hacerlo de forma interactiva de la siguiente manera:

$ vim '+argdo %s#usr/local/lib#usr/lib#gce|update' +q \
        $(find . -type f -name '*.[c|h]')

Después de esto deberías encontrar (en el archivo Makefile) el objetivo «install» (busca una línea que comience por install:) y renombra todas las referencias a directorios distintos de los definidos al comienzo del Makefile.

En el original, el objetivo «install» de gentoo declaraba:

install: gentoo-target
        install ./gentoo $(BIN)
        install icons/* $(ICONS)
        install gentoorc-example $(HOME)/.gentoorc

Ahora corregiremos el error, conservando las modificaciones en el archivo debian/patches/install.patch con la orden dquilt.

$ dquilt new install.patch
$ dquilt add Makefile

Y ahora escribe los cambios con el editor:

install: gentoo-target
        install -d $(BIN) $(ICONS) $(DESTDIR)/etc
        install ./gentoo $(BIN)
        install -m644 icons/* $(ICONS)
        install -m644 gentoorc-example $(DESTDIR)/etc/gentoorc

Seguramente has notado que ahora hay una orden install -d antes de las demás órdenes de la regla. El Makefile original no la tenía porque normalmente /usr/local/bin y otros directorios ya existen en el sistema donde se ejecuta make install. Sin embargo, dado que lo instalaremos en un directorio vacío (o incluso inexistente), tendremos que generar cada uno de estos directorios.

También podemos añadir otras cosas al final de la regla, como la instalación de documentación adicional que los desarrolladores originales a veces omiten:

       install -d $(DESTDIR)/usr/share/doc/gentoo/html
       cp -a docs/* $(DESTDIR)/usr/share/doc/gentoo/html

Después de comprobar que sea todo correcto, ejecuta dquilt para actualizar la modificación en el archivo debian/patches/install.patch y añade la descripción en la cabecera del archivo:

$ dquilt refresh
$ dquilt header -e
... describe el parche

Ahora ya tienes un par de parches en el paquete.

  1. Corrección de un error en el código fuente: debian/patches/fix-gentoo-target.patch

  2. Una modificación específica del empaquetado Debian: debian/patches/install.patch

Whenever you make changes that are not specific to the Debian package such as debian/patches/fix-gentoo-target.patch, be sure to send them to the upstream maintainer so they can be included in the next version of the program and be useful to everyone else. Also remember to avoid making your fixes specific to Debian or Linux — or even Unix! Make them portable. This will make your fixes much easier to apply.

Ten en cuenta que no tienes que enviar ninguno de los ficheros debian/* al desarrollador original.

There is one other common problem: libraries are often different from platform to platform. For example, a Makefile can contain a reference to a library that doesn't exist on the Debian system. In that case, we need to change it to a library that does exist in Debian, and serves the same purpose.

Vamos a suponer que en el archivo Makefile (o Makefile.in) de tu programa se declara algo como lo siguiente.

LIBS = -lfoo -lbar

Si el programa no se compila debido a que ya no existe la biblioteca nombre_biblioteca y su equivalente es proporcionada por la biblioteca nombre_biblioteca2 en el sistema Debian, puedes solucionar este problema de compilación, cambiando (en el archivo debian/patches/parche2.patch) nombre_biblioteca por nombre_biblioteca2 [26]:

$ dquilt new foo2.patch
$ dquilt add Makefile
$ sed -i -e 's/-lfoo/-lfoo2/g' Makefile
$ dquilt refresh
$ dquilt header -e
... describe el cambio


[22] El directorio debian/patches debería haberse creado en la anterior ejecución de dh_make. Sólo debes generarlo si no existe o bien si estás actualizando un paquete.

[24] Para paquetes con más de un archivo binario, la orden dh_auto_install utiliza como directorio temporal debian/tmp mientras que la orden dh_install con la ayuda de los archivos debian/paquete-1.install y debian/paquete-2.install distribuirá el contenido del directorio debian/tmp en los directorios temporales debian/paquete-1 y debian/paquete-2 para construir los paquetes binarios package-1_*.deb y package-2_*.deb.

[25] Se trata solo de un ejemplo del contenido del archivo Makefile. Si el archivo Makefile se construye con la orden ./configure, la forma correcta de solucionar este tipo de errores en los archivos Makefile es ejecutando la orden ./configure desde la orden dh_auto_configure con las opciones predeterminadas añadiendo --prefix=/usr.

[26] Si hay cambios en el API de la biblioteca nombre_biblioteca a nombre_biblioteca2, se deberá cambiar el código fuente para que se corresponda con la nueva API.