O Processo de Ligação Exposto – Bibliotecas Estáticas vs Dinâmicas
Criar uma Biblioteca Estática e Dinâmica
Para uma biblioteca estática, o código objecto de ficheiros binários (extensão .o
) são combinados num único ficheiro de arquivo com uma extensão .a
. Este arquivo é similar a uma caixa de ferramentas que contém todas as ferramentas que podem ser usadas em programas que chamam essa biblioteca durante a ligação. As ferramentas são inseridas em locais onde são necessárias. Na imagem abaixo, eu tenho uma série de .c
files.

Desde que uma biblioteca é um arquivo de código objeto, eu preciso converter todos estes .c
files em .o
files usando o seguinte comando:
gcc -Wall -Wextra -Werror -pedantic -c *.c
A opção -c
pára o processo de compilação logo antes de fazer o link após os arquivos de código objeto serem gerados. Agora tenho todos os ficheiros de código objecto:

Se executar o comando ar -rc libholbertonschool.a *.o
, posso arquivar estes ficheiros num único ficheiro .a
arquivo de biblioteca. O comando ar
é para arquivar, a opção -r
é para mover membros que tenham extensão .o
, e a opção -c
é para criar o arquivo se ele não existir. Um arquivo de biblioteca começa com um prefixo lib
e tem uma extensão .a
. O passo final que é necessário em alguns sistemas é indexar o conteúdo do arquivo para acelerar a ligação. Isto pode ser feito com ranlib libholbertonschool.a
. Agora eu tenho uma biblioteca que contém código objeto para todas as funções da imagem acima.
Usando a biblioteca estática
Para usar esta biblioteca com algum arquivo de teste, eu tenho que compilar o arquivo de teste com a biblioteca usando um dos dois comandos seguintes:
gcc test.c ./libholbertonschool.a -o exename
gcc test.c -L. -lholbertonschool -o exename
Bambos estes fazem a mesma coisa, mas o segundo é um pouco mais críptico. A opção -L.
procura bibliotecas no directório actual e a opção -l
que está ligada a holbertonschool
procura o ficheiro da biblioteca implicitamente onde um prefixo lib
e um sufixo .a
são assumidos. Sem compilar com um ficheiro de biblioteca, gcc
irá lançar um erro uma vez que as funções que está a tentar ligar não são fornecidas. Ao fornecer uma biblioteca na compilação, o compilador pode agora procurar a biblioteca pelas funções que necessita e inseri-las onde elas são necessárias.
Bibliotecas Dinâmicas
Criar bibliotecas dinâmicas é ligeiramente diferente das bibliotecas estáticas, mas os conceitos são geralmente os mesmos. Eu tenho o mesmo número de ficheiros .c
e o ficheiro de cabeçalho que define os seus protótipos num ficheiro chamado lists.h
.

Para criar a biblioteca dinâmica, que tem um .so
(que significa objeto compartilhado), o seguinte comando de compilação pode ser inserido:
gcc -fPIC -Wall -Werror -Wextra -pedantic *.c -shared -o libholberton.so
A bandeira -fPIC
significa Código Independente de Posição, que é necessário para a ligação dinâmica. O significado disto é exactamente o que parece – uma vez que as bibliotecas ligadas dinamicamente podem ser armazenadas em qualquer lugar na memória onde cabem, este sinalizador permite que o ficheiro da biblioteca seja utilizado independentemente do local onde está armazenado.
O sinalizador -shared
permite criar um arquivo partilhado e a opção -o
permite renomear o ficheiro de saída para libholberton.so
.
Após executar este comando, tenho agora uma biblioteca partilhada!

Usando a Biblioteca Dinâmica
Digamos que tenho o seguinte 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);
}
Posso compilar o programa com o seguinte código:
gcc -Wall -pedantic -Werror -Wextra -L. 0-main.c -lholberton -o len
Apenas como as bibliotecas estáticas, as opções -L.
procura no directório por ficheiros de biblioteca e a opção -l
que está anexada no início de holberton
é uma procura implícita por ficheiros de biblioteca que têm um prefixo lib
, um sufixo .so
, e holberton
entre os dois.
Para usar o ficheiro de biblioteca que acabei de criar, preciso de me certificar que o compilador é capaz de encontrar todos os ficheiros de biblioteca na memória e que eles estão devidamente carregados na memória para começar. Se eu executar ldd len
agora, eu posso ver o seguinte:

A linha libholberton.so => not found
diz-me que a dependência da biblioteca dinâmica que acabei de criar não está preenchida. Para corrigir isso, a variável ambiental $LD_LIBRARY_PATH
deve ser entendida. No Linux, esta variável é uma lista de diretórios separada por dois pontos que o sistema procura por arquivos de biblioteca. Na imagem acima, você pode ver que o eco desta variável no estado atual mostra que ela está vazia e assim, minha tentativa de executar o programa (len
) não funciona porque a biblioteca compartilhada não pode ser carregada.
Meu diretório atual se parece com isto:

Como você pode ver, o arquivo da biblioteca está localizado no mesmo diretório que o meu arquivo principal e o arquivo de cabeçalho (diretório de trabalho atual). Observe a seguinte imagem:

O comando export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
actualiza a variável ambiental $LD_LIBRARY_PATH
com um .:
que indica que o sistema deve procurar bibliotecas no directório de trabalho actual. O comando export
torna esta mudança global para que qualquer shell possa acessar o mesmo valor. Assim, quando eu ecoo a variável, eu vejo minhas atualizações. Executando ldd len
novamente, eu vejo que libholberton.so
está na localização do endereço 0x00007fb9216b9000
que é provavelmente a sua localização no directório de trabalho actual na memória. Assim, a dependência do executável da biblioteca compartilhada é agora satisfeita e o programa retorna 9
que é o comprimento da palavra “Holberton
“.