Idioma: 日本語 | Español | Français | Português | 中文 | English
Anterior | Próximo | Índice | Original em inglês (gnu.org)

4 Como escrever regras

Uma regra (rule) aparece em um makefile e indica quando e como refazer determinados arquivos, chamados de alvos (target) da regra (na maioria das vezes, apenas um por regra). Ela lista os outros arquivos que são os pré-requisitos (prerequisite, antes chamados de dependências) do alvo, bem como a receita (recipe, o que a regra executa) usada para criar ou atualizar o alvo.

A ordem em que as regras são escritas, em princípio, não importa, exceto para determinar a meta padrão: o alvo que o make deve considerar se você não especificar nada em particular. A meta padrão é o primeiro alvo da primeira regra no primeiro makefile. Há duas exceções a isso: um alvo que comece com um ponto não será a meta padrão, a menos que contenha também uma ou mais barras «/»; e um alvo que defina uma regra de padrão não tem efeito algum sobre a meta padrão. (Consulte Definição e redefinição de regras de padrão.)

Portanto, normalmente escrevemos o makefile de modo que a primeira regra seja aquela para compilar o programa inteiro (ou todos os programas descritos pelo makefile). Muitas vezes esse alvo recebe o nome «all». Consulte Argumentos para especificar as metas.


4.1 Um exemplo de regra

Vejamos primeiro um exemplo de regra:

foo.o : foo.c defs.h       # módulo para mexer no frob
        cc -c -g foo.c

O alvo dessa regra é foo.o, e seus pré-requisitos são foo.c e defs.h. A receita contém um único comando: «cc -c -g foo.c». A linha da receita começa com um caractere de tabulação, o que a identifica como receita.

Essa regra diz duas coisas:


4.2 Sintaxe das regras

Em geral, uma regra tem a seguinte forma:

targets : prerequisites
        recipe

ou ainda esta forma:

targets : prerequisites ; recipe
        recipe

Os targets (alvos) são nomes de arquivo, separados por espaços. Aqui podem ser usados caracteres curinga (consulte Uso de curingas em nomes de arquivos) e um nome da forma «a(m)» representa o membro m do arquivo de arquivo a (consulte Membros de arquivo como alvos). Normalmente há apenas um alvo por regra, mas há ocasiões em que faz sentido haver mais de um (consulte Múltiplos alvos em uma regra).

As linhas de recipe (receita) começam com um caractere de tabulação (ou com o primeiro caractere do valor da variável .RECIPEPREFIX; consulte Outras variáveis especiais). A primeira linha da receita pode aparecer na linha seguinte à dos pré-requisitos, precedida de uma tabulação, ou na mesma linha, após um ponto e vírgula. Qualquer uma das formas tem o mesmo efeito. Há outras diferenças na sintaxe das receitas. Consulte Como escrever receitas em regras.

Como o cifrão é usado para iniciar uma referência a variável do make, se você realmente quiser escrever um cifrão em um alvo ou pré-requisito, deve escrevê-lo dobrado, «$$» (consulte Como usar variáveis). Além disso, se você tiver habilitado a expansão secundária (consulte Expansão secundária) e quiser um cifrão literal na lista de pré-requisitos, deverá, na verdade, escrever quatro cifrões («$$$$»).

Linhas longas podem ser divididas inserindo uma barra invertida seguida de uma nova linha. Isso, porém, não é obrigatório, já que o make não impõe limite ao comprimento de uma linha em um makefile.

Uma regra informa ao make duas coisas: quando os alvos ficam desatualizados (precisam ser atualizados) e como atualizá-los quando necessário.

O critério para estar desatualizado é especificado em termos dos prerequisites (pré-requisitos), que consistem em nomes de arquivo separados por espaços. (Aqui também são permitidos curingas e membros de arquivo de arquivo — consulte Uso do make para atualizar arquivos de arquivo.) Um alvo é considerado desatualizado se não existir ou se for mais antigo do que qualquer um dos pré-requisitos (comparando-se as horas de última modificação). A ideia é que o conteúdo do arquivo-alvo seja calculado com base nas informações dos pré-requisitos; portanto, se algum dos pré-requisitos mudar, o conteúdo do arquivo-alvo existente pode deixar de ser válido.

Como atualizar é especificado por uma recipe (receita). Trata-se de um ou mais comandos a serem executados pelo shell (geralmente «sh»), porém com alguns recursos adicionais (consulte Como escrever receitas em regras).


4.3 Tipos de pré-requisitos

Há dois tipos de pré-requisitos que o GNU make entende: pré-requisitos normais, como os descritos na seção anterior, e pré-requisitos somente de ordem (order-only). Um pré-requisito normal expressa duas coisas. Primeiro, define a ordem em que as receitas serão invocadas: as receitas de todos os pré-requisitos de um alvo são concluídas antes que comece a receita do alvo. Segundo, impõe uma dependência: se algum dos pré-requisitos for mais recente do que o alvo, este é considerado desatualizado e deve ser refeito.

Normalmente, esse é exatamente o comportamento desejado: se um pré-requisito do alvo for atualizado, o alvo também deve ser atualizado.

Às vezes, porém, você quer garantir que um pré-requisito seja construído antes do alvo, mas sem forçar a atualização do alvo caso o pré-requisito seja atualizado. Os pré-requisitos somente de ordem servem para criar esse tipo de relação. Um pré-requisito somente de ordem é indicado colocando-se uma barra vertical (|) na lista de pré-requisitos: tudo o que está à esquerda da barra são pré-requisitos normais, e tudo o que está à direita são pré-requisitos somente de ordem:

targets : normal-prerequisites | order-only-prerequisites

A parte dos pré-requisitos normais pode, é claro, estar vazia. Além disso, você pode declarar pré-requisitos para o mesmo alvo em várias linhas, e eles são concatenados de modo apropriado (pré-requisitos normais são acrescentados à lista de pré-requisitos normais, e pré-requisitos somente de ordem à lista de pré-requisitos somente de ordem). Observe que, se você declarar o mesmo arquivo como pré-requisito normal e também somente de ordem, o pré-requisito normal prevalece (já que um pré-requisito normal abrange por completo o comportamento de um pré-requisito somente de ordem).

Pré-requisitos somente de ordem nunca são verificados ao se determinar se o alvo está desatualizado; mesmo que um pré-requisito somente de ordem esteja marcado como alvo falso (consulte Alvos falsos (phony)), isso não fará com que o alvo seja refeito.

Como exemplo, considere o caso em que você quer colocar os alvos em um diretório separado, e esse diretório pode não existir antes de o make ser executado. Nessa situação, você quer criar o diretório antes de colocar quaisquer alvos nele, mas, como os carimbos de data/hora dos diretórios mudam toda vez que um arquivo é adicionado, removido ou renomeado, certamente não queremos refazer todos os alvos sempre que o carimbo de data/hora do diretório mudar. Uma forma de administrar isso são os pré-requisitos somente de ordem: faça do diretório um pré-requisito somente de ordem de todos os alvos:

OBJDIR := objdir
OBJS := $(addprefix $(OBJDIR)/,foo.o bar.o baz.o)

$(OBJDIR)/%.o : %.c
        $(COMPILE.c) $(OUTPUT_OPTION) $<

all: $(OBJS)

$(OBJS): | $(OBJDIR)

$(OBJDIR):
        mkdir $(OBJDIR)

Agora a regra para criar o diretório objdir será executada, se necessário, antes que qualquer «.o» seja construído, mas nenhum «.o» será construído apenas porque o carimbo de data/hora do diretório objdir mudou.


4.4 Uso de curingas em nomes de arquivos

Um único nome de arquivo pode especificar muitos arquivos usando caracteres curinga. Os caracteres curinga do make são «*», «?» e «[…]», os mesmos do shell Bourne. Por exemplo, *.c representa a lista de todos os arquivos (do diretório de trabalho) cujos nomes terminam em «.c».

Quando uma expressão corresponde a vários arquivos, o resultado é ordenado.2 Contudo, várias expressões não são ordenadas em conjunto. Por exemplo, *.c *.h lista todos os arquivos cujos nomes terminam em «.c» (ordenados), seguidos de todos os arquivos cujos nomes terminam em «.h» (ordenados).

O caractere «~» no início de um nome de arquivo também tem um significado especial. Sozinho ou seguido de uma barra, representa seu diretório pessoal; por exemplo, ~/bin expande-se para /home/voce/bin. Quando o «~» é seguido de uma palavra, a cadeia representa o diretório pessoal do usuário indicado por essa palavra; por exemplo, ~john/bin expande-se para /home/john/bin. Em sistemas que não possuem diretório pessoal por usuário (como o MS-DOS e o MS-Windows), esse recurso pode ser emulado definindo-se a variável de ambiente HOME.

A expansão de curingas é feita automaticamente pelo make em alvos e pré-requisitos. Nas receitas, a expansão de curingas é feita pelo shell. Nos demais contextos, a expansão de curingas só ocorre quando explicitamente solicitada com a função wildcard.

O significado especial de um caractere curinga pode ser anulado precedendo-o de uma barra invertida. Assim, foo\*bar refere-se a um arquivo específico cujo nome consiste em «foo», um asterisco e «bar».


4.4.1 Exemplos de curingas

Curingas podem ser usados na receita de uma regra, onde são expandidos pelo shell. Por exemplo, eis uma regra para remover todos os arquivos objeto:

clean:
        rm -f *.o

Curingas também são úteis nos pré-requisitos de uma regra. Com a regra a seguir no makefile, «make print» imprimirá apenas os arquivos «.c» que tiverem mudado desde a última impressão:

print: *.c
        lpr -p $?
        touch print

Essa regra usa print como um arquivo de alvo vazio; consulte Arquivos de alvo vazios para registrar eventos. (A variável automática «$?» é usada para imprimir apenas os arquivos que mudaram; consulte Variáveis automáticas.)

A expansão de curingas não ocorre quando você define uma variável. Assim, se você escrever:

objects = *.o

o valor da variável objects será a cadeia literal «*.o». Contudo, se você usar o valor de objects em um alvo ou pré-requisito, a expansão de curingas ocorrerá ali. Se você usar o valor de objects em uma receita, o shell poderá fazer a expansão de curingas no momento em que a receita é executada. Se você quiser definir objects com o resultado já expandido, use, em vez disso:

objects := $(wildcard *.o)

Consulte A função wildcard.


4.4.2 Armadilhas no uso de curingas

Eis aqui um exemplo do uso ingênuo da expansão de curingas que não funciona como pretendido. Suponha que você queira criar o executável foo a partir de todos os arquivos objeto do diretório, e que escreva:

objects = *.o

foo : $(objects)
        cc -o foo $(CFLAGS) $(objects)

O valor de objects é a cadeia literal «*.o». A expansão de curingas ocorre na regra de foo, de modo que cada arquivo «.o» existente torna-se um pré-requisito de foo e será recompilado conforme necessário.

Mas o que acontece se você apagar todos os arquivos «.o»? Quando um curinga não corresponde a nenhum arquivo, ele é deixado intacto. Então foo passa a depender do arquivo de nome estranho *.o. Como esse arquivo provavelmente não existe, o make emitirá o erro de que não sabe como criar *.o. Não é esse o comportamento desejado!

Na verdade, é possível obter os resultados desejados com a expansão de curingas, mas isso requer técnicas um pouco mais sofisticadas, com a função wildcard e substituição de cadeias. Consulte A função wildcard.

Os sistemas operacionais da Microsoft (MS-DOS e MS-Windows) usam barras invertidas para separar diretórios em nomes de caminho, assim:

  c:\foo\bar\baz.c

Isso equivale ao c:/foo/bar/baz.c no estilo Unix (a parte c: é a chamada letra de unidade). Quando o make é executado nesses sistemas, ele aceita tanto barras no estilo Unix quanto barras invertidas nos nomes de caminho. No entanto, esse suporte não se estende à expansão de curingas, em que a barra invertida é um caractere de citação. Portanto, nesses casos, você deve usar barras no estilo Unix.


4.4.3 A função wildcard

A expansão de curingas ocorre automaticamente nas regras. Mas, ao definir uma variável ou nos argumentos de uma função, normalmente ela não ocorre. Se você quiser expandir curingas nesses lugares, precisará usar a função wildcard, assim:

$(wildcard pattern…)

Onde quer que essa cadeia seja usada em um makefile, ela é substituída por uma lista, separada por espaços, dos nomes dos arquivos existentes que correspondem a um dos padrões de nome de arquivo dados. Se nenhum arquivo existente corresponder a um padrão, esse padrão é omitido da saída da função wildcard. Observe que isso difere de como os curingas sem correspondência se comportam nas regras, onde eles são usados tal e qual, em vez de ignorados (consulte Armadilhas no uso de curingas).

Assim como na expansão de curingas nas regras, os resultados da função wildcard são ordenados. Mas, de novo, cada expressão individual é ordenada separadamente. Portanto, «$(wildcard *.c *.h)» expande-se para todos os arquivos que correspondem a «.c» (ordenados), seguidos de todos os que correspondem a «.h» (ordenados).

Um uso da função wildcard é obter a lista de todos os arquivos fonte em C de um diretório, assim:

$(wildcard *.c)

Podemos transformar a lista de arquivos fonte em C em uma lista de arquivos objeto substituindo o sufixo «.c» por «.o» no resultado, assim:

$(patsubst %.c,%.o,$(wildcard *.c))

(Aqui usamos outra função, patsubst. Consulte Funções para substituição e análise de texto.)

Assim, um makefile para compilar e ligar todos os arquivos fonte em C de um diretório pode ser escrito da seguinte forma:

objects := $(patsubst %.c,%.o,$(wildcard *.c))

foo : $(objects)
        cc -o foo $(objects)

(Isto aproveita a regra implícita para compilar programas em C, de modo que não há necessidade de escrever regras explícitas para compilar cada arquivo. O «:=» é uma variante do «=»; para sua explicação, consulte Os dois tipos de variáveis.)


4.5 Busca em diretórios por pré-requisitos

Em sistemas grandes, muitas vezes é desejável manter os fontes em um diretório separado dos binários. O recurso de busca em diretórios (directory search) do make facilita isso ao procurar automaticamente os pré-requisitos em vários diretórios. Quando você reorganiza arquivos entre diretórios, não precisa alterar as regras individuais — basta mudar o caminho de busca.


4.5.1 VPATH: caminho de busca para todos os pré-requisitos

O valor da variável VPATH do make especifica uma lista de diretórios em que o make deve buscar. Na maioria das vezes, espera-se que esses diretórios contenham arquivos de pré-requisito que não estão no diretório atual; entretanto, o make usa o VPATH como lista de busca tanto para os pré-requisitos quanto para os alvos das regras.

Assim, se um arquivo listado como alvo ou pré-requisito não existir no diretório atual, o make procura um arquivo com esse nome entre os diretórios listados em VPATH. Se algum deles contiver o arquivo, esse arquivo pode tornar-se o pré-requisito (veja a seguir). Isso permite que você escreva nomes de arquivo na lista de pré-requisitos de uma regra como se todos existissem no diretório atual. Consulte Escrita de receitas considerando a busca em diretórios.

Na variável VPATH, os nomes de diretório são separados por dois-pontos ou por espaços em branco. A ordem em que os diretórios são listados é a ordem em que o make realiza a busca. (No MS-DOS e no MS-Windows, usam-se ponto e vírgula como separador dos nomes de diretório em VPATH, pois os dois-pontos podem aparecer no próprio nome de caminho, após uma letra de unidade.)

Por exemplo,

VPATH = src:../headers

especifica um caminho contendo dois diretórios, src e ../headers, que o make procura nessa ordem.

Com esse valor de VPATH, a regra a seguir,

foo.o : foo.c

é interpretada como se tivesse sido escrita assim:

foo.o : src/foo.c

mas isso somente se foo.c não existir no diretório atual e for encontrado no diretório src.


4.5.2 A diretiva vpath

Semelhante à variável VPATH, mas mais seletiva, é a diretiva vpath (note que está em minúsculas). Ela permite especificar um caminho de busca para uma determinada classe de nomes de arquivo — aqueles que correspondem a um padrão. Desse modo, você pode atribuir certos diretórios de busca a uma classe de nomes de arquivo e outros diretórios (ou nenhum) a outros nomes.

Há três formas da diretiva vpath:

vpath pattern directories

Especifica directories como o caminho de busca para os nomes de arquivo que correspondem a pattern.

O caminho de busca directories é uma lista de diretórios a serem percorridos, separados por dois-pontos (ponto e vírgula no MS-DOS e no MS-Windows) ou por espaços em branco, tal como o caminho de busca usado na variável VPATH.

vpath pattern

Apaga o caminho de busca associado a pattern.

vpath

Apaga todos os caminhos de busca especificados anteriormente com diretivas vpath.

Um padrão de vpath é uma cadeia contendo um caractere «%». A cadeia deve corresponder ao nome de arquivo de um pré-requisito que está sendo buscado. O caractere «%» corresponde a qualquer sequência de zero ou mais caracteres (como nas regras de padrão; consulte Definição e redefinição de regras de padrão). Por exemplo, %.h corresponde a arquivos terminados em .h. (Se não houver «%», o padrão deverá corresponder exatamente ao pré-requisito, o que raramente é útil.)

Os caracteres «%» no padrão de uma diretiva vpath podem ser citados precedendo-os de uma barra invertida («\»). As barras invertidas que de outra forma citariam caracteres «%» podem, por sua vez, ser citadas com mais barras invertidas. As barras invertidas que citam caracteres «%» ou outras barras invertidas são removidas do padrão antes de ele ser comparado com nomes de arquivo. As barras invertidas que não correm o risco de citar caracteres «%» são deixadas intactas.

Quando um pré-requisito não existe no diretório atual, se o pattern de uma diretiva vpath corresponder ao nome do arquivo do pré-requisito, então os directories dessa diretiva são percorridos da mesma forma que (e antes de) os diretórios da variável VPATH.

Por exemplo,

vpath %.h ../headers

diz ao make para procurar no diretório ../headers qualquer pré-requisito cujo nome termine em .h que não seja encontrado no diretório atual.

Se vários padrões vpath corresponderem ao nome do arquivo do pré-requisito, o make processa cada diretiva vpath correspondente, uma de cada vez, percorrendo todos os diretórios listados em cada diretiva. O make processa as múltiplas diretivas vpath na ordem em que aparecem no makefile; várias diretivas com o mesmo padrão são independentes entre si.

Assim,

vpath %.c foo
vpath %   blish
vpath %.c bar

procura por arquivos terminados em «.c» em foo, depois em blish e depois em bar, ao passo que

vpath %.c foo:bar
vpath %   blish

procura por arquivos terminados em «.c» em foo, depois em bar e depois em blish.


4.5.3 Como funciona a busca em diretórios

Quando um pré-requisito é encontrado por meio da busca em diretórios (geral ou seletiva), o nome de caminho encontrado nem sempre é o que o make efetivamente lhe fornece na lista de pré-requisitos. Às vezes, o caminho descoberto pela busca em diretórios é descartado.

O algoritmo que o make usa para decidir se mantém ou descarta um caminho encontrado pela busca em diretórios é o seguinte:

  1. Se o arquivo-alvo não existir no caminho especificado no makefile, a busca em diretórios é realizada.
  2. Se a busca em diretórios for bem-sucedida, esse caminho é mantido e o arquivo é registrado provisoriamente como alvo.
  3. Todos os pré-requisitos desse alvo são examinados da mesma maneira.
  4. Depois de processar os pré-requisitos, o alvo pode ou não precisar ser refeito:
    1. Se o alvo não precisar ser refeito, o caminho do arquivo encontrado pela busca em diretórios é usado em qualquer lista de pré-requisitos que contenha esse alvo. Em suma, se o make não precisa refazer o alvo, ele usa o caminho encontrado pela busca em diretórios.
    2. Se o alvo precisar ser refeito (estiver desatualizado), o nome de caminho encontrado pela busca em diretórios é descartado, e o alvo é refeito usando o nome de arquivo especificado no makefile. Em suma, se o make tiver de refazer o alvo, este é refeito localmente, e não no diretório encontrado pela busca em diretórios.

Esse algoritmo pode parecer complicado, mas, na prática, costuma ser exatamente o que se deseja.

Outras versões do make usam um algoritmo mais simples: se o arquivo não existe e é encontrado pela busca em diretórios, então esse nome de caminho é sempre usado, independentemente de o alvo precisar ou não ser refeito. Assim, se o alvo é refeito, ele é criado no local do nome de caminho descoberto pela busca em diretórios.

Na verdade, se você deseja esse comportamento para alguns ou todos os diretórios, pode informá-lo ao make usando a variável GPATH.

A GPATH tem a mesma sintaxe e formato que a VPATH (isto é, uma lista de nomes de caminho separados por espaços em branco ou dois-pontos). Se um alvo desatualizado for encontrado pela busca em diretórios em um diretório que também apareça em GPATH, esse nome de caminho não é descartado, e o alvo é refeito usando o caminho expandido.


4.5.4 Escrita de receitas considerando a busca em diretórios

Quando um pré-requisito é encontrado em outro diretório pela busca em diretórios, isso não altera a receita da regra; ela é executada como foi escrita. Portanto, você deve escrever a receita com cuidado, de modo que ela procure o pré-requisito no diretório em que o make o encontrou.

Isso é feito com as variáveis automáticas, como «$^» (consulte Variáveis automáticas). Por exemplo, o valor de «$^» é a lista de todos os pré-requisitos da regra, incluindo os nomes dos diretórios em que foram encontrados, e o valor de «$@» é o alvo. Assim:

foo.o : foo.c
        cc -c $(CFLAGS) $^ -o $@

(A variável CFLAGS existe para que você possa especificar as opções a serem passadas às compilações em C pelas regras implícitas. Aqui a usamos com sentido uniforme, para que afete uniformemente todas as compilações em C. Consulte Variáveis usadas pelas regras implícitas.)

Muitas vezes os pré-requisitos incluem também arquivos de cabeçalho, que você não quer mencionar na receita. A variável automática «$<» representa apenas o primeiro pré-requisito:

VPATH = src:../headers
foo.o : foo.c defs.h hack.h
        cc -c $(CFLAGS) $< -o $@

4.5.5 Busca em diretórios e regras implícitas

A busca nos diretórios especificados com VPATH ou vpath também ocorre durante a consideração das regras implícitas (consulte Uso de regras implícitas).

Por exemplo, quando um arquivo foo.o não tem regra explícita, o make considera as regras implícitas, como a regra embutida de compilar foo.c caso esse arquivo exista. Se esse arquivo não estiver no diretório atual, os diretórios apropriados são percorridos. Se foo.c existir (ou for mencionado no makefile) em algum desses diretórios, aplica-se a regra implícita de compilação em C.

As receitas das regras implícitas costumam usar variáveis automáticas por necessidade; em consequência, elas usam os nomes de arquivo encontrados pela busca em diretórios sem nenhum esforço adicional.


4.5.6 Busca em diretórios para bibliotecas de ligação

A busca em diretórios aplica-se de forma especial às bibliotecas usadas com o ligador. Esse recurso especial entra em ação quando você escreve um pré-requisito cujo nome tem a forma «-lname». (Dá para perceber que algo de incomum acontece aqui, pois normalmente um pré-requisito é o nome de um arquivo, ao passo que o nome de arquivo de uma biblioteca costuma ter a forma libname.a, e não «-lname».)

Quando o nome de um pré-requisito tem a forma «-lname», o make o trata de modo especial, procurando primeiro um arquivo libname.so e, se não o encontrar, um arquivo libname.a, nesta ordem: no diretório atual, nos diretórios especificados pelos caminhos de busca vpath correspondentes e pelo caminho de busca VPATH, e em seguida nos diretórios /lib, /usr/lib e prefix/lib (normalmente /usr/local/lib, mas as versões do make para MS-DOS/MS-Windows comportam-se como se prefix estivesse definido como a raiz da árvore de instalação do DJGPP).

Por exemplo, se houver no seu sistema a biblioteca /usr/lib/libcurses.a (e nenhum arquivo /usr/lib/libcurses.so), então

foo : foo.c -lcurses
        cc $^ -o $@

fará com que o comando «cc foo.c /usr/lib/libcurses.a -o foo» seja executado quando foo for mais antigo do que foo.c ou do que /usr/lib/libcurses.a.

O conjunto padrão de arquivos a procurar é libname.so e libname.a, mas isso pode ser personalizado pela variável .LIBPATTERNS. Cada palavra no valor dessa variável é uma cadeia de padrão. Quando aparece um pré-requisito como «-lname», o make substitui o sinal de porcentagem em cada padrão da lista por name e realiza a busca em diretórios descrita acima usando cada nome de arquivo de biblioteca resultante.

O valor padrão de .LIBPATTERNS é «lib%.so lib%.a», que produz o comportamento padrão descrito acima.

Você pode desabilitar completamente a expansão de bibliotecas de ligação definindo essa variável com um valor vazio.


4.6 Alvos falsos (phony)

Um alvo falso (phony target) é aquele que não é, na verdade, o nome de um arquivo; é apenas um nome dado a uma receita que será executada quando você o requisitar explicitamente. Há duas razões para usar um alvo falso: evitar conflitos com um arquivo de mesmo nome e melhorar o desempenho.

Se você escrever uma regra cuja receita não cria o arquivo-alvo, a receita será executada toda vez que esse alvo for considerado para refazimento. Eis um exemplo:

clean:
        rm *.o temp

Como o comando rm não cria um arquivo chamado clean, esse arquivo provavelmente nunca existirá. Portanto, o comando rm será executado toda vez que você digitar «make clean».

Nesse exemplo, o alvo clean deixará de funcionar corretamente se um arquivo chamado clean vier a ser criado nesse diretório. Como não tem pré-requisitos, clean sempre seria considerado atualizado e sua receita não seria executada. Para evitar esse problema, você pode declarar explicitamente o alvo como falso, tornando-o um pré-requisito do alvo especial .PHONY (consulte Nomes especiais de alvos embutidos), assim:

.PHONY: clean
clean:
        rm *.o temp

Feito isso, «make clean» executará a receita independentemente de existir ou não um arquivo chamado clean.

Os pré-requisitos de .PHONY são sempre interpretados como nomes literais de alvo, nunca como padrões (mesmo que contenham o caractere «%»). Para fazer com que uma regra de padrão seja sempre refeita, considere usar um «alvo de força» (consulte Regras sem receitas nem pré-requisitos).

Alvos falsos também são úteis em conjunto com invocações recursivas do make (consulte Uso recursivo do make). Nessa situação, o makefile costuma conter uma variável que lista o conjunto de subdiretórios a construir. Uma forma simplista de lidar com isso é definir uma única regra cuja receita percorre os subdiretórios em laço, assim:

SUBDIRS = foo bar baz

subdirs:
        for dir in $(SUBDIRS); do \
          $(MAKE) -C $$dir; \
        done

Esse método, porém, tem alguns problemas. Primeiro, qualquer erro detectado em um sub-make é ignorado por esta regra, de modo que a construção dos demais diretórios prossegue mesmo se um deles falhar. Isso pode ser contornado acrescentando um comando de shell para registrar o erro e sair, mas então o make sairá ainda que tenha sido iniciado com a opção -k, o que é indesejável. Segundo, e talvez mais importante, não é possível tirar pleno proveito da capacidade do make de construir alvos em paralelo (consulte Execução paralela), pois há apenas uma regra. Os alvos de cada makefile são construídos em paralelo, mas os subdiretórios são construídos um de cada vez.

Ao declarar os subdiretórios como alvos .PHONY (você precisa fazê-lo, pois é óbvio que o subdiretório sempre existe; caso contrário, ele não seria construído), você pode eliminar esses problemas:

SUBDIRS = foo bar baz

.PHONY: subdirs $(SUBDIRS)

subdirs: $(SUBDIRS)

$(SUBDIRS):
        $(MAKE) -C $@

foo: baz

Aqui também declaramos que o subdiretório foo não pode ser construído até que o subdiretório baz esteja concluído. Esse tipo de declaração de relação é especialmente importante ao se tentar uma construção em paralelo.

A busca por regras implícitas (consulte Uso de regras implícitas) é omitida para alvos .PHONY. Por isso declarar um alvo como .PHONY é bom em termos de desempenho, mesmo quando não há preocupação quanto à existência de um arquivo real.

Alvos falsos não devem ser pré-requisitos de um arquivo-alvo real; se forem, a receita do alvo falso será executada toda vez que o make for considerar esse arquivo. Enquanto um alvo falso não for pré-requisito de um alvo real, sua receita só será executada quando o alvo falso for uma meta especificada (consulte Argumentos para especificar as metas).

Os makefiles incluídos não devem ser declarados como alvos falsos. Alvos falsos não se destinam a representar arquivos reais e, como o alvo é sempre considerado desatualizado, o make sempre o refaria e, em seguida, executaria a si mesmo de novo (consulte Como os makefiles são refeitos). Para evitar isso, o make não executa a si mesmo de novo se um arquivo incluído marcado como falso for refeito.

Um alvo falso pode ter pré-requisitos. Quando um diretório contém vários programas, é mais conveniente descrever todos eles em um único makefile ./Makefile. Como o alvo refeito por padrão é o primeiro do makefile, é comum torná-lo um alvo falso chamado «all» e listar todos os programas individuais como seus pré-requisitos. Por exemplo:

all : prog1 prog2 prog3
.PHONY : all

prog1 : prog1.o utils.o
        cc -o prog1 prog1.o utils.o

prog2 : prog2.o
        cc -o prog2 prog2.o

prog3 : prog3.o sort.o utils.o
        cc -o prog3 prog3.o sort.o utils.o

Assim, basta digitar «make» para refazer todos os três programas, ou você pode especificar como argumento aquele que deseja refazer (como em «make prog1 prog3»). A condição de falso não é herdada: os pré-requisitos de um alvo falso não se tornam falsos por si mesmos, a menos que sejam explicitamente declarados assim.

Quando um alvo falso é pré-requisito de outro alvo falso, ele atua como uma sub-rotina deste último. Por exemplo, no exemplo a seguir «make cleanall» apaga os arquivos objeto, os arquivos de diferenças e o arquivo program:

.PHONY: cleanall cleanobj cleandiff

cleanall : cleanobj cleandiff
        rm program

cleanobj :
        rm *.o

cleandiff :
        rm *.diff

4.7 Regras sem receitas nem pré-requisitos

Se uma regra não tem pré-requisitos nem receita, e seu alvo é um arquivo que não existe, então o make considera esse alvo como atualizado sempre que a regra é executada. Isso implica que todos os alvos que dependem desse executarão sempre as suas receitas.

Um exemplo deixará isso mais claro:

clean: FORCE
        rm $(objects)
FORCE:

Aqui o alvo «FORCE» satisfaz a condição especial acima, de modo que o alvo clean, que depende dele, é forçado a executar sua receita. O nome «FORCE» em si não tem nenhum significado especial, mas é um dos nomes comumente usados para esse fim.

Como se vê, usar «FORCE» dessa forma tem o mesmo resultado que usar «.PHONY: clean».

Usar «.PHONY» é mais explícito e mais eficiente. No entanto, outras versões do make não dão suporte a «.PHONY»; por isso «FORCE» aparece em muitos makefiles. Consulte Alvos falsos (phony).


4.8 Arquivos de alvo vazios para registrar eventos

O alvo vazio (empty target) é uma variante do alvo falso; ele é usado para manter a receita de uma ação que você requisita explicitamente de vez em quando. Diferentemente do alvo falso, esse arquivo-alvo pode realmente existir; mas o conteúdo do arquivo não importa e, em geral, está vazio.

O objetivo do arquivo de alvo vazio é registrar, por meio de sua hora de última modificação, o momento em que a receita da regra foi executada pela última vez. Isso é possível porque um dos comandos da receita é um comando touch que atualiza o arquivo-alvo.

Um arquivo de alvo vazio deve ter alguns pré-requisitos (caso contrário, não faz sentido). Quando você solicita refazer o alvo vazio, a receita é executada se algum dos pré-requisitos for mais recente do que o alvo — em outras palavras, se algum dos pré-requisitos tiver mudado desde a última vez que o alvo foi refeito. Eis um exemplo:

print: foo.c bar.c
        lpr -p $?
        touch print

Com essa regra, «make print» executará o comando lpr se algum dos arquivos fonte tiver mudado desde o último «make print». A variável automática «$?» é usada para imprimir apenas os arquivos que mudaram (consulte Variáveis automáticas).


4.9 Nomes especiais de alvos embutidos

Certos nomes têm significado especial quando aparecem como alvos.

.PHONY

Os pré-requisitos do alvo especial .PHONY são considerados alvos falsos. Quando um desses alvos é considerado, o make executa sua receita incondicionalmente, independentemente de existir ou não um arquivo com esse nome e qual seja sua hora de última modificação. Consulte Alvos falsos (phony).

.SUFFIXES

Os pré-requisitos do alvo especial .SUFFIXES são a lista de sufixos a serem usados ao verificar as regras de sufixo. Consulte Regras de sufixo do estilo antigo.

.DEFAULT

A receita especificada para .DEFAULT é usada para qualquer alvo para o qual nenhuma regra (nem explícita, nem implícita) tenha sido encontrada. Consulte Definição de regras padrão de último recurso. Se uma receita .DEFAULT for especificada, ela é executada para todos os arquivos que sejam mencionados como pré-requisitos, mas não como alvos, em uma regra. Consulte Algoritmo de busca de regras implícitas.

.PRECIOUS

Os alvos listados como pré-requisitos de .PRECIOUS recebem o seguinte tratamento especial: se o make for morto ou interrompido durante a execução da receita, o alvo não é apagado. Consulte Interrupção ou término do make. Além disso, se o alvo for um arquivo intermediário, ele normalmente seria apagado depois de deixar de ser necessário, mas essa remoção também não ocorre. Consulte Encadeamento de regras implícitas. Nesse último aspecto, há sobreposição com o alvo especial .SECONDARY.

Você também pode listar um padrão de alvo de regra implícita (como «%.o») como arquivo de pré-requisito do alvo especial .PRECIOUS. Isso preserva os arquivos intermediários criados por regras cujos alvos têm nomes correspondentes a esse padrão.

.INTERMEDIATE

Os alvos dos quais .INTERMEDIATE depende são tratados como arquivos intermediários. Consulte Encadeamento de regras implícitas. Um .INTERMEDIATE sem pré-requisitos não tem efeito.

.NOTINTERMEDIATE

Os pré-requisitos do alvo especial .NOTINTERMEDIATE nunca são considerados arquivos intermediários. Consulte Encadeamento de regras implícitas. Um .NOTINTERMEDIATE sem pré-requisitos faz com que todos os alvos sejam tratados como não intermediários.

Quando o pré-requisito é um padrão de alvo, os alvos construídos usando essa regra de padrão deixam de ser considerados arquivos intermediários.

.SECONDARY

Os alvos dos quais .SECONDARY depende são tratados como arquivos intermediários, mas nunca são apagados automaticamente. Consulte Encadeamento de regras implícitas.

.SECONDARY pode ser usado para evitar reconstruções redundantes em algumas situações incomuns. Por exemplo:

hello.bin: hello.o bye.o
        $(CC) -o $@ $^

%.o: %.c
        $(CC) -c -o $@ $<

.SECONDARY: hello.o bye.o

Considere a situação em que hello.bin está atualizado em relação aos arquivos fonte, mas o arquivo objeto hello.o não é encontrado. Sem .SECONDARY, o make refaria hello.o mesmo que os arquivos fonte não tenham mudado e, em seguida, refaria também hello.bin. Ao declarar hello.o como .SECONDARY, o make não precisa refazê-lo, e então também não precisa refazer hello.bin. Naturalmente, se algum dos arquivos fonte for atualizado, todos os arquivos objeto serão refeitos para que a geração de hello.bin seja bem-sucedida.

Um .SECONDARY sem pré-requisitos faz com que todos os alvos sejam tratados como secundários (isto é, nenhum alvo é apagado por ter sido considerado um arquivo intermediário).

.SECONDEXPANSION

Se .SECONDEXPANSION for mencionado como alvo em algum lugar do makefile, todas as listas de pré-requisitos definidas depois de ele aparecer serão expandidas uma segunda vez após a leitura de todos os makefiles. Consulte Expansão secundária.

.DELETE_ON_ERROR

Se .DELETE_ON_ERROR for mencionado como alvo em algum lugar do makefile, então o make apagará o alvo de uma regra se ele tiver sido alterado e sua receita terminar com status de saída diferente de zero, exatamente como faria ao receber um sinal. Consulte Erros em receitas.

.IGNORE

Se você especificar pré-requisitos para .IGNORE, o make ignorará os erros na execução da receita desses arquivos específicos. A receita de .IGNORE (se houver) é ignorada.

Se mencionado como um alvo sem pré-requisitos, .IGNORE instrui a ignorar erros na execução das receitas de todos os arquivos. Esse uso de «.IGNORE» tem suporte apenas por compatibilidade histórica. Como ele afeta todas as receitas do makefile, não é muito útil; recomendamos usar os métodos mais seletivos de ignorar erros de receitas específicas. Consulte Erros em receitas.

.LOW_RESOLUTION_TIME

Se você especificar pré-requisitos para .LOW_RESOLUTION_TIME, o make presume que esses arquivos são criados por comandos que geram carimbos de data/hora de baixa resolução. A receita do alvo .LOW_RESOLUTION_TIME é ignorada.

Os carimbos de data/hora de alta resolução de muitos sistemas de arquivos modernos reduzem a chance de o make julgar erroneamente que um arquivo está atualizado. Infelizmente, porém, alguns hospedeiros não oferecem meios de definir carimbos de data/hora de alta resolução, de modo que comandos que definem explicitamente o carimbo de um arquivo, como «cp -p», são obrigados a descartar a parte de subsegundo. Os arquivos criados por tais comandos devem ser listados como pré-requisitos de .LOW_RESOLUTION_TIME, para que o make não os julgue erroneamente desatualizados. Por exemplo:

.LOW_RESOLUTION_TIME: dst
dst: src
        cp -p src dst

Como «cp -p» descarta a parte de subsegundo do carimbo de data/hora de src, dst normalmente fica um pouco mais antigo do que src, ainda que esteja atualizado. A linha .LOW_RESOLUTION_TIME faz com que o make considere dst atualizado se seu carimbo de data/hora estiver no início do mesmo segundo do carimbo de src.

Por causa de restrições do formato de arquivos de arquivo, os carimbos de data/hora dos membros de arquivo de arquivo são sempre de baixa resolução. Você não precisa listar membros de arquivo de arquivo como pré-requisitos de .LOW_RESOLUTION_TIME, pois o make faz isso automaticamente.

.SILENT

Se você especificar pré-requisitos para .SILENT, o make não exibirá, antes de executá-las, as receitas usadas para refazer esses arquivos específicos. A receita de .SILENT é ignorada.

Se mencionado como um alvo sem pré-requisitos, .SILENT instrui a não exibir nada antes de executar qualquer receita. Você também pode usar métodos mais seletivos para silenciar apenas linhas de comando de receitas específicas. Consulte Eco das receitas. Se quiser silenciar todas as receitas em uma determinada execução do make, use a opção «-s» ou «--silent» (consulte Resumo das opções).

.EXPORT_ALL_VARIABLES

Simplesmente mencionando-o como alvo, isto instrui o make a exportar, por padrão, todas as variáveis para os processos-filhos. Trata-se de uma alternativa a usar export sem argumentos. Consulte Comunicação de variáveis a um sub-make.

.NOTPARALLEL

Se .NOTPARALLEL for mencionado como um alvo sem pré-requisitos, todos os alvos desta invocação do make serão executados em série, ainda que a opção «-j» seja dada. Qualquer comando make invocado recursivamente continua executando suas receitas em paralelo (a menos que o makefile dele também contenha esse alvo).

Se .NOTPARALLEL tiver alvos como pré-requisitos, todos os pré-requisitos desses alvos serão executados em série. Isso equivale a acrescentar implicitamente um .WAIT entre cada pré-requisito dos alvos listados. Consulte Desabilitar a execução paralela.

.ONESHELL

Se .ONESHELL for mencionado como alvo, então, ao construir o alvo, todas as linhas da receita serão passadas a uma única invocação do shell, em vez de cada linha ser invocada separadamente. Consulte Execução de receitas.

.POSIX

Se .POSIX for mencionado como alvo, então o makefile será analisado e executado em modo de conformidade com o POSIX. Isso não significa que só serão aceitos makefiles conformes ao POSIX: todos os recursos avançados do GNU make continuam disponíveis. Esse alvo faz com que o make se comporte conforme o POSIX exige, naquilo em que o comportamento padrão do make difere do POSIX.

Em particular, quando esse alvo é mencionado, as receitas são invocadas como se o sinalizador -e tivesse sido passado ao shell, isto é, o primeiro comando que falhar dentro de uma receita fará com que a receita falhe imediatamente.

Os sufixos das regras implícitas predefinidas também são considerados alvos especiais quando aparecem como alvos, assim como a concatenação de dois sufixos, como «.c.o». Esses alvos são regras de sufixo, uma forma antiga de definir regras implícitas (mas ainda muito usada). Em princípio, qualquer nome de alvo pode receber significado especial dessa forma, se você o dividir em duas partes e acrescentar ambas as partes à lista de sufixos. Na prática, os sufixos costumam começar com «.», de modo que esses nomes especiais de alvo também começam com «.». Consulte Regras de sufixo do estilo antigo.


4.10 Múltiplos alvos em uma regra

Quando uma regra explícita tem vários alvos, eles podem ser tratados de duas maneiras: como alvos independentes ou como alvos agrupados. Qual tratamento se aplica é determinado pelo separador que aparece depois da lista de alvos.

Regras com alvos independentes

Regras que usam o separador de alvos padrão, «:», definem alvos independentes. Isso equivale a escrever a mesma regra uma vez para cada alvo, com pré-requisitos e receita duplicados. Normalmente a receita usa variáveis automáticas, como «$@», para especificar qual alvo está sendo construído.

Regras com alvos independentes são úteis em dois casos:

A propósito, assim como a variável «$@» permite variar a receita, talvez você queira variar os pré-requisitos de acordo com o alvo. Isso não é possível com vários alvos em uma regra comum, mas é possível com uma regra de padrão estática. Consulte Regras de padrão estáticas.

Regras com alvos agrupados

Se você tem uma receita que produz vários arquivos a partir de uma única invocação, em vez de alvos independentes, é possível expressar essa relação declarando que a regra usa alvos agrupados (grouped targets). Uma regra de alvos agrupados usa o separador «&:» (aqui o «&» é usado para sugerir «todos»).

Quando o make constrói qualquer um dos alvos agrupados, ele entende que todos os demais alvos do grupo também serão atualizados como resultado da invocação da receita. Além disso, se apenas alguns dos alvos agrupados estiverem desatualizados ou ausentes, o make reconhece que executar a receita atualizará todos os alvos. Por fim, se qualquer um dos alvos agrupados estiver desatualizado, todos os alvos agrupados são considerados desatualizados.

Como exemplo, a regra a seguir define alvos agrupados:

foo bar biz &: baz boz
        echo $^ > foo
        echo $^ > bar
        echo $^ > biz

Durante a execução da receita de alvos agrupados, a variável automática «$@» é definida com o nome do alvo específico do grupo que provocou o disparo da regra. Tome cuidado ao depender dessa variável na receita de uma regra de alvos agrupados.

Diferentemente dos alvos independentes, uma regra de alvos agrupados deve incluir uma receita. No entanto, um alvo que seja membro de um grupo de alvos agrupados também pode aparecer em definições de regra de alvo independente que não tenham receita.

Cada alvo tem associada apenas uma receita. Se um alvo agrupado aparecer em uma regra de alvo independente ou em outra regra de alvos agrupados com receita, será emitido um aviso e a receita posterior substituirá a anterior. Além disso, esse alvo é removido do grupo anterior e passa a aparecer somente no novo grupo.

Se você quiser que um alvo apareça em vários grupos, deve usar o separador de alvos agrupados de dois-pontos duplo, «&::», ao declarar todos os grupos que contêm esse alvo. Os alvos agrupados de dois-pontos duplo são tratados de forma independente uns dos outros, e a receita de cada regra de alvos agrupados de dois-pontos duplo é executada no máximo uma vez, se pelo menos um de seus vários alvos precisar ser atualizado.


4.11 Múltiplas regras para um alvo

Um arquivo pode ser o alvo de várias regras. Todos os pré-requisitos mencionados em todas as regras são reunidos em uma única lista de pré-requisitos para esse alvo. Se o alvo for mais antigo do que qualquer pré-requisito de qualquer uma das regras, a receita é executada.

Só pode haver uma receita a ser executada para um arquivo. Se duas ou mais regras fornecerem receita para o mesmo arquivo, o make usa a última que foi dada e exibe uma mensagem de erro. (Como caso especial, se o nome do arquivo começar com um ponto, nenhuma mensagem de erro é exibida. Esse comportamento estranho existe apenas por compatibilidade com outras implementações do make… então evite usá-lo.) Às vezes você quer disparar, para o mesmo alvo, várias receitas definidas em pontos distintos do makefile; para isso, pode usar as regras de dois-pontos duplo (consulte Regras de dois-pontos duplo).

Uma regra adicional que tenha apenas pré-requisitos pode ser usada para dar, de uma só vez, alguns pré-requisitos adicionais a muitos arquivos. Por exemplo, um makefile costuma ter uma variável, como objects, que lista todos os arquivos de saída do compilador no sistema que está sendo construído. Uma forma prática de dizer que todos eles devem ser recompilados se config.h mudar é escrever:

objects = foo.o bar.o
foo.o : defs.h
bar.o : defs.h test.h
$(objects) : config.h

Isso pode ser inserido ou removido sem alterar as regras que realmente especificam como construir os arquivos objeto. É uma forma conveniente quando se deseja acrescentar pré-requisitos adicionais de vez em quando.

Outra artimanha é especificar os pré-requisitos adicionais com uma variável definida por um argumento de linha de comando passado ao make (consulte Sobreposição de variáveis). Por exemplo,

extradeps=
$(objects) : $(extradeps)

faz com que o comando «make extradeps=foo.h» considere foo.h um pré-requisito de cada arquivo objeto, mas um simples «make» não.

Se nenhuma das regras explícitas de um alvo tiver receita, o make procura uma regra implícita aplicável que possa encontrar (consulte Uso de regras implícitas).


4.12 Regras de padrão estáticas

As regras de padrão estáticas (static pattern rules) são regras que especificam vários alvos e constroem o nome do pré-requisito de cada alvo com base no nome do próprio alvo. Elas são mais gerais do que uma regra comum com múltiplos alvos, pois os alvos não precisam ter pré-requisitos idênticos: os pré-requisitos precisam ser análogos, mas não necessariamente idênticos.


4.12.1 Sintaxe das regras de padrão estáticas

A sintaxe de uma regra de padrão estática é a seguinte:

targets …: target-pattern: prereq-patternsrecipe

A lista targets especifica os alvos aos quais a regra se aplica. Os alvos podem conter caracteres curinga, assim como os alvos de uma regra comum (consulte Uso de curingas em nomes de arquivos).

O target-pattern e os prereq-patterns dizem como calcular os pré-requisitos de cada alvo. Cada alvo é confrontado com o target-pattern para extrair uma parte do nome do alvo, chamada de radical (stem). Esse radical é substituído em cada prereq-pattern para produzir os nomes dos pré-requisitos (um de cada prereq-pattern).

Cada padrão contém normalmente exatamente um caractere «%». Quando o target-pattern corresponde a um alvo, o «%» pode corresponder a qualquer parte do nome do alvo; essa parte é chamada de radical. O restante do padrão deve corresponder exatamente. Por exemplo, o alvo foo.o corresponde ao padrão «%.o», com «foo» como radical. Os alvos foo.c e foo.out não correspondem a esse padrão.

O nome do pré-requisito de cada alvo é formado substituindo-se o «%» de cada padrão de pré-requisito pelo radical. Por exemplo, se um padrão de pré-requisito for %.c, então substituir o radical «foo» dá o nome de pré-requisito foo.c. É permitido escrever um padrão de pré-requisito que não contenha «%»; nesse caso, esse pré-requisito é o mesmo para todos os alvos.

Os caracteres «%» nas regras de padrão podem ser citados com uma barra invertida precedente («\»). As barras invertidas que de outra forma citariam caracteres «%» podem, por sua vez, ser citadas com mais barras invertidas. As barras invertidas que citam caracteres «%» ou outras barras invertidas são removidas antes de o padrão ser comparado com nomes de arquivo ou de o radical ser substituído. As barras invertidas que não correm o risco de citar caracteres «%» são deixadas intactas. Por exemplo, no padrão the\%weird\\%pattern\\, há «the%weird\» antes do «%» que tem efeito, seguido de «pattern\\». As duas barras invertidas finais são deixadas intactas porque não afetam nenhum caractere «%».

Eis um exemplo que compila cada um de foo.o e bar.o a partir do arquivo .c correspondente:

objects = foo.o bar.o

all: $(objects)

$(objects): %.o: %.c
        $(CC) -c $(CFLAGS) $< -o $@

Aqui «$<» é a variável automática que contém o nome do pré-requisito, e «$@» é a variável automática que contém o nome do alvo. Consulte Variáveis automáticas.

Cada alvo especificado deve corresponder ao padrão de alvo; um aviso é emitido para cada alvo que não corresponder. Se você tiver uma lista de arquivos em que apenas alguns correspondem ao padrão, pode usar a função filter para remover os nomes que não correspondem (consulte Funções para substituição e análise de texto):

files = foo.elc bar.o lose.o

$(filter %.o,$(files)): %.o: %.c
        $(CC) -c $(CFLAGS) $< -o $@
$(filter %.elc,$(files)): %.elc: %.el
        emacs -f batch-byte-compile $<

Nesse exemplo, o resultado de «$(filter %.o,$(files))» é bar.o lose.o, e a primeira regra de padrão estática faz com que esses arquivos objeto sejam atualizados compilando-se o arquivo fonte em C correspondente a cada um. O resultado de «$(filter %.elc,$(files))» é foo.elc, então esse arquivo é criado a partir de foo.el.

Outro exemplo mostra como usar $* nas regras de padrão estáticas:

bigoutput littleoutput : %output : text.g
        generate text.g -$* > $@

Quando o comando generate é executado, $* se expande para o radical — «big» ou «little».


4.12.2 Regras de padrão estáticas e regras implícitas

As regras de padrão estáticas têm muito em comum com as regras implícitas definidas como regras de padrão (consulte Definição e redefinição de regras de padrão). Ambas têm um padrão para o alvo e padrões para construir os nomes dos pré-requisitos. A diferença está em como o make decide quando a regra se aplica.

Uma regra implícita pode aplicar-se a qualquer alvo que corresponda ao seu padrão, mas só se aplica quando o alvo não tem nenhuma outra receita especificada e quando seus pré-requisitos podem ser encontrados. Se mais de uma regra implícita parecer aplicável, apenas uma se aplica; a escolha depende da ordem das regras.

Em contraste, uma regra de padrão estática aplica-se à lista exata de alvos especificada na regra. Ela não pode aplicar-se a nenhum outro alvo e se aplica invariavelmente a cada um dos alvos especificados. Se duas regras conflitantes se aplicarem e ambas tiverem receita, isso é um erro.

A regra de padrão estática pode ser melhor do que uma regra implícita pelas seguintes razões:


4.13 Regras de dois-pontos duplo

As regras de dois-pontos duplo (double-colon) são regras explícitas escritas com «::» em vez de «:» após o nome do alvo. Elas são tratadas de forma diferente das regras comuns quando o mesmo alvo aparece em mais de uma regra. As regras de padrão com dois-pontos duplo têm um significado totalmente diferente (consulte Regras de padrão que correspondem a qualquer coisa).

Quando um alvo aparece em várias regras, todas elas devem ser do mesmo tipo: todas comuns ou todas de dois-pontos duplo. No caso de dois-pontos duplo, cada uma é independente das demais. A receita de cada regra de dois-pontos duplo é executada se o alvo for mais antigo do que qualquer pré-requisito dessa regra. Se a regra não tiver pré-requisitos, sua receita é sempre executada (ainda que o alvo já exista). Em consequência, das regras de dois-pontos duplo, pode ser que nenhuma seja executada, ou que apenas algumas, ou ainda todas, sejam.

As regras de dois-pontos duplo com o mesmo alvo estão, na verdade, completamente separadas umas das outras. Cada regra de dois-pontos duplo é processada individualmente, exatamente como seriam processadas regras com alvos diferentes.

As regras de dois-pontos duplo de um alvo são executadas na ordem em que aparecem no makefile. Contudo, as regras de dois-pontos duplo só têm sentido de verdade nos casos em que a ordem de execução das receitas não importa.

As regras de dois-pontos duplo são um tanto obscuras e raramente são úteis. Elas oferecem um mecanismo para os casos em que a forma de atualizar um alvo varia conforme o arquivo de pré-requisito que provocou a atualização, mas tais casos são raros.

Cada regra de dois-pontos duplo deve especificar uma receita; se não o fizer, uma regra implícita aplicável será usada, caso exista. Consulte Uso de regras implícitas.


4.14 Gerar pré-requisitos automaticamente

No makefile de um programa, muitas das regras que você precisa escrever costumam dizer apenas que algum arquivo objeto depende de algum arquivo de cabeçalho. Por exemplo, se main.c usa defs.h por meio de um #include, você escreveria:

main.o: defs.h

Essa regra é necessária para informar ao make que main.o deve ser refeito sempre que defs.h mudar. Em um programa grande, você teria de escrever dezenas dessas regras no makefile. E, o que é pior, teria de ter sempre o cuidado de atualizar o makefile toda vez que adicionasse ou removesse um #include.

Para evitar esse trabalho, a maioria dos compiladores C modernos escreve essas regras por você, examinando as linhas #include nos arquivos fonte. Normalmente isso é feito com a opção «-M» do compilador. Por exemplo, o comando:

cc -M main.c

gera a saída:

main.o : main.c defs.h

Assim, você não precisa mais escrever todas essas regras por conta própria. O compilador as faz por você.

Observe que tal regra constitui a menção de main.o no makefile, de modo que ele nunca poderá ser considerado um arquivo intermediário pela busca por regras implícitas. Isso significa que o make nunca apagará o arquivo após usá-lo. Consulte Encadeamento de regras implícitas.

Com programas make antigos, a prática tradicional era usar esse recurso do compilador para gerar os pré-requisitos sob demanda, com um comando como «make depend». Esse comando criava um arquivo depend contendo todos os pré-requisitos gerados automaticamente, e o makefile o carregava com include (consulte Inclusão de outros makefiles).

No GNU make, o recurso de refazer makefiles tornou essa prática obsoleta — como o make sempre regenera um makefile desatualizado, não há mais necessidade de dizer explicitamente ao make que regenere os pré-requisitos. Consulte Como os makefiles são refeitos.

A prática que recomendamos para a geração automática de pré-requisitos é ter um makefile para cada arquivo fonte. Para cada arquivo fonte name.c, há um makefile name.d que lista de quais arquivos o arquivo objeto name.o depende. Dessa forma, basta reanalisar apenas os arquivos fonte que mudaram para refazer os novos pré-requisitos.

Eis uma regra de padrão para gerar um arquivo de pré-requisitos (isto é, um makefile) chamado name.d a partir de um arquivo fonte em C name.c:

%.d: %.c
        @set -e; rm -f $@; \
         $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
         sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
         rm -f $@.$$$$

Para a definição de regras de padrão, consulte Definição e redefinição de regras de padrão. O sinalizador «-e» do shell faz com que o shell termine imediatamente se o comando $(CC) (ou qualquer outro comando) falhar (terminar com status diferente de zero).

Com o compilador GNU C, talvez você queira usar o sinalizador «-MM» em vez de «-M». Ele omite os pré-requisitos relativos aos arquivos de cabeçalho do sistema. Para mais detalhes, consulte Using GNU CC, em Opções que controlam o pré-processador.

O propósito do comando sed é transformar (por exemplo) isto:

main.o : main.c defs.h

nisto:

main.o main.d : main.c defs.h

Isso faz com que cada arquivo «.d» dependa de todos os arquivos fonte e de cabeçalho dos quais o arquivo «.o» correspondente depende. O make então sabe que deve regenerar os pré-requisitos sempre que algum dos arquivos fonte ou de cabeçalho mudar.

Depois de definir a regra para refazer os arquivos «.d», você usa a diretiva include para lê-los todos. Consulte Inclusão de outros makefiles. Por exemplo:

sources = foo.c bar.c

include $(sources:.c=.d)

(Este exemplo usa uma referência de substituição para transformar a lista de arquivos fonte «foo.c bar.c» na lista de makefiles de pré-requisitos «foo.d bar.d». Para informações detalhadas sobre referências de substituição, consulte Referências de substituição.) Como os arquivos «.d» são makefiles como quaisquer outros, o make os refaz conforme necessário, sem que você precise fazer nada. Consulte Como os makefiles são refeitos.

Observe que os arquivos «.d» contêm definições de alvo, portanto a diretiva include deve ser colocada depois da primeira meta padrão do makefile; caso contrário, há o risco de que algum arquivo objeto se torne a meta padrão. Consulte Como o make processa um makefile.


[N. do T.] Sobre a nota de rodapé (2) no texto. A nota de rodapé do original afirma que algumas versões antigas do GNU make não ordenavam o resultado da expansão de curingas. No GNU make atual, o resultado é ordenado para cada expressão de curinga individualmente.


Anterior | Próximo | Índice | Original em inglês (gnu.org)