TL; DR : use a error
função :
ifndef MY_FLAG
$(error MY_FLAG is not set)
endif
Observe que as linhas não devem ser recuadas. Mais precisamente, nenhuma guia deve preceder essas linhas.
Solução genérica
Caso você teste várias variáveis, vale a pena definir uma função auxiliar para isso:
# Check that given variables are set and all have non-empty values,
# die with an error otherwise.
#
# Params:
# 1. Variable name(s) to test.
# 2. (optional) Error message to print.
check_defined = \
$(strip $(foreach 1,$1, \
$(call __check_defined,$1,$(strip $(value 2)))))
__check_defined = \
$(if $(value $1),, \
$(error Undefined $1$(if $2, ($2))))
E aqui está como usá-lo:
$(call check_defined, MY_FLAG)
$(call check_defined, OUT_DIR, build directory)
$(call check_defined, BIN_DIR, where to put binary artifacts)
$(call check_defined, \
LIB_INCLUDE_DIR \
LIB_SOURCE_DIR, \
library path)
Isso geraria um erro como este:
Makefile:17: *** Undefined OUT_DIR (build directory). Stop.
Notas:
A verificação real é feita aqui:
$(if $(value $1),,$(error ...))
Isso reflete o comportamento da ifndef
condicional, de modo que uma variável definida com um valor vazio também é considerada "indefinida". Mas isso só é verdade para variáveis simples e variáveis recursivas explicitamente vazias:
# ifndef and check_defined consider these UNDEFINED:
explicitly_empty =
simple_empty := $(explicitly_empty)
# ifndef and check_defined consider it OK (defined):
recursive_empty = $(explicitly_empty)
Conforme sugerido por @VictorSergienko nos comentários, um comportamento ligeiramente diferente pode ser desejado:
$(if $(value $1)
testa se o valor não está vazio. Às vezes, tudo bem se a variável for definida com um valor vazio . Eu usaria$(if $(filter undefined,$(origin $1)) ...
E:
Além disso, se é um diretório e deve existir quando a verificação é executada, eu usaria $(if $(wildcard $1))
. Mas seria outra função.
Verificação específica do alvo
Também é possível estender a solução para que se possa exigir uma variável apenas se um determinado destino for invocado.
$(call check_defined, ...)
de dentro da receita
Basta mover o cheque para a receita:
foo :
@:$(call check_defined, BAR, baz value)
O @
sinal principal desativa o eco do comando e :
é o comando real, um esboço de no-op do shell .
Mostrando o nome do destino
A check_defined
função pode ser aprimorada para também gerar o nome do destino (fornecido através da $@
variável):
check_defined = \
$(strip $(foreach 1,$1, \
$(call __check_defined,$1,$(strip $(value 2)))))
__check_defined = \
$(if $(value $1),, \
$(error Undefined $1$(if $2, ($2))$(if $(value @), \
required by target `$@')))
Portanto, agora uma verificação com falha produz uma saída bem formatada:
Makefile:7: *** Undefined BAR (baz value) required by target `foo'. Stop.
check-defined-MY_FLAG
alvo especial
Pessoalmente, eu usaria a solução simples e direta acima. No entanto, por exemplo, esta resposta sugere o uso de um destino especial para executar a verificação real. Pode-se tentar generalizar isso e definir o destino como uma regra padrão implícita:
# Check that a variable specified through the stem is defined and has
# a non-empty value, die with an error otherwise.
#
# %: The name of the variable to test.
#
check-defined-% : __check_defined_FORCE
@:$(call check_defined, $*, target-specific)
# Since pattern rules can't be listed as prerequisites of .PHONY,
# we use the old-school and hackish FORCE workaround.
# You could go without this, but otherwise a check can be missed
# in case a file named like `check-defined-...` exists in the root
# directory, e.g. left by an accidental `make -t` invocation.
.PHONY : __check_defined_FORCE
__check_defined_FORCE :
Uso:
foo :|check-defined-BAR
Observe que ele check-defined-BAR
está listado como pré-requisito somente para pedido ( |...
).
Prós:
- (sem dúvida) uma sintaxe mais limpa
Contras:
Eu acredito que essas limitações podem ser superadas usando um pouco de eval
magia e truques de expansão secundários , embora não tenha certeza de que vale a pena.