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

3 Como escrever Makefiles

As informações que dizem ao make como recompilar um sistema vêm da leitura de uma base de dados chamada makefile.

3.1 O que um makefile contém

Um makefile contém cinco tipos de coisas: regras explícitas, regras implícitas, definições de variáveis, diretivas (directives) e comentários. As regras, as variáveis e as diretivas são descritas em detalhe nos capítulos posteriores.

3.1.1 Dividir linhas longas

Os makefiles usam uma sintaxe «baseada em linhas», na qual o caractere de nova linha é especial e marca o fim de uma instrução. O GNU make não impõe limite ao comprimento de uma linha de instrução, até o tamanho da memória do seu computador.

No entanto, é difícil ler linhas longas demais para serem exibidas sem quebra automática ou rolagem. Por isso, você pode formatar seus makefiles para facilitar a leitura inserindo novas linhas no meio de uma instrução: faça isso escapando as novas linhas internas com um caractere de barra invertida (\). Quando for necessário distinguir, chamaremos de «linha física» uma única linha terminada por uma nova linha (esteja ela escapada ou não) e de «linha lógica» uma instrução completa que inclui todas as novas linhas escapadas até a primeira nova linha não escapada.

A forma como as combinações de barra invertida/nova linha são tratadas depende de a instrução ser uma linha de receita ou uma linha que não é de receita. O tratamento da barra invertida/nova linha em uma linha de receita é discutido mais adiante (consulte Dividir linhas de receita).

Fora das linhas de receita, as combinações de barra invertida/nova linha são convertidas em um único caractere de espaço. Feito isso, todo o espaço em branco em torno da barra invertida/nova linha é condensado em um único espaço: isso inclui todo o espaço em branco que precede a barra invertida, todo o espaço em branco no início da linha após a barra invertida/nova linha e quaisquer combinações consecutivas de barra invertida/nova linha.

Se o alvo especial .POSIX estiver definido, o tratamento da barra invertida/nova linha é ligeiramente modificado para estar em conformidade com o POSIX.2: primeiro, o espaço em branco que precede uma barra invertida não é removido; segundo, barras invertidas/novas linhas consecutivas não são condensadas.

Dividir sem adicionar espaço em branco

Se você precisar dividir uma linha mas não quiser adicionar nenhum espaço em branco, pode usar um truque sutil: substitua os pares de barra invertida/nova linha pelos três caracteres cifrão, barra invertida e nova linha:

var := one$\
       word

Depois que o make remove a barra invertida/nova linha e condensa a linha seguinte em um único espaço, isso equivale a:

var := one$ word

Em seguida, o make realiza a expansão de variáveis. A referência à variável «$ » refere-se a uma variável com o nome de um caractere « » (espaço), que não existe, e portanto expande para a cadeia vazia, resultando em uma atribuição final equivalente a:

var := oneword

3.2 Que nome dar ao seu makefile

Por padrão, quando o make procura pelo makefile, ele tenta os seguintes nomes, nesta ordem: GNUmakefile, makefile e Makefile.

Normalmente, você deve dar ao seu makefile o nome makefile ou Makefile. (Recomendamos Makefile porque ele aparece em destaque perto do início de uma listagem de diretório, bem próximo de outros arquivos importantes, como o README.) O primeiro nome verificado, GNUmakefile, não é recomendado para a maioria dos makefiles. Você deve usar esse nome apenas se tiver um makefile específico para o GNU make e que não será compreendido por outras versões do make. Outros programas make procuram por makefile e Makefile, mas não por GNUmakefile.

Se o make não encontrar nenhum desses nomes, ele não usa nenhum makefile. Nesse caso, você deve especificar uma meta como argumento de comando, e o make tentará descobrir como refazê-la usando apenas suas regras implícitas embutidas. Consulte Uso de regras implícitas.

Se você quiser usar um nome não padrão para o seu makefile, pode especificar o nome do makefile com a opção «-f» ou «--file». Os argumentos «-f name» ou «--file=name» dizem ao make para ler o arquivo name como o makefile. Se você usar mais de uma opção «-f» ou «--file», poderá especificar vários makefiles. Todos os makefiles são efetivamente concatenados na ordem especificada. Os nomes de makefile padrão GNUmakefile, makefile e Makefile não são verificados automaticamente se você especificar «-f» ou «--file».

3.3 Incluir outros makefiles

A diretiva include diz ao make para suspender a leitura do makefile atual e ler um ou mais outros makefiles antes de continuar. A diretiva é uma linha no makefile parecida com esta:

include filenames

filenames pode conter padrões de nome de arquivo do shell. Se filenames estiver vazio, nada é incluído e nenhum erro é exibido.

Espaços extras são permitidos e ignorados no início da linha, mas o primeiro caractere não pode ser uma tabulação (ou o valor de .RECIPEPREFIX); se a linha começar com uma tabulação, ela será considerada uma linha de receita. É obrigatório haver espaço em branco entre include e os nomes dos arquivos, e entre os nomes dos arquivos; espaço em branco extra é ignorado ali e ao final da diretiva. É permitido um comentário começando com «#» ao final da linha. Se os nomes dos arquivos contiverem referências a variáveis ou funções, elas são expandidas. Consulte Como usar variáveis.

Por exemplo, se você tiver três arquivos .mk, a.mk, b.mk e c.mk, e $(bar) expandir para bish bash, então a seguinte expressão

include foo *.mk $(bar)

equivale a

include foo a.mk b.mk c.mk bish bash

Quando o make processa uma diretiva include, ele suspende a leitura do makefile que a contém e lê cada arquivo listado, um a um. Quando termina, o make retoma a leitura do makefile em que a diretiva aparece.

Uma ocasião para usar diretivas include é quando vários programas, tratados por makefiles individuais em diretórios distintos, precisam usar um conjunto comum de definições de variáveis (consulte Definir variáveis) ou de regras de padrão (consulte Definição e redefinição de regras de padrão).

Outra dessas ocasiões é quando você quer gerar pré-requisitos a partir de arquivos fonte automaticamente; os pré-requisitos podem ser colocados em um arquivo que é incluído pelo makefile principal. Essa prática é, em geral, mais limpa do que a de, de alguma forma, acrescentar os pré-requisitos ao fim do makefile principal, como tradicionalmente se fazia com outras versões do make. Consulte Gerar pré-requisitos automaticamente.

Se o nome especificado não começar com uma barra (ou com uma letra de unidade e dois-pontos, quando o GNU Make é compilado com suporte a caminhos do MS-DOS / MS-Windows) e o arquivo não for encontrado no diretório atual, vários outros diretórios são pesquisados. Primeiro, são pesquisados quaisquer diretórios especificados com as opções «-I» ou «--include-dir» (consulte Resumo das opções). Em seguida, os seguintes diretórios (se existirem) são pesquisados, nesta ordem: prefix/include (normalmente /usr/local/include 1), /usr/gnu/include, /usr/local/include, /usr/include.

A variável .INCLUDE_DIRS contém a lista atual de diretórios em que o make pesquisará por arquivos incluídos. Consulte Outras variáveis especiais.

Você pode evitar a pesquisa nesses diretórios padrão acrescentando à linha de comando a opção -I com o valor especial - (por exemplo, -I-). Isso fará com que o make esqueça quaisquer diretórios de inclusão já definidos, incluindo os diretórios padrão.

Se um makefile incluído não puder ser encontrado em nenhum desses diretórios, isso não é um erro imediatamente fatal; o processamento do makefile que contém o include continua. Depois de terminar de ler os makefiles, o make tentará refazer qualquer um que esteja desatualizado ou que não exista. Consulte Como os makefiles são refeitos. Somente depois de não conseguir encontrar uma regra para refazer o makefile, ou de encontrar uma regra cuja receita falhou, é que o make diagnostica o makefile ausente como um erro fatal.

Se você quiser que o make simplesmente ignore um makefile que não existe ou não pode ser refeito, sem mensagem de erro, use a diretiva -include em vez de include, assim:

-include filenames

Isso funciona como include em todos os aspectos, exceto que não há erro (nem mesmo um aviso) se qualquer um dos filenames (ou qualquer pré-requisito de qualquer um dos filenames) não existir ou não puder ser refeito.

Para compatibilidade com algumas outras implementações do make, sinclude é outro nome para -include.

3.4 A variável MAKEFILES

Se a variável de ambiente MAKEFILES estiver definida, o make considera seu valor como uma lista de nomes (separados por espaço em branco) de makefiles adicionais a serem lidos antes dos demais. Isso funciona de modo muito parecido com a diretiva include: vários diretórios são pesquisados em busca desses arquivos (consulte Incluir outros makefiles). Além disso, a meta padrão nunca é tomada a partir de um desses makefiles (ou de qualquer makefile por eles incluído), e não é um erro se os arquivos listados em MAKEFILES não forem encontrados.

O principal uso de MAKEFILES é na comunicação entre invocações recursivas do make (consulte Uso recursivo do make). Em geral, não é desejável definir essa variável de ambiente antes de uma invocação de nível superior do make, porque normalmente é melhor não mexer em um makefile a partir de fora. No entanto, se você está executando o make sem um makefile específico, um makefile em MAKEFILES pode fazer coisas úteis para ajudar as regras implícitas embutidas a funcionarem melhor, como definir caminhos de busca (consulte Busca em diretórios por pré-requisitos).

Alguns usuários são tentados a definir MAKEFILES no ambiente automaticamente ao fazer login, e a escrever makefiles que esperam que isso seja feito. Essa é uma ideia muito ruim, porque tais makefiles deixarão de funcionar se forem executados por outra pessoa. É muito melhor escrever diretivas include explícitas nos makefiles. Consulte Incluir outros makefiles.

3.5 Como os makefiles são refeitos

Às vezes, os makefiles podem ser refeitos a partir de outros arquivos, como arquivos RCS ou SCCS. Se um makefile pode ser refeito a partir de outros arquivos, você provavelmente quer que o make obtenha uma versão atualizada do makefile para ler.

Para isso, depois de ler todos os makefiles, o make considerará cada um como um alvo de meta, na ordem em que foram processados, e tentará atualizá-lo. Se as compilações paralelas (consulte Execução paralela) estiverem habilitadas, os makefiles também serão reconstruídos em paralelo.

Se um makefile tiver uma regra que indique como atualizá-lo (encontrada no próprio makefile ou em outro) ou se uma regra implícita se aplicar a ele (consulte Uso de regras implícitas), ele será atualizado se necessário. Depois que todos os makefiles tiverem sido verificados, se algum deles tiver sido de fato alterado, o make recomeça do zero e lê todos os makefiles novamente. (Ele também tentará atualizar cada um deles de novo, mas normalmente isso não os alterará outra vez, pois já estão atualizados.) Cada reinício faz com que a variável especial MAKE_RESTARTS seja atualizada (consulte Outras variáveis especiais).

Se você sabe que um ou mais dos seus makefiles não podem ser refeitos e quer impedir que o make realize uma busca por regra implícita sobre eles, talvez por razões de eficiência, você pode usar qualquer método normal de impedir a busca por regra implícita. Por exemplo, você pode escrever uma regra explícita com o makefile como alvo e uma receita vazia (consulte Uso de receitas vazias).

Se os makefiles especificarem uma regra de dois-pontos duplo para refazer um arquivo com uma receita mas sem pré-requisitos, esse arquivo será sempre refeito (consulte Regras de dois-pontos duplo). No caso dos makefiles, um makefile que tenha uma regra de dois-pontos duplo com uma receita mas sem pré-requisitos será refeito toda vez que o make for executado, e refeito novamente depois que o make recomeça e lê os makefiles outra vez. Isso provocaria um laço infinito: o make ficaria constantemente refazendo o makefile e reiniciando, sem nunca fazer mais nada. Por isso, para evitar isso, o make não tentará refazer makefiles que sejam especificados como alvos de uma regra de dois-pontos duplo com uma receita mas sem pré-requisitos.

Os alvos falsos (phony) (consulte Alvos falsos (phony)) têm o mesmo efeito: como nunca são considerados atualizados, um arquivo incluído marcado como falso faria com que o make reiniciasse continuamente. Para evitar isso, o make não tentará refazer makefiles que estejam marcados como falsos.

Você pode tirar proveito disso para otimizar o tempo de inicialização: se você sabe que não precisa que o seu Makefile seja refeito, pode impedir que o make tente refazê-lo acrescentando uma das seguintes linhas:

.PHONY: Makefile

ou:

Makefile:: ;

Se você não especificar nenhum makefile a ser lido com as opções «-f» ou «--file», o make tentará os nomes de makefile padrão; consulte Que nome dar ao seu makefile. Ao contrário dos makefiles solicitados explicitamente com as opções «-f» ou «--file», o make não tem certeza de que esses makefiles devam existir. No entanto, se um makefile padrão não existe mas pode ser criado pela execução de regras do make, você provavelmente quer que as regras sejam executadas para que o makefile possa ser usado.

Portanto, se nenhum dos makefiles padrão existir, o make tentará criar cada um deles até conseguir criar um, ou até esgotar os nomes a tentar. Observe que não é um erro se o make não conseguir encontrar nem criar nenhum makefile; um makefile nem sempre é necessário.

Ao usar a opção «-t» ou «--touch» (consulte Em vez de executar receitas), você não quer usar um makefile desatualizado para decidir quais alvos tocar. Por isso, a opção «-t» não tem efeito sobre a atualização dos makefiles; eles são realmente atualizados mesmo que «-t» seja especificado. Da mesma forma, «-q» (ou «--question») e «-n» (ou «--just-print») não impedem a atualização dos makefiles, porque um makefile desatualizado resultaria em saída incorreta para outros alvos. Assim, «make -f mfile -n foo» atualizará mfile, fará sua leitura e então exibirá a receita para atualizar foo e seus pré-requisitos sem executá-la. A receita exibida para foo será aquela especificada no conteúdo atualizado de mfile.

Contudo, em certas ocasiões você pode de fato querer impedir até mesmo a atualização dos makefiles. Você pode fazer isso especificando os makefiles como metas na linha de comando, além de especificá-los como makefiles. Quando o nome do makefile é especificado explicitamente como uma meta, as opções «-t» e afins passam a se aplicar a ele.

Assim, «make -f mfile -n mfile foo» leria o makefile mfile, exibiria a receita necessária para atualizá-lo sem realmente executá-la e, em seguida, exibiria a receita necessária para atualizar foo sem executá-la. A receita para foo será aquela especificada pelo conteúdo existente de mfile.

3.6 Sobrepor parte de outro makefile

Às vezes é útil ter um makefile que seja, em sua maior parte, igual a outro makefile. Muitas vezes você pode usar a diretiva «include» para incluir um no outro e acrescentar mais alvos ou definições de variáveis. No entanto, é inválido que dois makefiles forneçam receitas diferentes para o mesmo alvo. Mas há outra maneira.

No makefile que contém (aquele que quer incluir o outro), você pode usar uma regra de padrão que corresponde a qualquer coisa para indicar que, para refazer qualquer alvo que não possa ser criado a partir das informações do makefile que contém, o make deve consultar outro makefile. Para mais informações sobre regras de padrão, consulte Definição e redefinição de regras de padrão.

Por exemplo, se você tem um makefile chamado Makefile que indica como criar o alvo «foo» (e outros alvos), você pode escrever um makefile chamado GNUmakefile que contém:

foo:
        frobnicate > foo

%: force
        @$(MAKE) -f Makefile $@
force: ;

Se você digitar «make foo», o make encontrará o GNUmakefile, fará sua leitura e verá que, para criar foo, ele precisa executar a receita «frobnicate > foo». Se você digitar «make bar», o make não encontrará no GNUmakefile nenhuma maneira de criar bar, então usará a receita da regra de padrão: «make -f Makefile bar». Se o Makefile fornecer uma regra para atualizar bar, o make aplicará essa regra. E o mesmo vale para qualquer outro alvo cuja forma de criação não esteja indicada no GNUmakefile.

A razão pela qual isso funciona é que o padrão da regra de padrão é apenas «%», que corresponde a qualquer alvo. A regra especifica um pré-requisito force, para garantir que a receita seja executada mesmo que o arquivo do alvo já exista. Damos ao alvo force uma receita vazia para impedir que o make procure uma regra implícita para construí-lo; caso contrário, ele aplicaria a mesma regra que corresponde a qualquer coisa ao próprio force e criaria um laço de pré-requisitos!

3.7 Como o make lê um makefile

O GNU make realiza seu trabalho em duas fases distintas. Durante a primeira fase, ele lê todos os makefiles, makefiles incluídos etc. e internaliza todas as variáveis e seus valores, além das regras implícitas e explícitas, e constrói um grafo de dependências de todos os alvos e seus pré-requisitos. Durante a segunda fase, o make usa esses dados internalizados para determinar quais alvos precisam ser atualizados e executa as receitas necessárias para atualizá-los.

É importante compreender essa abordagem em duas fases, porque ela tem impacto direto sobre quando ocorre a expansão de variáveis e funções; isso costuma ser fonte de confusão ao escrever makefiles. A seguir, um resumo das diferentes construções que podem aparecer em um makefile e a fase em que ocorre a expansão de cada parte da construção.

Dizemos que a expansão é imediata (immediate) se ocorre durante a primeira fase: o make expandirá aquela parte da construção à medida que o makefile é analisado. Dizemos que a expansão é adiada (deferred) se não for imediata. A expansão de uma parte de construção adiada é retardada até que a expansão seja usada: seja quando é referenciada em um contexto imediato, seja quando é necessária durante a segunda fase.

Você pode ainda não estar familiarizado com algumas dessas construções. Você pode consultar esta seção à medida que se familiarizar com elas, nos capítulos posteriores.

Atribuição de variáveis

As definições de variáveis são analisadas da seguinte forma:

immediate = deferred
immediate ?= deferred
immediate := immediate
immediate ::= immediate
immediate :::= immediate-with-escape
immediate += deferred or immediate
immediate != immediate

define immediate
  deferred
endef

define immediate =
  deferred
endef

define immediate ?=
  deferred
endef

define immediate :=
  immediate
endef

define immediate ::=
  immediate
endef

define immediate :::=
  immediate-with-escape
endef

define immediate +=
  deferred or immediate
endef

define immediate !=
  immediate
endef

No operador de acréscimo «+=», o lado direito é considerado imediato se a variável tiver sido definida anteriormente como uma variável simples («:=» ou «::=»), e adiado caso contrário.

No operador imediato com escape «:::=», o valor do lado direito é expandido imediatamente, mas depois é escapado (isto é, todas as ocorrências de $ no resultado da expansão são substituídas por $$).

No operador de atribuição via shell «!=», o lado direito é avaliado imediatamente e entregue ao shell. O resultado é armazenado na variável indicada à esquerda, e essa variável é considerada uma variável de expansão recursiva (e, portanto, será reavaliada a cada referência).

Diretivas condicionais

As diretivas condicionais são analisadas imediatamente. Isso significa, por exemplo, que não é possível usar variáveis automáticas em diretivas condicionais, pois as variáveis automáticas só são definidas quando a receita daquela regra é invocada. Se você precisar usar variáveis automáticas em uma diretiva condicional, você deve mover a condição para dentro da receita e usar, em vez disso, a sintaxe condicional do shell.

Definição de regras

Uma regra é sempre expandida da mesma forma, independentemente do seu formato:

immediate : immediate ; deferred
        deferred

Ou seja, as seções de alvo e de pré-requisitos são expandidas imediatamente, e a receita usada para construir o alvo é sempre adiada. Isso vale para regras explícitas, regras de padrão, regras de sufixo, regras de padrão estáticas e definições simples de pré-requisitos.

3.8 Como os makefiles são analisados

O GNU make analisa os makefiles linha por linha. A análise prossegue pelos seguintes passos:

  1. Ler uma linha lógica completa, incluindo as linhas escapadas por barra invertida (consulte Dividir linhas longas).
  2. Remover os comentários (consulte O que um makefile contém).
  3. Se a linha começar com o caractere de prefixo de receita e estivermos em um contexto de regra, adicionar a linha à receita atual e ler a linha seguinte (consulte Sintaxe de receitas).
  4. Expandir os elementos da linha que aparecem em um contexto de expansão imediata (consulte Como o make lê um makefile).
  5. Examinar a linha em busca de um caractere separador, como «:» ou «=», para determinar se a linha é uma atribuição de macro ou uma regra (consulte Sintaxe de receitas).
  6. Internalizar a operação resultante e ler a linha seguinte.

Uma consequência importante disso é que uma macro pode se expandir em uma regra inteira, desde que caiba em uma linha. O exemplo a seguir funciona:

myrule = target : ; echo built

$(myrule)

No entanto, o exemplo a seguir não funciona, porque o make não redivide as linhas depois de expandi-las:

define myrule
target:
        echo built
endef

$(myrule)

O makefile acima resulta na definição de um alvo «target» com os pré-requisitos «echo» e «built», como se o makefile contivesse target: echo built, em vez de uma regra com uma receita. As novas linhas que ainda restam em uma linha após a conclusão da expansão são ignoradas como espaço em branco comum.

Para expandir corretamente uma macro de múltiplas linhas, você deve usar a função eval: isso faz com que o analisador do make seja executado sobre os resultados da macro expandida (consulte A função eval).

3.9 Expansão secundária

Anteriormente, aprendemos que o GNU make opera em duas fases distintas: uma fase de leitura e uma fase de atualização dos alvos (consulte Como o make lê um makefile). O GNU Make também tem a capacidade de habilitar uma segunda expansão dos pré-requisitos (apenas) para alguns ou todos os alvos definidos no makefile. Para que essa segunda expansão ocorra, o alvo especial .SECONDEXPANSION deve ser definido antes da primeira lista de pré-requisitos que faça uso desse recurso.

Se .SECONDEXPANSION estiver definido, então, quando o GNU make precisar verificar os pré-requisitos de um alvo, os pré-requisitos são expandidos uma segunda vez. Na maioria das circunstâncias, essa expansão secundária não terá efeito algum, pois todas as referências a variáveis e funções já terão sido expandidas durante a análise inicial dos makefiles. Para tirar proveito da fase de expansão secundária do analisador, é necessário escapar a referência à variável ou à função no makefile. Nesse caso, a primeira expansão apenas desfaz o escape da referência, mas não a expande, deixando a expansão para a fase de expansão secundária. Por exemplo, considere este makefile:

.SECONDEXPANSION:
ONEVAR = onefile
TWOVAR = twofile
myfile: $(ONEVAR) $$(TWOVAR)

Após a primeira fase de expansão, a lista de pré-requisitos do alvo myfile será onefile e $(TWOVAR); a primeira referência (não escapada) à variável ONEVAR é expandida, enquanto a segunda referência (escapada) é simplesmente desescapada, sem ser reconhecida como uma referência a variável. Agora, durante a expansão secundária, a primeira palavra é expandida de novo, mas como não contém referências a variáveis nem a funções, permanece com o valor onefile, enquanto a segunda palavra é agora uma referência normal à variável TWOVAR, que é expandida para o valor twofile. O resultado final é que há dois pré-requisitos, onefile e twofile.

Obviamente, este não é um caso muito interessante, pois o mesmo resultado poderia ser obtido mais facilmente bastando que ambas as variáveis aparecessem, sem escape, na lista de pré-requisitos. Uma diferença torna-se aparente se as variáveis forem redefinidas; considere este exemplo:

.SECONDEXPANSION:
AVAR = top
onefile: $(AVAR)
twofile: $$(AVAR)
AVAR = bottom

Aqui, o pré-requisito de onefile será expandido imediatamente e resolverá para o valor top, enquanto o pré-requisito de twofile não será totalmente expandido até a expansão secundária e resultará no valor bottom.

Isso é um pouco mais empolgante, mas o verdadeiro poder desse recurso só se torna aparente quando você descobre que as expansões secundárias sempre ocorrem dentro do escopo das variáveis automáticas daquele alvo. Isso significa que você pode usar variáveis como $@, $* etc. durante a segunda expansão, e elas terão seus valores esperados, exatamente como na receita. Tudo o que você precisa fazer é adiar a expansão escapando o $. Além disso, a expansão secundária ocorre tanto para regras explícitas quanto para regras implícitas (de padrão). Sabendo disso, os usos possíveis desse recurso aumentam drasticamente. Por exemplo:

.SECONDEXPANSION:
main_OBJS := main.o try.o test.o
lib_OBJS := lib.o api.o

main lib: $$($$@_OBJS)

Aqui, após a expansão inicial, os pré-requisitos dos alvos main e lib serão $($@_OBJS). Durante a expansão secundária, a variável $@ é definida com o nome do alvo, de modo que a expansão para o alvo main resultará em $(main_OBJS), ou main.o try.o test.o, enquanto a expansão secundária para o alvo lib resultará em $(lib_OBJS), ou lib.o api.o.

Você também pode misturar funções aqui, desde que estejam devidamente escapadas:

main_SRCS := main.c try.c test.c
lib_SRCS := lib.c api.c

.SECONDEXPANSION:
main lib: $$(patsubst %.c,%.o,$$($$@_SRCS))

Esta versão permite que os usuários especifiquem arquivos fonte em vez de arquivos objeto, mas produz a mesma lista de pré-requisitos resultante do exemplo anterior.

A avaliação de variáveis automáticas durante a fase de expansão secundária, em especial da variável do nome do alvo $$@, comporta-se de forma semelhante à avaliação dentro das receitas. No entanto, há algumas diferenças sutis e «casos especiais» que entram em jogo para os diferentes tipos de definição de regra que o make interpreta. As sutilezas do uso das diferentes variáveis automáticas são descritas a seguir.

Expansão secundária de regras explícitas

Durante a expansão secundária de regras explícitas, $$@ e $$% avaliam, respectivamente, para o nome do arquivo do alvo e, quando o alvo é membro de um arquivo de arquivo (archive), para o nome do membro alvo. A variável $$< avalia para o primeiro pré-requisito da primeira regra desse alvo. $$^ e $$+ avaliam para a lista de todos os pré-requisitos das regras que já apareceram para o mesmo alvo ($$+ com repetições e $$^ sem). O exemplo a seguir ajudará a ilustrar esses comportamentos:

.SECONDEXPANSION:

foo: foo.1 bar.1 $$< $$^ $$+    # linha #1

foo: foo.2 bar.2 $$< $$^ $$+    # linha #2

foo: foo.3 bar.3 $$< $$^ $$+    # linha #3

Na primeira lista de pré-requisitos, as três variáveis ($$<, $$^ e $$+) expandem para a cadeia vazia. Na segunda, elas terão os valores foo.1, foo.1 bar.1 e foo.1 bar.1, respectivamente. Na terceira, terão os valores foo.1, foo.1 bar.1 foo.2 bar.2 e foo.1 bar.1 foo.2 bar.2 foo.1 foo.1 bar.1 foo.1 bar.1, respectivamente.

As regras passam pela expansão secundária na ordem do makefile, exceto que a regra que possui a receita é sempre avaliada por último.

As variáveis $$? e $$* não estão disponíveis e expandem para a cadeia vazia.

Expansão secundária de regras de padrão estáticas

As regras para a expansão secundária de regras de padrão estáticas são idênticas às das regras explícitas, acima, com uma exceção: nas regras de padrão estáticas, a variável $$* é definida com o radical (stem) do padrão. Assim como nas regras explícitas, $$? não está disponível e expande para a cadeia vazia.

Expansão secundária de regras implícitas

À medida que o make procura uma regra implícita, ele substitui o radical e então realiza a expansão secundária para cada regra com um padrão de alvo correspondente. O valor das variáveis automáticas é derivado da mesma forma que para as regras de padrão estáticas. Como exemplo:

.SECONDEXPANSION:

foo: bar

foo foz: fo%: bo%

%oo: $$< $$^ $$+ $$*

Quando a regra implícita é experimentada para o alvo foo, $$< expande para bar, $$^ expande para bar boo, $$+ também expande para bar boo e $$* expande para f.

Observe que o prefixo de diretório (D), descrito em Algoritmo de busca de regras implícitas, é acrescentado (após a expansão) a todos os padrões da lista de pré-requisitos. Como exemplo:

.SECONDEXPANSION:

/tmp/foo.o:

%.o: $$(addsuffix /%.c,foo bar) foo.h
        @echo $^

A lista de pré-requisitos exibida, após a expansão secundária e a reconstrução do prefixo de diretório, será /tmp/foo/foo.c /tmp/bar/foo.c foo.h. Se você não tiver interesse nessa reconstrução, pode usar $$* em vez de % na lista de pré-requisitos.


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