Ответ 1
Используйте функцию 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.
Проверка по конкретным объектам
Также можно расширить решение, чтобы можно было потребовать переменную, только если вызывается определенная цель.
$(call check_defined, ...)
изнутри рецепта
Просто переместите чек в рецепт:
foo :
@:$(call check_defined, BAR, baz value)
Ведущий знак @
отключает команду эхо-сигнала, а :
- действительная команда, оболочка no-op stub.
Отображение имени цели
Функция check_defined
может быть улучшена для вывода целевого имени (предоставляется через переменную [email protected]
):
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 `[email protected]')))
Итак, теперь неудавшаяся проверка производит хорошо отформатированный вывод:
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
указан как только для заказа (|...
).
Плюсы:
- (возможно) более чистый синтаксис
Минусы:
- Невозможно указать пользовательское сообщение об ошибке
- Запуск
make -t
(см. Вместо выполнения рецептов) загрязнит ваш корневой каталог большим количеством файловcheck-defined-...
. Это печальный недостаток в том, что шаблонные правила не могут быть объявлены.PHONY
.
Я считаю, что эти ограничения можно преодолеть, используя eval
magic и вторичное расширение, хотя я не уверен, что это того стоит.