Как сделать сбой прерывания команды $ (shell) Make
Вопрос
У меня есть Makefile, который запускается с запуска инструмента перед применением правил сборки (которые этот инструмент пишет для меня). Если этот инструмент, представляющий собой скрипт Python, завершает работу с ненулевым кодом состояния, я хочу, чтобы GNU Make остановилась и не продолжала сборку программы.
В настоящее время я делаю что-то вроде этого (верхний уровень, то есть столбец 1):
$(info Generating build rules...)
$(shell python collect_sources.py)
include BuildRules.mk
Но это не останавливает make, если collect_sources.py
выходит с кодом состояния 1. Это также фиксирует стандартный вывод <=>, но не выводит его на печать, поэтому у меня такое ощущение, что я смотрю неправильно направление. р>
Если это вообще возможно, решение должно работать даже тогда, когда простая оболочка MS-DOS является стандартной системной оболочкой.
Есть предложения?
Решение 2
Хорошо, вот мое собственное решение, которое, к сожалению, не основано на коде состояния скрипта collect_sources.py, но которое работает для меня (TM) и позволяет мне видеть любой вывод, который генерирует скрипт:
SHELL_OUTPUT := $(shell python collect_sources.py 2>&1)
ifeq ($(filter error: [Errno %],$(SHELL_OUTPUT)),)
$(info $(SHELL_OUTPUT))
else
$(error $(SHELL_OUTPUT))
endif
Сценарий написан так, что любая ошибка приводит к выводу, начинающемуся с "collect_sources: error:"
. Кроме того, если python не может найти или выполнить данный скрипт, он выводит сообщение об ошибке, содержащее сообщение "[Errno 2]"
или подобное. Так что этот маленький кусочек кода просто захватывает выходные данные (перенаправляет stderr на stdout) и ищет сообщения об ошибках. Если ничего не найдено, он просто использует $(info)
для распечатки вывода, в противном случае он использует $(error)
, что фактически делает Make stop.
Обратите внимание, что отступ в ifeq ... endif
делается с пробелами. Если используются вкладки, Make думает, что вы пытаетесь вызвать команду, и жалуется на нее.
Другие советы
Возможно, есть лучший способ, но я попробовал следующее, и это работает:
$(if $(shell if your_command; then echo ok; fi), , $(error your_command failed))
Здесь я предположил, что your_command
не дает никакого вывода, но не должно быть сложно обойти эту ситуацию.
Изменить: чтобы заставить его работать со стандартной оболочкой Windows (и, возможно, любой приличной оболочкой), вы можете написать your_command && echo ok
вместо if
внутри функции shell
. Я не думаю, что это возможно для (более старых) оболочек DOS. Для этого вы, вероятно, захотите адаптировать <=> или написать скрипт-обертку, чтобы что-то напечатать в случае ошибки (или успеха).
Для создания BuildRules.mk вы должны использовать обычную цель:
BuildRules.mk: collect_sources.py
python $< >$@
include BuildRules.mk
Это стандартный прием, используемый при автоматической генерации зависимостей.
Исправление https://stackoverflow.com/a/226974/192373
.PHONY: BuildRules.mk
BuildRules.mk: collect_sources.py
echo Generating build rules...)
python $< >$@
$(MAKE) -f BuildRules.mk
Убедитесь, что вы не запускаете make / gmake с параметром -k.