El proceso de vinculación expuesto – Bibliotecas estáticas frente a dinámicas
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: