Ferramentas do usuário

Ferramentas do site


prog2:construcao_de_bibliotecas

Diferenças

Aqui você vê as diferenças entre duas revisões dessa página.

Link para esta página de comparações

Ambos lados da revisão anterior Revisão anterior
prog2:construcao_de_bibliotecas [2019/04/09 13:26]
maziero
prog2:construcao_de_bibliotecas [2019/04/09 13:27] (atual)
maziero
Linha 1: Linha 1:
 +====== Construção de bibliotecas ======
 +
 +Bibliotecas são amplamente utilizadas na linguagem C. Além da biblioteca padrão (LibC) e das bibliotecas disponibilizadas pelo sistema operacional,​ o programador pode desenvolver suas próprias bibliotecas,​ para usar em seus projetos ou disponibilizá-las a terceiros.
 +
 +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 =====
 +
 +Para usar um exemplo concreto, considera-se uma biblioteca ''​hello'',​ que oferece funções para escrever na tela mensagens de "​olá"​ em diversas linguagens. O código-fonte dessa biblioteca é composto pelos seguintes arquivos:
 +
 +<code c hello_pt.c>​
 +#include <​stdio.h>​
 +#include "​hello.h"​
 +
 +void hello_pt ()
 +{
 +  printf ("Ola, mundo!\n"​) ;
 +}
 +</​code>​
 +
 +<code c hello_en.c>​
 +#include <​stdio.h>​
 +#include "​hello.h"​
 +
 +void hello_en ()
 +{
 +  printf ("​Hello,​ world!\n"​) ;
 +}
 +</​code>​
 +
 +<code c hello_fr.c>​
 +#include <​stdio.h>​
 +#include "​hello.h"​
 +
 +void hello_fr ()
 +{
 +  printf ("​Salut,​ le monde !\n") ;
 +}
 +</​code>​
 +
 +O arquivo de cabeçalho também faz parte da biblioteca:
 +
 +<code c hello.h>
 +#ifndef __HELLO__
 +#define __HELLO__
 +
 +void hello_pt () ;
 +void hello_en () ;
 +void hello_fr () ;
 +
 +#endif
 +</​code>​
 +
 +Um programa que utilize a biblioteca ''​hello''​ pode ser escrito desta forma:
 +
 +<code c main.c>
 +#include "​hello.h"​
 +
 +int main ()
 +{
 +  hello_pt () ;
 +  hello_en () ;
 +  hello_fr () ;
 +
 +  return 0 ;
 +}
 +</​code>​
 +
 +===== Bibliotecas estáticas =====
 +
 +Para construir uma biblioteca de ligação estática são necessários vários passos. Inicialmente,​ todos os arquivos-fonte que irão compor a biblioteca devem ser compilados, para gerar seus arquivos-objeto correspondentes:​
 +
 +<​code>​
 +~> gcc -c hello_pt.c
 +~> gcc -c hello_en.c
 +~> gcc -c hello_fr.c
 +</​code>​
 +
 +A seguir, deve ser usado o utilitário ''​ar''​ (//​archiver//​) para juntar todos os arquivos-objeto em uma biblioteca estática chamada ''​libhello.a'':​
 +
 +<​code>​
 +~> ar rvs libhello.a hello_pt.o hello_en.o hello_fr.o
 +</​code>​
 +
 +Os flags ''​rvs''​ indicam: ​
 +
 +  * ''​r''​ (//​replace//​):​ substituir versões anteriores dos arquivos na biblioteca, caso existam
 +  * ''​v''​ (//​verbose//​):​ mostrar na tela as inclusões que estão sendo realizadas
 +  * ''​s''​ (//​symbols//​):​ criar uma tabela dos símbolos que estão sendo agregados à biblioteca
 +
 +O utilitário ''​ar''​ possui diversos outros //flags//. Por exemplo, pode-se consultar o conteúdo de uma biblioteca estática:
 +
 +<​code>​
 +~> ar t libhello.a
 +hello_en.o
 +hello_fr.o
 +hello_pt.o
 +</​code>​
 +
 +Pode-se consultar todos os símbolos definidos em uma biblioteca estática (ou em qualquer arquivo objeto) através do utilitário ''​nm'':​
 +
 +<​code>​
 +~> 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
 +</​code>​
 +
 +Para atualizar/​incluir qualquer arquivo da biblioteca, basta executar ''​ar''​ novamente, indicando o(s) arquivo(s) a atualizar/​incluir:​
 +
 +<​code>​
 +~> ar rvs libhello.a hello_it.o hello_es.o hello_jp.o
 +</​code>​
 +
 +A forma mais simples de usar a biblioteca é indicá-la ao compilador no momento da compilação ou ligação:
 +
 +<​code>​
 +~> gcc main.c -o main libhello.a
 +</​code>​
 +
 +Uma opção abreviada de ligação pode ser utilizada. Nela, não é necessário indicar o nome completo da biblioteca:
 +
 +<​code>​
 +~> gcc main.c -o main -L. -lhello
 +</​code>​
 +
 +A opção ''​-L.''​ é necessária para incluir o diretório corrente nos caminhos de busca de bibliotecas do ligador. 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. ​
 +
 +Observe que a biblioteca foi informada ao ligador na opção ''​-lhello''​. Por default, ao encontrar uma opção ''​-labc'',​ o ligador irá procurar pela biblioteca ''​libabc.a''​ nos diretórios default de bibliotecas (''/​lib'',​ ''/​usr/​lib'',​ ''/​usr/​local/​lib'',​ ...) e depois disso nos diretórios informados pela opção ''​-L''​.
 +
 +===== Bibliotecas dinâmicas =====
 +
 +A construção de uma biblioteca de ligação dinâmica é um pouco mais complexa. Primeiro, é necessário compilar os arquivos-fonte que irão compor a biblioteca usando a opção ''​-fPIC'',​ que irá gerar código binário independente de posição (PIC - [[https://​en.wikipedia.org/​wiki/​Position-independent_code|Position Independent Code]])((Como a ligação da biblioteca ocorre durante a carga/​execução,​ a posição de seu código na memória dos processos que irão utilizá-la não pode ser determinada previamente.)):​
 +
 +<​code>​
 +~> gcc -fPIC -c hello_pt.c
 +~> gcc -fPIC -c hello_en.c
 +~> gcc -fPIC -c hello_fr.c
 +</​code>​
 +
 +Depois, pode-se criar a biblioteca dinâmica, a partir dos arquivos-objeto:​
 +
 +<​code>​
 +~> gcc -g -shared -Wl,​-soname,​libhello.so.0 -o libhello.so.0.0 hello_pt.o hello_en.o hello_fr.o
 +</​code>​
 +
 +Observe que a opção ''​-Wl''​ transfere a opção ''​-soname=libhello.so.0''​ ao ligador. Essa opção permite definir o nome e versão da biblioteca.
 +
 +Finalmente, para instalar a biblioteca, deve-se movê-la para o diretório adequado (geralmente ''/​usr/​lib''​ ou ''/​usr/​local/​lib''​) e gerar os links necessários para indicar os números de versão (0) e revisão (0):
 +
 +<​code>​
 +~> mv libhello.so.0.0 /​usr/​local/​lib
 +~> cd /​usr/​local/​lib
 +~> ln -s libhello.so.0.0 libhello.so.0
 +~> ln -s libhello.so.0 libhello.so
 +
 +~> ls -l
 +lrwxrwxrwx ​ 1  prof      12   Out 2 18:20  libhello.so -> libhello.so.0
 +lrwxrwxrwx ​ 1  prof      14   Out 2 18:06  libhello.so.0 -> libhello.so.0.0
 +-rwxr-xr-x ​ 1  prof    6914   Out 2 18:06  libhello.so.0.0
 +</​code>​
 +
 +A compilação usando a biblioteca ocorre da mesma forma que no caso estático:
 +
 +<​code>​
 +~> gcc main.c -o main -L. -lhello
 +~> ./main
 +</​code>​
 +
 +Caso a biblioteca esteja em um diretório não listado em ''/​etc/​ld.so.conf''​ (arquivo de configuração do carregador e ligador dinâmico), deve-se incluir o diretório nesse arquivo e a seguir executar ''​ldconfig'',​ ou informar o carregador dinâmico através da variável de ambiente ''​LD_LIBRARY_PATH'':​
 +
 +<​code>​
 +~> export LD_LIBRARY_PATH=.
 +~> ./main
 +</​code>​
  
prog2/construcao_de_bibliotecas.txt · Última modificação: 2019/04/09 13:27 por maziero