Capítulo 3. Modificar las fuentes

# Capítulo 3. Modificar las fuentes

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.

## 3.1. Configurar quilt

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.

## 3.2. Corregir un error en el código fuente

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

## 3.3. Instalación de los archivos en su destino

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.

## 3.4. Diferencias en las bibliotecas

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.

[23] Consulta GNU Coding Standards: 7.2.4 DESTDIR: Support for Staged Installs.

[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.

Capítulo 2. Primeros pasos |  | Capítulo 4. Archivos necesarios en el directorio `debian`