########################################################## Howto crear paquetes .deb y mirror debian ########################################################## A muchos de los participantes del Concurso de Software libre puede que aún no les interese el tema de empaquetar sus aplicaciones sobre algunas distribuciones Linux. Pero una vez llegue el final del concurso será un tema bastante interesante. 1.- Introducción El fin de realizar un programa es para que alguien lo use y una forma de multiplicar por muchos esto, es creando paquetes para las distribuciones más usuales: * Debian * Ubuntu * Fedora * SuSe * Mandriva * Slackware * Gentoo ..... Cada distribución tiene su propio sistema de empaquetado y distribución de paquetes, siendo los más usuales: * Paquetes .deb * Paquetes .rpm * Paquetes .tgz * ebuilds de gentoo En este howto me voy a encargar de explicar como hacer que nuestro software se pueda empaquetar para distribuciones basadas en debian ya que hoy cumplen un gran espectro del total y entre las que están: * Debian (padre y madre de muchas distribuciones) * Ubuntu hijo de Debian y con gran aceptación entre usuarios nuevos de escritorio, y equipos nuevos. (Las autonómicas) * Linex, basado en Debian, distribución autonómica de Castilla la Mancha * Guadalinex, basado en Ubuntu, distribución de Anadalucía * MaX, basado en Ubuntu, distribución de Madrid. * Lliurex, basado en Ubuntu, distribución de Valencia. (Otras conocidas) * Knoppix, distribución live, basada en debian * Morphix, más de lo mismo, con un sistema de módulos muy interesante * Elive, basada en debian con el escritorio Enlightment. ... El motivo de empaquetar en .deb creo que queda claro. Ahora vamos al método. 2.- Preparar nuestras fuentes para hacer un paquete deb Seguramente tenemos un directorio donde tenemos código fuente (en cualquier lenguaje) y lo compilamos con ayuda de un script o Makefile. Nuestro código tiene dependencias de compilación es decir, aquellas librerías o programas que necesitamos tener instaladas para que la compilación funcione y genere el código binario, por ejemplo si nuestro programa está escrito en C las dependencias serán el compilador gcc, la librería libc6 y quizás las cabeceras del kernel. Si además usamos Makefiles, necesitaremos make y quizás autoconf, automake, etc... Estas son las dependencias que se llaman "Build-Depends", ya veremos luego para que sirven. Una vez el código está compilado si generamos el paquete y lo instalamos en una máquina distinta a donde lo hemos desarrollado quizás tenga dependencias de ejecución, es decir, si lo hemos enlazado a libc6, y al toolkit gráfico de KDE: qt, necesitaremos al menos que ese equipo disponga de libc6 (que se instala siempre y el toolkit de ejecución qt (kdelibs). A estas se les llama "Depends". Hay muchos más casos, por ejemplo, nuestro código no se compila porque hemos usado un lenguaje interpretado (python, perl, bash), las dependencias de compilación ya no se necesitan pero si las de ejecución. Cada distribución ha resuelto esta gran papeleta con un gestor de paquetes, en debian y todas las derivadas tenemos dpkg y por encima apt-get. 3.- Estructura del directorio debian en nuestro código fuente El primer paso para crear un paquete deb es crear un directorio llamado debian en la raiz del código fuente donde se situarán una serie de archivos que serán usados para la construcción del paquetes y para su posterior clasificación en los repositorios. La forma más sencilla es copiarnos nuestro código fuente a un directorio nuevo con el siguiente nombre: mi-proyecto-0.0.1 Muy importante: * no usar mayúsculas * no usar caracteres especiales en el nombre (se pueden usar guiones, letras y numeros) * usar una nomenclatura de versiones lo más estandar posible (con 3 números sirve) * separar el nombre del proyecto de la versión con un guión medio. Instalaremos ciertos paquetes de desarrollador de debian que nos ayudarán en el proceso de empaquetar: # apt-get install devscripts build-essential dpkg-dev \ dh-make debhelper fakeroot Entramos al directorio de las fuentes y generamos el directorio debian con ayuda de dh-make: $ cd mi-proyecto-0.0.1 $ dh_make --createorig (nos va a preguntar por el tipo de paquete, diremos "s" ) Tipos de paquetes: s = single (las fuentes generan un paquete m = multimple (las fuentes generan varios paquetes quizás un programa y una librería) l = librería (las fuentes generan una librería) k = módulo kernel (las fuentes generan un módulo del kernel) c = paquete cdbs (nueva forma de crear paquetes que ya veremos) ( sería recomendable tener las siguientes variables de entorno declaradas: DEBNAME=Nombre Apellidos (nick) DEBEMAIL=correo@electronico.com DEBFULLNAME=Nombre Apellidos (nick) así como tambíen tener una clave GPG con los mismos datos: gpg --create ) Esto creará un tar.gz de las fuentes (nuestro código) y entonces añadirá el directorio debian con todas las herramientas que luego comentaremos. Dentro de ese directorio pueden encontrarse: * changelog (archivo del control de cambios del empaquetador) Este archivo es muy importante a la hora de empaquetar porque la versión, rama y prioridad se indican aquí así como el empaquetador. * control Este archivo describe el paquete del código fuente y los paquetes bianrios generados a partir de él. En la descripción de los fuentes es donde indicamos las dependencias de compilación "Build-Depends", en los binarios el propio constructor del paquete incluirá las dependencias de ejecución por nosotros. * rules (archivo de compilación Makefile) Este archivo es el que configurará compilará e instalará los binarios en un directorio temporal que luego se convertirá en el paquete deb. Tiene reglas como config.status, build, install, clean, etc... * copyright (información de licencia/licencias del código de ese paquete) * README.Debian (información de interés para el usuario debian de ese paquete) * docs (archivo donde se lista los archivos de documentación que acompañan al programa) * install (archivo que indica que archivos estan en el paquete) * post|pre int|rm ( scripts que se ejecutan antes|después de la instalación|desinstalación ) * manpages (páginas man) En debian todos los bianrios que se encuentren en el PATH deben tener página man. .... Hay muchos más pero con saber estos nos vale de momento. 4.- Compilando.... Si nuestro paquete usa autotools ( ./configure && make && make install ) dh_make lo habrá detectado y seguramente no haya que tocar nada más que el archivo changelog (se edita con el comando debchange) y el archivo control (se edita con cualquier editor) "debchange -i" añadirá una nueva revisión al changelog, completando por nosotros, la fecha, hora y autor (los datos los toma de las variables de entorno DEB***** que hemos visto antes). Si nuestro paquete no usa autotools y compila cosas tendremos que editar el archivo rules y llamar a lo que se compila desde allí. Para generar nuestro primer paquete deb ejecutamos lo siguiente: $ dpkg-buildpackage -rfakeroot IMPORTANTE: la compilación de paquetes hay que hacerla como usuario (como root podemos cargarnos algo si tenemos un Makefile mal diseñado!!!!) NOTA: Se puede usar debuild (que es más corto y se recuerda mejor, además que ejecuta una serie de herramientas extra) Este comando llama secuencialmente a lo siguiente: - make clean - dpkg-source (genera el tar.gz de las fuentes y el diff.gz de debian) - configure - make - make install DESTDIR=$(CURDIR)/debian/mi-proyecto - builddeb Es decir, se limpian las fuentes, se crea un archivo comprimido con nuestro código fuente y los parches que aplica debian (una de las políticas de debian es distribuir el código funete original y parchearlo en el momento de la compilación) Después el proceso es el de siempre, configurar, compilar y para instalar se usa la variable DESTDIR que será / en caso de no indicarse pero que aquí es un subdirectorio del directorio debian. Luego se copian la documentación, el changelog, se generan las dependencias de ejecución mirando el linkado dinámico de nuestros binarios (ldd nuestro_programa) y se mete todo en uno (o varios) archivos deb. Si tenemos clave GPG nos pedirá firmar dos archivos. 5.- Ejemplo de paquete deb Tenemos nuestro super programa adios-mundo-0.0.1: #include int main(){ print "Adios Mundo.\n"; return(0); } y un Makefile: all: gcc adios-mundo.c -o adios-mundo clean: rm -f *~ adios-mundo install: install -m 755 adios-mundo $DESTDIR/usr/bin/adios-mundo Como no tenemos configure, dh_make no va a llamarlo, una vez generado el directorio debian editamos el archivo debian/control para indicar el empaquetador, la sección, y una descripción (corta y larga). Los archivos terminados en ex o EX (example) se pueden borrar. ejecutamos dpkg-buildpackage -rfakeroot y obtenemos estos archivos: adios-mundo_0.0.1-1.diff.gz adios-mundo_0.0.1-1.dsc adios-mundo_0.0.1-1.build adios-mundo_0.0.1.orig.tar.gz adios-mundo_0.0.1-1_i386.deb El archivo dsc contiene la información del paquete fuente y los hash (md5, sha1) de los archivos diff.gz y orig.tar.gz) El archivo build es una copia de lo que vemos es consola cuando se compila o también llamado log de construcción. El "-1" extra que aparece añadido a nuestra versión es la versión del paquete en debian, ya que el empaquetador puede añadir parches o empaquetarlo de otra manera antes de que nosotros publiquemos la próxima versión 0.0.2 Por último el paquete deb, se puede instalar con un simple: # dpkg -i adios-mundo_0.0.1-1_i386.deb Este paquete tiene muchos fallos, uno de ellos es que no tiene página man y otro es que no hemos indicado dependencias de compilación, que a groso modo serían: libc6-dev, gcc, make Para ver la "calidad" de los paquetes deb se usa lintian y linda, si instalamos estos paquetes se ejecutarán justo antes de terminar el proceso de empaquetado y nos dirán que cosas tenemos mal. 6.- Ahora le toca al mirror Ahora bien, tenemos un paquete y lo queremos redistribuir, la forma más sencilla es colgar el paquete en nuestra página web, enlazarlo y que la gente lo descargue e instale por medio de "dpkg -i". Esto no es buena idea ya que para cuando publiquemos una actualización nuestros usuarios no podrán instalarla hasta que vuelvan a entrar a la web. Otro problema es que dpkg no resuelve dependencias, sino apt, por lo que puede quedar el paquete roto hasta que no se ejecute "apt-get -f install". Quizás sea mejor idea mantener un pequeño repositorio y que los usuarios lo añadan a su sources.list para que el proceso sea más automático. Hay dos tipos de mirror, los simples y los complejos, vamos a ver los dos: 6.1.- Mirror simple Es básicamente un directorio (con subdirectorios) que no tiene que cumplir ningún estándar y en el que se copian los archivos deb o todos los archivos de compilación (deb, diff.gz, ,tar.gz, dsc, changes) y se ejecuta algo como esto: $ apt-ftparchive packages . | gzip > Packages.gz $ apt-ftparchive sources . | gzip > Sources.gz Se copia a un directorio accesible por ftp o http y se añade al sources.list algo como esto: deb http://nuestrositio/directorio/ ./ Ventajas: * muy rápido de hacer y mantener * admite varias versiones del mismo paquete Inconvenietes: * Dificil de mantener réplicas (mirrors) * No se puede firmar con gpg (al menos de forma sencilla) 6.2.- Mirror completo y complejo Hay varias herramientas para hacer un mirror completo la que yo he usado se llama "reprepro" y básicamente el mirror tendrá esta estructura: . |-- conf |-- dists `-- pool En el directorio dists tendremos un directorio por cada versión de la distribución por ejemplo (sarge, etch, sid, unstable, dapper, etc...) En el directorio pool es donde se encuentran los paquetes clasificados por sección (main, contrib, non-free, universe, multiverse) y luego por su primera letra (o 4 primeras para librerías). No tenemos que crear directorios a mano ya que reprepro se encargará de todo. Lo primero es hacer un archivo conf/distributions que tenga bloques como este: Origin: Tcos-Packages Label: Tcos-Packages Suite: unstable Codename: unstable Architectures: i386 source Components: main Description: Tcos Debian unstable packages mirror SignWith: Nombre Apellidos (nick) Creo que las etiquetas se autoexplican todas, salvo arquitecturas y componentes. Arquitecturas corresponde a las arquitecturas para las que vayamos a compilar nuestro paquete y si vamos a incluir el código fuente y componentes es la sección del repositorio donde se guardará al paquete (main, contrib, non-free, universe, multiverse) SignWith es con lo que se firmará (GPG) nuestro repositorio. Haremos tantos bloques como este, como secciones y suites queramos tener. para añadir paquetes al repositorio ejecutamos lo siguiente: $ reprepro --ask-passphrase -b . -V -C [COMPONENT]\ include [SUITE] archivo_0.0.1-1.dsc Para añadir un archivo deb sólo: $ reprepro --ask-passphrase -b . -V -C [COMPONENT]\ includedeb [SUITE] archivo_0.0.1-1_i386.deb Cuando vayamos a añadir la versión 0.0.2 reprepo borrará la versión 0.0.1 Si vamos a añadir una revisión de debian 0.0.1-2 reprepro sólo actualiza el fichero diff.gz ya que el orig.tar.gz no cambia entre versiones de debian. Para borrar un paquete del repositorio: $ reprepro --ask-passphrase -b . -V -C [COMPONENT] remove [SUITE] archivo Si el paquete tiene varios deb hay que borrarles también: $ reprepro --ask-passphrase -b . -V -C [COMPONENT]\ remove [SUITE] archivo-dev libarchivo archivo-doc Por último para poder acceder a este mirror con apt-get añadimos al sources.list: deb http://servidor/directorio/ SUITE COMPONENTE Ejemplo: deb http://servidor/directorio/ unstable main Podemos añadir otra línea para poder bajarnos el código fuente: deb-src http://servidor/directorio/ unstable main El código fuente se puede bajar así: $ mkdir sources $ cd sources $ apt-get source mi-proyecto Esto se descarga el archivo dsc, el orig.tar.gz y el diff.gz reconstruyendo el directorio de las fuentes al que podemos añadir algun parche y volver a compilar con: $ dpkg-buildpackage -rfakeroot Si hemos firmado el repositorio cuando nuestros usuarios ejecuten "apt-get update" les avisará de que no conoce nuestra clave, para que ellos la importen tenemos que generar un archivo con ella: $ gpg --armor --export CLAVE > nuestra-clave-pub.key Y que ellos lo descargen y añadan así: # wget http://servidor/nuestra-clave-pub.key -O- | apt-key add O bien si la hemos publicado en un servidor de claves: # gpg --keyserver wwwkeys.eu.pgp.net --recv-keys CLAVE # gpg --armor --export CLAVE | apt-key add - 7.- Enlaces Debian: http://www.debian.org http://www.debian.org/doc/manuals/maint-guide/index.es.html http://www.es.debian.org/devel/ http://www.es.debian.org/devel/join/ http://www.us.debian.org/devel/wnpp/index.es.html Reprepro: http://mirrorer.alioth.debian.org/reprepro.1.html AutoTools: http://sources.redhat.com/autobook/ GPG: http://www.linuca.org/body.phtml?nIdNoticia=88