Tutorial de Empaquetamiento 2: GNU Hello

Este tutorial demuestra el empaquetamiento RPM empaquetando el programa GNU Hello. Si bien el programa es sencillo, viene con la mayoría de los componentes periféricos de un proyecto FOSS: entorno de configuración/compilación/instalación, documentación, internacionalización, etc.

Este tutorial es la segunda parte del tutorial de empaquetamiento de Fedora. Sigue la misma estructura básica que la parte 1. Si no la ha completado todavía, hágalo antes de continuar con este tutorial.

Los pasos en esta parte son similares a los de la parte 1. Sin embargo, GNU Hello tiene más peculiaridades que Banner, por lo que se necesitan algunos rodeos y pasos personalizados. Las peculiaridades de cada paquete son únicas, por lo que es mejor verlos como ejemplos del tipo de problemas que pueden surgir al empaquetar.

Instalar Herramientas de Empaquetador

Crear el directorio del paquete

Para GNU Hello, el paquete puede llamarse simplemente hello. Este es también el nombre oficial del paquete GNU Hello de Fedora.

$ mkdir hello && cd hello

Dentro de un Archivo de Especificaciones

Cree un archivo llamado hello.spec y pegue el siguiente archivo de especificaciones mínimo. Este ya tiene etiquetas BuildRequires para gcc y make, puesto que este tema ya fue tratado en la parte 1. Del mismo modo, la sección %files ya incluye el binario resultante, las páginas de manual, la documentación y el archivo de licencia. Para GNU Hello, todos estos archivos son muy parecidos a los archivos correspondiente en Banner por lo que ya están cubiertos en la parte 1.

También, por razones que son demasiado complejas para explicar en un tutorial, en algunas situaciones también es necesario el paquete texinfo y de este modo se añade una línea BuildRequires para él.

Name:           hello
Version:        2.10
Release:        %autorelease
Summary:        Produces a familiar, friendly greeting
License:        GPL-3.0-or-later
URL:            https://www.gnu.org/software/hello/
Source:         http://ftp.gnu.org/gnu/hello/hello-%{version}.tar.gz
BuildRequires:  gcc
BuildRequires:  make
BuildRequires:  texinfo

%description
The GNU Hello program produces a familiar, friendly greeting. Yes, this is
another implementation of the classic program that prints "Hello, world!" when
you run it.

%prep
%autosetup

%build
%configure
%make_build

%install
%make_install

%files
%{_bindir}/hello
%{_mandir}/man1/hello.1.*
%doc AUTHORS ChangeLog NEWS README THANKS TODO
%license COPYING

%changelog
%autochangelog

Descargar la fuente

Descargar las fuentes y comprobar que ahora las tiene:

$ spectool -g hello.spec
$ ls *.tar.gz
hello-2.10.tar.gz

Construir el Paquete

$ fedpkg --release f40 mockbuild

Este comando falla debido a archivos no empaquetados.

Instalar archivos

Como en la parte 1, iremos a través de la lista de archivos uno por uno. Ejecute`fedpkg --release f40 mockbuild` otra vez después de cada cambio para ver el progreso.

Páginas Texinfo

Installed (but unpackaged) file(s) found:
/usr/share/info/dir
/usr/share/info/hello.info.gz

Estas son las páginas Texinfo. Texinfo es un sistema de documentación parecido a las páginas de manual. El directorio está definido por la macro predeterminada {_infodir}, de modo que el manual Texinfo se puede añadir como sigue:

%files
⋮
%{_infodir}/hello.info.*

El archivo dir generado por el script de compilación GNU Hello indexa todas las páginas texinfo en su sistema. Como las páginas instaladas difieren entre sistemas, el archivo no puede ser precompilado y empaquetado. En su lugar necesita ser creado y actualizado cuando el paquete es instalado. La actualización se lleva a cabo automáticamente por los disparadores rpm triggers en el paquete binario info del paquete fuente texinfo.

Para evitar instalar el archivo dir, elimínelo del buildroot al final de la sección %install con el comando rm.

Sin embargo, el script de compilación GNU Hello solo genera el archivo dir si se instala el paquete info durante la compilación. Eliminar ciegamente el archivo podría hacer surgir un error si el paquete hello fue compilado en un sistema sin el paquete`info`. Para tratar con ambos temas, borre el archivo si existe:

%install
⋮
test -f %{buildroot}/%{_infodir}/dir && rm %{buildroot}/%{_infodir}/dir

Traducciones

Installed (but unpackaged) file(s) found:
/usr/share/locale/bg/LC_MESSAGES/hello.mo
/usr/share/locale/ca/LC_MESSAGES/hello.mo
/usr/share/locale/da/LC_MESSAGES/hello.mo
⋮

Dado que nuestro programa utiliza traducciones e internacionalización, estamos viendo muchos archivos i18n no declarados. El método recomendado para instalarlos es:

  1. Añadir la dependencia de compilación requerida con BuildRequires: gettext.

  2. Encontrar los nombres de archivos en el paso %install con %find_lang %{name}.

  3. Instalar los archivos con %files -f %{name}.lang.

Después de estos cambios, la compilación tendrá éxito.

Ejecutar pruebas

GNU Hello, como muchos otros proyectos, incluye un conjunto de pruebas automatizadas en las fuentes. Si es posible, el conjunto de pruebas debe realizarse durante la compilación rpm. Esto ayuda a asegurar que se produjo una compilación funcional. Esto se hace añadiendo el conjunto de pruebas a la sección %check% del archivo de especificaciones, que viene en orden después de %install. En el caso de GNU Hello:

%check
make check

Ejecute una compilación simulada otra vez y verifique el resultado para asegurarse de que las pruebas realmente se ejecutaron. Algo como esto debería estar en algún lugar del resultado:

============================================================================
Testsuite summary for GNU Hello 2.10
============================================================================
# TOTAL: 5
# PASS:  4
# SKIP:  1
# XFAIL: 0
# FAIL:  0
# XPASS: 0
# ERROR: 0
============================================================================

Arreglando automagic

Ahora el paquete se ha compilado con éxito. Pero no significa que el archivo .spec es correcto.

Listado de todas las dependencias en tiempo de compilación

Si lee cuidadosamente un resultado de compilación, puede descubrir líneas que mencionan el comando sed:

+ /usr/bin/make -O -j4 V=1 VERBOSE=1
rm -f lib/arg-nonnull.h-t lib/arg-nonnull.h && \
sed -n -e '/GL_ARG_NONNULL/,$p' \

Por lo tanto debe de añadir esta línea cerca de otras líneas de BuildRequires:

BuildRequires:  sed

De manera similar, al estudiar el script configure en las fuentes no empaquetadas, que se ejecuta mediante la macro %configure, se revela que es un script /bin/sh:

$ head configure
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for GNU Hello 2.10.

Por lo tanto, también debería registrar esta dependencia en bash:

BuildRequires:  bash

¿Por qué en bash? Porque el programa /bin/sh está proporcionado por el paquete bash:

$ rpm --queryformat '%{name}\n' --query --file /bin/sh
bash

Especificar todas las dependencias utilizadas ayuda al archivo .spec a ser resistente a los cambios en el entorno de compilación. Sí, por ejemplo, el paquete sed fuera eliminado del entorno, este paquete GNU Hello podría fallar al compilar.

Listar todas las opciones de compilación

El script de compilación de GNU Hello, configure tiene muchas opciones de compilación que habilitan o deshabilitan funciones opcionales. Sus formatos no predeterminados se pueden listar con la opción --help:

$ ./configure --help
`configure' configures GNU Hello 2.10 to adapt to many kinds of systems.

Usage: ./configure [OPTION]... [VAR=VALUE]...
⋮
Optional Features:
  --disable-option-checking  ignore unrecognized --enable/--with options
  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
  --enable-silent-rules   less verbose build output (undo: "make V=1")
  --disable-silent-rules  verbose build output (undo: "make V=0")
  --enable-dependency-tracking
                          do not reject slow dependency extractors
  --disable-dependency-tracking
                          speeds up one-time build
  --disable-nls           do not use Native Language Support
  --disable-rpath         do not hardcode runtime library paths

Algunas de ellas ya están especificadas dentro de las macros %configure y`%make_build`. El resto de las opciones, si son importantes para la compilación del paquete, se deberían escribir explícitamente en el archivo .spec para evitar cambios repentinos e inadvertidos. Bien porque una nueva versión de Hello cambia lo predeterminado o porque un paquete del que dependen aparece o desaparece del entorno de compilación.

Por lo tanto modifique la invocación %configure en la sección %build de esta manera:

%configure --enable-nls --disable-rpath

Comprobar el resultado con rpmlint

Verifique con fedpkg lint que revela un problema:

$ fedpkg --release f40 lint
hello.x86_64: W: file-not-utf8 /usr/share/doc/hello/THANKS

Para garantizar una instalación pura utf-8, se necesita convertir el archivo en %prep. Esto se puede hacer con la utilidad iconv proporcionada por el paquete glibc-common y la herramienta mv de coreutils:

BuildRequires:  coreutils
BuildRequires:  glibc-common
⋮
%prep
⋮
mv THANKS THANKS.old
iconv --from-code=ISO-8859-1 --to-code=UTF-8 --output=THANKS THANKS.old

Ejecute fedpkg lint otra vez y observe que la advertencia se ha corregido.

Un Archivo hello.spec Completo

Aquí está la versión final de hello.spec:

Name:           hello
Version:        2.10
Release:        %autorelease
Summary:        Produces a familiar, friendly greeting

License:        GPL-3.0-or-later
URL:            http://ftp.gnu.org/gnu/%{name}
Source:         http://ftp.gnu.org/gnu/%{name}/%{name}-%{version}.tar.gz

BuildRequires:  bash
BuildRequires:  coreutils
BuildRequires:  gcc
BuildRequires:  gettext
BuildRequires:  glibc-common
BuildRequires:  make
BuildRequires:  sed
BuildRequires:  texinfo

%description
The GNU Hello program produces a familiar, friendly greeting. Yes, this is
another implementation of the classic program that prints "Hello, world!" when
you run it.

%prep
%autosetup
mv THANKS THANKS.old
iconv --from-code=ISO-8859-1 --to-code=UTF-8 --output=THANKS THANKS.old

%build
%configure --enable-nls --disable-rpath
%make_build

%install
%make_install
test -f %{buildroot}/%{_infodir}/dir && rm %{buildroot}/%{_infodir}/dir
%find_lang %{name}

%check
make check

%files -f %{name}.lang
%{_mandir}/man1/hello.1.*
%{_infodir}/hello.info.*
%{_bindir}/hello
%doc AUTHORS ChangeLog NEWS README THANKS TODO
%license COPYING

%changelog
%autochangelog

Con este archivo .spec, debería ser capaz de completar con éxito el proceso de compilación y crear los paquetes RPM fuente y binario.

Comprobar el resultado

Ahora puede comprobar el resultado con rpm, como lo ha hecho en la parte 1.

Archivos

Listar los archivos contenidos en el paquete:

$ rpm --query --package --list results_hello/2.10/1.fc40/hello-2.10-1.fc40.x86_64.rpm
/usr/bin/hello
/usr/lib/.build-id
/usr/lib/.build-id/39
/usr/lib/.build-id/39/c97ecb15c6292ce23e8b00e15e6e72a61e5072
/usr/share/doc/hello
/usr/share/doc/hello/AUTHORS
⋮
/usr/share/doc/hello/TODO
/usr/share/info/hello.info.gz
/usr/share/licenses/hello
/usr/share/licenses/hello/COPYING
/usr/share/locale/bg/LC_MESSAGES/hello.mo
⋮
/usr/share/locale/zh_TW/LC_MESSAGES/hello.mo
/usr/share/man/man1/hello.1.gz

Usted puede ver que todos los archjvos listados en la sección`%files` del archivo de especificaciones están incluidos, incluyendo los archivos locales procesados automáticamente. También está aquí el archvo .build-id, igual que en la parte 1.

Requiere y Proporciona

Puede listar la lista de las dependencias en tiempo de ejecución el paquete y las capacidades que proporciona con los dos comandos siguiente. La salida es similar a la salida correspondiente en la parte 1.

$ rpm --query --package --requires results_hello/2.10/1.fc40/hello-2.10-1.fc40.x86_64.rpm
$ rpm --query --package --provides results_hello/2.10/1.fc40/hello-2.10-1.fc40.x86_64.rpm

Instalar

Como comprobación final, el paquete puede ser instalado y ejecutado:

$ sudo dnf -C -y install ./results_hello/2.10/1.fc40/hello-2.10-1.fc40.x86_64.rpm
$ hello --greeting="Hello, rpm!"
Hello, rpm!

Para limpiar su sistema, deshaga la instalación:

$ sudo dnf -C -y history undo last