A receita (recipe, o que a regra executa) de uma regra é composta por uma ou mais linhas de comandos de shell a serem executados, um de cada vez, na ordem em que aparecem. Normalmente, o resultado da execução desses comandos é deixar o alvo da regra atualizado.
Os usuários usam muitos programas de shell diferentes, mas as receitas nos makefiles são sempre interpretadas por /bin/sh, a menos que o makefile especifique o contrário. Consulte Execução de receitas.
Os makefiles têm a peculiaridade de que, na verdade, há duas sintaxes distintas misturadas em um único arquivo. A maior parte de um makefile usa a sintaxe do make (consulte Como escrever Makefiles). No entanto, as receitas devem ser interpretadas pelo shell e, por isso, são escritas usando a sintaxe do shell. O programa make não tenta entender a sintaxe do shell: ele realiza apenas algumas transformações específicas e limitadas no conteúdo de uma receita antes de entregá-lo ao shell.
Cada linha de uma receita deve começar com um caractere de tabulação (ou com o caractere definido na variável .RECIPEPREFIX; consulte Outras variáveis especiais), com uma exceção: a primeira linha da receita pode ser anexada à linha do alvo e dos pré-requisitos, separada por um ponto e vírgula. Qualquer linha em um makefile que comece com uma tabulação e apareça em um "contexto de regra" (ou seja, depois de uma regra ter começado, até que outra regra ou definição de variável apareça) será considerada parte de uma receita. Linhas em branco e linhas contendo apenas comentários podem aparecer entre as linhas da receita; elas são ignoradas.
Algumas consequências dessas regras incluem:
make; ele é repassado ao shell tal como está. O fato de o shell tratá-lo como um comentário depende do shell que você usa.
make, e será repassada ao shell.
ifdef, ifeq etc.; consulte Sintaxe das condicionais) cujo primeiro caractere da linha esteja recuado com uma tabulação será considerada parte de uma receita e será repassada ao shell.
Uma das poucas situações em que o make interpreta as receitas é a verificação de uma barra invertida imediatamente antes de uma nova linha. Como na sintaxe normal dos makefiles, uma única linha lógica de receita pode ser dividida em várias linhas físicas no makefile colocando uma barra invertida antes de cada nova linha. Uma sequência de linhas assim é considerada uma única linha de receita, e uma única invocação do shell será feita para executá-la.
No entanto, em contraste com o tratamento dado em outros lugares do makefile (consulte Dividir linhas longas), as combinações de barra invertida e nova linha não são removidas da receita. Tanto a barra invertida quanto a nova linha são preservadas e repassadas ao shell. A forma como a barra invertida/nova linha é interpretada depende do seu shell. Se o primeiro caractere da linha seguinte à barra invertida/nova linha for o prefixo de receita (uma tabulação, por padrão; consulte Outras variáveis especiais), então esse caractere (e apenas ele) será removido. Espaços em branco nunca são adicionados à receita.
Por exemplo, considere a receita do alvo all no seguinte makefile:
all :
@echo no\
space
@echo no\
space
@echo one \
space
@echo one\
space
Ela é composta por quatro comandos de shell distintos, e sua saída é:
nospace nospace one space one space
Como um exemplo um pouco mais complexo, considere este makefile:
all : ; @echo 'hello \
world' ; echo "hello \
world"
Ele invocará o shell uma vez com o seguinte comando:
echo 'hello \
world' ; echo "hello \
world"
o que, seguindo as regras de citação (quoting) do shell, produzirá a seguinte saída:
hello \ world hello world
Observe como a combinação de barra invertida/nova linha é removida dentro da cadeia entre aspas duplas ("…"), enquanto é mantida dentro da cadeia entre aspas simples ('…'). Essa é a forma como o shell padrão (/bin/sh) trata a barra invertida/nova linha. Se você especificar um shell diferente em seu makefile, o tratamento poderá ser diferente.
Às vezes você quer dividir uma linha longa dentro de aspas simples, mas não quer que a barra invertida/nova linha apareça no conteúdo entre aspas. Isso acontece com frequência ao passar scripts para linguagens como Perl, onde uma barra invertida estranha dentro do script pode alterar seu significado ou até causar um erro de sintaxe. Uma maneira simples de lidar com isso é colocar a cadeia entre aspas, ou mesmo o comando inteiro, em uma variável do make e, então, usar essa variável na receita. Nesse caso, são aplicadas as regras de citação de novas linhas dos makefiles, e a barra invertida/nova linha é removida. Se reescrevermos o exemplo anterior dessa maneira:
HELLO = 'hello \ world' all : ; @echo $(HELLO)
obteremos a seguinte saída:
hello world
Se preferir, você também pode usar variáveis específicas de alvo (consulte Valores de variáveis específicas de alvo). Assim, você pode associar a variável de forma mais estreita à receita que a utiliza.
Outro processamento que o make realiza nas receitas é a expansão de quaisquer referências a variáveis presentes nelas (consulte Fundamentos das referências a variáveis). Isso ocorre depois que o make termina de ler todos os makefiles e determina que o alvo está desatualizado (que precisa ser atualizado). Portanto, a receita de um alvo que não será reconstruído nunca é expandida.
As referências a variáveis e a funções nas receitas têm exatamente a mesma sintaxe e o mesmo significado que em qualquer outro lugar do makefile. As regras de citação também são as mesmas. Quando você quiser que apareça um cifrão literal em uma receita, deve duplicá-lo ($$). Em shells, como o shell padrão, que introduzem variáveis com um cifrão, é importante manter clara na mente a distinção entre uma variável do make (que usa um único cifrão) e uma variável do shell (que usa dois cifrões) que você queira referenciar. Por exemplo:
LIST = one two three
all:
for i in $(LIST); do \
echo $$i; \
done
Isso resulta no seguinte comando sendo repassado ao shell:
for i in one two three; do \
echo $i; \
done
que produz o resultado esperado:
one two three
Normalmente, o make exibe na tela cada linha da receita antes de executá-la. Isso é chamado de eco (echo), pois parece que você está digitando a linha por conta própria.
Quando uma linha começa com "@", o eco dessa linha é suprimido. O "@" é descartado antes de a linha ser repassada ao shell. Isso é usado tipicamente para comandos cujo único propósito é exibir algo, como um comando echo que indica o progresso do makefile:
@echo About to make distribution files
Quando o make recebe a opção "-n" ou "--just-print", ele apenas faz o eco da maioria das receitas, sem executá-las (consulte Resumo das opções). Nesse caso, até as linhas de receita que começam com "@" são exibidas. Essa opção é útil para descobrir quais receitas o make considera necessárias, sem efetivamente fazer nada.
A opção "-s" ou "--silent" do make impede totalmente o eco, como se todas as receitas começassem com "@". O mesmo efeito pode ser obtido com uma regra para o alvo especial .SILENT sem pré-requisitos no makefile (consulte Nomes de alvos especiais embutidos).
Quando chega o momento de executar receitas para atualizar um alvo, elas são executadas invocando um novo subshell para cada linha da receita, a menos que o alvo especial .ONESHELL esteja em vigor (consulte Como usar um único shell). (Na prática, o make pode tomar atalhos que não afetem o resultado.)
Atenção: isso significa que definir uma variável de shell, ou invocar um comando de shell que estabeleça um contexto local a cada processo, como cd, não afeta as linhas seguintes da receita. (N. do T.: como cd etc. são independentes em cada subshell, não são herdados pela linha seguinte.) Se você quiser usar cd para afetar a próxima instrução, coloque ambas as instruções em uma única linha de receita. Assim, o make executará a linha inteira em um único shell, e o shell executará cada instrução em sequência. Por exemplo:
foo : bar/lose
cd $(<D) && gobble $(<F) > ../$@
Aqui usamos o operador AND do shell (&&). Dessa forma, se o comando cd falhar, o script falha sem tentar invocar o comando gobble no diretório errado, o que poderia causar problemas (neste caso, ao menos, certamente ../foo ficaria truncado e vazio).
Às vezes você prefere que todas as linhas de uma receita sejam passadas a uma única invocação do shell. Existem geralmente duas situações em que isso é útil: primeiro, pode melhorar o desempenho em makefiles cujas receitas tenham muitas linhas de comando, evitando processos extras; segundo, você pode querer que comandos da receita contenham novas linhas, por exemplo, caso esteja usando um interpretador completamente distinto como SHELL. Se o alvo especial .ONESHELL aparecer em qualquer lugar do makefile, então todas as linhas da receita de cada alvo serão passadas a uma única invocação do shell. As novas linhas entre as linhas da receita são preservadas. Por exemplo:
.ONESHELL:
foo : bar/lose
cd $(<D)
gobble $(<F) > ../$@
Agora o comportamento será o esperado, mesmo com os comandos escritos em linhas de receita separadas.
Quando .ONESHELL é especificado, apenas a primeira linha da receita é verificada quanto aos prefixos especiais ("@", "-" e "+"). Nas linhas seguintes, quando o SHELL é invocado, os caracteres especiais permanecem incluídos na linha da receita. Se você quiser iniciar sua receita com um desses caracteres especiais, terá de tomar cuidado para que ele não seja o primeiro caractere da primeira linha (por exemplo, adicionando um comentário). Assim, o exemplo a seguir é um erro de sintaxe em Perl, porque o primeiro "@" é removido pelo make:
.ONESHELL:
SHELL = /usr/bin/perl
.SHELLFLAGS = -e
show :
@f = qw(a b c);
print "@f\n";
No entanto, qualquer uma das duas formas a seguir funcionará corretamente:
.ONESHELL:
SHELL = /usr/bin/perl
.SHELLFLAGS = -e
show :
# Evita que o primeiro caractere da primeira linha seja "@"
@f = qw(a b c);
print "@f\n";
ou
.ONESHELL:
SHELL = /usr/bin/perl
.SHELLFLAGS = -e
show :
my @f = qw(a b c);
print "@f\n";
Como recurso especial, se o SHELL for considerado um shell no estilo POSIX, os prefixos especiais presentes nas linhas de receita "internas" (da segunda linha em diante) serão removidos antes de a receita ser processada. Esse recurso tem o objetivo de permitir que makefiles existentes funcionem corretamente, sem grandes modificações, quando o alvo especial .ONESHELL é adicionado. Como esses prefixos especiais não podem aparecer no início de uma linha em scripts de shell POSIX, nenhuma funcionalidade é perdida. Por exemplo, o seguinte funciona como esperado:
.ONESHELL:
foo : bar/lose
@cd $(@D)
@gobble $(@F) > ../$@
Ainda assim, mesmo com esse recurso especial, makefiles que usam .ONESHELL podem ter seu comportamento alterado de formas perceptíveis. Por exemplo, normalmente, se qualquer linha da receita falhar, a regra falha e nenhuma linha de receita posterior é processada. Sob .ONESHELL, porém, uma falha em qualquer linha exceto a última não será percebida pelo make. Você pode modificar .SHELLFLAGS para adicionar a opção -e ao shell, fazendo com que uma falha em qualquer ponto da linha de comando provoque a falha do shell, mas isso, por si só, também pode alterar o comportamento da receita. Em última análise, talvez seja necessário reescrever as linhas da receita de forma robusta para que funcionem sob .ONESHELL.
O programa usado como shell é obtido da variável SHELL. Se essa variável não estiver definida em seu makefile, o programa /bin/sh é usado como shell. Os argumentos passados ao shell são obtidos da variável .SHELLFLAGS. O valor padrão de .SHELLFLAGS é normalmente -c, ou -ec no modo de conformidade com POSIX.
Diferentemente da maioria das variáveis, a variável SHELL nunca é definida a partir do ambiente. Isso ocorre porque a variável de ambiente SHELL é usada para especificar a preferência pessoal do usuário quanto ao programa de shell usado interativamente. Seria muito ruim que essas escolhas pessoais afetassem o funcionamento dos makefiles. Consulte Variáveis do ambiente.
Além disso, quando você define SHELL em seu makefile, esse valor não é exportado no ambiente para as linhas de receita que o make invoca. Em vez disso, o valor herdado do ambiente do usuário (se houver) é exportado. Você pode alterar esse comportamento exportando explicitamente a variável SHELL (consulte Como comunicar variáveis a um sub-make), forçando-a a ser passada no ambiente para as linhas de receita.
No entanto, em MS-DOS e MS-Windows, o valor de SHELL presente no ambiente é usado, pois nesses sistemas a maioria dos usuários não define essa variável e, portanto, se ela estiver definida, é provável que tenha sido definida especificamente para uso com o make. Em MS-DOS, se a configuração de SHELL não for adequada ao make, você pode definir a variável MAKESHELL com o shell que deseja que o make use; se estiver definida, ela será usada como shell em vez do valor de SHELL.
O mecanismo de escolha de um shell em MS-DOS e MS-Windows é muito mais complexo do que em outros sistemas.
Em MS-DOS, se SHELL não estiver definido, o valor da variável COMSPEC (que está sempre definido) é usado em seu lugar.
O processamento das linhas que definem a variável SHELL em um makefile é diferente em MS-DOS. O shell padrão, command.com, é ridiculamente limitado em sua funcionalidade, e muitos usuários do make tendem a instalar um shell alternativo. Por isso, em MS-DOS, o make examina o valor de SHELL e altera seu comportamento conforme ele aponte para um shell no estilo Unix ou no estilo DOS. Isso permite uma funcionalidade razoável mesmo que SHELL aponte para command.com.
Se SHELL apontar para um shell no estilo Unix, o make em MS-DOS verifica adicionalmente se esse shell pode realmente ser encontrado; caso contrário, ele ignora a linha que define SHELL. Em MS-DOS, o GNU make procura o shell nos seguintes lugares:
SHELL. Por exemplo, se o makefile especificar "SHELL = /bin/sh", o make examinará o diretório /bin da unidade atual.
PATH, na ordem.
Em cada diretório examinado, o make procura primeiro o arquivo com o próprio nome (sh, no exemplo acima). Se não o encontrar, procura também, nesse diretório, arquivos com extensões conhecidas que indiquem um arquivo executável, como .exe, .com, .bat, .btm, .sh e outras.
Se qualquer uma dessas tentativas tiver êxito, o valor de SHELL é definido com o caminho completo do shell encontrado. Mas se nenhum for encontrado, o valor de SHELL não é alterado e, em consequência, a linha que o define é efetivamente ignorada. Isso garante que o make só ofereça suporte aos recursos específicos de um shell no estilo Unix em sistemas em que tal shell esteja efetivamente instalado.
Observe que essa busca estendida pelo shell só ocorre quando SHELL é definido a partir do makefile. Se for definido no ambiente ou na linha de comando, espera-se que você defina o caminho completo do shell por conta própria, exatamente como em Unix.
Em decorrência do processamento específico do DOS descrito acima, um makefile que contenha "SHELL = /bin/sh" (como fazem muitos makefiles de Unix) funcionará sem alterações em MS-DOS, desde que você tenha instalado sh.exe em algum diretório do PATH.
O GNU make sabe executar várias receitas ao mesmo tempo. Normalmente, o make executa apenas uma receita de cada vez, aguardando sua conclusão antes de executar a próxima. No entanto, a opção "-j" ou "--jobs" instrui o make a executar muitas receitas simultaneamente. Você também pode inibir a execução paralela, a partir do makefile, para alguns ou para todos os alvos (consulte Como desabilitar a execução paralela).
Em MS-DOS, a opção "-j" não tem efeito, pois esse sistema não oferece suporte a multiprocessamento.
Se a opção "-j" for seguida de um inteiro, esse é o número de receitas a executar de uma vez; isso é chamado de número de vagas de tarefa (job slots). Se não houver nada que se pareça com um inteiro após a opção "-j", não há limite para o número de vagas de tarefa. O número padrão de vagas de tarefa é um, o que significa execução serial (uma de cada vez).
Um problema relacionado à execução paralela surge ao lidar com invocações recursivas do make. Para mais detalhes sobre isso, consulte Como comunicar opções a um sub-make.
Se uma receita falhar (for terminada por um sinal ou sair com status diferente de zero) e os erros dessa receita não forem ignorados (consulte Erros nas receitas), as demais linhas de receita para refazer o mesmo alvo não serão executadas. Se uma receita falhar e a opção "-k" ou "--keep-going" não tiver sido especificada (consulte Resumo das opções), o make interrompe a execução. Quando o make termina por qualquer motivo (inclusive um sinal) com processos filhos ainda em execução, ele aguarda que eles terminem antes de efetivamente encerrar.
Quando a carga do sistema está alta, você provavelmente quer executar menos tarefas do que quando ela está baixa. Você pode usar a opção "-l" para instruir o make a limitar o número de tarefas executadas ao mesmo tempo com base na média de carga. A opção "-l" ou "--max-load" é seguida por um número de ponto flutuante. Por exemplo,
-l 2.5
faz com que o make não inicie mais de uma tarefa enquanto a média de carga estiver acima de 2,5. A opção "-l" sem número a seguir remove o limite de carga estabelecido por uma opção "-l" anterior.
Mais precisamente, quando o make vai iniciar uma tarefa e já há ao menos uma tarefa em execução, ele verifica a média de carga atual; se ela não estiver abaixo do limite dado em "-l", o make aguarda até que a média de carga fique abaixo desse limite ou até que todas as outras tarefas terminem.
Por padrão, não há limite de carga.
Se um makefile definir de forma completa e correta as dependências entre todos os seus alvos, então o make construirá corretamente as metas, esteja a execução paralela habilitada ou não. Essa é a forma ideal de escrever um makefile.
No entanto, há situações em que alguns ou todos os alvos de um makefile não podem ser executados em paralelo e em que não é viável adicionar os pré-requisitos para informar isso ao make. Nesses casos, o makefile pode desabilitar a execução paralela de diversas maneiras.
Se o alvo especial .NOTPARALLEL, sem pré-requisitos, for especificado em qualquer lugar, então toda a instância do make será executada de forma serial, independentemente da configuração de paralelismo. Por exemplo:
all: one two three one two three: ; @sleep 1; echo $@ .NOTPARALLEL:
Nesse caso, não importa como o make seja invocado, os alvos one, two e three serão executados de forma serial.
Se o alvo especial .NOTPARALLEL tiver pré-requisitos, então cada um desses pré-requisitos será considerado um alvo, e todos os pré-requisitos desses alvos serão executados de forma serial. Observe que os pré-requisitos só são executados de forma serial quando esse alvo é construído; se algum outro alvo listar os mesmos pré-requisitos e não estiver sujeito a .NOTPARALLEL, esses pré-requisitos poderão ser executados em paralelo. Por exemplo:
all: base notparallel base: one two three notparallel: one two three one two three: ; @sleep 1; echo $@ .NOTPARALLEL: notparallel
Aqui, "make -j base" executa os alvos one, two e three em paralelo, mas "make -j notparallel" os executa de forma serial. Se você executar "make -j all", eles serão executados em paralelo, pois base os lista como pré-requisitos e não está serializado.
O alvo .NOTPARALLEL não deve ter comandos associados.
Por fim, você pode usar o alvo especial .WAIT para controlar de forma mais detalhada a serialização de pré-requisitos específicos. Se esse alvo aparecer na lista de pré-requisitos e a execução paralela estiver habilitada, então o make não construirá nenhum dos pré-requisitos à direita de .WAIT até que todos os pré-requisitos à esquerda de .WAIT tenham sido concluídos. Por exemplo:
all: one two .WAIT three one two three: ; @sleep 1; echo $@
Se a execução paralela estiver habilitada, o make tentará construir one e two em paralelo, mas não começará a construir three até que ambos tenham sido concluídos.
Assim como ocorre com os alvos fornecidos a .NOTPARALLEL, o .WAIT só tem efeito ao construir o alvo em cuja lista de pré-requisitos ele aparece. Se os mesmos pré-requisitos aparecerem em outros alvos sem .WAIT, eles ainda poderão ser executados em paralelo. Por isso, nem o .NOTPARALLEL com alvos nem o .WAIT são meios tão confiáveis de controlar a execução paralela quanto a definição das relações de pré-requisitos. Ainda assim, são fáceis de usar e suficientes em situações menos complexas.
Um pré-requisito .WAIT não aparece em nenhuma das variáveis automáticas da regra.
Por portabilidade, você pode criar um alvo .WAIT real em seu makefile, mas isso não é necessário para usar esse recurso. Se você criar um alvo .WAIT, ele não deverá ter pré-requisitos nem comandos.
O recurso .WAIT também é implementado em outras versões do make e está especificado no padrão POSIX para o make.
Quando várias receitas são executadas em paralelo, a saída de cada uma aparece à medida que é gerada. Em consequência, mensagens de receitas diferentes podem se misturar e até aparecer sobrepostas na mesma linha, o que torna a saída muito difícil de ler.
Para evitar isso, você pode usar a opção "--output-sync" ("-O"). Essa opção instrui o make a armazenar a saída dos comandos que ele invoca e a exibi-la de uma só vez assim que cada comando for concluído. Além disso, se houver várias invocações recursivas do make em execução paralela, elas se coordenam entre si de modo que apenas uma gere saída por vez.
Se a exibição do diretório de trabalho estiver habilitada (consulte A opção "--print-directory"), as mensagens de "entrando no/saindo do diretório" serão exibidas antes e depois de cada grupo de saída. Se você não quiser ver essas mensagens, adicione a opção "--no-print-directory" a MAKEFLAGS.
Há quatro níveis de granularidade para a sincronização da saída, especificados ao fornecer um argumento à opção (por exemplo, "-Oline" ou "--output-sync=recurse").
noneEste é o padrão. Toda a saída é enviada diretamente tal como é gerada, sem nenhuma sincronização.
lineA saída de cada linha individual de uma receita é agrupada e exibida assim que essa linha é concluída. Se uma receita for composta por várias linhas, elas poderão se misturar com as linhas de outras receitas.
targetA saída de toda a receita de cada alvo é agrupada e exibida quando esse alvo é concluído. Este é o padrão quando a opção --output-sync ou -O é fornecida sem argumento.
recurseA saída de cada invocação recursiva do make é agrupada e exibida quando essa invocação recursiva é concluída.
Independentemente do modo escolhido, o tempo total de toda a construção não muda. O que muda é apenas a forma como a saída aparece.
Tanto o modo "target" quanto o modo "recurse" coletam a saída de toda a receita de um alvo e a exibem de forma ininterrupta quando a receita é concluída. A diferença entre eles está na forma como tratam as receitas que incluem invocações recursivas do make (consulte Uso recursivo do make). Para receitas que não têm linhas recursivas, os modos "target" e "recurse" se comportam exatamente da mesma forma.
Se você escolher o modo "recurse", as receitas que contêm invocações recursivas do make serão tratadas como qualquer outro alvo. Ou seja, a saída da receita, incluindo a saída do make recursivo, é armazenada e exibida depois que a receita inteira é concluída. Isso reúne em um bloco a saída de todos os alvos construídos por uma instância recursiva do make, o que às vezes facilita a compreensão da saída. Por outro lado, também pode resultar em longos períodos durante a construção em que nenhuma saída é vista, seguidos de uma grande quantidade de saída exibida de uma só vez. Se você não estiver acompanhando o progresso da construção em tempo real, mas sim consultando o log da construção mais tarde, essa pode ser a melhor opção.
Se você estiver acompanhando a saída em tempo real, longos silêncios durante a construção podem ser frustrantes. O modo de sincronização de saída "target" detecta quando o make está prestes a ser invocado recursivamente da maneira padrão e não sincroniza a saída dessa linha. O make recursivo realiza a sincronização para seus próprios alvos, e a saída de cada um é exibida assim que é concluída. Observe que a saída das linhas recursivas da receita não é sincronizada (por exemplo, se uma linha recursiva exibir uma mensagem antes de executar o make, essa mensagem não será sincronizada).
O modo "line" é útil para uma interface (frontend) que monitora a saída do make para acompanhar o início e o término das receitas.
Alguns dos programas que o make invoca alteram seu comportamento conforme determinem que a saída vai para um terminal ou para um arquivo (modos muitas vezes chamados de "interativo" e "não interativo"). Por exemplo, muitos programas que podem colorir a saída não a colorem se determinarem que não estão escrevendo em um terminal. Se o seu makefile invoca programas assim, o uso das opções de sincronização de saída fará com que eles acreditem estar operando em modo "não interativo", embora a saída acabe por chegar ao terminal.
Dois processos não podem receber entrada do mesmo dispositivo ao mesmo tempo. Para garantir que apenas uma receita por vez receba entrada do terminal, o make desabilita os fluxos de entrada padrão de todas as receitas em execução, exceto uma. Se outra receita tentar ler da entrada padrão, geralmente ocorre um erro fatal (um sinal "Broken pipe").
Não é possível prever qual receita receberá o fluxo de entrada padrão válido (aquele vindo do terminal ou do destino para onde a entrada padrão do make foi redirecionada). A primeira receita executada sempre o recebe primeiro, e a primeira receita iniciada após o término dessa o recebe em seguida, e assim por diante.
Se encontrarmos uma alternativa melhor, pretendemos mudar essa parte do comportamento do make. Enquanto isso, se você estiver usando o recurso de execução paralela, nenhuma receita deve usar a entrada padrão. Por outro lado, se você não estiver usando esse recurso, a entrada padrão funciona normalmente em todas as receitas.
Após o retorno de cada invocação do shell, o make examina seu status de saída. Se o shell foi concluído com êxito (status de saída zero), a próxima linha da receita é executada em um novo shell; quando a última linha termina, a regra está completa.
Se houver um erro (status de saída diferente de zero), o make desiste da regra atual e, possivelmente, de todas as regras.
Às vezes, a falha de uma linha de receita não indica um problema. Por exemplo, você pode usar o comando mkdir para garantir que um diretório exista. Se o diretório já existir, o mkdir relatará um erro, mas você provavelmente ainda quer que o make prossiga.
Para ignorar os erros de uma linha de receita, escreva um "-" no início do texto da linha (depois da tabulação inicial). O "-" é descartado antes de a linha ser repassada ao shell para execução.
Por exemplo,
clean:
-rm -f *.o
Isso faz com que o make prossiga mesmo que o rm não consiga remover um arquivo.
Quando você executa o make com a opção "-i" ou "--ignore-errors", os erros são ignorados em todas as receitas de todas as regras. Uma regra para o alvo especial .IGNORE no makefile, sem pré-requisitos, tem o mesmo efeito. Essa forma é menos flexível, mas às vezes é útil.
Quando os erros são ignorados em razão dos sinalizadores "-" ou "-i", o make trata o retorno com erro da mesma forma que o êxito, exceto que exibe uma mensagem informando o código de status com o qual o shell saiu e indicando que o erro foi ignorado.
Quando ocorre um erro que não foi instruído a ignorar, isso significa que o alvo atual não pode ser refeito corretamente e que os demais alvos que dependem dele, direta ou indiretamente, também não podem ser refeitos. Como os pré-requisitos desses alvos não foram cumpridos, nenhuma outra receita é executada para eles.
Normalmente, o make desiste imediatamente nessa situação, retornando um status diferente de zero. No entanto, se a opção "-k" ou "--keep-going" estiver especificada, o make continua a considerar os outros pré-requisitos dos alvos pendentes, refazendo-os se necessário, antes de desistir e retornar um status diferente de zero. Por exemplo, depois de um erro ao compilar um arquivo objeto, "make -k" continua compilando os demais arquivos objeto, mesmo já sabendo que será impossível ligá-los (link). Consulte Resumo das opções.
O comportamento normal pressupõe que seu objetivo seja deixar atualizados os alvos especificados; assim que o make descobre que isso é impossível, convém relatar a falha de imediato. A opção "-k" diz que o objetivo real é testar o maior número possível de alterações feitas no programa — talvez para encontrar diversos problemas independentes e poder corrigi-los todos de uma vez antes da próxima tentativa de compilação. É por isso que o comando compile do Emacs passa, por padrão, a opção "-k".
Normalmente, quando uma linha de receita falha, se ela tiver alterado um pouco que seja o arquivo do alvo, esse arquivo fica corrompido e não pode ser usado — ou, ao menos, não está completamente atualizado. Ainda assim, o carimbo de data/hora do arquivo indica que ele está agora atualizado, de modo que, na próxima vez que o make for executado, ele não tentará atualizá-lo. A situação é exatamente a mesma de quando o shell é terminado por um sinal; consulte Interrupção ou término do make. Por isso, em geral, a atitude correta é remover o arquivo do alvo se a receita falhar depois de ter começado a alterar o arquivo. O make fará isso se .DELETE_ON_ERROR aparecer como alvo. Isso é quase sempre o que você quer que o make faça, mas não é a prática histórica; por isso, por compatibilidade, você precisa solicitá-lo explicitamente.
Se o make receber um sinal fatal enquanto um shell está em execução, ele poderá remover o arquivo do alvo que essa receita deveria atualizar. Isso é feito quando a hora da última modificação do arquivo do alvo mudou desde o momento em que o make a verificou pela primeira vez.
O objetivo de remover o alvo é garantir que ele seja refeito do zero na próxima vez que o make for executado. Por quê? Suponha que você pressione Ctrl-c enquanto um compilador está em execução e que ele tenha acabado de começar a escrever o arquivo objeto foo.o. O Ctrl-c termina o compilador, deixando um arquivo incompleto cuja hora da última modificação é mais recente que a do arquivo fonte foo.c. Mas o make também recebe o sinal Ctrl-c e remove esse arquivo incompleto. Se o make não fizesse isso, na próxima invocação ele consideraria foo.o como não precisando de atualização — e, em consequência, o ligador (linker) tentaria ligar um arquivo objeto pela metade, produzindo mensagens de erro estranhas.
Você pode impedir a remoção de um arquivo de alvo dessa forma fazendo o alvo especial .PRECIOUS depender dele. Antes de refazer um alvo, o make verifica se ele aparece como pré-requisito de .PRECIOUS e, com base nisso, decide se deve removê-lo caso um sinal ocorra. Algumas razões para querer isso são: o alvo é atualizado de alguma maneira atômica (indivisível); ele existe apenas para registrar uma hora de modificação (e seu conteúdo não importa); ou ele precisa existir sempre para evitar outros tipos de problemas.
O make faz o possível para fazer a limpeza, mas há situações em que isso é impossível. Por exemplo, o make pode ser terminado por um sinal que não consegue capturar. Ou um dos programas que o make invoca pode ser terminado ou travar, deixando um arquivo de alvo corrompido cujo carimbo de data/hora indica que está atualizado; nesse caso, o make não percebe que aquela falha exigiria a limpeza do alvo. Ou ainda, o próprio make pode encontrar um defeito (bug) e travar.
Por essas razões, o melhor é escrever receitas defensivas (defensive recipe). Receitas defensivas não deixam alvos corrompidos, mesmo que falhem. A forma mais comum é criar um arquivo temporário em vez de atualizar o alvo diretamente e, depois, renomear o arquivo temporário com o nome final do alvo. Alguns compiladores já funcionam dessa maneira, de modo que, nesses casos, não é necessário escrever uma receita defensiva.
O uso recursivo do make significa usar o make como um comando dentro de um makefile. Essa técnica é útil quando você quer makefiles separados para os diversos subsistemas que compõem um sistema maior. Por exemplo, suponha que você tenha um subdiretório subdir com seu próprio makefile e queira que o makefile do diretório que o contém execute o make nesse subdiretório. Você pode fazer isso escrevendo o seguinte:
subsystem:
cd subdir && $(MAKE)
ou, de forma equivalente, o seguinte (consulte Resumo das opções):
subsystem:
$(MAKE) -C subdir
Você pode escrever comandos recursivos do make simplesmente copiando este exemplo, mas há muito que saber sobre como e por que eles funcionam e sobre como o sub-make se relaciona com o make de nível superior. Também pode ser útil declarar como ".PHONY" o alvo que invoca um comando recursivo do make (para mais detalhes sobre quando isso é útil, consulte Alvos falsos).
Por conveniência, ao iniciar (depois de processar quaisquer opções -C), o GNU make define a variável CURDIR com o nome de caminho do diretório de trabalho atual. Esse valor nunca é tocado pelo make depois disso: em particular, observe que o valor de CURDIR não muda se você incluir (include) arquivos de outros diretórios. Esse valor tem a mesma precedência que teria se fosse definido no makefile (por padrão, uma variável de ambiente CURDIR não sobrepõe esse valor). Observe que definir essa variável não afeta o funcionamento do make (por exemplo, o make não muda seu diretório de trabalho).
Em comandos recursivos do make, você deve sempre usar a variável MAKE, e não o nome de comando explícito "make", como mostrado a seguir:
subsystem:
cd subdir && $(MAKE)
O valor dessa variável é o nome de arquivo com o qual o make foi invocado. Se esse nome de arquivo fosse /bin/make, a receita executada seria "cd subdir && /bin/make". Se você usar uma versão especial do make para executar o makefile de nível superior, a mesma versão especial será executada nas invocações recursivas.
Como recurso especial, usar a variável MAKE na receita de uma regra altera os efeitos das opções "-t" ("--touch"), "-n" ("--just-print") e "-q" ("--question"). Usar a variável MAKE tem o mesmo efeito que colocar um caractere "+" no início da linha da receita. Consulte Em vez de executar as receitas. Esse recurso especial só é ativado quando a variável MAKE aparece diretamente na receita; ele não se aplica quando a variável MAKE é referenciada por meio da expansão de outra variável. Nesse caso, você precisa usar o token "+" para obter esses efeitos especiais.
Considere o comando "make -t" no exemplo acima. (A opção "-t" marca os alvos como atualizados sem executar nenhuma receita; consulte Em vez de executar as receitas.) Seguindo a definição usual de "-t", o comando "make -t" desse exemplo apenas criaria um arquivo chamado subsystem e não faria mais nada. O que você realmente quer é executar "cd subdir && make -t", mas isso exigiria executar a receita, e "-t" diz para não executar receitas.
O recurso especial faz exatamente o que você deseja. Sempre que uma linha de receita de uma regra contém a variável MAKE, as opções "-t", "-n" e "-q" não se aplicam a essa linha. As linhas de receita que contêm MAKE são executadas normalmente, apesar da presença de opções que impedem a execução da maioria das receitas. E o mecanismo normal de MAKEFLAGS repassa as opções ao sub-make (consulte Como comunicar opções a um sub-make), de modo que seu pedido de tocar (touch) os arquivos ou de exibir as receitas se propaga ao subsistema.
Os valores das variáveis do make de nível superior podem ser passados ao sub-make por meio do ambiente, mediante solicitação explícita. Essas variáveis são definidas no sub-make como valores padrão, mas não sobrepõem as variáveis definidas no makefile usado pelo sub-make, a menos que você use a opção "-e" (consulte Resumo das opções).
Para passar, ou exportar (export), uma variável para os níveis inferiores, o make adiciona a variável e seu valor ao ambiente no qual executa cada linha da receita. O sub-make, por sua vez, usa esse ambiente para inicializar sua tabela de valores de variáveis. Consulte Variáveis do ambiente.
Exceto mediante solicitação explícita, o make exporta uma variável apenas se ela já estiver definida no ambiente desde o início, ou se for definida na linha de comando e seu nome consistir apenas em letras, dígitos e sublinhados.
O valor da variável SHELL do make não é exportado. Em vez disso, o valor da variável SHELL presente no ambiente de invocação é passado ao sub-make. Você pode usar a diretiva export, descrita a seguir, para fazer o make exportar o valor de SHELL. Consulte Como escolher um shell.
A variável especial MAKEFLAGS é sempre exportada (a menos que você a desexporte com unexport). A variável MAKEFILES é exportada se você lhe atribuir algum valor.
O make repassa automaticamente para os níveis inferiores os valores de variáveis definidos na linha de comando, colocando-os na variável MAKEFLAGS. Consulte Como comunicar opções a um sub-make.
Se uma variável tiver sido criada por padrão pelo make (consulte Variáveis usadas pelas regras implícitas), normalmente ela não é repassada aos níveis inferiores. O sub-make as define por conta própria.
Se você quiser exportar variáveis específicas para um sub-make, use a diretiva export da seguinte forma:
export variable …
Por outro lado, se você quiser impedir que uma variável seja exportada, use a diretiva unexport da seguinte forma:
unexport variable …
Em ambas as formas, os argumentos de export e unexport são expandidos. Assim, você pode especificar variáveis ou funções que se expandam em (uma lista de) nomes de variáveis a serem (un)exportadas.
Por conveniência, você também pode definir e exportar uma variável ao mesmo tempo:
export variable = value
o que tem o mesmo resultado que:
variable = value export variable
E
export variable := value
tem o mesmo resultado que:
variable := value export variable
De modo semelhante,
export variable += value
é exatamente o mesmo que:
variable += value export variable
Consulte Acrescentar texto a variáveis.
Talvez você tenha notado que as diretivas export e unexport funcionam no make exatamente como funcionam no shell sh.
Se você quiser exportar todas as variáveis por padrão, pode usar export sozinho:
export
Isso instrui o make a exportar também as variáveis não mencionadas explicitamente em uma diretiva export ou unexport. As variáveis indicadas em uma diretiva unexport, mesmo assim, não são exportadas.
O comportamento provocado por export sozinho era o padrão em versões antigas do GNU make. Se o seu makefile depende desse comportamento e você quer manter compatibilidade com versões antigas do make, você pode adicionar o alvo especial .EXPORT_ALL_VARIABLES ao makefile em vez de usar a diretiva export. Ele será ignorado pelas versões antigas do make, ao passo que a diretiva export causaria um erro de sintaxe nelas.
Ao exportar variáveis por padrão usando export sozinho ou .EXPORT_ALL_VARIABLES, apenas as variáveis cujos nomes consistem em caracteres alfanuméricos e sublinhados são exportadas. Para exportar outras variáveis, você precisa nomeá-las individualmente em uma diretiva export.
Para adicionar o valor de uma variável ao ambiente, é necessário expandi-lo. Se a expansão da variável tiver efeitos colaterais (como ocorre com funções como info ou eval), esses efeitos colaterais ocorrerão toda vez que um comando for invocado. Você pode evitar isso usando, para essas variáveis, nomes que não sejam exportados por padrão. De qualquer forma, a melhor solução é não usar de modo algum esse recurso de "exportar por padrão" e, em vez disso, exportar explicitamente as variáveis em questão, nomeando-as.
Usar unexport sozinho instrui o make a não exportar variáveis por padrão. Como esse é o comportamento padrão, isso só é necessário se export tiver sido usado sozinho anteriormente (provavelmente em um makefile incluído). Você não pode usar export e unexport sozinhos para exportar variáveis em algumas receitas e não em outras. A última diretiva export ou unexport que aparecer sozinha determina o comportamento de toda a execução do make.
Como recurso especial, a variável MAKELEVEL é alterada ao ser passada de nível para nível inferior. O valor dessa variável é uma cadeia que representa, em decimal, a profundidade do nível: "0" para o make de nível superior, "1" para um sub-make, "2" para um sub-sub-make, e assim por diante. Esse incremento ocorre quando o make configura o ambiente para uma receita.
O principal uso de MAKELEVEL é testá-la dentro de diretivas condicionais (consulte Partes condicionais dos makefiles). Dessa forma, você pode escrever um makefile que se comporte de um jeito quando executado recursivamente e de outro quando executado diretamente por você.
Você pode usar a variável MAKEFILES para fazer com que todos os comandos do sub-make usem makefiles adicionais. O valor de MAKEFILES é uma lista de nomes de arquivos separados por espaços em branco. Se essa variável estiver definida em um makefile de nível externo, ela é passada para os níveis inferiores por meio do ambiente; ela então funciona como uma lista de makefiles adicionais que o sub-make lê antes dos makefiles usuais ou especificados. Consulte A variável MAKEFILES.
Sinalizadores como "-s" e "-k" são passados automaticamente ao sub-make por meio da variável MAKEFLAGS. Essa variável é configurada automaticamente pelo make para conter as letras dos sinalizadores que o make recebeu. Assim, se você executar "make -ks", MAKEFLAGS recebe o valor "ks".
Em consequência, todos os sub-makes recebem em seu ambiente o valor de MAKEFLAGS. Em resposta, o sub-make extrai os sinalizadores desse valor e os processa como se tivessem sido dados como argumentos. Consulte Resumo das opções. Isso significa que, ao contrário de outras variáveis de ambiente, o MAKEFLAGS especificado no ambiente tem precedência sobre o MAKEFLAGS especificado no makefile.
O valor de MAKEFLAGS é um conjunto (possivelmente vazio) de caracteres que representam opções de uma só letra que não recebem argumento, seguido por um espaço e pelas opções que recebem argumento ou que têm nomes longos. Se uma opção tiver tanto a versão de uma só letra quanto a versão de nome longo, a versão de uma só letra é sempre preferida. Se não houver nenhuma opção de uma só letra na linha de comando, o valor de MAKEFLAGS começa com um espaço.
De modo semelhante, as variáveis definidas na linha de comando também são passadas ao sub-make por meio de MAKEFLAGS. As palavras no valor de MAKEFLAGS que contêm "=" são tratadas pelo make como definições de variáveis, como se tivessem aparecido na linha de comando. Consulte Sobrepor variáveis.
As opções "-C", "-f", "-o" e "-W" não são colocadas em MAKEFLAGS; essas opções não são passadas aos níveis inferiores.
A opção "-j" é um caso especial (consulte Execução paralela). Se você defini-la com algum valor numérico "N" e seu sistema operacional der suporte a isso (a maioria dos sistemas UNIX dá, mas os demais geralmente não), o make pai e todos os sub-makes se coordenam para que, no total, haja apenas "N" tarefas executando simultaneamente entre todos eles. Observe que as tarefas marcadas como recursivas (consulte Em vez de executar as receitas) não são contadas no total de tarefas (caso contrário, poderíamos ter "N" sub-makes em execução, sem deixar nenhuma vaga para o trabalho real!).
Se o seu sistema operacional não der suporte à coordenação acima, "-j" não é adicionado a MAKEFLAGS; assim, os sub-makes são executados em modo não paralelo. Se a opção "-j" fosse passada ao sub-make, você acabaria executando em paralelo muito mais tarefas do que solicitou. Se você fornecer "-j" sem argumento numérico, significa executar o máximo possível de tarefas em paralelo, e isso é passado aos níveis inferiores, pois muitos infinitos não diferem de um único infinito.
Se você não quiser passar os outros sinalizadores aos níveis inferiores, precisará alterar o valor de MAKEFLAGS, da seguinte forma:
subsystem:
cd subdir && $(MAKE) MAKEFLAGS=
As definições de variáveis da linha de comando, na verdade, aparecem na variável MAKEOVERRIDES, e MAKEFLAGS contém uma referência a essa variável. Se você quiser passar os sinalizadores aos níveis inferiores normalmente, mas não as definições de variáveis da linha de comando, pode redefinir MAKEOVERRIDES como vazio, da seguinte forma:
MAKEOVERRIDES =
Isso não é algo que você costuma fazer. Contudo, alguns sistemas têm um limite fixo pequeno para o tamanho do ambiente, e colocar tanta informação no valor de MAKEFLAGS pode ultrapassá-lo. Se você vir a mensagem de erro "Arg list too long", esta pode ser a causa. (Para conformidade estrita com POSIX.2, se o alvo especial ".POSIX" aparecer no makefile, alterar MAKEOVERRIDES não afeta MAKEFLAGS. Você provavelmente não precisa se preocupar com isso.)
Por compatibilidade histórica, existe também uma variável muito parecida, MFLAGS. Ela tem o mesmo valor que MAKEFLAGS, exceto por não conter as definições de variáveis da linha de comando e por começar sempre com um hífen, a menos que esteja vazia (MAKEFLAGS começa com um hífen apenas quando começa com uma opção que não tem versão de uma só letra, como "--warn-undefined-variables"). MFLAGS era usada tradicionalmente de forma explícita em comandos recursivos do make, assim:
subsystem:
cd subdir && $(MAKE) $(MFLAGS)
Mas agora que existe MAKEFLAGS, esse uso é desnecessário. Use essa técnica se quiser manter o makefile compatível com programas make antigos; ela funciona bem também em versões mais recentes do make.
A variável MAKEFLAGS também é útil quando você quer definir determinadas opções, como "-k" (consulte Resumo das opções), toda vez que executa o make. Basta colocar o valor de MAKEFLAGS no ambiente. Você também pode definir MAKEFLAGS dentro de um makefile para especificar sinalizadores adicionais que devam estar em vigor naquele makefile. (Observe que MFLAGS não pode ser usada para esse fim: aquela variável é definida apenas por compatibilidade, e o make não interpreta de forma alguma o valor que você definir nela.)
Quando o make interpreta o valor de MAKEFLAGS (vindo do ambiente ou de um makefile), primeiro acrescenta um hífen ao início do valor caso ele ainda não comece com um. Em seguida, divide o valor em palavras separadas por espaços em branco e analisa essas palavras como se fossem opções dadas na linha de comando (exceto que "-C", "-f", "-h", "-o", "-W" e suas versões de nome longo são ignoradas, e uma opção inválida não causa erro).
Se você colocar MAKEFLAGS no ambiente, tome cuidado para nunca incluir opções que alterem drasticamente o funcionamento do make e que arruínem o propósito do seu makefile ou do próprio make. Por exemplo, colocar as opções "-t", "-n" ou "-q" em uma dessas variáveis pode ter resultados desastrosos e certamente terá efeitos no mínimo surpreendentes e provavelmente incômodos.
Se você também quiser usar outras implementações do make além do GNU make e, por isso, não quiser adicionar sinalizadores específicos do GNU make à variável MAKEFLAGS, pode adicioná-los à variável GNUMAKEFLAGS. Essa variável é analisada imediatamente antes de MAKEFLAGS, da mesma forma que MAKEFLAGS. Ao montar o MAKEFLAGS a ser passado para um make recursivo, o make inclui todos os sinalizadores, inclusive os obtidos de GNUMAKEFLAGS. Em consequência, depois de analisar GNUMAKEFLAGS, o GNU make define essa variável como uma cadeia vazia para evitar a duplicação de sinalizadores durante a recursão.
O melhor é usar em GNUMAKEFLAGS apenas sinalizadores que não alterem de fato o comportamento do makefile. Se o seu makefile exigir o GNU Make de qualquer maneira, basta usar MAKEFLAGS. Sinalizadores como "--no-print-directory" ou "--output-sync" podem ser adequados para GNUMAKEFLAGS.
Se você usar vários níveis de invocações recursivas do make, a opção "-w" ou "--print-directory" pode tornar a saída muito mais fácil de entender, fazendo o make exibir cada diretório ao começar e ao terminar de processá-lo. Por exemplo, se você executar "make -w" no diretório /u/gnu/make, o make exibe uma linha como esta antes de fazer qualquer outra coisa:
make: Entering directory `/u/gnu/make'.
e uma linha como esta quando o processamento for concluído:
make: Leaving directory `/u/gnu/make'.
Normalmente, você não precisa especificar essa opção, porque o "make" o faz automaticamente: "-w" é ativada automaticamente quando você usa a opção "-C" e nos sub-makes. No entanto, o make não ativa "-w" automaticamente se você também estiver usando "-s", que instrui a operar em silêncio, ou se você usar "--no-print-directory", que a desabilita explicitamente.
Quando a mesma sequência de comandos é útil para criar vários alvos, você pode defini-la como uma sequência predefinida (canned sequence) com a diretiva define e referenciar essa sequência predefinida a partir das receitas desses alvos. A sequência predefinida é, na verdade, uma variável, de modo que seu nome não deve entrar em conflito com outros nomes de variáveis.
Aqui está um exemplo de definição de uma receita predefinida:
define run-yacc = yacc $(firstword $^) mv y.tab.c $@ endef
Aqui, run-yacc é o nome da variável que está sendo definida; endef marca o fim da definição, e as linhas entre eles são os comandos. A diretiva define não expande as referências a variáveis nem as chamadas de função dentro da sequência predefinida; o caractere "$", os parênteses, os nomes de variáveis e tudo o mais passam a fazer parte do valor da variável que você está definindo. Para uma descrição completa de define, consulte Definir variáveis de múltiplas linhas.
O primeiro comando deste exemplo executa o Yacc sobre o primeiro pré-requisito de qualquer regra que use esta sequência predefinida. O arquivo de saída do Yacc é sempre chamado de y.tab.c. O segundo comando move essa saída para o nome do arquivo do alvo da regra.
Para usar a sequência predefinida, atribua a variável à receita de uma regra. Você pode atribuí-la como qualquer outra variável (consulte Fundamentos das referências a variáveis). Como as variáveis definidas por define são variáveis de expansão recursiva, todas as referências a variáveis que você escreveu dentro de define são expandidas aqui e agora. Por exemplo:
foo.c : foo.y
$(run-yacc)
Quando "$^" aparece no valor de run-yacc, ele é substituído por "foo.y", e "$@" é substituído por "foo.c".
Este é um exemplo realista, mas este caso específico não é, na verdade, necessário, porque o make tem uma regra implícita que determina esses comandos com base nos nomes de arquivos envolvidos (consulte Uso de regras implícitas).
Na execução das receitas, cada linha de uma sequência predefinida é tratada como se essa linha aparecesse sozinha na regra, precedida por uma tabulação. Em particular, o make invoca um subshell separado para cada linha. Você pode usar os prefixos especiais que atuam sobre uma linha de comando ("@", "-" e "+") em cada linha de uma sequência predefinida. Consulte Como escrever receitas em regras. Por exemplo, usando esta sequência predefinida:
define frobnicate = @echo "frobnicating target $@" frob-step-1 $< -o $@-step-1 frob-step-2 $@-step-1 -o $@ endef
o make não fará o eco da primeira linha, o comando echo. Mas fará o eco das duas linhas de receita seguintes.
Por outro lado, os prefixos colocados na linha de receita que referencia uma sequência predefinida se aplicam a todas as linhas dessa sequência. Assim, a seguinte regra:
frob.out: frob.in
@$(frobnicate)
não faz o eco de nenhuma linha da receita. (Para uma descrição completa de "@", consulte Eco das receitas.)
Às vezes é útil definir receitas que não fazem nada. Isso é feito simplesmente fornecendo uma receita composta apenas por espaços em branco. Por exemplo:
target: ;
Isso define uma receita vazia para target. Você também pode usar uma linha que comece com o prefixo de receita para definir uma receita vazia, mas isso é confuso, porque tal linha parece estar vazia.
Você pode se perguntar por que iria querer definir uma receita que não faz nada. Uma das razões para isso ser útil é impedir que um alvo receba receitas implícitas (vindas de uma regra implícita ou do alvo especial .DEFAULT; consulte Uso de regras implícitas e Como definir regras padrão de último recurso).
Receitas vazias também podem ser usadas para evitar erros em alvos que são criados como efeito colateral de outra receita. Se o alvo não existir, a receita vazia garante que o make não reclame de não saber como criar o alvo e considere o alvo desatualizado.
Você pode se sentir tentado a definir uma receita vazia para um alvo que não é um arquivo real, mas que existe apenas para fazer com que seus pré-requisitos sejam refeitos. No entanto, essa não é a melhor maneira de fazer isso, porque os pré-requisitos podem não ser refeitos corretamente se o arquivo do alvo realmente existir. Para uma forma melhor de fazer isso, consulte Alvos falsos.