TL; DR : использовать error
функцию :
ifndef MY_FLAG
$(error MY_FLAG is not set)
endif
Обратите внимание, что строки не должны иметь отступ. Точнее, никакие вкладки не должны предшествовать этим строкам.
Универсальное решение
Если вы собираетесь тестировать много переменных, для этого стоит определить вспомогательную функцию:
# 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))))
А вот как это использовать:
$(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)
Это вывело бы ошибку как это:
Makefile:17: *** Undefined OUT_DIR (build directory). Stop.
Ноты:
Настоящая проверка сделана здесь:
$(if $(value $1),,$(error ...))
Это отражает поведение ifndef
условия, так что переменная, определенная для пустого значения, также считается «неопределенной». Но это верно только для простых переменных и явно пустых рекурсивных переменных:
# 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)
Как предполагает @VictorSergienko в комментариях, может потребоваться немного другое поведение:
$(if $(value $1)
проверяет, является ли значение не пустым Иногда нормально, если переменная определена с пустым значением . Я бы использовал$(if $(filter undefined,$(origin $1)) ...
И:
Более того, если это каталог, и он должен существовать при запуске проверки, я бы использовал $(if $(wildcard $1))
. Но была бы другая функция.
Целевая проверка
Также возможно расширить решение, так что можно потребовать переменную, только если вызывается определенная цель.
$(call check_defined, ...)
изнутри рецепт
Просто переместите чек в рецепт:
foo :
@:$(call check_defined, BAR, baz value)
Ведущий @
знак отключает отображение команд и :
является фактической командой, заглушка no-op оболочки .
Отображение имени цели
check_defined
Функция может быть улучшена также выход целевого имени ( при условии , через $@
переменную):
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 `$@')))
Таким образом, теперь неудачная проверка выдает красиво отформатированный вывод:
Makefile:7: *** Undefined BAR (baz value) required by target `foo'. Stop.
check-defined-MY_FLAG
особая цель
Лично я бы использовал простое и понятное решение выше. Однако, например, этот ответ предлагает использовать специальную цель для выполнения фактической проверки. Можно попытаться обобщить это и определить цель как неявное шаблонное правило:
# 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 :
Использование:
foo :|check-defined-BAR
Обратите внимание, что в check-defined-BAR
качестве обязательного условия указан только order ( |...
).
Плюсы:
- (возможно) более чистый синтаксис
Минусы:
Я считаю, что эти ограничения могут быть преодолены с помощью некоторых eval
магических и вторичных хакерских расширений , хотя я не уверен, что оно того стоит.