Utilizando O GNU Make

Introdução

A tarefa de manter manualmente quais partes de um programa precisam ser recompilados devido a alguma alteração nos arquivos fontes é monótona e sujeita a erros. Para automatizar essa tarefa o Unix dispõe da ferramenta make.

O make trabalha a partir de um arquivo que contém regras que descrevem como reconstruir outros arquivos caso os seus fontes sofram alguma modificação. Para verificar se algum arquivo sofreu modificação o make vai consultar a data de atualização de cada um dos arquivos envolvidos e tomar alguma ação caso sejam diferentes entre si.

Ao invocar o make na linha de comando, este vai procurar no diretório corrente um arquivo de nome Makefile ou makefile e carregar as instruções contidas nele. Um Makefile é feito basicamente de regras que podem ser escolhidas ou não de acordo com parâmetros que oferecemos.

O GNU make é a versão da Free Software Fundation para o make.

Exemplos de uso do make:

$ make foo.o    # recompila o módulo foo.o (a partir de um foo.c)
$ make hello    # compila o programa hello
$ make install  # instala

Elementos Sintáticos

Comentários

Um comentário começa com o símbolo # e o seu conteúdo é desprezado até ao final da linha.
# Makefile:
#   Isto é um comentário.

Variáveis

Uma variável é declarada como em variável = conteúdo. O conteúdo é obtido através da sintaxe $(variável).
PREFIX = /usr/local
SOURCES = foo.c bar.c baz.c
echo $(PREFIX)
gcc $(SOURCES) -o prog

Regras

Uma regra é a estrutura que dá "movimento" a um Makefile, sua forma é:
objetivo: dependências
	ação
Essa regra simplesmente informa que, para fazer o objetivo, as dependências devem estar desatualizadas. Se pelo menos uma das dependências estiver desatualizada, toma-se então a ação para deixar o objetivo coerente novamente. Por exemplo:
foo: foo.c foo.h
	gcc foo.c -o foo

O arquivo foo depende dos arquivos foo.c e foo.h. Se algum desses arquivos sofrer modificações então ao executar o comando make foo a ação gcc foo.c -o foo será executada.

Uma regra pode conter uma lista de dependências vazia, neste caso a ação será sempre tomada. A ação inclusive pode estar vazia, essa forma é utilizada quando se deseja desencadear ações em cascata com outras dependências. Como em:

all: listargs hello

listargs: listargs.c
	gcc listargs.c -o listargs

hello: hello.c hello.h
	gcc hello.c -o hello

Nota: É essencial utilizar-se de <TAB> no campo da ação, em um arquivo do make pois espaços nesse caso são considerados como erro de sintaxe.

Um Makefile Completo

CC = gcc
CFLAGS = -Wall -ansi -c
#DEBUG = -g
LD = gcc
#LDFLAGS = -lm

PREFIX = /usr/local
BINDIR = $(PREFIX)/bin

all: listargs

main.o: main.c write.h
	$(CC) $(CFLAGS) $(DEBUG) main.c

write.o: write.c write.h
	$(CC) $(CFLAGS) $(DEBUG) write.c

listargs: main.o write.o
	$(LD) $(LDFLAGS) main.o write.o -o listargs

install: all
	install -m755 listargs $(BINDIR)/listargs

clean:
	rm *.o *.c~ core listargs
Baixe o example.mk e renomeie para Makefile.

Exemplos de uso:

$ make main
$ make
$ make install
$ make PREFIX=/usr install
$ make -n install
$ make -f example.mk
$ make clean