Прервать makefile, если переменная не установлена
как я могу прервать выполнение make/makefile на основе переменной makefile, которая не задана/не оценена?
Я придумал это, но работает только если вызывающий объект явно не запускает цель (т. е. запускает make только).
ifeq ($(MY_FLAG),)
abort: ## This MUST be the first target :( ugly
@echo Variable MY_FLAG not set && false
endif
all:
@echo MY_FLAG=$(MY_FLAG)
Я думаю, что что-то вроде этого было бы хорошей идеей, но ничего не нашел в руководстве make:
ifndef MY_FLAG
.ABORT
endif
4 ответов:
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,, \ $(call __check_defined,,$(strip $(value 2))))) __check_defined = \ $(if $(value ),, \ $(error Undefined $(if , ())))а вот как его использовать:
$(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 окурок.отображение имени цели
The
check_definedфункция может быть улучшена, чтобы также вывести целевое имя (предоставленное через$@переменной):check_defined = \ $(strip $(foreach 1,, \ $(call __check_defined,,$(strip $(value 2))))) __check_defined = \ $(if $(value ),, \ $(error Undefined $(if , ())$(if $(value @), \ required by target `$@')))так что теперь неудачная проверка дает хорошо отформатированный вывод:
Makefile:7: *** Undefined BAR (baz value) required by target `foo'. Stop.
check-defined-MY_FLAGспециальный элементлично я бы использовал простое и понятное решение выше. Однако, например, ответ предлагает использовать a специальная цель для выполнения фактической проверки. Можно попытаться обобщить это и определить цель как неявное правило шаблона:
# 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магия и вторичное расширение хаки, хотя я не уверен, что это того стоит.
используйте функцию оболочки
test:foo: test $(something)использование:
$ make foo test Makefile:2: recipe for target 'foo' failed make: *** [foo] Error 1 $ make foo something=x test x
используйте обработку ошибок оболочки для неназначенных переменных (обратите внимание на double
$):$ cat Makefile foo: echo "something is set to $${something:?}" $ make foo echo "something is set to ${something:?}" /bin/sh: something: parameter null or not set make: *** [foo] Error 127 $ make foo something=x echo "something is set to ${something:?}" something is set to xЕсли вам нужно пользовательское сообщение об ошибке, добавьте его после
?:$ cat Makefile hello: echo "hello $${name:?please tell me who you are via $$name}" $ make hello echo "hello ${name:?please tell me who you are via $name}" /bin/sh: name: please tell me who you are via $name make: *** [hello] Error 127 $ make hello name=jesus echo "hello ${name:?please tell me who you are via $name}" hello jesus
вы можете использовать IF для тестирования:
check: @[ "${var}" ] || ( echo ">> var is not set"; exit 1 )результат:
$ make check >> var is not set Makefile:2: recipe for target 'check' failed make: *** [check] Error 1
Comments