Diferenças
Aqui você vê as diferenças entre duas revisões dessa página.
c:construcao_de_bibliotecas [2023/08/01 18:12] – criada maziero | c:construcao_de_bibliotecas [2023/08/01 20:12] (atual) – edição externa 127.0.0.1 | ||
---|---|---|---|
Linha 1: | Linha 1: | ||
+ | ====== Construção de bibliotecas ====== | ||
+ | |||
+ | {{ progc_bibliotecas_construcao.mkv |Video desta aula}} | ||
+ | |||
+ | {{ data-collection.png|https:// | ||
+ | |||
+ | As bibliotecas podem ser construídas para ligação estática ou dinâmica (DLL) com o código executável que as utiliza. Este texto explica as duas técnicas em ambiente Linux. | ||
+ | |||
+ | ===== Estrutura geral ===== | ||
+ | |||
+ | Vamos usar como exemplo uma biblioteca simples chamada //Hello//, que oferece funções para escrever na tela mensagens de " | ||
+ | |||
+ | O arquivo de cabeçalho define a interface da biblioteca //Hello//: | ||
+ | |||
+ | <code c hello.h> | ||
+ | #ifndef __HELLO__ | ||
+ | #define __HELLO__ | ||
+ | |||
+ | void hello_pt () ; | ||
+ | void hello_en () ; | ||
+ | void hello_fr () ; | ||
+ | |||
+ | #endif | ||
+ | </ | ||
+ | |||
+ | Os demais arquivos definem a implementação dessas funções: | ||
+ | |||
+ | <code c hello_pt.c> | ||
+ | #include < | ||
+ | #include " | ||
+ | |||
+ | void hello_pt () | ||
+ | { | ||
+ | printf ("Ola, mundo!\n" | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | <code c hello_en.c> | ||
+ | #include < | ||
+ | #include " | ||
+ | |||
+ | void hello_en () | ||
+ | { | ||
+ | printf (" | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | <code c hello_fr.c> | ||
+ | #include < | ||
+ | #include " | ||
+ | |||
+ | void hello_fr () | ||
+ | { | ||
+ | printf (" | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Um programa que utilize a biblioteca //Hello// pode ser escrito desta forma: | ||
+ | |||
+ | <code c main.c> | ||
+ | #include " | ||
+ | |||
+ | int main () | ||
+ | { | ||
+ | hello_pt () ; | ||
+ | hello_en () ; | ||
+ | hello_fr () ; | ||
+ | |||
+ | return 0 ; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | ===== Bibliotecas estáticas ===== | ||
+ | |||
+ | Bibliotecas estáticas são ligadas ao programa durante o processo de compilação, | ||
+ | |||
+ | 1) Inicialmente, | ||
+ | |||
+ | < | ||
+ | $ gcc -Wall -c hello_pt.c | ||
+ | $ gcc -Wall -c hello_en.c | ||
+ | $ gcc -Wall -c hello_fr.c | ||
+ | </ | ||
+ | |||
+ | 2) A seguir, deve ser usado o utilitário '' | ||
+ | |||
+ | < | ||
+ | $ ar rvs libhello.a hello_pt.o hello_en.o hello_fr.o | ||
+ | </ | ||
+ | |||
+ | Os flags '' | ||
+ | |||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | |||
+ | O utilitário '' | ||
+ | |||
+ | < | ||
+ | $ ar t libhello.a | ||
+ | hello_en.o | ||
+ | hello_fr.o | ||
+ | hello_pt.o | ||
+ | </ | ||
+ | |||
+ | Pode-se consultar todos os símbolos definidos em uma biblioteca estática (ou em qualquer arquivo objeto) através do utilitário '' | ||
+ | |||
+ | < | ||
+ | $ nm libhello.a | ||
+ | |||
+ | hello-en.o: | ||
+ | 0000000000000000 T hello_en | ||
+ | U puts | ||
+ | |||
+ | hello-fr.o: | ||
+ | 0000000000000000 T hello_fr | ||
+ | U puts | ||
+ | |||
+ | hello-pt.o: | ||
+ | 0000000000000000 T hello_pt | ||
+ | U puts | ||
+ | </ | ||
+ | |||
+ | Para atualizar/ | ||
+ | |||
+ | < | ||
+ | $ ar rvs libhello.a hello_it.o hello_es.o hello_jp.o | ||
+ | </ | ||
+ | |||
+ | 3) A forma mais simples de usar a biblioteca é indicá-la ao compilador no momento da compilação ou ligação: | ||
+ | |||
+ | < | ||
+ | $ gcc -Wall main.c -o main libhello.a | ||
+ | </ | ||
+ | |||
+ | Uma opção abreviada de ligação pode ser utilizada. Nela, não é necessário indicar o nome completo da biblioteca: | ||
+ | |||
+ | < | ||
+ | $ gcc -Wall main.c -o main -L. -lhello | ||
+ | </ | ||
+ | |||
+ | Esta abordagem é melhor que a anterior, pois neste caso o ligador somente irá incluir no executável final os objetos que forem efetivamente necessários. | ||
+ | |||
+ | <note important> | ||
+ | A opção '' | ||
+ | </ | ||
+ | |||
+ | Observe que a biblioteca foi informada ao ligador na opção '' | ||
+ | |||
+ | ===== Bibliotecas dinâmicas ===== | ||
+ | |||
+ | Bibliotecas dinâmicas (DLLs) são ligadas ao programa durante a carga do executável na memória, resultando em um executável menores, mas que dependem das bibliotecas necessárias estarem instaladas no sistema operacional. | ||
+ | |||
+ | A construção de uma biblioteca de ligação dinâmica é um pouco mais complexa: | ||
+ | |||
+ | 1) Primeiro, é necessário compilar os arquivos-fonte que irão compor a biblioteca usando a opção '' | ||
+ | |||
+ | < | ||
+ | $ gcc -Wall -fPIC -c hello_pt.c | ||
+ | $ gcc -Wall -fPIC -c hello_en.c | ||
+ | $ gcc -Wall -fPIC -c hello_fr.c | ||
+ | </ | ||
+ | |||
+ | 2) A seguir, pode-se criar a biblioteca dinâmica, a partir dos arquivos-objeto: | ||
+ | |||
+ | < | ||
+ | $ gcc -Wall -g -shared -Wl, | ||
+ | </ | ||
+ | |||
+ | Observe que a opção '' | ||
+ | |||
+ | 3) Finalmente, para instalar a biblioteca, deve-se movê-la para o diretório adequado (geralmente ''/ | ||
+ | |||
+ | < | ||
+ | # mv libhello.so.0.0 / | ||
+ | # cd / | ||
+ | # ln -s libhello.so.0.0 libhello.so.0 | ||
+ | # ln -s libhello.so.0 libhello.so | ||
+ | |||
+ | $ ls -l | ||
+ | lrwxrwxrwx | ||
+ | lrwxrwxrwx | ||
+ | -rwxr-xr-x | ||
+ | </ | ||
+ | |||
+ | 4) A compilação usando a biblioteca ocorre da mesma forma que no caso estático: | ||
+ | |||
+ | < | ||
+ | $ gcc -Wall main.c -o main -L. -lhello | ||
+ | </ | ||
+ | |||
+ | Ao carregar o executável, | ||
+ | |||
+ | < | ||
+ | $ ./main | ||
+ | </ | ||
+ | |||
+ | Caso a biblioteca esteja em um diretório não listado em ''/ | ||
+ | |||
+ | < | ||
+ | $ export LD_LIBRARY_PATH=. | ||
+ | $ ./main | ||
+ | </ | ||