Crie Bibliotecas Estáticas em Linux com o Comando `ar`: Guia Completo

Para organizar funções em bibliotecas durante o desenvolvimento de software, o comando `ar` do Linux é uma ferramenta indispensável. Este guia prático demonstra a criação, modificação e utilização de uma biblioteca estática em um programa, incluindo exemplos de código.

O comando `ar` é uma ferramenta clássica, existindo desde 1971. Seu nome remete à sua função original: gerenciar arquivos de arquivo. Um arquivo de arquivo é um único arquivo que funciona como um repositório para múltiplos arquivos, que podem ser adicionados, removidos ou extraídos. Embora hoje em dia outras ferramentas como o `tar` sejam mais usadas para essas funções, o `ar` ainda é valioso para tarefas especializadas, como a criação de bibliotecas estáticas e arquivos de pacotes, como os “.deb” utilizados em distribuições Linux como Debian e Ubuntu.

Vamos explorar o processo de criação e alteração de uma biblioteca estática, além de mostrar como essa biblioteca é usada em um programa. Para isso, vamos criar uma biblioteca para codificar e decodificar strings de texto.

É importante notar que este exemplo é simplificado para fins de demonstração. Não use este tipo de criptografia em situações onde a segurança é importante. A cifra de substituição aqui utilizada é básica, onde cada letra é substituída pela seguinte no alfabeto (A por B, B por C, e assim por diante).

Funções cipher_encode() e cipher_decode()

Vamos criar um diretório chamado “biblioteca” e, dentro dele, um subdiretório chamado “teste”.

No diretório “biblioteca”, teremos dois arquivos: cipher_encode.c, contendo a função cipher_encode():

void cipher_encode(char *text)
{
 for (int i=0; text[i] != 0x0; i++) {
   text[i]++;
 }

} // fim de cipher_encode
  

E o arquivo cipher_decode.c, com a função cipher_decode():

void cipher_decode(char *text)
{
 for (int i=0; text[i] != 0x0; i++) {
   text[i]--;
 }

} // fim de cipher_decode
  

Estes são os arquivos de código-fonte. Vamos gerar um arquivo de biblioteca chamado libcipher.a, que incluirá as versões compiladas desses arquivos, além de um arquivo de cabeçalho libcipher.h, com as definições das duas funções da biblioteca.

Com a biblioteca e o cabeçalho, qualquer um pode utilizar as funções em seus projetos, sem precisar reescrevê-las.

Compilando cipher_encode.c e cipher_decode.c

Usaremos o gcc, o compilador GNU, para compilar os arquivos de código-fonte. A opção `-c` (compilar, sem linkar) instrui o `gcc` a compilar os arquivos e gerar arquivos-objeto. Normalmente, o `gcc` pegaria esses arquivos e os vincularia para criar um executável, mas vamos pular essa etapa, pois só precisamos dos arquivos-objeto.

Vamos verificar os arquivos no diretório.

ls -l

Os dois arquivos de código-fonte estão presentes. Vamos compilá-los:

gcc -c cipher_encode.c
gcc -c cipher_decode.c

Se tudo ocorrer bem, não haverá saída do `gcc`.

Isso gerará dois arquivos-objeto com as extensões `.o`.

ls -l

Criando a biblioteca libcipher.a

Usaremos o comando `ar` para gerar o arquivo de biblioteca, que é essencialmente um arquivo compactado.

A opção `-c` (criar) gera o arquivo da biblioteca, `-r` (adicionar com substituição) adiciona arquivos ao arquivo e `-s` (índice) cria um índice dos arquivos.

Vamos nomear o arquivo da biblioteca libcipher.a e fornecer os arquivos-objeto para adicionar.

ar -crs libcipher.a cipher_encode.o cipher_decode.o

Listando os arquivos do diretório, vemos o libcipher.a.

ls -l

A opção `-t` (tabela) com o comando `ar` permite visualizar os módulos dentro da biblioteca.

ar -t libcipher.a

Criando o arquivo de cabeçalho libcipher.h

O arquivo libcipher.h é incluído em qualquer programa que utilize a biblioteca libcipher.a. Este arquivo deve conter as definições das funções da biblioteca.

As definições das funções são inseridas em um editor de texto como o `gedit` e o arquivo é salvo como `libcipher.h` no mesmo diretório que libcipher.a:

void cipher_encode(char *text);
void cipher_decode(char *text);
  

Usando a biblioteca libcipher

A melhor forma de testar a biblioteca é criar um programa que a utilize. Vamos começar criando o diretório “teste”.

mkdir test

Vamos copiar a biblioteca e o arquivo de cabeçalho para o diretório.

cp libcipher.* ./test

Mudando para o diretório “teste”.

cd test

Verificando os arquivos.

ls -l

Agora, criamos um programa que use a biblioteca. O seguinte código deve ser salvo no arquivo `test.c`:

#include <stdio.h>
#include <stdlib.h>

#include "libcipher.h"

int main(int argc, char *argv[])
{
 char text[]="How-To Geek loves Linux";

 puts(text);

 cipher_encode(text);
 puts(text);

 cipher_decode(text);
 puts(text);

 exit (0);

} // fim de main
  

O programa:

  • Inclui o arquivo libcipher.h para acessar as funções da biblioteca.
  • Cria uma string com o valor “How-To Geek loves Linux”.
  • Imprime a string original.
  • Codifica a string usando cipher_encode() e imprime o resultado.
  • Decodifica a string usando cipher_decode() e imprime o resultado.

Para compilar o programa de teste, devemos vinculá-lo à biblioteca. A opção `-o` (saída) indica o nome do executável a ser criado.

gcc test.c libcipher.a -o test

Se não houver saída do `gcc`, tudo correu bem. Vamos executar o programa:

./test

O programa imprime o texto original, o texto codificado e, finalmente, o texto decodificado, demonstrando o uso bem-sucedido da biblioteca.

Adicionando outro módulo à biblioteca

Vamos adicionar uma função à biblioteca que exibe a versão utilizada. Isso envolverá a criação, compilação e adição do novo arquivo-objeto à biblioteca.

O seguinte código, salvo como `cipher_version.c`, adiciona essa funcionalidade:

#include <stdio.h>

void cipher_version(void)
{
 puts("How-To Geek :: VERY INSECURE Cipher Library");
 puts("Version 0.0.1 Alphan");

} // fim de cipher_version
  

É necessário adicionar a nova função ao arquivo de cabeçalho `libcipher.h`:

void cipher_encode(char *text);
void cipher_decode(char *text);
void cipher_version(void);
  

Compilando cipher_version.c:

gcc -c cipher_version.c

O novo arquivo-objeto `cipher_version.o` é adicionado à biblioteca com o seguinte comando.
A opção `-v` (detalhada) faz com que o `ar` exiba o que está sendo executado.

ar -rsv libcipher.a cipher_version.o

O `ar` confirmará a adição do novo arquivo. O “a” significa “adicionado”.

Podemos usar a opção `-t` (tabela) para ver os módulos na biblioteca:

ar -t libcipher.a

Agora existem três módulos na nossa biblioteca. Vamos usar a nova função.

Usando a função cipher_version()

Vamos remover a biblioteca e o arquivo de cabeçalho antigos do diretório de teste, copiar os novos arquivos e voltar para o diretório.

Excluindo os arquivos antigos:

rm ./test/libcipher.*

Copiando os novos arquivos:

cp libcipher.* ./test

Voltando ao diretório:

cd test

Agora vamos modificar o programa `test.c` para que ele utilize a nova função.

Adicione uma linha chamando a função cipher_version() antes da primeira chamada a `puts(text)`:

#include <stdio.h>
#include <stdlib.h>

#include "libcipher.h"

int main(int argc, char *argv[])
{
 char text[]="How-To Geek loves Linux";

 // nova linha adicionada aqui
 cipher_version();

 puts(text);

 cipher_encode(text);
 puts(text);

 cipher_decode(text);
 puts(text);

 exit (0);

} // fim de main
  

Salve como `test.c`. Vamos compilar e testar a nova função:

gcc test.c libcipher.a -o test

Executando a nova versão:

A nova função está funcionando e a versão da biblioteca aparece no inicio da saída.

Mas pode haver um problema.

Substituindo um Módulo na Biblioteca

Esta é a segunda versão da biblioteca. A primeira versão não tinha a função cipher_version(). Essa versão deve ser a “0.0.2”. Vamos substituir a função na biblioteca.

O comando `ar` facilita essa substituição.

Primeiro, vamos editar o arquivo cipher_version.c, alterando o texto “Version 0.0.1 Alpha” para “Version 0.0.2 Alpha”:

#include <stdio.h>

void cipher_version(void)
{
 puts("How-To Geek :: VERY INSECURE Cipher Library");
 puts("Version 0.0.2 Alphan");

} // fim de cipher_version
  

Salve o arquivo. Vamos compilá-lo novamente:

gcc -c cipher_version.c

Agora, vamos substituir o arquivo `cipher_version.o` na biblioteca.

Usando a opção `-r` (adicionar com substituir) com um módulo existente, o `ar` substitui a versão antiga pela nova. As opções `-s` (índice) e `-v` (detalhado) atualizam o índice e fornecem mais informações sobre a ação.

ar -rsv libcipher.a cipher_version.o

O `ar` informa que substituiu o módulo cipher_version.o. O “r” significa “substituído”.

Usando a função cipher_version() atualizada

Vamos testar a biblioteca modificada.

Copiando os arquivos para o diretório de teste:

cp libcipher.* ./test

Mudando para o diretório:

cd ./test

Compilando o programa de teste novamente:

gcc test.c libcipher.a -o test

Executando o programa:

./test

O programa apresenta o número de versão correto e as rotinas de criptografia e descriptografia funcionam.

Excluindo Módulos de uma Biblioteca

Vamos remover o arquivo cipher_version.o da biblioteca.

A opção `-d` (excluir), juntamente com `-v` (detalhado) e `-s` (índice) permite remover e atualizar a biblioteca:

ar -dsv libcipher.a cipher_version.o

O `ar` confirma que removeu o módulo. O “d” significa “excluído”.

Listando os módulos na biblioteca:

ar -t libcipher.a

Se remover módulos da biblioteca, lembre-se de remover as definições correspondentes do arquivo de cabeçalho.

Compartilhe seu código

Bibliotecas facilitam o compartilhamento de código de forma privada. Ao fornecer o arquivo da biblioteca e o arquivo de cabeçalho, você permite que outros usem suas funcionalidades sem expor seu código-fonte.