Conceptos clave
Enlace estático: Durante la fase de compilación, el código de la biblioteca (archivos .a) se integra directamente en el binario final. Esto permite que la aplicación se ejecute de forma autónoma, sin depender de archivos externos en tiempo de ejecución.
Enlace dinámico: En la compilación, únicamente se resuelven las referencias a los símbolos (como los prototipos de funciones). La implementación real se carga en memoria durante la ejecución mediante el enlazador dinámico, leyendo desde archivos .so o .dll. El ejecutable solo contiene punteros a estas funciones.
Generación de una biblioteca estática
El propósito de empaquetar código en una biblioteca estática suele ser ocultar la lógica de implementación, evitando modificaciones no autorizadas sobre el código fuente original.
Primero, definimos nuestro archivo de cabecera calculator.h:
#ifndef CALCULATOR_H
#define CALCULATOR_H
int sumar(int x, int y);
#endif
Luego, la implementación en calculator.cpp:
#include "calculator.h"
int sumar(int x, int y) {
return x + y;
}
Y nuestro archivo principle main.cpp que consumirá la función:
#include <iostream>
#include "calculator.h"
int main() {
int val1, val2;
std::cin >> val1 >> val2;
int resultado = sumar(val1, val2);
std::cout << resultado << std::endl;
return 0;
}
Para consrtuir la biblioteca, primero generamos el archivo objeto con la opción -c:
g++ -c calculator.cpp -o calculator.o
A continuación, empaquetamos el objeto en un archivo .a utilizando la herramienta ar:
ar rcs libcalculadora.a calculator.o
Una vez generada, podemos eliminar el código fuente original y compilar nuestro programa principal indicando la ruta de búsqueda con -L y el nombre de la biblioteca con -l:
g++ main.cpp -L. -lcalculadora
Generación de una biblioteca dinámica
Para crear una biblioteca compartida (Shared Object), utilizamos los mismos archivos fuente. Sin embargo, al compilar a código objeto, es obligatorio añadir la bandera -fPIC. Esto genera Código Independiente de Posición, lo que permite que el binario se cargue en cualquier dirección de memoria durante la ejecución.
g++ -fPIC -c calculator.cpp -o calculator.o
Con el objeto compilado, procedemos a crear la biblioteca dinámica usando la opción -shared:
g++ -shared -o libcalculadora.so calculator.o
Es fundamental entender que al intentar ejecutar el binario resultante, el sistema no sabrá dónde encontrar el archivo .so por defecto. Para solucionar esto en tiempo de ejecución, debemos exportar la variable de entorno LD_LIBRARY_PATH indicando el directorio actual:
export LD_LIBRARY_PATH=$PWD