Cómo manejar las bibliotecas compartidas en el
árbol de portes
Qué son las reglas numéricas de las
bibliotecas compartidas
Las bibliotecas compartidas son algo complicadas por varias
razones. Para su manejo es necesario entender antes el
esquema de nombres de las bibliotecas:
libfoo.so.major.minor.
Cuando se enlaza un programa, el enlazador ld
embebe esa información en el binario que se genera.
Esto se puede ver con ldd.
Más tarde, cuando se ejecuta este programa, el
enlazador dinámico ld.so utiliza esa
información para encontrar la biblioteca
dinámica pertinente:
- Requiere una biblioteca con la numeración
superior exactamente igual.
- Requiere una biblioteca con la numeración
inferior igual o mayor.
Esto quiere decir que todas las bibliotecas
con el mismo número superior y con un número
inferior igual o mayor al requerido, deben satisfacer
el API binario que el programa espera encontrar. Si
no fuera así, entonces el porte sería
erróneo; en concreto, el porte no funcionaría
cuando los usuarios intentaran actualizar sus sistemas.
Las reglas para las bibliotecas compartidas son bastante
simples.
- Si se añaden funciones a la bibliotecas, es
necesario incrementar el número inferior de la
biblioteca: un programa que necesite esas funciones
no tiene otro modo para requerirlas que no sea el de
pedirlas de forma explícita para, por lo menos,
esta versión.
- Si el API actual cambia, o sea, si se altera la
firma de cualquier función, o si las secuencias
de llamada ya no son válidas, si un tipo cambia
de forma incompatible, el número superior
se debe incrementar.
- Esto incluye la eliminación de funciones
antiguas. Cualquier eliminación de funciones
debería ir acompañada por un incremento
en el número superior.
Algunas veces sucede que una biblioteca está escrita en
varios ficheros, y las funciones internas son visibles para
permitir la comunicación entre esos ficheros.
Esos nombre de funciones suelen empezar con un guión
bajo, y no son parte del API.
Nótese que el esquema de nombres de las bibliotecas es
ubicuo en las plataformas de OpenBSD, tanto si el formato es
ELF como a.out.
Cambios en los portes para obtener nombre correctos
Un buen número de portes necesitan cambios para poder
ser compilados con bibliotecas compartidas. Recuerde que la
compilación de las bibliotecas compartidas se debe
hacer mediante
gcc -shared -fpic|-fPIC -o libfoo.so.4.5 obj1 obj2
Si intenta cambiar el nombre de la biblioteca más tarde
para ajustar el número de versión, no
funcionará: las bibliotecas ELF usan magia adicional
para el nombre interno de la biblioteca, por lo que debe
enlazar desde la primera vez con la versión correcta.
Por otra parte, recuerde que puede anular y cambiar variables
de Makefile desde la línea de órdenes,
usando MAKE_FLAGS en el fichero
Makefile del porte. Esto le será de gran
utilidad en algunos portes, como por ejemplo los basados en
libtool, ya que proveen de una de estas variables de
versión por cada biblioteca que crean.
Intente poner todas las bibliotecas visibles en
/usr/local/lib
Exigir que el usuario añada directorios a su camino a
ldconfig es, como regla general, una mala idea: todas las
bibliotecas compartidas que se encuentran directamente
enlazadas a programas deberían aparecer en
/usr/local/lib. Sin embargo, es posible usar un
enlace simbólico a una determinada biblioteca. Es
necesario que se comprendan las reglas de búsqueda de
las bibliotecas:
- En el momento de la compilación,
ld usa los indicadores -L
para configurar un camino en el que buscar la
biblioteca. En cuanto encuentra una biblioteca que
coincide con sus requisitos, para de buscar.
- En el momento de la ejecución,
ld.so usa la información guardada
mediante ldconfig para encontrar la
biblioteca requerida.
Asumamos que tenemos dos portes que provean dos versiones
principales de una cierta biblioteca, pongamos como ejemplo
qt.1.45 y qt.2.31. Como los dos
portes no se pueden instalar de forma simultánea, para
asegurarnos de que un programa cualquiera enlace con qt.1, esa
biblioteca se proveerá como
/usr/local/lib/qt/libqt.so.1.45, y los programas
se enlazarán usando
ld -o program program.o -L/usr/local/lib/qt -lqt.
De igual modo, un programa que enlace con qt.2 usará el
fichero /usr/local/lib/qt2/libqt.so.2.31 con
ld -o program program.o -L/usr/local/lib/qt2 -lqt.
Para resolver esas bibliotecas en el momento de la
ejecución, se proveerá un enlace llamado
/usr/local/lib/libqt.so.1.45 y otro llamado
/usr/local/lib/libqt.so.2.31. Esto será
suficiente para satisfacer a ld.so.
Enlazar un programa usando qt1 con
ld -o program program.o -L/usr/local/lib -lqt es
un error. Este código asume que qt.2.31
no ha sido instalado, lo que es una presunción
errónea.
Estos trucos sólo son necesarios en casos especiales en
los que se den bibliotecas para las que se necesite proveer de
un periodo de transición entre versiones. Por lo
general, bastará con asegurarse de que la biblioteca
aparezca en /usr/local/lib.
Cómo escribir correctamente las dependencias de las
bibliotecas
El nuevo código de dependencia necesita dependencias de
bibliotecas completas. Debe usar make
lib-depends-check para verificar que un porte mencione
todas las bibliotecas que requiere. Separe las
especificaciones de bibliotecas con comas:
LIB_DEPENDS=gtk.1.2,gdk.1.2::x11/gtk+.
Además, especificar las bibliotecas estáticas en
una línea de LIB_DEPENDS no es un error. LIB_DEPENDS
es evaluado por completo en el momento de la
compilación de un paquete: el paquete resultante
tendrá la información sobre dependencias de
bibliotecas embebido, en forma de líneas para
ld.so, que contienen el número
superior.inferior que fue usado para su compilación, y
nada para las bibliotecas compartidas.
También debe proveer de RUN_DEPENDS si un porte
requiere algo más que compilar enlazando a una
biblioteca. Esto permitirá al porte compilar
correctamente en arquitecturas que no tengan soporte para
bibliotecas compartidas.
De hecho, proveer líneas LIB_DEPENDS para bibliotecas
estáticas es una buena idea: esto simplificará
la acutalización del porte si una cierta dependencia
pasa de biblioteca estática a biblioteca compartida.
La líneas LIB_DEPENDS deben especificar los mismos
caminos que se utilizan para ld. Por ejemplo, el
fragmento de dependencia típico de qt2 dice:
LIB_DEPENDS+=lib/qt2/qt.2::x11/qt2, para que las
líneas de dependencias de la biblioteca se resuelvan
correctamente. Esto permite a la dependencia comprobar el
código para poder hacer lo correcto si se encuentra con
varias versiones de la misma biblioteca.
Cómo actualizar los portes correctamente
Cuando se actualice o añada un porte en el que haya por
medio bibliotecas compartidas, hay que tener en cuenta unos
cuantos detalles.
- Asegúrese de que los números
superior.inferior de las bibliotecas compartidas sean
los correctos.
- Verifique todos los portes que dependan de su
porte. Verifique que compilen correctamente con sus
cambio. Notifique de la actualización a los
mantenedores correspondientes, para que éstos
puedan verificar que sus portes todavía
funcionan bien.
- Puede que tenga que ajustar LIB_DEPENDS. Si
introduce nuevas bibliotecas compartidas, preste
atención a los BUILD_DEPENDS que tengan que ser
convertidos en LIB_DEPENDS.
- Siempre que introduzca un nuevo porte debe
verificar que no esté creando una biblioteca
que entre en conflicto con otra ya existente: las
bibliotecas de dos portes con el mismo número
son mortales, debido a que sus esquemas de
enumeración de versiones no pueden coincidir.
Debe intentar resolver esta situación con el
programa del autor (por ejemplo, una biblioteca que se
llame libnet es un mal comienzo).
www@openbsd.org
Originally [OpenBSD: libraries.html,v 1.4 ]
$Translation: libraries.html,v 1.3 2004/08/29 16:14:27 santana Exp $
$OpenBSD: libraries.html,v 1.3 2004/08/29 16:55:04 jufi Exp $