User Tools

Site Tools


prog2:construcao_de_bibliotecas

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:

hello_pt.c
#include <stdio.h>
#include "hello.h"
 
void hello_pt ()
{
  printf ("Ola, mundo!\n") ;
}
hello_en.c
#include <stdio.h>
#include "hello.h"
 
void hello_en ()
{
  printf ("Hello, world!\n") ;
}
hello_fr.c
#include <stdio.h>
#include "hello.h"
 
void hello_fr ()
{
  printf ("Salut, le monde !\n") ;
}

O arquivo de cabeçalho também faz parte da biblioteca:

hello.h
#ifndef __HELLO__
#define __HELLO__
 
void hello_pt () ;
void hello_en () ;
void hello_fr () ;
 
#endif

Um programa que utilize a biblioteca hello pode ser escrito desta forma:

main.c
#include "hello.h"
 
int main ()
{
  hello_pt () ;
  hello_en () ;
  hello_fr () ;
 
  return 0 ;
}

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:

~> gcc -c hello_pt.c
~> gcc -c hello_en.c
~> gcc -c hello_fr.c

A seguir, deve ser usado o utilitário ar (archiver) para juntar todos os arquivos-objeto em uma biblioteca estática chamada libhello.a:

~> ar rvs libhello.a hello_pt.o hello_en.o hello_fr.o

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:

~> 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:

~> 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/incluir qualquer arquivo da biblioteca, basta executar ar novamente, indicando o(s) arquivo(s) a atualizar/incluir:

~> ar rvs libhello.a hello_it.o hello_es.o hello_jp.o

A forma mais simples de usar a biblioteca é indicá-la ao compilador no momento da compilação ou ligação:

~> gcc 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 main.c -o main -L. -lhello

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 - Position Independent Code)1):

~> gcc -fPIC -c hello_pt.c
~> gcc -fPIC -c hello_en.c
~> gcc -fPIC -c hello_fr.c

Depois, pode-se criar a biblioteca dinâmica, a partir dos arquivos-objeto:

~> gcc -g -shared -Wl,-soname,libhello.so.0 -o libhello.so.0.0 hello_pt.o hello_en.o hello_fr.o

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):

~> 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

A compilação usando a biblioteca ocorre da mesma forma que no caso estático:

~> gcc main.c -o main -L. -lhello
~> ./main

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:

~> export LD_LIBRARY_PATH=.
~> ./main
1)
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.
prog2/construcao_de_bibliotecas.txt · Last modified: 2019/04/09 13:27 (external edit)