MarioDebian, mi devlog

Bitácora de un desarrollador newbie.

NUEVA URL==> HOWTO Crear paquetes .deb y mirror debian (en mariodebian.com)

HOWTO Crear paquetes .deb y mirror debian

A muchos de los participantes del I 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.

El trabajo con TCOS continúa y ya puedo anunciar que tengo el repositorio listo para descargar paquetes para debian y ubuntu.

Debian (testing o unstable)

deb http://cls-tcos.forja.rediris.es/repos/  unstable main

Ubuntu Dapper

deb http://cls-tcos.forja.rediris.es/repos/  dapper main

Ubuntu Edgy

deb http://cls-tcos.forja.rediris.es/repos/  edgy main

He tenido que compilar los paquetes en varias versiones por lo que he usado jaulas instaladas con debootstrap, ya lo explicaré como se hace en otro artículo.

Hay más información sobre el repositorio, la clave GPG en la web de TCOS de la forja.


Este fin de semana he estado escribiendo un pequeño HOWTO que explica como empaquetar nuestro proyecto en un paquete deb y luego crear un mirror personal para que nuestros usuarios puedan descargarlo.

Sigue....

Howto crear paquetes .deb y mirror debian


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 Core
  • 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 Extremadura
  • Guadalinex, basado en Ubuntu, distribución de Anadalucía
  • MoLinux, basado en Ubuntu, distribución de Castilla la Mancha
  • 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 más automática)

( 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 (última persona que hizo cambios y que firmará con su clave GPG el paquete).
  • 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 fuente 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 es el que 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


Las dependencias de compilación se resuelven fácilmente con el comando:

# apt-get build-dep mi-proyecto


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
Articulos relacionados:

Comentarios

  1. Juan Luis Lledó Pagina del man
    20/11/2006 | 13:19

    Hola, quisiera saber cómo puedo incluir una pagina de man cuando creo un paquete, porque lo he intentado copiando el archivo de man creado con nroff y con la extension *.1 en la carpeta debian del paquete (antes de empaquetarlo), y luego al empaquetar no se incluye el manual en el paquete. He comprobado que el archivo man está bien escrito sin fallos.

  2. mariodebian Re: página man
    20/11/2006 | 14:16

    Para incluir una página man tienes que editar el archivo "manpages" del directorio debian y añadir la ruta de tu archivo, algo como esto:

    debian/miprograma.1

    Cuando se construya el paquete automáticamente se comprimirá con gzip y se situará en el directorio man que corresponda.

  3. Thanatermesis Muy bueno
    20/11/2006 | 15:37

    Muy bueno el articulo mariodebian, me lo he leido un poco pero la falta de tiempo a hecho que mejor lo guarde en mis bookmarks, en mi TODO está el mover todo el repo a un mejor estandard que el "raw hack" que usaba, a ver si encuentro un poco de tiempo y ganas, gracias de nuevo

  4. Raul repositorios en CDROM
    20/11/2006 | 19:27

    Quizas este problema lo suframos varios usuarios:
    Debian es una excelente distribucion siempre y cuando dispongamos de una conexion de banda ancha.
    Si solo tenemos internet veloz en el curro y dial up en casa, como podemos transportar los .deb instalados en una maquina hacia la otra?
    Copiar el /var/apt/cache no parece dar resultado dado que la maqiona destino no acepta la copia como un repositorio.
    Existe alguna manera de crear un cd de repositorios a partir de un grupo de archivos .deb?

  5. Resete-e Gracias
    20/11/2006 | 20:12

    Muchas gracias por este pedazo de artículo, seguro que a muchos nos resulta muy útil.

    Raul yo cuando era becario en la facultad me bajaba el repositorio entero a un HD y luego lo montaba en el servidor de casa XDD
    La forma de crear un repositorio es lo más fácil que te puedas imaginar: copia los archivos en un servidor web, ftp, directorio local... y luego lo añades al /etc/apt/sources.list puedes copiar la estructura de uno de los repositorios oficiales. De todas formas Mariodebian te lo comenta mucho mejor en este artículo.

  6. mariodebian Re repositorios en cdrom
    20/11/2006 | 21:18

    No confundir un repositorio personal donde colgamos nuestros paquetes con un repositorio (completo o no) de debian.

    Para clonar un repositorio se usa debmirror, yo tengo algo como esto:

    debmirror -a i386 --progress --ignore-release-gpg --getcontents --nosource -d testing,stable,unstable -s main,contrib,non-fr3e,main/debian-installer --method=htptp -h ftp.uk.debian.org /mirror/debian

    Para añadirlo al sources.list no se necesita un servidor web si la descarga es local:

    deb file:///mirror/debian unstable main contrib non-fr3e
    deb file:///mirror/debian-marillat sid main

    Para pasar a un cdrom un repositorio de estos creo que hay que definir un archivo especial que es el que se lee y que en algún sitio he leído y que no recuerdo ahora.

  7. Juan Carlos Backup de cache
    25/11/2006 | 16:24

    Si quieres hacer un backup de la cache de repositorios es facil hace falta hacer un poco mas que un backup de /var/apt/cache

    Para hacer una copia de seguridad del cache de los repositorios descargados

    $ mkdir -p $HOME/backup/var/lib/
    $ sudo cp -R /var/lib/apt/ $HOME/backup/var/lib/
    $ mkdir -p $HOME/backup/var/cache/
    $ sudo cp -R /var/cache/apt/ $HOME/backup/var/cache/
    $ mkdir -p $HOME/backup/etc/apt
    $ sudo cp -R /etc/apt/ $HOME/backup/etc/
    $ sudo chown -R $USER $HOME/backup/

    Para restaurar la copia de seguridad

    $ sudo cp -fR $HOME/backup/var/* /var/
    $ sudo cp -fR $HOME/backup/etc/apt/* /etc/apt/

    esto hara el backup en tu home ($HOME) si quieres elbackup en otro sitio sustituye $HOME por el sitio

    Mario una pregunta si tengo un paquete que compila con ./configure && make dependences && make ¿como le digo al constructor de paquetes(debuild checkinstall o dpkg-buildpackage) que tiene que crear las deps?

  8. mariodebian Re: compilar make dependences...
    25/11/2006 | 18:26

    Edita el debian/rules y en la regla "build:" después de $(MAKE) añades una linea (tabulada) con $(MAKE) dependences.

    No he querido hablar de checkinstall porque la calidad de sus paquetes y la personalización deja que desear... Además de instalarse en /usr/local sino se lo indicamos explícitamente.

  9. Juan Carlos checkinstall
    25/11/2006 | 19:10

    Gracias y si checkinstall es malisimo y la personalizacion del paquete es bastante mala bueno gracias.

    Cambiando de tema acabo de ver tu tuto en barrapunto espero que no le pase lo que al de metadistros

  10. Eduardo Moreno Y si quiero empaquetar un no programa
    28/11/2006 | 23:39

    Excelente tu explicación. Pero quiero empaquetar algunos archivos planos. Básicamente son dibujos de OpenClipart para OpenOffice.org. No tengo un programa, solo debe depositar los archivos en una estructura de directorios. ¿Sabras donde puedo conseguir información?

  11. martin KERNEL-PACKAGE !!!
    08/03/2007 | 20:03

    Por que tantos procedimientos con kernel package te puedes contruir un mirror debian parcial o total segun tus requerimientos.....??

  12. darkKnight AYUDA !!!! como agrego las dependencias a mi .deb
    25/06/2007 | 18:06

    Hola
    eh podido seguir bien el manual, pero aun no entiendo ¿como le puedo hacer para introducir en ese .deb las dependencias del programa que deseo instalar?

    por ejemplo

    quiero instalar el tcpdump, pero se que depende de libpcap...

    ¿Como le hago para instroducir en el .deb la libpcap y que primero se instale la libpcap antes de instalar el tcpdump?

    espero alguien me pueda ayudar... gracias

Comentarios cerrados