Conceptos básicos
Hoy proliferan las distribuciones basadas en Debian, con su conocido sistema de paquetes .deb. Sin embargo, no es el único sistema de empaquetado disponible. De hecho, el LSB dice que cualquier distribución que quiera cumplir los estándares debe soportar paquetes RPM. Vamos a ver cómo se crea uno.
Preparar el entorno
Se recomienda crear un usuario específicamente para crear los paquetes, de modo que no rompamos nada del nuestro. También necesitamos una selección básica de paquetes:
sudo yum install @development-tools @fedora-packager
Ya está listo lo que necesitamos. Ahora vamos a crear el entorno de construcción de paquetes:
rpmdev-setuptree
Ahora tenemos la carpeta ~/rpmbuild, en la que se encuentran algunas otras carpetas:
- BUILD: Aquí es donde se construirá el paquete.
- BUILDROOT: Aquí se realiza el simulacro de instalación. Se escribirán los ficheros que se supone que deben instalarse cuando el usuario final instala el paquete.
- RPMS: Una vez construido, se colocarán aquí los ficheros RPM binarios (.rpm) resultantes, listos para instalar.
- SRPMS: Si así lo indicamos, aquí se colocarán los ficheros RPM de fuentes (.src.rpm), ideales para hacer una versión revisada o actualizada del paquete.
- SOURCES: Aquí hay que poner las fuentes originales (.tar.gz, normalmente) y los parches que haya que usar.
- SPECS: Aquí se colocan los ficheros de especificaciones (.spec).
Con esto ya tenemos el entorno preparado. En el próximo capítulo aprenderemos cómo entender esos extraños ficheros spec.
Teoría de los ficheros SPEC
La magia de los RPM es que en un solo fichero SPEC se incluyen todas las instrucciones para construir un paquete. Eso sí, primero hay que entenderlo, y a veces no es fácil…
¿Qué es el fichero SPEC?
Básicamente, es el fichero en el que se indica cómo construir, instalar y desinstalar el paquete.
Las instrucciones que vayamos a darle se dividen por etapas, que a su vez son macros. Estas son las etapas básicas que hay:
- %prep: Se descomprimen las fuentes y se le aplican los parches.
- %build: Se compilan los binarios.
- %check: Se comprueba que se haya compilado bien.
- %install: Se realiza el simulacro de instalación.
- %files: Lista todos los archivos que aparecerán en el paquete. Se suele usar también para asignar atributos. Si hay algún fichero que no está listado, no se construirá.
Algunos SPEC puede que no tengan algunas de las etapas. No son de uso obligatorio.
Hay otras etapas que se llaman scriptlets. son especiales porque no se ejecutan en el momento de construir el paquete, sino cuando se instala o desinstala. Incluso puedes programar que se ejecute un trigger cuando se instale otro paquete. Esta es una de las grandes ventajas que tiene RPM sobre los ficheros DEB.
El gran lío de los RPM es que tiene la misma sintaxis para todo. Es decir, todas estas palabras especiales precedidas de un signo de porcentaje (%) son macros de RPM, pero hay macros de todo tipo:
- Funciones (%setup, %configure, %patch…)
- Variables predefinidas (%_bindir, %dist…)
- Variables definidas en el propio SPEC (%buildroot, %name, %version…)
- Secciones estáticas (%description, %changelog…)
- Etapas (%build, %install…)
- Triggers (%triggerin, %triggerpostun…)
- Scriptlets (%pretrans, %postun…)
Para saber cómo se usa una determinada macro, la única forma es consultar la documentación. Bueno, en realidad siempre puedes usar otros trucos como fijarse en cómo está hecho un SPEC de un paquete parecido al tuyo, o el método de prueba y error. Un par de comandos prácticos:
rpmbuild --showrc # Muestra todas tus macros rpmbuild --eval="%nombre_macro" # Muestra la macro expandida
Las macros son lo mismo si llevan un corchete alrededor. Si después del corchete hay un signo de interrogación, quedará en blanco si no hay nada que expandir. Por ejemplo, 1%{?dist} se expandirá a 1.fc16 en Fedora 16, pero en otra distro se quedará como 1.
Empaquetando LÖVE
Efectuaremos la primera práctica de empaquetar con RPM, y será empaquetando el motor del juego que queremos jugar. Sin él, el juego no funcionaría.
All you need is LÖVE
LÖVE es un motor para juegos 2D escritos en Lua, y Not Tetris 2 es un juego hecho para dicho motor. Debido a dependencias basadas en libmpg123 no se encuentran en los repositorios oficiales, así que es idóneo para el tutorial.Los ficheros SPEC disponibles en openSUSE me han servido de inspiración.
Descargar el código fuente
Habrá que descargar las fuentes y meterlas en la carpeta SOURCES.
cd ~/rpmbuild/SOURCES wget https://bitbucket.org/rude/love/downloads/love-0.7.2-linux-src.tar.gz
Crear una plantilla de spec en blanco
Este comando creará love.spec. En RPM es bastante importante el nombre de los ficheros, ya que su nomenclatura está estandarizada para que indique muchas cosas, como su arquitectura, versión, lanzamiento, distro, etc.
cd ~/rpmbuild/SPECS rpmdev-newspec love
Abriremos el recién creado fichero ~/rpmbuild/SPECS/love.spec. Veréis que es una plantilla en blanco. La primera parte creo que es bastante autoexplicativa. La rellenaremos con la información que se encuentra en su página oficial.
Rellenar la plantilla y crear nuestro primer SPEC
Os pongo cómo queda el fichero completo con un montón de comentarios que os explican cada sección:
# Nombre del paquete. # De acuerdo al estándar, quitamos la diéresis a la "o". Name: love # Versión según el autor original del paquete (upstream) Version: 0.7.2 # Versión de empaquetado. Cada vez que modificamos el paquete, sumamos uno a # este número. De este modo, yum sabe que debe actualizarlo. Release: 1%{?dist} # Descripción breve del paquete Summary: LÖVE is a free 2D game engine for easy game creation in Lua # Licencia (tan solo el nombre) License: ZLIB # Web del programa URL: http://love2d.org/ # URL exacta desde la que se descargan las fuentes originales, normalmente # en un archivador .tar.gz, .zip, o algo parecido. # # Como veis, usamos macros para que si actualizamos el paquete no haya que # modificar esta línea. Las macros "name" y "version" provienen de lo que # hemos indicado anteriormente. Source0: https://bitbucket.org/rude/%name/downloads/%name-%version-linux-src.tar.gz # Dependencias requeridas para construir el paquete. # Esto lo sabemos porque lo pone en su web. BuildRequires: flac-devel BuildRequires: freetype-devel BuildRequires: glibc-devel BuildRequires: libmpg123-devel BuildRequires: libmodplug-devel BuildRequires: physfs-devel BuildRequires: mesa-libGL-devel BuildRequires: openal-soft-devel BuildRequires: DevIL-devel BuildRequires: libvorbis-devel BuildRequires: SDL-devel BuildRequires: libmng-devel BuildRequires: libtiff-devel BuildRequires: lua-devel ########## # Descripción larga del paquete %description LÖVE is an unquestionably awesome 2D game engine, which allows rapid game development and prototyping in Lua. This project is constantly evolving and changes come and go, sometimes initiated by us and sometimes by the recommendations of others. If you have an idea on how to make the game engine better, it is greatly desired that you contact us and let us know what you think. ########## # En esta sección prepararemos las fuentes para compilar y aplicaríamos los # parches en caso de tener alguno %prep # Esta macro es una función que descomprime las fuentes originales. # Indicamos 2 parámetros: # -q: Modo calladito. No mandar mensajes por cada fichero # descomprimido. # -n %name-HEAD: En este caso al descomprimir se crea un directorio llamado # %name-HEAD. Si no indicáramos esto, el programa buscaría # uno llamado %name-%version y, al no hallarlo, daría error. %setup -q -n %name-HEAD # Como sabréis, los ficheros de texto creados en Windows terminan en rn, # mientras que en *nix terminan tan solo en n. Por eso, para mejor # compatibilidad, suprimiremos los r en la documentación incluida. sed -i 's/r//' *.txt ########## # En esta sección compilaremos el código fuente %build # Esto es lo mismo que hacer `./configure` con un montón de parámetros extra que # facilitan que no cometamos errores. %configure # Añade las opciones predeterminadas a make, en caso de haberlas. # En mi caso, esto se expande a `make -j3`. make %{?_smp_mflags} ########## # Aquí instalaremos el programa dentro de %buildroot. %install # Como `make install` con muchos parámetros necesarios predefinidos. %make_install ########## # Aquí auditamos los ficheros instalados %files # Indicaremos los ficheros que son de documentación con esta función %doc changes.txt license.txt readme.txt # A continuación hay que listar todos los ficheros que se instalarán. # El único fichero que instalará esto es /usr/bin/love, o lo que es lo mismo: %_bindir/%name ########## # Por último, hay que cumplimentar el registro de cambios en el paquete %changelog * Fri Nov 18 2011 Jairot Llopis 0.7.2-1 - Initial release@dominio.com>
Nos queda un último paso antes de crear el paquete: instalar las dependencias. Usaremos una utilidad del paquete yum-utils para leerlas directamente del fichero que acabamos de crear.
sudo yum-builddep ~/rpmbuild/SPECS/love.spec
Con eso debería bastar. A continuación crearemos el paquete.
rpmbuild -ba ~/rpmbuild/SPECS/love.spec
¡Listo! Ya tenemos nuestro paquete repartido en el árbol de directorios. Tendremos:
- ~/rpmbuild/RPMS/x86_64/love-0.7.2-1.fc16.x86_64.rpm: RPM listo para instalar.
- ~/rpmbuild/SRPMS/love-0.7.2-1.fc16.src.rpm: Source RPM listo para modificar el paquete con facilidad. Incluye el fichero SPEC, el código fuente y los parches.
Sin embargo, tener el motor del juego no nos servirá de nada por sí solo...
Empaquetando Not Tetris 2
Así quedará el SPEC de Not Tetris 2. Pongo comentarios para explicar las cosas que difieren con lo que se explicó en las partes anteriores.
Esta vez no hay sección %build. Esto se debe a que los juegos para LÖVE son ficheros ZIP con la extensión .love, que contienen scripts Lua. Vamos, que no hay que compilar nada.
Name: nottetris Version: 2 Release: 0%{?dist} Summary: Classic Tetris mixed with physics # En esta ocasión incluimos también el sumario en español Summary(es): Tetris clásico mezclado con física Group: Amusements/Games # Como es un script, la arquitectura del sistema nos es indiferente BuildArch: noarch License: ZLIB/libPng URL: http://stabyourself.net/%name/ Source0: http://stabyourself.net/dl.php?file=%name%version/%name%version-source.zip # Necesitamos estos programas para extraer el icono del lanzador del juego BuildRequires: unzip BuildRequires: /usr/bin/convert # El motor del juego hace falta para ejecutarlo, pero no para construir el RPM, # por eso lo etiquetamos como Requires en vez de como BuildRequires Requires: love %description Not Tetris 2 is the spiritual successor of the classic Tetris mixed with physics. The result is a fun spinoff in which blocks are no longer bound to the usual grid. Blocks can be rotated and placed at any angle, resulting in a complete mess if not careful. And with the newest cutting edge technology, Not tetris 2 allows line clears when the lines are sufficiently filled. The old mode is still available for play and is now called Stack. # También incluimos la traducción en español %description -l es Not Tetris 2 es el sucesor espiritual del Tetris clásico mezclado con física. El resultado es un juego divertido en el cual los bloques ya no están limitados a moverse por la típica rejilla. Los bloques se pueden rotar y colocar en cualquier ángulo, lo que resulta en un lío tremendo si no se lleva cuidado. Con la última tecnología, Not Tetris 2 permite que las líneas se vacíen cuando estan suficientemente completas. El antiguo modo todavía está disponible para jugar, y ahora se llama "Stack". %prep %setup -qc # Nuevamente eliminamos los finales de línea tipo Windows sed -i 's/r$//' *.txt # Renombramos los archivos para que queden más 'estilo GNU' mv 'Not Readme.txt' readme.txt mv 'Not Tetris 2.love' %name.love # Creamos un ejecutable echo -e "#!/bin/shnlove %_datadir/%name/%name.loven" > %name # Crear el lanzador para el escritorio echo "[Desktop Entry] Type=Application Version=%version Encoding=UTF-8 Name=Not Tetris 2 Comment=Classic Tetris mixed with physics Comment[es]=Tetris clásico mezclado con física Icon=%_icons96dir/%name.png Exec=%name Terminal=false StartupNotify=true Categories=Application;Game;ArcadeGame; " > %name.desktop # Creamos un icono para la aplicación, basado en una imagen que trae el juego unzip -p %name.love graphics/title.png | convert - -geometry 96x96 %name.png # Instalamos los ficheros necesarios: %install # 1. Los datos del juego install -pDm u=rw,go=r %name.love %buildroot%_datadir/%name/%name.love # 2. El ejecutable install -pDm u=rwx,go=rx %name %buildroot%_bindir/%name # 3. El lanzador de escritorio install -pDm u=rwx,go=rx %name.desktop %buildroot%_desktopdir/%name.desktop # 4. El icono para el lanzador install -pDm u=rw,go=r %name.png %buildroot%_icons96dir/%name.png %files # Indicamos que el dueño de los ficheros será root %defattr(-, root, root) # Indicamos qué ficheros son de documentación %doc readme.txt # Listamos los 4 ficheros que instalará este paquete %_bindir/%name %_datadir/%name/%name.love %_desktopdir/%name.desktop %_icons96dir/%name.png # Listamos también el directorio de datos para que se borre al desinstalar %_datadir/%name %changelog * Fri Nov 18 2011 Jairot Llopis 2-0 - Initial release
Hecho esto, repetimos la misma operación que con el anterior paquete:
sudo yum-builddep ~/rpmbuild/SPECS/nottetris.spec rpmbuild -ba ~/rpmbuild/SPECS/nottetris.spec
Ahora solo falta instalarlos y jugar:
sudo yum install ~/rpmbuild/RPMS/x86_64/love-0.7.2-1.fc16.x86_64.rpm ~/rpmbuild/RPMS/noarch/nottetris-2-0.fc16.noarch.rpm
Actualizaciones
Cuando queramos actualizar el paquete, deberemos aumentar el número indicado en Release, e incluir una nueva entrada en la sección %changelog. En caso de que la actualización sea porque ha salido una nueva versión, lo que haríamos sería aumentar el número indicado en Version.
Conclusión
Con esto finaliza el tutorial de empaquetado RPM. Solo cubre lo más básico, pero espero que hayáis aprendido mucho. Una vez le pilles el tranquillo, seguro que empiezas a empaquetarlo todo.
¡Ah!, y como dije al principio, ¡cuidado, que este juego engancha demasiado!