Tutorial de Empaquetamiento 1: banner

Este tutorial demuestra el empaquetamiento RPM empaquetando el programa banner. Es un sencillo programa con un simple script de construcción GNU Autotools.

Para una información completa sobre como crear archivos RPM, vea el Manual de Referencia RPM. Si usted planea crear un paquete RPM para el repositorio Fedora, siga el proceso para Unirse a los Mantenedores de Paquetes, incluyendo seguir las diversas directrices de Fedora.

Este tutorial está diseñado para ejecutarse en un sistema Fedora 40. Debería, sin embargo, trabajar también para otras versiones de Fedora. Solo reemplace las cadenas `f40`con su número de versión. Ya que este manual utiliza funciones específicas de Fedora que pueden no estar disponibles en otros entornos, los downstreams de Fedora como CentOS Stream o Red Hat Enterprise Linux puede que trabajen o no.

El tutorial sigue una forma de paso a paso, con la mayoría de los pasos editando el archivo de especificaciones del paquete. El archivo de especificaciones resultante se lista al final, de modo que, en caso de que no quede claro cómo se debe aplicar un cambio en particular, puede echar un vistazo allí.

Instalar Herramientas de Empaquetador

Crear el directorio del paquete

En Fedora, las instrucciones para construir un paquete están organizadas en los llamados repositorios dist-gits. Hay un repositorio separado para cada paquete. Imitamos este sistema creando un nuevo directorio para este tutorial. En dist-git, el nombre del repositorio coincide con el nombre del paquete. Las reglas de Fedora para la denominación de los paquetes están escritas en Directrices de Denominación. Para banner, el paquete debería denominarse simplemente banner. Este también es el nombre del paquete oficial banner de Fedora.

$ mkdir banner && cd banner

Dentro de un Archivo de Especificaciones

Los paquetes RPM son configurados por archivos .spec. Herramientas como rpmdev-newspec pueden ser usadas para generar archivos de especificaciones vacíos para diferentes propósitos. Para este tutorial, solo cree un archivo llamado banner.spec y pegue el siguiente archivo de especificaciones mínimo. No trabaja todavía, pero intentaremos construirlo y arreglar los errores según los vayamos encontrando.

Name:     banner
Version:  1.3.6
Release:  %autorelease
Summary:  Prints a short string to the console in very large letters
License:  GPL-2.0-only
URL:      https://github.com/pronovic/banner
Source:   https://github.com/pronovic/banner/releases/download/BANNER_V%{version}/banner-%{version}.tar.gz

%description
This is a classic-style banner program similar to the one found in Solaris or
AIX in the late 1990s. It prints a short string to the console in very large
letters.

%prep
%autosetup

%build
%configure
%make_build

%install
%make_install

%files

%changelog
%autochangelog

El archivo de especificaciones comienza con un conjunto de indicadores, como Name: y Version:, seguido de secciones como %description y %prep. Cada indicador se ajusta a un única línea, mientras que cada sección continúa hasta que comienza la siguiente.

Tenga en cuenta que, de manera confusa, además de marcar los nombres de sección, el signo porcentaje % marca también macros RPM. Por lo tanto %autosetup, %configure, %make_build,%make_install y %autochangelog no son secciones.

Indicadores

Version contiene el número de versión del software empaquetado.

Release numera las actualizaciones del fichero de especificaciones, las reconstrucciones del paquete y otro trabajo dentro de Fedora. El valor usado aquí, %autorelease, es parte de rpmautospec, que es el recomendado para los paquetes de Fedora. Se vincula Release al histórico Git del paquete. Como no tenemos un repositorio Git, %autorelease se evaluará al valor predeterminado de 1.

Con frecuencia, Summary puede ser copiado del README upstream. La primera letra debe ir en mayúscula para evitar quejas sobre rpmlint.

License describe la licencia del paquete binario resultante utilizando el identificador de licencia SPDX. Debe seguir las directrices de licencia. En la practica, determinar el valor correcto a menudo significa inspeccionar las notificaciones de licencias en los archivos fuente individuales. También puede ser necesario pedir a los desarrolladores upstream clarificaciones y correcciones. En este tutorial, simplemente tomamos la palabra de upstream de que la licencia es GNU Public License, versión 2.

URL apunta al sitio web del proyecto upstream, que en este caso es la página de repositorios GitHub.

Source define las fuentes upstream usadas cuando se construye el paquete. Usualmente, como en este caso, es una url apuntando a un archivo comprimido liberado por upstream, pero también puede ser un archivo local. Puede haber múltiples etiquetas Source si es necesario.

Secciones

%description puede ser copiado a menudo del README de upstream.

%prep contiene un script de shell para preparar las fuentes para la construcción. A menudo es solo la macro %autosetup, la cual, en este caso, simplemente extrae la fuente.

%build contiene un script de shell para los pasos requeridos de construcción, como compilar fuentes en binarios. Dado que el sistema de construcción de banner es Autotools, la construcción implica ejecutar configure y make. Las macros %configure y %make_build invocan estos comandos utilizando los indicadores de compilación de Fedora y otra configuración.

%install contiene un script de shell para copiar los resultados de %build en un directorio, inicialmente vacío, build root. Como banner está utilizando Autotools, se utiliza la macro %make_install.

%files lista el contenido del paquete resultante. Mayormente, los archivos vienen del build root creado en %install, pero la documentación y los archivos de licencia se pueden añadir directamente desde las fuentes. Esta sección se deja vacía por ahora, para rellenarse más tarde.

%changelog documenta los cambios en cada nueva versión y lanzamiento del paquete. Los datos del registro de cambios se pueden visualizar con rpm --query --changelog PACKAGE_NAME, que puede ser útil, por ejemplo, para encontrar si se han incluido la corrección a un error específico y parches de seguridad. Su valor, %autochangelog, también viene de rpmautospec. Completa el registro de cambios a partir de mensajes de confirmación de Git. Como no tenemos repositorio Git, el registro de cambios estará vacío.

Las líneas que no son necesarias se pueden comentar con almohadillas #.

Puede encontrar más información en la sección Formato del archivo de especificaciones del Manual de Referencia RPM.

Descargar la fuente

Necesitamos el código fuente definido por el indicador Source, nombrada a menudo como fuente upstream. Esto es más fácilmente alcanzable usando el comando spectool:

$ spectool -g banner.spec

Ahora usted debería tener el archivo listado en Source en su directorio de trabajo:

$ ls *.tar.gz
banner-1.3.6.tar.gz

Construir el Paquete

Estamos listos para la primera ejecución para crear paquetes fuente, binarios y de depuración. Esta y muchas otras tareas se hacen con la herramienta fedpkg. Las construcciones de producción para Fedora se crean en el sistema de compilación Koji, que a su vez utiliza Mock para administrar entornos de compilación aislados. Para acercarnos lo más posible a una compilación de producción a nivel local, usamos el comando fedpkg mockbuild que también invoca a Mock:

$ fedpkg --release f40 mockbuild

El entorno de compilación creado por Mock es muy básico. No incluye un compilador C de forma predeterminada, entonces la compilación fallará. La razón se explica en la salida:

checking whether the C compiler works... no
configure: error: in `/builddir/build/BUILD/banner-6':
configure: error: C compiler cannot create executables
See `config.log' for more details

RPM build errors:
error: Bad exit status from /var/tmp/rpm-tmp.R4Tf16 (%build)
    Bad exit status from /var/tmp/rpm-tmp.R4Tf16 (%build)

Herramientas de compilación adicionales se definen añadiendo filas BuildRequires: al archivo de especificaciones. En Fedora, GCC es el compilador estándar, de modo que necesitamos añadir una fila para gcc. Autotools también utiliza make, así que se debe añadir una fila para ella, también. Añada estas líneas después de Source:

BuildRequires:   gcc
BuildRequires:   make

Ejecute un mockbuild otra vez.

Installing files

The next thing rpm will complain about are unpackaged files, i.e. the files that would be installed in the system, but were not declared as belonging to the package. We need to declare them in the %files section. Fixing these errors is an iterative process. After declaring a missing file in the specfile, run fedpkg again, then declare the next missing file and so on.

We will go through the file list one by one.

Executable

Installed (but unpackaged) file(s) found:
/usr/bin/banner

This is the executable binary program. /usr/bin, like many other system directories, have a default rpm macro defined. The macros should always be used when available, so the executable is listed in %files as follows:

%files
%{_bindir}/banner

Man pages

Installed (but unpackaged) file(s) found:
/usr/share/man/man1/banner.1.gz

The Packaging Guidelines have a dedicated section for Manpages. Following its instructions, manpages are list as follows:

%{_mandir}/man1/banner.1.*

At this point, mockbuild completes successfully, but there are still more files that we should add to the package.

License file

Every package must install its license, tagged with %license directive. In banner’s case, as well as for many other projects, the license file is located at the source tarball’s top level, and perhaps not copied to the buildroot during installation at all. Regardless, it can be installed to the standard license directory by using a relative path:

%files
%license COPYING

Additional documentation

Often, package sources contain documentation that could be useful for the end users as well. These can be installed and marked as documentation with the %doc directive. Similarly to %license, relative paths can be used to include files directly from the source tarball rather than from the buildroot:

%doc AUTHORS ChangeLog NEWS README

Checking the result with rpmlint

Next you should check for conformance with RPM design rules, by running rpmlint on specfile, source rpm and binary rpm. Command fedpkg lint does this:

$ fedpkg --release f40 lint

If all is good, there should be no warnings or errors. For tutorial’s sake, we intentionally left a mistake in the previous steps:

 banner.x86_64: E: zero-length /usr/share/doc/banner/NEWS

Descriptions of various error codes can be queried with rpmlint -e <error_code>. In this case, the unnecessary zero-length file must be removed. Change the docs line to

%doc AUTHORS ChangeLog README.md

Run fedpkg mockbuild and fedpkg lint again and observe that the warning is fixed.

Complete specfile

Here is the final version of banner.spec:

Name:           banner
Version:        1.3.6
Release:        %autorelease
Summary:        Prints a short string to the console in very large letters
License:        GPL-2.0-only
URL:            https://github.com/pronovic/banner
Source:         https://github.com/pronovic/banner/releases/download/BANNER_V%{version}/banner-%{version}.tar.gz
BuildRequires:  gcc
BuildRequires:  make

%description
This is a classic-style banner program similar to the one found in Solaris or
AIX in the late 1990s. It prints a short string to the console in very large
letters.

%prep
%autosetup

%build
%configure
%make_build

%install
%make_install

%files
%{_bindir}/banner
%{_mandir}/man1/banner.1.*
%license COPYING
%doc AUTHORS ChangeLog README

%changelog
%autochangelog

With this specfile, you should be able to successfully complete the build process, and create the source and binary RPM packages.

Checking the result

Having a working specfile and rpms built from it, the result can be checked. Before checking the result by installing the package, let us do some simple checks. The RPM Package Manager rpm can be used for this.

Files

List the files contained in the package:

$ rpm --query --package --list results_banner/1.3.6/1.fc40/banner-1.3.6-1.fc40.x86_64.rpm
/usr/bin/banner
/usr/lib/.build-id
/usr/lib/.build-id/01
/usr/lib/.build-id/01/360ae02508eaa0a77d216953b8b658a1e90b10
/usr/share/doc/banner
/usr/share/doc/banner/AUTHORS
/usr/share/doc/banner/ChangeLog
/usr/share/doc/banner/README
/usr/share/licenses/banner
/usr/share/licenses/banner/COPYING
/usr/share/man/man1/banner.1.gz

You can see that all the files listed in the specfile %files section are included. Also, under /usr/lib/.build-id, there is an automatically generated file. It is actually a symlink, mapping a build id to the banner binary for debugging purposes.

Requires

List the package’s runtime dependencies with the following command:

$ rpm --query --package --requires results_banner/1.3.6/1.fc40/banner-1.3.6-1.fc40.x86_64.rpm
libc.so.6()(64bit)
libc.so.6(GLIBC_2.2.5)(64bit)
libc.so.6(GLIBC_2.3)(64bit)
libc.so.6(GLIBC_2.3.4)(64bit)
libc.so.6(GLIBC_2.34)(64bit)
libc.so.6(GLIBC_2.4)(64bit)
rpmlib(CompressedFileNames) <= 3.0.4-1
rpmlib(FileDigests) <= 4.6.0-1
rpmlib(PayloadFilesHavePrefix) <= 4.0-1
rpmlib(PayloadIsZstd) <= 5.4.18-1
rtld(GNU_HASH)

To check which packages in Fedora repositories provide these dependencies, you can use dnf repoquery:

$ dnf -C repoquery --whatprovides 'libc.so.6()(64bit)'
glibc-0:2.38-16.fc40.x86_64
glibc-0:2.38-7.fc40.x86_64

You will see that the only dependency of banner is glibc, which provides symbols in libc.so.6 as well as rtld(GNU_HASH).

The rpmlib requires are special. These specify various rpm features used in the rpm package itself, constraining the version of rpm that can be used to install the package.

Provides

Conversely, to check what capabilities the package provides, you can do:

$ rpm --query --package --provides results_banner/1.3.6/1.fc40/banner-1.3.6-1.fc40.x86_64.rpm
banner = 1.3.6-1.fc40
banner(x86-64) = 1.3.6-1.fc40

The provides of this package are very simple. It simply provides its own name, in plain and architecture specific forms.

Installing

As a final check, the package can be installed and ran:

$ sudo dnf -C -y install ./results_banner/1.3.6/1.fc40/banner-1.3.6-1.fc40.x86_64.rpm
$ banner success

 #####   #     #   #####    #####   #######   #####    #####
#     #  #     #  #     #  #     #  #        #     #  #     #
#        #     #  #        #        #        #        #
 #####   #     #  #        #        #####     #####    #####
      #  #     #  #        #        #              #        #
#     #  #     #  #     #  #     #  #        #     #  #     #
 #####    #####    #####    #####   #######   #####    ##### ..

To clean up your system, undo the installation:

$ sudo dnf -C -y history undo last

Building in Fedora infrastructure

Even though the package is not part of Fedora distribution yet, a scratch build can be performed to ensure that the package builds successfully in Fedora’s Koji build system, and that it builds successfully for all architectures supported by Fedora. Such build is started by passing a source rpm package to fedpkg scratch-build.

Note that Koji uses Kerberos for authentication. See Acquiring Kerberos Ticket for details.

$ fedpkg --release f40 scratch-build --srpm results_banner/1.3.6/1.fc40/banner-1.3.6-1.fc40.src.rpm
Building banner-1.3.6-1.fc40.src.rpm for f40-candidate
Created task: 92465688
Task info: https://koji.fedoraproject.org/koji/taskinfo?taskID=92465688
Watching tasks (this may be safely interrupted)...

You can open the task info link in a browser to view build progress, logs and results. The command line program also reports on progress as it happens. Successful execution looks something like this:

92465688 build (f40-candidate, banner-1.3.6-1.fc40.src.rpm): free
92465688 build (f40-candidate, banner-1.3.6-1.fc40.src.rpm): free -> open (buildvm-ppc64le-25.iad2.fedoraproject.org)
  92465698 rebuildSRPM (noarch): open (buildvm-s390x-24.s390.fedoraproject.org)
  92465745 buildArch (banner-1.3.6-1.fc40.src.rpm, x86_64): free
  92465748 buildArch (banner-1.3.6-1.fc40.src.rpm, s390x): open (buildvm-s390x-19.s390.fedoraproject.org)
  92465746 buildArch (banner-1.3.6-1.fc40.src.rpm, aarch64): open (buildvm-a64-26.iad2.fedoraproject.org)
  92465747 buildArch (banner-1.3.6-1.fc40.src.rpm, ppc64le): open (buildvm-ppc64le-11.iad2.fedoraproject.org)
  92465744 buildArch (banner-1.3.6-1.fc40.src.rpm, i686): open (buildhw-x86-12.iad2.fedoraproject.org)
  92465698 rebuildSRPM (noarch): open (buildvm-s390x-24.s390.fedoraproject.org) -> closed
  1 free  5 open  1 done  0 failed
  92465745 buildArch (banner-1.3.6-1.fc40.src.rpm, x86_64): free -> open (buildhw-x86-06.iad2.fedoraproject.org)
  92465745 buildArch (banner-1.3.6-1.fc40.src.rpm, x86_64): open (buildhw-x86-06.iad2.fedoraproject.org) -> closed
  0 free  5 open  2 done  0 failed
  92465748 buildArch (banner-1.3.6-1.fc40.src.rpm, s390x): open (buildvm-s390x-19.s390.fedoraproject.org) -> closed
  0 free  4 open  3 done  0 failed
  92465746 buildArch (banner-1.3.6-1.fc40.src.rpm, aarch64): open (buildvm-a64-26.iad2.fedoraproject.org) -> closed
  0 free  3 open  4 done  0 failed
  92465744 buildArch (banner-1.3.6-1.fc40.src.rpm, i686): open (buildhw-x86-12.iad2.fedoraproject.org) -> closed
  0 free  2 open  5 done  0 failed
92465688 build (f40-candidate, banner-1.3.6-1.fc40.src.rpm): open (buildvm-ppc64le-25.iad2.fedoraproject.org) -> closed
  0 free  1 open  6 done  0 failed
  92465747 buildArch (banner-1.3.6-1.fc40.src.rpm, ppc64le): open (buildvm-ppc64le-11.iad2.fedoraproject.org) -> closed
  0 free  0 open  7 done  0 failed

92465688 build (f40-candidate, banner-1.3.6-1.fc40.src.rpm) completed successfully