O Processo de Ligação Exposto – Bibliotecas Estáticas vs Dinâmicas

Out 19, 2021
admin

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“.

Deixe uma resposta

O seu endereço de email não será publicado.