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 | ||
| + | </ | ||