GNU/Linux >> Tutoriales Linux >  >> Linux

Cómo manejar bibliotecas dinámicas y estáticas en Linux

Linux, en cierto modo, es una serie de bibliotecas estáticas y dinámicas que dependen unas de otras. Para los nuevos usuarios de sistemas basados ​​en Linux, todo el manejo de las bibliotecas puede ser un misterio. Pero con experiencia, la gran cantidad de código compartido integrado en el sistema operativo puede ser una ventaja al escribir nuevas aplicaciones.

Para ayudarlo a ponerse en contacto con este tema, preparé un pequeño ejemplo de aplicación que muestra los métodos más comunes que funcionan en las distribuciones comunes de Linux (estos no han sido probados en otros sistemas). Para seguir este tutorial práctico con la aplicación de ejemplo, abra un símbolo del sistema y escriba:

$ git clone https://github.com/hANSIc99/library_sample
$ cd library_sample/
$ make
cc -c main.c -Wall -Werror
cc -c libmy_static_a.c -o libmy_static_a.o -Wall -Werror
cc -c libmy_static_b.c -o libmy_static_b.o -Wall -Werror
ar -rsv libmy_static.a libmy_static_a.o libmy_static_b.o
ar: creating libmy_static.a
a - libmy_static_a.o
a - libmy_static_b.o
cc -c -fPIC libmy_shared.c -o libmy_shared.o
cc -shared -o libmy_shared.so libmy_shared.o
$ make clean
rm *.o

Después de ejecutar estos comandos, estos archivos deben agregarse al directorio (ejecutar ls para verlos):

my_app
libmy_static.a
libmy_shared.so

Acerca de los enlaces estáticos

Cuando su aplicación se vincula con una biblioteca estática, el código de la biblioteca se convierte en parte del ejecutable resultante. Esto se realiza solo una vez en el momento del enlace, y estas bibliotecas estáticas generalmente terminan con un .a extensión.

Una biblioteca estática es un archivo (ar) de archivos de objetos. Los archivos de objetos suelen estar en formato ELF. ELF es la abreviatura de Executable and Linkable Format, que es compatible con muchos sistemas operativos.

La salida del file El comando le dice que la biblioteca estática libmy_static.a es el ar tipo de archivo:

$ file libmy_static.a
libmy_static.a: current ar archive

Con ar -t , puede buscar en este archivo; muestra dos archivos de objeto:

$ ar -t libmy_static.a 
libmy_static_a.o
libmy_static_b.o

Puede extraer los archivos del archivo con ar -x <archive-file> . Los archivos extraídos son archivos objeto en formato ELF:

$ ar -x libmy_static.a
$ file libmy_static_a.o
libmy_static_a.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped

Acerca de los enlaces dinámicos

Más recursos de Linux

  • Hoja de trucos de los comandos de Linux
  • Hoja de trucos de comandos avanzados de Linux
  • Curso en línea gratuito:Descripción general técnica de RHEL
  • Hoja de trucos de red de Linux
  • Hoja de trucos de SELinux
  • Hoja de trucos de los comandos comunes de Linux
  • ¿Qué son los contenedores de Linux?
  • Nuestros últimos artículos sobre Linux

La vinculación dinámica significa el uso de bibliotecas compartidas. Las bibliotecas compartidas generalmente terminan con .so (abreviatura de "objeto compartido").

Las bibliotecas compartidas son la forma más común de administrar las dependencias en los sistemas Linux. Estos recursos compartidos se cargan en la memoria antes de que se inicie la aplicación, y cuando varios procesos requieran la misma biblioteca, se cargará solo una vez en el sistema. Esta función ahorra el uso de memoria por parte de la aplicación.

Otra cosa a tener en cuenta es que cuando se corrige un error en una biblioteca compartida, todas las aplicaciones que hacen referencia a esta biblioteca se beneficiarán de ello. Esto también significa que si el error no se detecta, todas las aplicaciones de referencia lo sufrirán (si la aplicación usa las partes afectadas).

Puede ser muy difícil para los principiantes cuando una aplicación requiere una versión específica de la biblioteca, pero el enlazador solo conoce la ubicación de una versión incompatible. En este caso, debe ayudar al enlazador a encontrar la ruta a la versión correcta.

Aunque este no es un problema cotidiano, comprender los enlaces dinámicos seguramente lo ayudará a solucionar tales problemas.

Afortunadamente, la mecánica para esto es bastante sencilla.

Para detectar qué bibliotecas son necesarias para que se inicie una aplicación, puede usar ldd , que imprimirá las bibliotecas compartidas utilizadas por un archivo determinado:

$ ldd my_app 
        linux-vdso.so.1 (0x00007ffd1299c000)
        libmy_shared.so => not found
        libc.so.6 => /lib64/libc.so.6 (0x00007f56b869b000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f56b8881000)

Tenga en cuenta que la biblioteca libmy_shared.so es parte del repositorio pero no se encuentra. Esto se debe a que el enlazador dinámico, que es responsable de cargar todas las dependencias en la memoria antes de ejecutar la aplicación, no puede encontrar esta biblioteca en las ubicaciones estándar que busca.

Errores asociados con enlazadores que encuentran versiones incompatibles de bibliotecas comunes (como bzip2 , por ejemplo) puede ser bastante confuso para un nuevo usuario. Una forma de evitar esto es agregar la carpeta del repositorio a la variable de entorno LD_LIBRARY_PATH para decirle al enlazador dónde buscar la versión correcta. En este caso, la versión correcta está en esta carpeta, por lo que puede exportarla:

$ LD_LIBRARY_PATH=$(pwd):$LD_LIBRARY_PATH
$ export LD_LIBRARY_PATH

Ahora el enlazador dinámico sabe dónde encontrar la biblioteca y la aplicación se puede ejecutar. Puede volver a ejecutar ldd para invocar el enlazador dinámico, que inspecciona las dependencias de la aplicación y las carga en la memoria. La dirección de memoria se muestra después de la ruta del objeto:

$ ldd my_app 
        linux-vdso.so.1 (0x00007ffd385f7000)
        libmy_shared.so => /home/stephan/library_sample/libmy_shared.so (0x00007f3fad401000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f3fad21d000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f3fad408000)

Para averiguar qué enlazador se invoca, puede usar file :

$ file my_app 
my_app: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=26c677b771122b4c99f0fd9ee001e6c743550fa6, for GNU/Linux 3.2.0, not stripped

El enlazador /lib64/ld-linux-x86–64.so.2 es un enlace simbólico a ld-2.30.so , que es el enlazador predeterminado para mi distribución de Linux:

$ file /lib64/ld-linux-x86-64.so.2 
/lib64/ld-linux-x86-64.so.2: symbolic link to ld-2.31.so

Mirando hacia atrás a la salida de ldd , también puede ver (junto a libmy_shared.so ) que cada dependencia termina con un número (por ejemplo, /lib64/libc.so.6 ). El esquema de nomenclatura habitual de los objetos compartidos es:

**lib** XYZ.so **.<MAJOR>** . **<MINOR>**

En mi sistema, libc.so.6 también es un enlace simbólico al objeto compartido libc-2.30.so en la misma carpeta:

$ file /lib64/libc.so.6 
/lib64/libc.so.6: symbolic link to libc-2.31.so

Si se enfrenta al problema de que una aplicación no se inicia porque la biblioteca cargada tiene una versión incorrecta, es muy probable que pueda solucionar este problema inspeccionando y reorganizando los enlaces simbólicos o especificando la ruta de búsqueda correcta (consulte "El cargador dinámico :ld.so" a continuación).

Para obtener más información, consulte el ldd página man.

Carga dinámica

La carga dinámica significa que una biblioteca (por ejemplo, un .so archivo) se carga durante el tiempo de ejecución de un programa. Esto se hace usando un determinado esquema de programación.

La carga dinámica se aplica cuando una aplicación utiliza complementos que se pueden modificar durante el tiempo de ejecución.

Ver el dlopen página del manual para obtener más información.

El cargador dinámico:ld.so

En Linux, la mayoría de las veces se trata de objetos compartidos, por lo que debe haber un mecanismo que detecte las dependencias de una aplicación y las cargue en la memoria.

ld.so busca objetos compartidos en estos lugares en el siguiente orden:

  1. La ruta relativa o absoluta en la aplicación (codificada con -rpath opción del compilador en GCC)
  2. En la variable de entorno LD_LIBRARY_PATH
  3. En el archivo /etc/ld.so.cache

Tenga en cuenta que agregar una biblioteca al archivo de biblioteca de sistemas /usr/lib64 requiere privilegios de administrador. Podrías copiar libmy_shared.so manualmente al archivo de la biblioteca y hacer que la aplicación funcione sin configurar LD_LIBRARY_PATH :

unset LD_LIBRARY_PATH
sudo cp libmy_shared.so /usr/lib64/

Cuando ejecutas ldd , puede ver que aparece ahora la ruta al archivo de la biblioteca:

$ ldd my_app 
        linux-vdso.so.1 (0x00007ffe82fab000)
        libmy_shared.so => /lib64/libmy_shared.so (0x00007f0a963e0000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f0a96216000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f0a96401000)

Personalizar la biblioteca compartida en tiempo de compilación

Si desea que su aplicación use sus bibliotecas compartidas, puede especificar una ruta absoluta o relativa durante el tiempo de compilación.

Modifique el archivo MAKE (línea 10) y vuelva a compilar el programa invocando make -B . Luego, la salida de ldd muestra libmy_shared.so aparece en la lista con su ruta absoluta.

Cambia esto:

CFLAGS =-Wall -Werror -Wl,-rpath,$(shell pwd) 

Para esto (asegúrese de editar el nombre de usuario):

CFLAGS =/home/stephan/library_sample/libmy_shared.so 

Luego vuelve a compilar:

$ make

Confirme que está usando la ruta absoluta que configuró, que puede ver en la línea 2 de la salida:

$ ldd my_app
    linux-vdso.so.1 (0x00007ffe143ed000)
        libmy_shared.so => /lib64/libmy_shared.so (0x00007fe50926d000)
        /home/stephan/library_sample/libmy_shared.so (0x00007fe509268000)
        libc.so.6 => /lib64/libc.so.6 (0x00007fe50909e000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fe50928e000)

Este es un buen ejemplo, pero ¿cómo funcionaría si estuviera creando una biblioteca para que otros la usen? Se pueden registrar nuevas ubicaciones de bibliotecas escribiéndolas en /etc/ld.so.conf o creando un <library-name>.conf archivo que contiene la ubicación en /etc/ld.so.conf.d/ . Luego, ldconfig debe ejecutarse para reescribir el ld.so.cache expediente. Este paso a veces es necesario después de instalar un programa que incluye algunas bibliotecas compartidas especiales.

Ver el ld.so página man para obtener más información.

Cómo manejar múltiples arquitecturas

Por lo general, existen diferentes bibliotecas para las versiones de aplicaciones de 32 y 64 bits. La siguiente lista muestra sus ubicaciones estándar para diferentes distribuciones de Linux:

Familia Red Hat

  • 32 bits:/usr/lib
  • 64 bits:/usr/lib64

Familia Debian

  • 32 bits:/usr/lib/i386-linux-gnu
  • 64 bits:/usr/lib/x86_64-linux-gnu

Familia Arch Linux

  • 32 bits:/usr/lib32
  • 64 bits:/usr/lib64

FreeBSD (técnico, no una distribución de Linux)

  • 32 bits:/usr/lib32
  • 64 bits:/usr/lib

Saber dónde buscar estas bibliotecas clave puede hacer que los enlaces de biblioteca rotos sean un problema del pasado.

Si bien puede resultar confuso al principio, comprender la gestión de dependencias en las bibliotecas de Linux es una forma de sentirse en control del sistema operativo. Realice estos pasos con otras aplicaciones para familiarizarse con las bibliotecas comunes y continúe aprendiendo cómo solucionar cualquier desafío de la biblioteca que pueda surgir en su camino.


Linux
  1. Cómo establecer una dirección IP estática y configurar la red en Linux

  2. Cómo administrar el inventario de hosts estáticos y dinámicos de Ansible

  3. Cómo instalar y probar Ansible en Linux

  4. Cómo establecer una dirección IP estática y modificar la tabla de enrutamiento en Linux

  5. Cómo configurar encabezados y bibliotecas para el desarrollo de Linux

Cómo cambiar el nombre de archivos y directorios en Linux

Cómo comprimir archivos y directorios en Linux

Cómo instalar y usar PuTTY en Linux

Cómo configurar la dirección IP estática en Linux y Unix

Cómo instalar y usar phpMyAdmin en Linux

Cómo configurar una dirección IP estática en Alpine Linux