Uma variável (variable) é um nome definido em um makefile para representar uma cadeia de caracteres chamada de valor (value). Esses valores são expandidos e inseridos, mediante solicitação explícita, em alvos, pré-requisitos (prerequisite), receitas (recipe) e em diversas outras partes do makefile. (Em algumas outras versões do make, as variáveis são chamadas de macros (macro).)
Em princípio, as variáveis e funções de um makefile são expandidas no momento em que são lidas. Há exceções, porém: dentro das receitas, no lado direito de uma definição de variável que usa ‘=’ e no corpo de uma definição de variável feita com a diretiva define, a expansão não ocorre nesse momento. O valor obtido ao expandir uma variável é o da definição mais recente vigente no momento da expansão. Em outras palavras, as variáveis têm escopo determinado dinamicamente (escopo dinâmico).
As variáveis podem representar listas de nomes de arquivos, opções a passar aos compiladores, programas a executar, diretórios onde procurar arquivos fonte, diretórios onde escrever a saída ou qualquer outra coisa que você possa imaginar.
Um nome de variável pode ser qualquer cadeia de caracteres que não contenha ‘:’, ‘#’, ‘=’ ou espaço em branco. No entanto, nomes de variáveis que contenham caracteres diferentes de letras, números e sublinhados devem ser usados com cautela, pois em alguns shells eles não podem ser passados pelo ambiente a um sub-make (veja Comunicando variáveis a um sub-make). Nomes de variáveis que começam com ‘.’ e uma letra maiúscula podem receber significado especial em versões futuras do make.
Os nomes de variáveis diferenciam maiúsculas de minúsculas. Os nomes ‘foo’, ‘FOO’ e ‘Foo’ referem-se, todos, a variáveis diferentes.
É tradicional usar letras maiúsculas nos nomes de variáveis, mas recomendamos usar letras minúsculas para os nomes de variáveis destinados a usos internos do makefile, reservando as maiúsculas para os parâmetros que controlam as regras implícitas ou para os parâmetros que o usuário deve poder sobrepor por meio de opções de comando (veja Sobrepondo variáveis).
Um pequeno número de variáveis tem nomes formados por um único caractere de pontuação ou apenas alguns caracteres. Essas variáveis são chamadas de variáveis automáticas (automatic variable) e cada uma tem um uso especializado específico. Veja Variáveis automáticas.
override
Para inserir o valor de uma variável, escreva um cifrão seguido do nome da variável entre parênteses ou chaves: tanto ‘$(foo)’ quanto ‘${foo}’ são referências válidas à variável foo. É justamente por causa desse significado especial de ‘$’ que, quando você quiser representar um único cifrão literal em um nome de arquivo ou em uma receita, é preciso escrever ‘$$’.
As referências a variáveis podem ser usadas em qualquer contexto: alvos, pré-requisitos, receitas, na maioria das diretivas e em valores de novas variáveis. Eis um exemplo comum, em que uma variável guarda os nomes de todos os arquivos objeto que compõem um programa:
objects = program.o foo.o utils.o
program : $(objects)
cc -o program $(objects)
$(objects) : defs.h
As referências a variáveis funcionam por substituição estritamente textual. Assim, a regra
foo = c
prog.o : prog.$(foo)
$(foo)$(foo) -$(foo) prog.$(foo)
pode ser usada para compilar um programa C prog.c. Como o espaço em branco antes do valor é ignorado nas atribuições de variável, o valor de foo é exatamente ‘c’. (Não escreva makefiles reais desse jeito!)
Se um cifrão for seguido de um caractere que não seja um cifrão, um parêntese de abertura nem uma chave de abertura, esse único caractere é tratado como o nome da variável. Assim, você pode referenciar a variável x com ‘$x’. No entanto, essa prática pode causar confusão (por exemplo, ‘$foo’ é interpretado como a variável f seguida da cadeia de caracteres oo). Por isso, recomendamos cercar todas as variáveis com parênteses ou chaves, mesmo as de um único caractere, exceto quando a omissão melhorar muito a legibilidade. Um caso em que omitir os parênteses costuma melhorar a legibilidade é o das variáveis automáticas (veja Variáveis automáticas).
No GNU make há algumas diferenças no modo como uma variável obtém seu valor. A isso chamamos de tipo (flavor) da variável. O tipo se distingue por como o valor atribuído no makefile é tratado e por como o valor é gerenciado quando a variável é posteriormente usada e expandida.
O primeiro tipo de variável é a variável de expansão recursiva (recursively expanded). Esse tipo de variável é definido em uma linha que usa ‘=’ (veja Definindo variáveis) ou com a diretiva define (veja Definindo variáveis de várias linhas). O valor que você especificar é armazenado literalmente; se ele contiver referências a outras variáveis, essas referências são expandidas sempre que esta variável é inserida (no processo de expandir alguma outra cadeia de caracteres). Quando isso ocorre, chamamos de expansão recursiva (recursive expansion).
Por exemplo,
foo = $(bar) bar = $(ugh) ugh = Huh? all:;echo $(foo)
produz ‘Huh?’. Isso ocorre porque ‘$(foo)’ é expandido para ‘$(bar)’, que é expandido para ‘$(ugh)’, que por fim é expandido para ‘Huh?’.
Esse tipo de variável é o único que a maioria das outras versões do make oferece. Ele tem vantagens e desvantagens. A vantagem (que muitos diriam ser uma vantagem) é a seguinte:
CFLAGS = $(include_dirs) -O include_dirs = -Ifoo -Ibar
Isso funciona como pretendido: quando ‘CFLAGS’ é expandido em uma receita, ele se expande para ‘-Ifoo -Ibar -O’. A grande desvantagem é que você não pode acrescentar algo ao fim da variável, como em
CFLAGS = $(CFLAGS) -O
porque isso provocaria um laço infinito na expansão da variável. (Na verdade, o make detecta o laço infinito e relata um erro.)
Outra desvantagem é que quaisquer funções referenciadas na definição (veja Funções para transformação de texto) são executadas toda vez que a variável é expandida. Isso deixa o make mais lento; pior ainda, faz com que as funções wildcard e shell produzam resultados imprevisíveis, pois não é fácil controlar quando, ou mesmo quantas vezes, elas serão chamadas.
Para evitar os problemas e inconvenientes das variáveis de expansão recursiva, existe outro tipo: a variável de expansão simples.
As variáveis de expansão simples (simply expanded variable) são definidas em linhas que usam ‘:=’ ou ‘::=’ (veja Definindo variáveis). No GNU make as duas formas são equivalentes, mas apenas a forma ‘::=’ é especificada pelo padrão POSIX (o suporte a ‘::=’ foi acrescentado ao padrão POSIX na POSIX Issue 8).
O valor de uma variável de expansão simples é percorrido uma única vez, quando a variável é definida, expandindo eventuais referências a outras variáveis e funções. Concluída essa expansão, o valor da variável nunca mais é expandido. Quando a variável é usada, seu valor é copiado literalmente e passa a ser o resultado da expansão. Se o valor contiver referências a variáveis, o resultado da expansão conterá os valores que essas variáveis tinham no momento em que esta variável foi definida. Portanto,
x := foo y := $(x) bar x := later
é equivalente a:
y := foo bar x := later
O exemplo a seguir, um pouco mais elaborado, mostra o uso de ‘:=’ em combinação com a função shell. (Veja A função shell.) Este exemplo também mostra o uso da variável MAKELEVEL, que muda à medida que é passada de um nível para outro. (Para detalhes sobre MAKELEVEL, veja Comunicando variáveis a um sub-make.)
ifeq (0,${MAKELEVEL})
whoami := $(shell whoami)
host-type := $(shell arch)
MAKE := ${MAKE} host-type=${host-type} whoami=${whoami}
endif
A vantagem desse uso de ‘:=’ é que uma típica receita de “descer aos diretórios” pode ser escrita assim:
${subdirs}:
${MAKE} -C $@ all
As variáveis de expansão simples geralmente se comportam como as variáveis na maioria das linguagens de programação, o que torna a programação de makefiles complexos mais previsível. Com elas, você pode redefinir uma variável usando seu próprio valor (ou um valor próprio processado de alguma forma por uma das funções de expansão) e usar as funções de expansão de modo muito mais eficiente (veja Funções para transformação de texto).
As variáveis de expansão simples também permitem inserir espaço em branco controlado no início do valor de uma variável. Os caracteres de espaço em branco no início do valor informado são removidos antes que as substituições de referências a variáveis e de chamadas de função sejam feitas. Assim, se você quiser incluir espaço em branco no início do valor da variável, proteja-o com uma referência a variável, da seguinte forma:
nullstring := space := $(nullstring) # end of the line
Aqui o valor da variável space é exatamente um único espaço. O comentário ‘# end of the line’ está incluído aqui apenas por clareza. Como os caracteres de espaço em branco no fim do valor de uma variável não são removidos, basta colocar um único espaço no fim da linha para obter o mesmo efeito (embora isso fique muito difícil de ler). Se você for colocar espaço em branco no fim do valor de uma variável, é melhor deixar a intenção clara, como aqui, com um comentário no fim da linha. Por outro lado, se você não quiser nenhum caractere de espaço em branco no fim do valor, lembre-se de não pôr descuidadamente um comentário no fim da linha após o espaço, como em:
dir := /foo/bar # directory to put the frobs in
Aqui o valor da variável dir acaba sendo ‘/foo/bar ’ (com quatro espaços ao fim), o que provavelmente não é o que se pretendia. (Imagine usar essa definição como ‘$(dir)/file’!)
Outra forma de atribuição realiza expansão imediata mas, diferente da atribuição simples, a variável resultante é de expansão recursiva: ou seja, ela é reexpandida toda vez que é usada. Para evitar resultados inesperados, depois que o valor é expandido imediatamente ele é automaticamente protegido com aspas: todo $ presente no valor expandido é convertido em $$. Esse tipo de atribuição usa o operador ‘:::=’. Por exemplo,
var = first OUT :::= $(var) var = second
faz com que a variável OUT contenha o texto ‘first’. Já no caso a seguir,
var = one$$two OUT :::= $(var) var = three$$four
a variável OUT contém o texto ‘one$$two’. Como o valor é expandido quando a variável é atribuída, o resultado é primeiro a expansão do valor inicial de var, ou seja, ‘one$two’. Em seguida, o valor é reescapado antes que a atribuição se complete, produzindo o resultado final ‘one$$two’.
Depois disso, a variável OUT é tratada como uma variável de expansão recursiva, de modo que é reexpandida quando usada.
Isso parece funcionalmente equivalente aos operadores ‘:=’ / ‘::=’, mas há algumas diferenças:
Em primeiro lugar, após a atribuição, a variável é uma variável de expansão recursiva comum. Ao acrescentar com ‘+=’, o valor do lado direito não é expandido imediatamente. Se você quiser que o lado direito seja expandido imediatamente com o operador ‘+=’, deve usar uma atribuição ‘:=’ / ‘::=’ em seu lugar.
Em segundo lugar, essas variáveis são ligeiramente menos eficientes do que as variáveis de expansão simples, pois precisam ser reexpandidas quando usadas, em vez de simplesmente copiadas. Ainda assim, como todas as referências a variáveis estão escapadas, essa expansão apenas desfaz o escape do valor, sem expandir variáveis nem executar funções.
Eis mais um exemplo:
var = one$$two OUT :::= $(var) OUT += $(var) var = three$$four
Depois disso, o valor de OUT é o texto ‘one$$two $(var)’. Quando essa variável é usada, ela é expandida e o resultado é ‘one$two three$four’.
Esse estilo de atribuição é equivalente ao operador ‘:=’ do make BSD tradicional. Como se vê, ele difere ligeiramente do operador ‘:=’ do GNU make. O operador :::= foi acrescentado na Issue 8 da especificação POSIX para oferecer portabilidade.
Outro operador de atribuição de variáveis é ‘?=’. Ele é chamado de operador de atribuição condicional de variável, pois só tem efeito se a variável ainda não estiver definida. A instrução
FOO ?= bar
é exatamente equivalente a esta (veja A função origin):
ifeq ($(origin FOO), undefined) FOO = bar endif
Observe que uma variável definida com um valor vazio também é considerada “definida”; por isso, ‘?=’ não a redefinirá.
Esta seção descreve alguns recursos avançados que você pode usar para referenciar variáveis de maneiras mais flexíveis.
Uma referência de substituição (substitution reference) insere o valor de uma variável aplicando-lhe uma alteração especificada. Sua forma é ‘$(var:a=b)’ (ou ‘${var:a=b}’) e seu significado é: tomar o valor da variável var, substituir cada a no fim de cada palavra por b e inserir a cadeia de caracteres resultante.
Quando dizemos “no fim de cada palavra”, queremos dizer que, para ser substituído, a deve estar seguido de um espaço em branco ou estar no fim do valor. As demais ocorrências de a no valor permanecem inalteradas. Por exemplo,
foo := a.o b.o l.a c.o bar := $(foo:.o=.c)
define ‘bar’ como ‘a.c b.c l.a c.c’. Veja Definindo variáveis.
A referência de substituição é, na verdade, uma forma abreviada da função de expansão patsubst (veja Funções para substituição e análise de cadeias de caracteres). ‘$(var:a=b)’ é equivalente a ‘$(patsubst %a,%b,var)’. Oferecemos as referências de substituição além de patsubst para compatibilidade com outras implementações do make.
Outro tipo de referência de substituição permite usar toda a força da função patsubst. A forma é a mesma ‘$(var:a=b)’ descrita acima, mas agora a precisa conter um único caractere ‘%’. Nesse caso, é equivalente a ‘$(patsubst a,b,$(var))’. Para a descrição da função patsubst, veja Funções para substituição e análise de cadeias de caracteres. Por exemplo,
foo := a.o b.o l.a c.o bar := $(foo:%.o=%.c)
define ‘bar’ como ‘a.c b.c l.a c.c’.
Os nomes de variáveis computados são um conceito avançado, muito útil em programação de makefiles mais sofisticada. Em situações simples você não precisa se preocupar com eles, mas podem ser extremamente úteis.
É possível referenciar variáveis dentro do nome de uma variável. A isso chamamos de nome de variável computado (computed variable name) ou referência de variável aninhada (nested variable reference). Por exemplo,
x = y y = z a := $($(x))
define a como ‘z’. Como o ‘$(x)’ interno em ‘$($(x))’ é expandido para ‘y’, ‘$($(x))’ é expandido para ‘$(y)’, que por sua vez é expandido para ‘z’. Aqui, o nome da variável a referenciar não é escrito explicitamente, mas é computado pela expansão de ‘$(x)’. A referência ‘$(x)’ está aninhada dentro da referência de variável externa.
O exemplo anterior mostra dois níveis de aninhamento, mas o aninhamento pode ter qualquer número de níveis. Por exemplo, eis um exemplo com três níveis:
x = y y = z z = u a := $($($(x)))
Aqui o ‘$(x)’ mais interno é expandido para ‘y’, de modo que ‘$($(x))’ é expandido para ‘$(y)’, que por sua vez é expandido para ‘z’. Resta então ‘$(z)’, que se torna ‘u’.
Referências a variáveis de expansão recursiva dentro do nome de uma variável são reexpandidas como de costume. Por exemplo,
x = $(y) y = z z = Hello a := $($(x))
define a como ‘Hello’. ‘$($(x))’ torna-se ‘$($(y))’, que se torna ‘$(z)’, que se torna ‘Hello’.
As referências de variáveis aninhadas também podem conter referências qualificadas e chamadas de função (veja Funções para transformação de texto), assim como qualquer outra referência. Por exemplo, usando a função subst (veja Funções para substituição e análise de cadeias de caracteres),
x = variable1 variable2 := Hello y = $(subst 1,2,$(x)) z = y a := $($($(z)))
acaba definindo a como ‘Hello’. Dificilmente alguém iria querer escrever uma referência aninhada tão rebuscada, mas ela funciona: ‘$($($(z)))’ é expandido para ‘$($(y))’, que se torna ‘$($(subst 1,2,$(x)))’. Isso toma o valor ‘variable1’ de x e, pela substituição, o transforma em ‘variable2’, de modo que a cadeia inteira se torna a simples referência de variável ‘$(variable2)’, cujo valor é ‘Hello’.
Um nome de variável computado não precisa consistir em uma única referência de variável. Ele pode conter várias referências a variáveis, além de texto invariável. Por exemplo,
a_dirs := dira dirb 1_dirs := dir1 dir2
a_files := filea fileb 1_files := file1 file2
ifeq "$(use_a)" "yes" a1 := a else a1 := 1 endif
ifeq "$(use_dirs)" "yes" df := dirs else df := files endif dirs := $($(a1)_$(df))
dá a dirs o mesmo valor de a_dirs, 1_dirs, a_files ou 1_files, dependendo das configurações de use_a e use_dirs.
Os nomes de variáveis computados também podem ser usados em referências de substituição:
a_objects := a.o b.o c.o 1_objects := 1.o 2.o 3.o sources := $($(a1)_objects:.o=.c)
define sources como ‘a.c b.c c.c’ ou ‘1.c 2.c 3.c’, dependendo do valor de a1.
A única restrição a esse uso de referências de variáveis aninhadas é que elas não podem ser usadas para especificar parte do nome de uma função a chamar. Isso porque a verificação de nomes de função reconhecidos é feita antes da expansão das referências aninhadas. Por exemplo,
ifdef do_sort func := sort else func := strip endif
bar := a d b g q c
foo := $($(func) $(bar))
tenta dar a ‘foo’ o valor da variável ‘sort a d b g q c’ ou ‘strip a d b g q c’, em vez de passar ‘a d b g q c’ como argumento à função sort ou strip. Essa restrição poderá ser removida no futuro, caso se mostre que a mudança é uma boa ideia.
Os nomes de variáveis computados também podem ser usados no lado esquerdo de uma atribuição de variável ou dentro de uma diretiva define. Por exemplo:
dir = foo $(dir)_sources := $(wildcard $(dir)/*.c) define $(dir)_print = lpr $($(dir)_sources) endef
Esse exemplo define as variáveis ‘dir’, ‘foo_sources’ e ‘foo_print’.
Observe que as referências de variáveis aninhadas são bem diferentes das variáveis de expansão recursiva (veja Os dois tipos de variáveis), embora ambas possam aparecer combinadas de maneira intrincada ao programar makefiles.
As variáveis podem obter seus valores de várias maneiras diferentes:
make. Veja Sobrepondo variáveis.
let (veja A função let) ou a função foreach (veja A função foreach).
make. Veja Variáveis vindas do ambiente.
Para definir uma variável a partir de um makefile, escreva uma linha que comece com o nome da variável, seguido de um dos operadores de atribuição ‘=’, ‘:=’, ‘::=’ ou ‘:::=’. O que vier depois do operador, descontado o espaço em branco no início, torna-se o valor. Por exemplo,
objects = main.o foo.o bar.o utils.o
define uma variável chamada objects com o valor ‘main.o foo.o bar.o utils.o’. O espaço em branco antes e depois do nome da variável e logo após o ‘=’ é ignorado.
Variáveis definidas com ‘=’ são variáveis de expansão recursiva. Variáveis definidas com ‘:=’ ou ‘::=’ são variáveis de expansão simples; essas definições podem conter referências a variáveis, que são expandidas antes de a definição ocorrer. Variáveis definidas com ‘:::=’ são variáveis de expansão imediata. Cada operador de atribuição é explicado em Os dois tipos de variáveis.
O nome da variável pode conter referências a funções e a variáveis, que são expandidas quando a linha é lida para determinar o nome de variável efetivamente usado.
Não há limite para o comprimento do valor de uma variável, exceto a quantidade de memória do computador. Para facilitar a leitura, você pode dividir o valor de uma variável em várias linhas físicas (veja Dividindo linhas longas).
A maioria dos nomes de variáveis é considerada como tendo o valor de cadeia vazia se nunca tiver sido definida. Algumas variáveis têm valores iniciais embutidos não vazios, mas também podem ser definidas pelos meios usuais (veja Variáveis usadas pelas regras implícitas). Algumas variáveis especiais recebem automaticamente um novo valor para cada regra; estas são chamadas de variáveis automáticas (veja Variáveis automáticas).
Se você quiser definir o valor de uma variável somente se ela ainda não estiver definida, pode usar o operador abreviado ‘?=’ em vez de ‘=’. As duas configurações da variável ‘FOO’ a seguir são idênticas (veja A função origin):
FOO ?= bar
e
ifeq ($(origin FOO), undefined) FOO = bar endif
Usando o operador de atribuição de shell ‘!=’, você pode executar um script de shell e atribuir sua saída a uma variável. Esse operador primeiro avalia o lado direito e passa o resultado a um shell para execução. Se o resultado da execução terminar com uma nova linha, essa única nova linha é removida; todas as demais novas linhas são substituídas por espaços. A cadeia de caracteres resultante é então armazenada na variável de expansão recursiva indicada. Por exemplo,
hash != printf '\043' file_list != find . -name '*.c'
Se o resultado da execução puder conter um $ e você não quiser que o que vem em seguida seja interpretado como referência a variável ou função do make, você deve substituir cada $ por $$ como parte da execução. Como alternativa, você também pode usar uma chamada à função shell para atribuir a saída de um programa a uma variável de expansão simples. Veja A função shell. Por exemplo,
hash := $(shell printf '\043') var := $(shell find . -name "*.c")
Assim como no caso da função shell, o status de saída do script de shell que acabou de ser iniciado é armazenado na variável .SHELLSTATUS.
Muitas vezes é útil poder acrescentar mais texto ao valor de uma variável já definida. Para isso, use uma linha com ‘+=’, como em:
objects += another.o
Isso toma o valor da variável objects e acrescenta-lhe o texto ‘another.o’ (precedido de um único espaço, se a variável já tiver um valor). Assim,
objects = main.o foo.o bar.o utils.o objects += another.o
define objects como ‘main.o foo.o bar.o utils.o another.o’.
Usar ‘+=’ é semelhante a:
objects = main.o foo.o bar.o utils.o objects := $(objects) another.o
mas difere de maneiras que se tornam importantes quando se usam valores mais complexos.
Quando a variável em questão não foi definida antes, ‘+=’ comporta-se exatamente como o ‘=’ comum: define uma variável de expansão recursiva. No entanto, quando há uma definição anterior, o que exatamente ‘+=’ faz depende de que tipo de variável foi definida originalmente. Para a explicação dos dois tipos de variáveis, veja Os dois tipos de variáveis.
Ao acrescentar a uma variável com ‘+=’, o make age essencialmente como se o texto acrescentado tivesse feito parte da definição original da variável. Se você a tiver definido primeiro com ‘:=’ ou ‘::=’, tornando-a uma variável de expansão simples, ‘+=’ acrescenta à definição de expansão simples e expande o novo texto antes de anexá-lo ao valor antigo, exatamente como faz ‘:=’ (para a explicação completa de ‘:=’ e ‘::=’, veja Definindo variáveis). De fato,
variable := value variable += more
é exatamente equivalente a:
variable := value variable := $(variable) more
Por outro lado, quando você usa ‘+=’ em uma variável que foi definida primeiro como variável de expansão recursiva, usando o ‘=’ puro ou ‘:::=’, o make acrescenta o texto não expandido ao valor existente, seja ele qual for. Ou seja,
variable = value variable += more
é aproximadamente equivalente a:
temp = value variable = $(temp) more
a não ser, claro, que ele nunca chega a definir realmente uma variável chamada temp. Isso importa quando o valor antigo da variável contém referências a variáveis. Veja este exemplo comum:
CFLAGS = $(includes) -O … CFLAGS += -pg # enable profiling
A primeira linha define a variável CFLAGS com uma referência a outra variável, includes. (CFLAGS é usada pelas regras de compilação C. Veja Catálogo das regras embutidas.) Usar ‘=’ na definição torna CFLAGS uma variável de expansão recursiva, o que significa que ‘$(includes) -O’ não é expandido quando o make processa a definição de CFLAGS. Assim, includes não precisa ainda estar definido para que o valor tenha efeito; basta que esteja definido antes de qualquer referência a CFLAGS. Se você tentasse acrescentar ao valor de CFLAGS sem usar ‘+=’, poderia fazer assim:
CFLAGS := $(CFLAGS) -pg # enable profiling
Isso chega bem perto, mas não é o que se deseja. Usar ‘:=’ redefine CFLAGS como uma variável de expansão simples; isso significa que o make expande o texto ‘$(CFLAGS) -pg’ antes de definir a variável. Se includes ainda não estiver definido, obtém-se ‘ -O -pg’ e uma definição posterior de includes não terá efeito. Em contrapartida, usando ‘+=’, define-se CFLAGS com o valor não expandido ‘$(includes) -O -pg’. Assim, a referência a includes é preservada e, se essa variável for definida em algum ponto posterior, uma referência como ‘$(CFLAGS)’ ainda usará seu valor.
override
Se uma variável foi definida por um argumento de comando (veja Sobrepondo variáveis), as atribuições comuns no makefile são ignoradas. Se você quiser definir a variável no makefile mesmo que ela tenha sido definida por um argumento de comando, pode usar a diretiva override, que é uma linha desta forma:
override variable = value
ou
override variable := value
Para acrescentar mais texto a uma variável definida na linha de comando, faça assim:
override variable += more text
Veja Acrescentando texto a variáveis.
Uma atribuição de variável marcada com o sinalizador override tem prioridade mais alta do que todas as outras atribuições, exceto outra override. Atribuições ou acréscimos subsequentes a essa variável que não tenham override são ignorados.
A diretiva override não foi concebida para intensificar a disputa entre o makefile e os argumentos de comando. Ela foi concebida para que o usuário possa alterar ou acrescentar valores que especifica nos argumentos de comando.
Por exemplo, suponha que você queira sempre usar a opção ‘-g’ ao executar o compilador C, mas queira permitir que o usuário especifique as demais opções pelos argumentos de comando como de costume. Basta usar a seguinte diretiva override:
override CFLAGS += -g
A diretiva override também pode ser usada com a diretiva define. Isso é feito da maneira que você esperaria:
override define foo = bar endef
Veja Definindo variáveis de várias linhas.
Outra forma de definir o valor de uma variável é usar a diretiva define. Essa diretiva tem uma sintaxe peculiar que permite que o valor contenha caracteres de nova linha, o que é conveniente para definir sequências canônicas de comandos (veja Definindo receitas canônicas) ou trechos de sintaxe de makefile para usar com eval (veja A função eval).
A diretiva define é seguida, na mesma linha, do nome da variável a definir e de um operador de atribuição (opcional), e nada mais. O valor a dar à variável aparece nas linhas seguintes. O fim do valor é indicado por uma linha contendo apenas a palavra endef.
Afora essa diferença de sintaxe, define funciona exatamente como qualquer outra definição de variável. O nome da variável pode conter referências a funções e a variáveis, que são expandidas quando a diretiva é lida para determinar o nome de variável efetivamente usado.
A última nova linha, imediatamente antes de endef, não é incluída no valor. Se você quiser que o valor contenha uma nova linha ao final, é preciso incluir uma linha em branco. Por exemplo, para definir uma variável que contenha um caractere de nova linha, é preciso usar duas linhas em branco, não uma:
define newline endef
Você pode, se preferir, omitir o operador de atribuição de variável. Se o omitir, o make o considera como ‘=’ e cria uma variável de expansão recursiva (veja Os dois tipos de variáveis). Ao usar o operador ‘+=’, como em qualquer outra operação de acréscimo, o valor é acrescentado ao valor anterior, separando o valor antigo do novo por um único espaço.
A diretiva define pode ser aninhada. O make acompanha as diretivas aninhadas e relata um erro se elas não forem todas devidamente fechadas com endef. Observe que linhas que começam com o prefixo de receita são consideradas parte de uma receita; portanto, qualquer ocorrência de define ou endef que apareça em tais linhas não é tratada como diretiva do make.
define two-lines echo foo echo $(bar) endef
Quando usado em uma receita, o exemplo anterior é funcionalmente equivalente a:
two-lines = echo foo; echo $(bar)
porque dois comandos separados por ponto e vírgula comportam-se praticamente como dois comandos de shell separados. Note, porém, que usar duas linhas separadas faz com que o make inicie o shell duas vezes, executando um subshell independente para cada linha. Veja Execução de receitas.
Se você quiser que a definição de variável feita com define tenha prioridade sobre uma definição de variável na linha de comando, pode usar a diretiva override junto com define:
override define two-lines = foo $(bar) endef
Veja A diretiva override.
Se você quiser limpar uma variável, normalmente basta definir seu valor como vazio. Expandir uma variável assim produz o mesmo resultado (cadeia vazia), tenha ela sido definida ou não. Contudo, se você estiver usando as funções flavor (veja A função flavor) ou origin (veja A função origin), há diferença entre uma variável que nunca foi definida e uma variável com valor vazio. Nesses casos, você pode querer usar a diretiva undefine para fazer com que pareça que a variável nunca foi definida. Por exemplo,
foo := foo bar = bar undefine foo undefine bar $(info $(origin foo)) $(info $(flavor bar))
Esse exemplo exibe “undefined” para ambas as variáveis.
Se você quiser cancelar a definição de uma variável feita na linha de comando, pode usar a diretiva override junto com undefine, da mesma forma que na definição de variável:
override undefine CFLAGS
As variáveis do make podem vir do ambiente em que o make é executado. Toda variável de ambiente que o make vê ao iniciar é convertida em uma variável do make com o mesmo nome e valor. No entanto, uma atribuição explícita no makefile, ou uma atribuição em um argumento de comando, sobrepõe o ambiente. (Se o sinalizador ‘-e’ for especificado, os valores do ambiente sobrepõem as atribuições no makefile. Veja Sumário das opções. Mas esse uso não é recomendado.)
Assim, configurando a variável CFLAGS no ambiente, você pode fazer com que a maioria dos makefiles use as opções de compilador de sua preferência em todas as compilações C. Isso é seguro para variáveis com significado padronizado ou convencional, pois você sabe que nenhum makefile as usaria para outro fim. (Mas isso não é totalmente confiável; alguns makefiles definem CFLAGS explicitamente e, nesse caso, não são afetados pelo valor do ambiente.)
Quando o make executa uma receita, algumas variáveis definidas no makefile são colocadas no ambiente de cada comando que o make invoca. Por padrão, apenas as variáveis que vieram do ambiente do make ou que foram definidas na linha de comando são colocadas no ambiente dos comandos. Para passar outras variáveis, você pode usar a diretiva export. Para todos os detalhes, veja Comunicando variáveis a um sub-make.
Outros usos de variáveis vindas do ambiente não são recomendados. Não é prudente que um makefile faça seu comportamento depender de variáveis de ambiente definidas fora de seu controle, pois isso faria com que o mesmo makefile produzisse resultados diferentes para usuários diferentes. Isso vai contra o propósito da maioria dos makefiles.
Esse tipo de problema seria especialmente provável com a variável SHELL, que normalmente está presente no ambiente para especificar o shell interativo escolhido pelo usuário. Seria muito indesejável que essa escolha afetasse o make; por isso, o make trata a variável de ambiente SHELL de maneira especial. Veja Escolhendo o shell.
Os valores de variáveis do make são normalmente globais: ou seja, são os mesmos onde quer que sejam avaliados (a menos, claro, que sejam redefinidos). As exceções são as variáveis definidas pelas funções let (veja A função let) e foreach (veja A função foreach) e as variáveis automáticas (veja Variáveis automáticas).
Outra exceção são os valores de variáveis específicos de alvo (target-specific variable value). Esse recurso permite definir valores diferentes para a mesma variável conforme o alvo que o make está construindo no momento. Assim como as variáveis automáticas, esses valores só estão disponíveis no contexto da receita do alvo (e em outras atribuições específicas do alvo).
Os valores de variáveis específicos de alvo são definidos assim:
target … : variable-assignment
Uma atribuição de variável específica de alvo pode ter como prefixo qualquer uma, ou todas, das palavras-chave especiais export, unexport, override ou private. Elas aplicam seu comportamento usual apenas a esta instância da variável.
Quando vários target são especificados, é criado um valor de variável específico de alvo individual para cada membro da lista de alvos.
O variable-assignment pode ser qualquer forma de atribuição válida: recursiva (‘=’), simples (‘:=’ ou ‘::=’), imediata (‘::=’), de acréscimo (‘+=’) ou condicional (‘?=’). Todas as variáveis que aparecem no variable-assignment são avaliadas no contexto do alvo; assim, quaisquer valores de variáveis específicos de alvo definidos antes têm efeito. Observe que essa variável é, na verdade, distinta de qualquer valor “global”; as duas variáveis não precisam ser do mesmo tipo (recursiva ou simples).
As variáveis específicas de alvo têm a mesma prioridade que qualquer outra variável de makefile. As variáveis fornecidas na linha de comando (e, quando a opção ‘-e’ está ativa, as variáveis do ambiente) têm precedência. Especificando a diretiva override, é possível fazer com que o valor de variável específico de alvo tenha precedência.
As variáveis específicas de alvo têm outro recurso especial: ao definir uma variável específica de alvo, esse valor de variável tem efeito em todos os pré-requisitos desse alvo, e em seus pré-requisitos, e assim por diante, recursivamente (a menos que esses pré-requisitos a sobreponham com seu próprio valor de variável específico de alvo). Por exemplo, uma instrução como
prog : CFLAGS = -g prog : prog.o foo.o bar.o
define CFLAGS como ‘-g’ na receita de prog, mas também define CFLAGS como ‘-g’ nas receitas que criam prog.o, foo.o e bar.o e em qualquer receita que crie seus pré-requisitos.
Observe, porém, que um dado pré-requisito é construído, no máximo, uma vez por invocação do make. Se o mesmo arquivo for pré-requisito de vários alvos, e esses alvos tiverem valores diferentes para a mesma variável específica de alvo, então o primeiro alvo a ser construído fará com que o pré-requisito seja construído, e o pré-requisito herda o valor específico de alvo do primeiro alvo. Os valores específicos de alvo dos outros alvos são ignorados.
Além dos valores de variáveis específicos de alvo (veja Valores de variáveis específicos de alvo), o GNU make também oferece suporte a valores de variáveis específicos de padrão. Nessa forma, a variável é definida para qualquer alvo que corresponda ao padrão especificado.
Os valores de variáveis específicos de padrão são definidos assim:
pattern … : variable-assignment
onde pattern é um padrão com %. Assim como nos valores de variáveis específicos de alvo, quando vários pattern são especificados, é criado um valor de variável específico de padrão individual para cada padrão. O variable-assignment pode ser qualquer forma de atribuição válida. Uma definição de variável na linha de comando tem precedência, a menos que override seja especificado.
Por exemplo,
%.o : CFLAGS = -O
atribui o valor ‘-O’ a CFLAGS para todos os alvos que correspondam ao padrão %.o.
Se um alvo corresponder a vários padrões, os valores de variáveis específicos de padrão correspondentes são interpretados primeiro pelos de radical (stem) mais longo. Isso faz com que as variáveis mais específicas tenham precedência sobre as mais genéricas. Por exemplo,
%.o: %.c
$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@
lib/%.o: CFLAGS := -fPIC -g
%.o: CFLAGS := -g
all: foo.o lib/bar.o
Nesse exemplo, embora a segunda definição também se aplique ao alvo lib/bar.o, é a primeira definição da variável CFLAGS que é usada para atualizar lib/bar.o. As variáveis específicas de padrão cujo radical tenha o mesmo comprimento são consideradas na ordem em que são definidas no makefile.
As variáveis específicas de padrão são procuradas depois das variáveis específicas de alvo definidas explicitamente para esse alvo e antes das variáveis específicas de alvo definidas para o alvo pai.
Como descrito nas seções anteriores, as variáveis do make são herdadas pelos pré-requisitos. Esse recurso permite alterar o comportamento de um pré-requisito conforme o alvo que o fez ser reconstruído. Por exemplo, se você definir uma variável específica de alvo no alvo debug, ao executar ‘make debug’ essa variável é herdada por todos os pré-requisitos de debug; já ao executar simplesmente ‘make all’ (por exemplo), essa atribuição não acontece.
Às vezes, porém, você pode não querer que uma variável seja herdada. Para essas situações, o make oferece o modificador private. Embora esse modificador possa ser usado em qualquer atribuição de variável, ele faz mais sentido com variáveis específicas de alvo e específicas de padrão. Uma variável marcada com private é visível ao seu alvo local, mas não é herdada por seus pré-requisitos. Uma variável global marcada com private é visível no escopo global, mas não é herdada por nenhum alvo e, portanto, não é visível em nenhuma receita.
Como exemplo, considere o seguinte makefile:
EXTRA_CFLAGS = prog: private EXTRA_CFLAGS = -L/usr/local/lib prog: a.o b.o
Graças ao modificador private, a.o e b.o não herdam a atribuição da variável EXTRA_CFLAGS feita a partir do alvo prog.
O GNU make oferece suporte a algumas variáveis com propriedades especiais.
MAKEFILE_LIST
Mantém o nome de cada makefile que o make analisou, na ordem em que foram analisados. O nome é acrescentado imediatamente antes de o make começar a analisar aquele makefile. Assim, se a primeira coisa que um makefile faz é examinar a última palavra desta variável, esse será o nome do makefile atual. No entanto, depois que o makefile atual usa include, a última palavra passa a ser o makefile que acabou de ser lido.
Suponha que um makefile chamado Makefile tenha o seguinte conteúdo:
name1 := $(lastword $(MAKEFILE_LIST))
include inc.mk
name2 := $(lastword $(MAKEFILE_LIST))
all:
@echo name1 = $(name1)
@echo name2 = $(name2)
Então, pode-se esperar a seguinte saída:
name1 = Makefile name2 = inc.mk
.DEFAULT_GOAL
Define a meta padrão a ser usada quando nenhum alvo é especificado na linha de comando (veja Argumentos para especificar as metas). A variável .DEFAULT_GOAL permite examinar a meta padrão atual, limpar seu valor para reiniciar o algoritmo de seleção da meta padrão ou definir a meta padrão explicitamente. O exemplo a seguir ilustra esses casos:
# Query the default goal. ifeq ($(.DEFAULT_GOAL),) $(warning no default goal is set) endif .PHONY: foo foo: ; @echo $@ $(warning default goal is $(.DEFAULT_GOAL)) # Reset the default goal. .DEFAULT_GOAL := .PHONY: bar bar: ; @echo $@ $(warning default goal is $(.DEFAULT_GOAL)) # Set our own. .DEFAULT_GOAL := foo
Esse makefile produz a seguinte saída:
no default goal is set default goal is foo default goal is bar foo
Observe que atribuir mais de um nome de alvo a .DEFAULT_GOAL é inválido e resulta em erro.
MAKE_RESTARTS
Esta variável só é definida se esta instância do make tiver sido reiniciada (veja Como os makefiles são regenerados). Ela contém o número de vezes que esta instância foi reiniciada. Observe que isso é diferente da recursão (contada pela variável MAKELEVEL). Você não deve definir, alterar nem exportar esta variável.
MAKE_TERMOUTMAKE_TERMERR
Ao iniciar, o make verifica se a saída padrão e a saída de erro padrão exibem, cada uma, sua saída em um terminal. Em caso afirmativo, define MAKE_TERMOUT e MAKE_TERMERR, respectivamente, com o nome do dispositivo de terminal (ou true, se isso não puder ser determinado). Quando definidas, essas variáveis são marcadas para exportação. Essas variáveis não são modificadas pelo make e não são alteradas se já estiverem definidas.
Esses valores podem ser usados (especialmente em combinação com a sincronização de saída; veja Saída durante a execução paralela) para determinar se o próprio make está escrevendo em um terminal. Por exemplo, você pode testá-los para decidir se deve forçar saída colorida nos comandos de uma receita.
Se você invocar um sub-make e redirecionar sua saída padrão ou sua saída de erro padrão, é responsabilidade sua redefinir ou desexportar também essas variáveis, caso o makefile dependa delas.
.RECIPEPREFIXO primeiro caractere do valor desta variável é usado como o caractere que o make considera indicar o início de uma linha de receita. Se a variável estiver vazia (como é por padrão), esse caractere é o caractere de tabulação padrão. Por exemplo, o seguinte é um makefile válido:
.RECIPEPREFIX = > all: > @echo Hello, world
O valor de .RECIPEPREFIX pode ser alterado quantas vezes você quiser. Uma vez definido, ele permanece em vigor para todas as regras analisadas a seguir, até ser alterado.
.VARIABLESExpande-se para uma lista dos nomes de todas as variáveis globais definidas até o momento. Isso inclui variáveis com valor vazio e variáveis embutidas (veja Variáveis usadas pelas regras implícitas), mas não inclui variáveis definidas apenas em um contexto específico de alvo. Observe que qualquer valor atribuído a esta variável é ignorado; ela sempre retorna esse valor especial.
.FEATURES
Expande-se para uma lista dos recursos especiais aos quais esta versão do make oferece suporte. Os valores possíveis incluem, mas não se limitam a:
Oferece suporte a arquivos ar (de arquivo) usando a sintaxe especial de nome de arquivo. Veja Atualizando arquivos de arquivo com o make.
Oferece suporte ao sinalizador -L (--check-symlink-times). Veja Sumário das opções.
Oferece suporte a condicionais “else if” não aninhados. Veja Sintaxe dos condicionais.
Oferece suporte ao alvo especial .EXTRA_PREREQS.
Oferece suporte à sintaxe de alvos agrupados de regras explícitas. Veja Vários alvos em uma regra.
GNU Guile está disponível como linguagem de extensão embutida. Veja Integração com o GNU Guile.
Oferece suporte a construções em paralelo aprimoradas por meio de um “jobserver”. Veja Execução paralela.
Oferece suporte a construções em paralelo aprimoradas por meio de um “jobserver” que usa pipes nomeados. Veja Integrando o GNU make.
Oferece suporte a objetos carregáveis dinamicamente para criar extensões personalizadas. Veja Carregamento de objetos dinâmicos.
Oferece suporte ao alvo especial .NOTINTERMEDIATE. Veja Integrando o GNU make.
Oferece suporte ao alvo especial .ONESHELL. Veja Usando um único shell.
Oferece suporte a pré-requisitos somente de ordem. Veja Tipos de pré-requisitos.
Oferece suporte à opção de linha de comando --output-sync. Veja Sumário das opções.
Oferece suporte à expansão secundária das listas de pré-requisitos.
Oferece suporte à exportação de variáveis do make para a função shell.
Usa o método do “radical mais curto” para escolher qual padrão usar dentre as várias alternativas aplicáveis. Veja Como os padrões correspondem.
Oferece suporte a atribuições de variáveis específicas de alvo e específicas de padrão. Veja Valores de variáveis específicos de alvo.
Oferece suporte à diretiva undefine. Veja Removendo a definição de variáveis.
.INCLUDE_DIRS
Expande-se para a lista de diretórios em que o make procura makefiles incluídos (veja Incluindo outros makefiles). Observe que alterar o valor desta variável não altera a lista de diretórios pesquisados.
.EXTRA_PREREQSCada palavra desta variável é um novo pré-requisito acrescentado aos alvos para os quais ela está definida. Esses pré-requisitos diferem dos pré-requisitos normais por não aparecerem em nenhuma das variáveis automáticas (veja Variáveis automáticas). Isso permite definir pré-requisitos que não afetam a receita.
Considere uma regra para vincular um programa:
myprog: myprog.o file1.o file2.o
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)
Suponha agora que você queira aprimorar este makefile para que o programa seja revinculado sempre que houver uma atualização do compilador. Você pode acrescentar o compilador como pré-requisito, mas precisa garantir que ele não seja passado como argumento ao comando de vinculação. Seria necessário algo como:
myprog: myprog.o file1.o file2.o $(CC)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ \
$(filter-out $(CC),$^) $(LDLIBS)
Considere agora o caso em que há vários pré-requisitos adicionais; seria preciso excluir todos eles. Usando .EXTRA_PREREQS e uma variável específica de alvo, obtém-se uma solução mais simples:
myprog: myprog.o file1.o file2.o
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)
myprog: .EXTRA_PREREQS = $(CC)
Esse recurso também é útil quando você quer acrescentar pré-requisitos a um makefile que não pode ser alterado facilmente. Crie um novo arquivo, como extra.mk:
myprog: .EXTRA_PREREQS = $(CC)
e então invoque make -f extra.mk -f Makefile.
Definir .EXTRA_PREREQS globalmente acrescenta esses pré-requisitos a todos os alvos (que não os tenham sobreposto com um valor específico de alvo). Observe que o make é esperto o suficiente para não acrescentar um pré-requisito listado em .EXTRA_PREREQS como pré-requisito de si mesmo.