Bibliotecas estáticas c/c++

Este é um tópico muito batido, tão velho quanto a linguagem C, mas que muita gente procura. Já que existem milhares de livros de c/c++ parecidos que podem fazer diferença para cada leitor, resolvi escrevi este artigo. Em resumo será mostrado como fazer um programa em c++ com funções e como fazê-lo da mesma forma com uma biblioteca.

[ Hits: 39.806 ]

Por: Fábio A. B. em 03/06/2007


Gerando bibliotecas estáticas



Agora o que significa fazer uma biblioteca (estática)?
RESPOSTA: É separar nossa função (ou procedure ou classe) do nosso programa.

Como fazer isso:

1) Aquilo que chamamos "protótipo da função" vai virar nosso arquivo ".h"! Isso mesmo, aquele arquivo que vai no início dos programas, como por exemplo #include "iostream.h".

2) A função propriamente dita int soma (int a, int b) { .......} que é o corpo matemático da função vai virar um arquivo chamado primeiramente "soma_function.cpp" e depois disso ele será compilado e passará a se chamar : "soma_function.o". A função "soma_function.o" fará parte de uma biblioteca "libsoma_function.a". Mais a frente serão explicados estes passos.

3) Nosso programa principal continuará o mesmo, a única coisa nova agora é que na hora de criar o executável com o g++ ele precisa estar compilado e saber onde está o arquivo "cabeçalho.h" e a biblioteca "libsoma_function.a", porque antes tudo estava dentro do mesmo código e agora tudo está separado.

Então mãos a obra:

Vá à pasta "programas" que você criou anteriormente:

Passo 1) Crie um arquivo texto na pasta programas com o nome soma_head.h com o seguinte conteúdo (leia o comentário!!!):

/* neste arquivo "soma_head.h" só se tem o protótipo da função e não a função propriamente dita. Este arquivo "soma_head.h" somente avisará ao gcc que seu programa deverá usar uma função chamada soma_function.a, a qual fará efetivamente as contas */

int soma(int a, int b);


Passo 2) crie um arquivo texto em /home/programas com o nome soma_function.cpp com isso isso dentro (leia os comentários):

/* este arquivo contém os códigos que farão as contas da função, a qual tem um header (cabeçalho) soma_head.h, Este header (soma_head.h) será incluído no programa principal como # include "soma_head.h", ou seja (mais uma vez), é o protótipo da função estará no arquivo "soma_head.h";

Agora o arquivo "soma_function.cpp" é uma função que fará cálculos, MAS ESTA FUNÇÃO DEVE SER COMPILADA para virar o arquivo soma_function.o */


int soma (int a, int b)  //É, precisa declarar as varáveis de novo!
{
  int r;  // r é uma variável  que tem do tipo inteiro
  r=a+b;  // "r" recebe a soma de dois números  "a" e "b"
          // que serão fornecidos pelo programa principal.
   return (r); // retorna ao programa principal o valor da variável "r"
} // acabou a função

Passo 2.1) Compilando a função soma_function.cpp

É, antes da função virar parte de uma biblioteca ela deve virar um "arquivo.o", ou seja, ser compilada! Pra nosso arquivo "soma_function.cpp" virar o arquivo "soma_function.o" precisamos compilá-lo, e para tanto devemos fazer entrar na pasta onde esta o "soma_function.cpp" e digitar:

$ g++ -c soma_function.cpp functop

A opção -c (compile only) indica ao gcc só pra compilar o soma_function.cpp e não gerar um executável a partir dele, mesmo porque ele é meio incompleto.

Então dentro da nossa pasta programas já temos nosso arquivo "soma_head.h" e o nosso arquivo "soma_function.o" (além do soma_function.cpp e do velho programa_com_função.cpp).

Pra sermos mais geral, temos que criar uma biblioteca ".a", nem que ela tenha pelo menos uma função ".o" (no caso será a nossa função soma_function.o). A saber, bibliotecas são um conjunto de funções (compiladas), que serão ligadas (linkadas) aos nosso programa fonte. Mas para isso precisamos agrupar estas funções na biblioteca.

Então pra gerar a biblioteca ".a" a partir do nosso soma_function.o digitamos no shell (devemos estar dentro da pasta programas):

$ ar rc libsoma_function.a soma_fuction.o

Assim geramos a biblioteca "libsoma_function.a", que contém a função "soma_function.o".

Mas compiladores são terríveis mesmo, depois que você gera uma biblioteca "lib_qualquer.a" eles ainda querem reindexá-las da maneira deles, da forma que eles acham mais fácil de entender, então já que você não pode lutar contra eles, faça isso (em nosso exemplo):

$ ranlib libsoma_fuction.a

A biblioteca libsoma_function.a será a mesma ainda, mas agora como o gcc gosta. Isso fará que o gcc possa manipulá-la digamos, mais eficientemente.

Página anterior     Próxima página

Páginas do artigo
   1. Funções
   2. Gerando bibliotecas estáticas
   3. Retomando o programa principal
   4. Gerando o executável
Outros artigos deste autor
Nenhum artigo encontrado.
Leitura recomendada

Criando uma aplicação gráfica com o Qt Designer

Criando uma calculadora com o KDevelop

Utilizando a função QSort em C

Vírus de computador e criação de um vírus em C/C++ (parte 1 - básico)

Introdução a GTK+ em C

  
Comentários
[1] Comentário enviado por linuxalexsandro em 03/06/2007 - 11:30h

Gostei muito do artigo. Ele é bastante útil para estudantes iniciantes das linguagens c/cpp que desejam conhecer mais sobre o compilador gcc. Parabéns FAB

[2] Comentário enviado por sombriks em 03/06/2007 - 17:00h

Olá,

sombriks@comander:~/variados$ g++ -Wall pograma.cc -o pograma
In file included from /usr/lib/gcc/i486-slackware-linux/4.1.2/../../../../include/c++/4.1.2/backward/iostream.h:31,
from pograma.cc:3:
/usr/lib/gcc/i486-slackware-linux/4.1.2/../../../../include/c++/4.1.2/backward/backward_warning.h:32:2: warning: #warning This file includes at least one deprecated or antiquated header. Please consider using one of the 32 headers found in section 17.4.1.2 of the C++ standard. Examples include substituting the <X> header for the <X.h> header for C++ includes, or <iostream> instead of the deprecated header <iostream.h>. To disable this warning use -Wno-deprecated.
sombriks@comander:~/variados$

todavia a execução é perfeita. Aparentemente no C++ o .h no final do arquivo foi depreciado.

Em C/C++ não basta apenas saber a linguagem; tem-se que aprender também os pormenores do compilador! Como estou estudando isso há umas 48 horas (direto, hahahaha) não resisti e decidi comentar.

Um Livro (pdf, mas deve existir como papel tb!) que eu recomendo se vc quiser uma rápida referência de C/C++ e um excelente tutorial de gcc é o do Brian Gough; dêem uma boa gloogada.

[3] Comentário enviado por V_Style em 03/06/2007 - 18:25h

Ola sombriks,

Então, o que significa efetivamente esse lance do se colocar o .h ou nao se colocar o .h no header?
Valeu
FAB

[4] Comentário enviado por feraf em 03/06/2007 - 19:48h

Para tornar o código portável, deve-se utilizar o iostream sem o .h. Isso se deve ao fato de que a iostream é uma namespace, ou seja, um aglomerado de classes. Na hora de invocar os métodos da iostream, deve-se chamá-los com std::cin e std::cout para entrada e saída padrão respectivamente. Opcionalmente pode-se importar o namespace std com 'using namespace std' e depois usar cin e cout diretamente.

[5] Comentário enviado por osirix em 25/02/2009 - 18:41h

Otimoooooooooooooo!!!
muito bom seu artigo ..
muito facil de entender .. !!
poxa dou nota 10000000000000000 pra ele .. ^^

vlw


[6] Comentário enviado por staltux em 23/04/2009 - 01:54h

cara legal...mas eu tenho uma pergunta...eu fiz isso que você mostrou e funcionou...
depois eu fiz novamente mas no code::blocks...sabe, criei um projeto e coloquei os arquivos nele...entao eu mandei compilar e executar e funcionou perfeitamente tambem...agora eu te pergunto:

Como o Code::Blocks sabe que o arquivo soma_function.cpp é a implementação do soma_header.h se em nenhum desses arquivos existe algo os relacionando...e eu tambem nao fiz nenhuma modificação nos scriptis de compilação do code...
é magica? magia negra? como ele adivinha isso?

[7] Comentário enviado por sombriks em 23/04/2009 - 09:18h

@alexfernandognr, essa é fácil.

ao compilar cada um dos N fontes individualmente o compilador vai apenas averiguar se todos os protótipos de função existem (i.e. não vai atrás da implementação ainda)

"g++ -c" não faz o executável, apenas o que é chamado de "código objeto".

No exemplo dado se vc der "g++ -c soma_function.cpp ; g++ -c g++ -c soma_principal.cpp" ambos vão gerar seus respectivos ".o" sem maiores dificuldades. Você somente teria problemas se os protótipos de função (declarados neste caso como manda a boa prática, no header) fossem usados de forma errada, o que implica em erro de compilação.

A mágica aqui é a etapa de linkagem ou linkedição.

"g++ soma_function.o soma_principal.o -o soma" faz a linkagem, é aqui o truque: o linker não precisa mais conhecer o código, apenas assegurar que cada chamada tem uma implementação em algum lugar no meio de todos os códigos objeto. dessa forma o problema é quebrado em pedaços menores e fica mais simples de resolver, ;)

em resumo, lembre-se que há duas etapas bem distintas: compilação e linkedição. A primeira cuida de achar os protótipos, mas é na segunda que juntamos as implementações.

[8] Comentário enviado por staltux em 23/04/2009 - 16:20h

entendido...
existe algum paramentro que possa ser colocado dentro do arquivo que implementa, para especificar de qual header se trata?
pois acho que teria problema se mais de um arquivo cpp implementa-se a mesma função...
tipo dois cpps implementando a mesma função com apenas um header...

[9] Comentário enviado por sombriks em 23/04/2009 - 19:55h

tem não, mas se você tiver no meio do seu mar de arquivos fontes dois que implementem o mesmo protótipo o linker irá falhar ao tentar juntar essas duas.


Contribuir com comentário




Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts