Ubuntu logo

Packaging Guide

8. Bibliotecas compartidas

Las bibliotecas compartidas es código compilado que se supone que será compartido por diferentes programas. Se distribuyen como archivos .so en /usr/lib/.

Una biblioteca exporta símbolos que son versiones compiladas de funciones, clases y variables. Una biblioteca tiene un nombre denominado SONAME que incluye un número de versión. Esta versión de SONAME no tiene por qué coincidir con el número de versión de emisión pública. Un programa se compila contra una versión determinada de SONAME de la biblioteca. Si cualquiera de los símbolos es eliminado o modificado, entonces el número de versión debe ser cambiado lo que fuerza que que cualquier paquete que use la biblioteca sea recompilado contra la nueva versión. Los números de versiones normalmente son establecidos aguas arriba y los mantenemos en los nombres de los paquetes binarios, llamado número ABI, pero en ocasiones aguas arriba no usan números de versiones razonables y los empaquetadores tienen que mantener números de versiones separados.

Las bibliotecas se distribuyen normalmente aguas arriba como emisiones independientes. Algunas veces se distribuyen como partes de un programa. En este caso se pueden incluir en el paquete binario junto con el programa (esto se denomina «bundling», atado) si no espera que ningún otro programa use la biblioteca, pero lo más frecuente es que sean separadas en paquetes binarios independientes.

Las propias bibliotecas se meten en un paquete binario llamado libfoo1 donde foo es el nombre de la biblioteca y 1 es la versión del SONAME. Los archivos de desarrollo del paquete, como los archivos de cabecera, necesitan compilar programas contra la biblioteca que se ha metido en el paquete llamado libfoo-dev.

8.1. Un ejemplo

Usaremos libnova como un ejemplo:

$ bzr branch ubuntu:trusty/libnova
$ sudo apt-get install libnova-dev

Para encontrar el SONAME de una biblioteca ejecute:

$ readelf -a /usr/lib/libnova-0.12.so.2 | grep SONAME

El SONAME es libnova-0.12.so.2, lo que coincide con el nombre del archivo (es lo normal, pero no siempre ocurre). En este caso aguas arriba han puesto el número de versión como parte del SONAME y le han dado una versión ABI de 2. Los nombres de paquetes de bibliotecas deberían seguir el SONAME de la biblioteca que contienen. El paquete binario de la biblioteca se llama libnova--0.12-2, donde libnova-0.12 es el nombre de la biblioteca y 2 es nuestro número ABI.

SI aguas arriban hacen cambios incompatible a su biblioteca tendrá que revisionar su SONAME y nosotros tendremos que cambiar de nombre a nuestra biblioteca. Cualquier otro paquete que use nuestra biblioteca deberá ser recompilado contra la nueva versión, esto es lo que se llama una transición y puede suponer cierto esfuerzo. Afortunadamente nuestro número ABI seguirá coincidiendo con el SONAME de aguas arriba, pero en ocasiones se introducen incompatibilidades sin cambiar el número de versión lo que nos fuerza a hacer cambios en el nuestro.

Si miramos en debian/libnova-0.12-2.install vemos que incluye estos dos archivos:

usr/lib/libnova-0.12.so.2
usr/lib/libnova-0.12.so.2.0.0

El último es la biblioteca en sí, completada con el número de menor de la versión y punto. El primero es un enlace simbólico que apunta a la biblioteca real. El enlace simbólico es lo que buscarán los programas que empleen la biblioteca, ya que los programas que se ejecutan no se preocupan por el número de menor de la versión.

libnova-dev.install incluye todo los archivos necesarios para compilar un programa con esta biblioteca. Los archivo de cabeceras, una configuración binaria, el archivo .la de libtool y libnova.so que es otro enlace simbólico apuntando a la misma biblioteca, programas compilados contra la biblioteca no se preocupan del número mayor de la versión (aunque el binario en el que se compilarán sí lo hará).

.la libtool files are needed on some non-Linux systems with poor library support but usually cause more problems than they solve on Debian systems. It is a current Debian goal to remove .la files and we should help with this.

8.2. Bibliotecas estáticas

El paquete -dev también incluye usr/lib/libnova.a. Es una biblioteca estática, una alternativa a las librerías compartidas. Cualquier programa compilado contra una biblioteca estática incluya el directorio de código dentro de sí mismo. Esto evita tener que preocuparse sobre la compatibilidad binaria de la biblioteca. Sin embargo, también significa que cualquier error, incluyendo las incidencias de seguridad, no serán actualizados junto con la biblioteca hasta que se recompile el programa. Por esta razón se desaconseja el uso de programas que usen librerías estáticas.

8.3. Archivos de símbolos

Cuando un paquete se compila contra una biblioteca el mecanismo de shlibs añadirá una dependencia del paquete a esa biblioteca. Este es el motivo de que la mayoría de los programas tengan Depends: ${shlibs:Depends} en el archivo debian/control. Eso se sustituye por las dependencias de la biblioteca en tiempo de compilación. Sin embargo, shlibs solo puede hacerla depender del número mayor de versión ABI, 2 en el ejemplo, así que si se añaden nuevos símbolos a libnova 2.1 un programa que use estos símbolos podría todavía seguir instalado contra libnova ABI 2.0, lo que podría producir un fallo.

Para hacer más precisas las dependencias de las bibliotecas matenemos archivos .symbols que listan todos los símbolos de una librería y la versión en la que aparecen.

libnova no tiene archivo de símbolos así que podemos crear uno. Comience por compilar el paquete:

$ bzr builddeb -- -nc

La opción -nc hará que se finalice al completar la compilación sin que se eliminen los archivos compilados. Cámbiese al directorio compilado y ejecute dpkg-gensymbols para el paquete de la biblioteca:

$ cd ../build-area/libnova-0.12.2/
$ dpkg-gensymbols -plibnova-0.12-2 > symbols.diff

Esto genera un archivo de diferencias (diff) que puede aplicar:

$ patch -p0 < symbols.diff

Lo que creará un archivo con un nombre similar a dpkg-gensymbolsnY_WWI que lista todos los símbolos. También lista la versión de paquete actual. Podemos eliminar la versión de empaquetado que se lista en el archivo de símbolos porque generalmente no se añaden nuevos símbolos por versiones más modernas de empaquetado, sino por los desarrolladores aguas arriba:

$ sed -i s,-0ubuntu2,, dpkg-gensymbolsnY_WWI

Ahora mueva el archivo a su ubicación, confirme y haga una prueba de compilación:

$ mv dpkg-gensymbolsnY_WWI ../../libnova/debian/libnova-0.12-2.symbols
$ cd ../../libnova
$ bzr add debian/libnova-0.12-2.symbols
$ bzr commit -m "add symbols file"
$ bzr builddeb

Si compila con éxito es que el archivo de símbolos es correcto. Con la siguiente versión aguas arriba de libnova podría ejecutar de nuevo dpkg-gensymbols y obtendrá un archivo de diferencias para actualizar el archivo de símbolos.

8.4. Archivos de símbolos de bibliotecas de C++

C++ has even more exacting standards of binary compatibility than C. The Debian Qt/KDE Team maintain some scripts to handle this, see their Working with symbols files page for how to use them.

8.5. Lecturas adicionales

Junichi Uekawa’s Debian Library Packaging Guide goes into this topic in more detail.