Прервать 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
596   4  

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 указана как только для заказа (|...) обязательное условие.

плюсы:

  • (возможно) более чистый синтаксис

плюсы:

я считаю, что эти ограничения можно преодолеть с помощью некоторых 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

    Ничего не найдено.