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.
Un ejemplo¶
Usaremos libnova como un ejemplo:
$ bzr branch ubuntu:natty/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á).
Los archivos .la de libtool son necesarios en algunos sistemas no-Linux con soporte de bibliotecas pobre, pero en sistemas Debian normalmente causan más problemas que los que resuelven. Actualmente es un objetivo de Debian eliminar los archivos .la Debian goal to remove .la files y deberíamos ayudar a hacerlo.
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.
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.
Archivos de símbolos de bibliotecas de C++¶
C++ tiene estándares de compatibilidad binaria incluso más exigentes que C. El equipo Qt/KDE de Debian mantiene algunos scripts para gestionarlo. Véase su página Working with symbols files para saber cómo usarlos.
Lecturas adicionales¶
Debian Library Packaging Guide (guía de empaquetado de bibliotecas Debian) de Junichi Uekawa profundiza en estos temas con más detalle.