El proceso de vinculación expuesto – Bibliotecas estáticas frente a dinámicas

Oct 19, 2021
admin

Creación de una biblioteca estática y dinámica

Para una biblioteca estática, el código objeto de los archivos binarios (extensión .o) se combinan en un único archivo comprimido con una extensión .a. Este archivo es similar a una caja de herramientas que contiene todas las herramientas que podrían utilizarse en los programas que llaman a esa biblioteca durante el enlace. Las herramientas se insertan en los lugares donde se necesitan. En la imagen de abajo, tengo una serie de archivos .c.

Como una biblioteca es un archivo de código objeto, necesito convertir todos estos archivos .c en archivos .o utilizando el siguiente comando:

gcc -Wall -Wextra -Werror -pedantic -c *.c

La opción -c detiene el proceso de compilación justo antes de enlazar después de que se generen los archivos de código objeto. Ahora tengo todos los archivos de código objeto:

Si ejecuto el comando ar -rc libholbertonschool.a *.o, puedo archivar estos archivos en un único archivo de biblioteca .a. El comando ar es para archivar, la opción -r es para mover los miembros que tienen extensión .o, y la opción -c es para crear el archivo si no existe. Un archivo de biblioteca comienza con un prefijo lib y tiene una extensión .a. El último paso que es necesario en algunos sistemas es indexar el contenido del archivo para acelerar la vinculación. Esto se puede hacer con ranlib libholbertonschool.a. Ahora tengo una biblioteca que contiene el código objeto para todas las funciones de la imagen anterior.

Usando la biblioteca estática

Para usar esta biblioteca con algún archivo de prueba, tengo que compilar el archivo de prueba con la biblioteca usando cualquiera de los dos comandos siguientes:

gcc test.c ./libholbertonschool.a -o exename

gcc test.c -L. -lholbertonschool -o exename

Ambos hacen lo mismo, pero el segundo es ligeramente más críptico. La opción -L. busca bibliotecas en el directorio actual y la -l que está conectada a holbertonschool busca el archivo de biblioteca implícitamente donde se asume un prefijo lib y un sufijo .a. Sin compilar con un archivo de biblioteca, gcc lanzará un error ya que las funciones que está tratando de enlazar no se proporcionan. Al proporcionar una biblioteca en la compilación, el compilador puede ahora buscar en la biblioteca las funciones que necesita e insertarlas donde se necesitan.

Bibliotecas dinámicas

Crear bibliotecas dinámicas es ligeramente diferente de las bibliotecas estáticas, pero los conceptos son generalmente los mismos. Tengo el mismo número de archivos .c y el archivo de cabecera que define sus prototipos en un archivo llamado lists.h.

Para crear la biblioteca dinámica, que tiene un .so (que significa objeto compartido), se puede introducir el siguiente comando de compilación:

gcc -fPIC -Wall -Werror -Wextra -pedantic *.c -shared -o libholberton.so

La bandera -fPIC significa Position Independent Code (código independiente de la posición) que se requiere para el enlace dinámico. El significado de esto es exactamente lo que parece – ya que las bibliotecas enlazadas dinámicamente pueden ser almacenadas en cualquier lugar de la memoria donde encajen, esta bandera permite que el archivo de la biblioteca se utilice independientemente de dónde se almacene.

La bandera -shared permite crear un archivo compartido y la opción -o nos permite cambiar el nombre del archivo de salida a libholberton.so.

Después de ejecutar este comando, ¡ya tengo una biblioteca compartida!

Usando la Biblioteca Dinámica

Digamos que tengo el siguiente código:

#include "holberton.h"
#include <stdlib.h>
#include <stdio.h>/**
* main - check the code for Holberton School students.
*
* Return: Always EXIT_SUCCESS.
*/
int main(void)
{
printf("%d\n", _strlen("Holberton"));
return (EXIT_SUCCESS);
}

Puedo compilar el programa con el siguiente código:

gcc -Wall -pedantic -Werror -Wextra -L. 0-main.c -lholberton -o len 

Al igual que las bibliotecas estáticas, las opciones -L. busca en el directorio los archivos de la biblioteca y el -l que se anexa al principio de holberton es una búsqueda implícita de los archivos de la biblioteca que tienen un prefijo lib, un sufijo .so, y holberton entre los dos.

Para utilizar el archivo de biblioteca que acabo de crear, tengo que asegurarme de que el compilador es capaz de encontrar todos los archivos de biblioteca en la memoria y que están correctamente cargados en la memoria para empezar. Si ahora ejecuto ldd len, veo lo siguiente:

La línea libholberton.so => not found me indica que no se cumple la dependencia de la biblioteca dinámica que acabo de crear. Para solucionarlo, hay que entender la variable de entorno $LD_LIBRARY_PATH. En Linux, esta variable es una lista separada por dos puntos de los directorios en los que el sistema busca los archivos de la biblioteca. En la imagen de arriba, se puede ver que el eco de esta variable en el estado actual muestra que está vacía y por lo tanto, mi intento de ejecutar el programa (len) no funciona porque la biblioteca compartida no se puede cargar.

Mi directorio actual tiene el siguiente aspecto:

Como puedes ver, el archivo de la biblioteca se encuentra en el mismo directorio que mi archivo principal y el de cabecera (directorio de trabajo actual). Observa la siguiente imagen:

El comando export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH actualiza la variable ambiental $LD_LIBRARY_PATH con un .: que indica que el sistema debe buscar bibliotecas en el directorio de trabajo actual. El comando export hace que este cambio sea global para que cualquier shell pueda acceder al mismo valor. Así, cuando me hago eco de la variable, veo mis actualizaciones. Ejecutando ldd len de nuevo, veo que libholberton.so está en la dirección 0x00007fb9216b9000 que es probablemente su ubicación en el directorio de trabajo actual en la memoria. Así, la dependencia del ejecutable de la biblioteca compartida se cumple ahora y el programa devuelve 9 que es la longitud de la palabra «Holberton«.

Deja una respuesta

Tu dirección de correo electrónico no será publicada.