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.