Académique Documents
Professionnel Documents
Culture Documents
Universidade de Sa
ncias Matema
ticas e de Computac
o
Instituto de Cie
a
2011
muito interessante criar bibliotecas cujas funcoes (classes e metodos, no caso de linE
guagens orientadas a objetos) possam ser reutilizadas em diversos programas. Voce pode
inclusive distribuir essas bibliotecas, com a opcao de esconder o codigo fonte utilizado
nas funcoes. Geralmente ao programar em C/C++, ja utilizamos muitas bibliotecas com
funcoes prontas como quando inclumos <stdio.h> ou <iostream>.
Para criarmos nossa propria biblioteca e preciso ter arquivos de cabecalho (com extensao .h) e arquivos de biblioteca (com extensao dependente do compilador e sistema
operacional, no gcc a extensao geralmente utilizada e .a).
Vamos mostrar um exemplo em C de biblioteca contendo uma u
nica funcao, que receba
um valor inteiro e retorne seu fatorial. O arquivo cabecalho sera funcoes.h, e o arquivo
com o codigo fonte da funcao sera nomeado funcoes.c e tem o seguinte conte
udo:
#include "funcoes.h"
int fatorial(int x) {
int a, fatx=1;
for (a=x; a>1; a--) {
fatx = fatx*a;
}
return fatx;
}
Veja que ja inclumos funcoes.h. Isso sera necessario para o compilador reconhecer
a funcao como sendo parte da biblioteca.
O arquivo cabecalho ira conter informacoes apenas da interface, tipicamente as assinaturas (ou prototipos) das funcoes. A extensao .h vem da palavra header (cabecalho
em ingles). Nesse caso teremos o arquivo cabecalho, nomeado funcoes.h, definido da
seguinte forma:
#ifndef FUNCOES_H
#define FUNCOES_H
int fatorial(int);
#endif
As primeiras linhas (#ifndef e #define) tem a funcao de verificar se o arquivo
cabecalho ja foi includo num projeto, antes de inclu-lo novamente de forma desnecessaria.
1
Temos entao dois arquivos: funcoes.c e funcoes.h. Para utiliza-los, devemos gerar
o arquivo objeto da biblioteca:
$ gcc -c funcoes.c -o funcoes.o
Se desejar criar um arquivo .a, que possa ser distribudo, utilize o comando:
$ ar -cru libfuncoes.a funcoes.o
Os arquivos .a sao bibliotecas estaticas, que tem a vantagem de poder carregar varios
objetos. Nesse caso nao faz muita diferenca, mas o comando e bastante u
til em projetos
maiores. Se quiser saber mais sobre o ar entre em seu manual digitando $ man ar.
Agora podemos copiar todos os arquivos para um diretorio separado, por exemplo
./biblioteca.
1.1
Utilizando a biblioteca
Agora, sempre que for necessario usar funcoes definidas no arquivo funcoes.c, incluimos
o arquivo funcoes.h no programa que vamos implementar. Abaixo um exemplo de codigo
fonte, que iremos nomear programa.c, que utiliza a biblioteca funcoes:
#include <stdio.h>
#include "funcoes.h"
int main(void) {
int b;
printf("Valor para calcular o fatorial: ");
scanf("%d", b);
printf("\n O fatorial de %d = %d", b, fatorial(b));
return 0;
}
Repare que nao utilizamos os sinais de menor/maior para incluir funcoes.h, como na
biblioteca stdio.h. Eles sao usados quando o arquivo cabecalho estiver instalado num
diretorio padrao do sistema.
Agora ha duas opcoes de compilacao: uma usando o arquivo objeto e outra usando a
biblioteca estatica
Usando biblioteca est
atica: e preciso instruir o compilador com as opcoes de
includes e edicao de ligacoes (linker ) para que a biblioteca possa ser includa no programa
executavel. No gcc isso e feito utilizando:
2
Compilac
ao e makefiles
A compilacao e ligacao de codigos fonte pode ser uma tarefa complexa quando se utiliza
referencias a diversas bibliotecas e quando temos muitos arquivos fonte (.c, .cpp, ...)
para juntar a` compilacao e gerar o programa. A forma mais simples de compilar arquivos
e obter um executavel utilizando o gcc e, por exemplo:
$ gcc programa.c biblioteca.c funcoes.c -o programa
Repare que, nesse exemplo, para obtermos o programa precisamos de tres arquivos de
codigo fonte. Muitas vezes temos tambem que adicionar o caminho para bibliotecas que
usamos no nosso programa, o que aumenta a linha de comando, como por exemplo:
$ gcc programa.c biblioteca.c funcoes.c -o programa -L/home/lib
Ainda, quando alteramos apenas um dos fontes, geralmente compilamos tudo novamente, de forma manual, para obter o programa desejado. Para minimizar esse esforco,
podemos utilizar arquivos makefile em conjunto com o utilitario make.
Makefiles sao arquivos com um formato especial que auxiliam na compilacao e ligacao
de projetos. Make e um programa especialmente criado para ler esses arquivos, que
contem as instrucoes para tudo o que deve ser feito (make).
Se voce executar:
3
$ make
esse programa ira procurar por um arquivo chamado Makefile no diretorio atual, e
ira executar utilizando as instrucoes desse arquivo. Se voce tiver mais do que um makefile
ou seu arquivo possuir um nome diferente, voce pode usar o comando:
$ make -f MeuMakefile
que especifica o arquivo que voce quer utilizar para gerar seu programa.
2.1
Arquivos Makefile
2.2
Depend
encias
Podemos definir m
ultiplos alvos, cada um com dependencias diferentes, para que o make
possa executar alvos a partir das dependencias, ou entao para que possamos escolher qual
alvo desejamos executar.
Suponha que tenhamos apenas dois arquivos para compilar, por exemplo, programa.c
e funcoes.c, e queremos gerar o executavel programa. Podemos definir o Makefile da
seguinte forma:
Veja que adicionamos o alvo clean que e responsavel por apagar o binario programa,
todos os objetos , ou seja, todos os arquivos com extensao .o. Para que o make execute
apenas a limpeza, utilizamos:
$ make clean
Definir esse tipo de dependencia e u
til quando queremos rapidamente excluir arquivos
para recompilar completamente o projeto.
2.3
Vari
aveis, coment
arios e detalhes
p1:
$(CP) p1.o biblioteca.h biblioteca.o funcoes.h funcoes.o \
lista.h lista.o -o p1
2.4
Para criar mais do que um executavel podemos usar o alvo all. Por exemplo, para criar
tres executaveis p1, p2 e p3:
all: p1 p2 p3
p1: funcoes.o prog1.o
gcc prog1.o funcoes.o -o p1
p2: biblioteca.o prog2.o
gcc prog2.o biblioteca.o -o p1
p3: biblioteca.o funcoes.o prog3.o
gcc prog3.o biblioteca.o funcoes.o -o p1
Nesse caso cada executavel tem suas dependencias, que devem ser definidas, se necessario no arquivo.
2.5
Muitas vezes precisamos gerar um arquivo compactado com todos os arquivos do projeto.
Adicionando um alvo extra podemos gerar por exemplo um arquivo tar:
tar:
tar cfv programa.tar funcoes.h funcoes.c biblioteca.h \
biblioteca.c lista.h lista.c programa.c
Nesse caso, assim como no clean, nao ha dependencias, sendo o arquivo programa.tar
criado quando chamado o comando:
$ make tar
2.6
Erros comuns
Os erros geralmente estao relacionados ao uso incorreto da tabulacao (<TAB>). Infelizmente elas sao difceis de visualizar. Uma dica e entrar no editor, posicionar o cursor no
incio da linha e mover o cursor para a frente uma vez, se ele pular varios espacos, temos
uma tabulacao.
Os erros mais comuns sao:
1. Esquecer de inserir a tabulacao antes do incio dos comandos,
2. Inserir uma tabulacao no incio de uma linha em branco,
3. Nao inserir uma quebra de linha logo apos uma barra invertida (quando se utiliza
esse recurso).
2.7
Muitos projetos em C/C++ utilizam diretorios diferentes para armazenar o codigo fonte,
os objetos e bibliotecas. Geralmente utilizam a estrutura:
./projeto
./include
./obj
./lib
./src
No diretorio include estao todos os cabecalhos, no diretorio obj todos os arquivos objeto,
no diretorio lib as bibliotecas utilizadas e em src os fontes. O uso de make auxilia muito
nesses casos.
Suponha um projeto em C++ que ira possuir um u
nico executavel manage, e que
utilize uma biblioteca Product que contem a implementacao de uma classe de mesmo
nome. Assim, temos os seguintes arquivos e diretorios:
./projeto
./include
Product.h
./obj
./lib
./src
Product.cc
manage.cc
Product:
$(CC) -c $(SRC)/Product.cc $(FLAGS) -I$(INCLUDE) -o $(OBJ)/Product.o
ar -cru $(LIB)/libProduct.a $(OBJ)/Product.o
Ao iniciar, o make ira tentar resolver manage, que depende de Product. O target
Product primeiro compila o arquivo Product.cc, gerando um objeto Product.o na pasta
obj.
A seguir, cria uma biblioteca no diretorio lib. Finalizada a dependencia, manage.cc
e compilado e um arquivo executavel e criado no diretorio do projeto.
Opcionalmente, podemos incluir uma opcao para limpar o projeto:
clean:
rm manage $(SRC)/*~ $(OBJ)/*o $(LIB)/*a
Apaga o executavel, todos os arquivos textos de backup, objetos e a biblioteca.
O arquivo Makefile final fica assim:
# compilador
CC=g++
# variaveis com diretorios
LIB=./lib
INCLUDE=./include
SRC=./src
OBJ=./obj
# opcoes de compilacao
LIBFLAGS = -lProduct
FLAGS = -Wall
manage: Product
$(CC) $(SRC)/manage.cc $(FLAGS) -I$(INCLUDE) -L$(LIB) $(LIBFLAGS) \
-o manage
Product:
$(CC) -c $(SRC)/Product.cc $(FLAGS) -I$(INCLUDE) -o $(OBJ)/Product.o
ar -cru $(LIB)/libProduct.a $(OBJ)/Product.o
clean:
rm *~ manage $(OBJ)/*o $(LIB)/*a
10