У меня есть Makefile, который запускается с запуска инструмента перед применением правил сборки (которые этот инструмент пишет для меня). Если этот инструмент, представляющий собой сценарий Python, завершается с кодом состояния, отличным от NULL, я хочу, чтобы GNU Make остановился прямо на этом и не продолжал сборку программы.
В настоящее время я делаю что-то вроде этого (верхний уровень, т.е. столбец 1):
$(info Generating build rules...)
$(shell python collect_sources.py)
include BuildRules.mk
Но это не останавливает make, если collect_sources.py выходит с кодом состояния 1. Это также захватывает стандартный вывод collect_sources.py, но не распечатывает его, поэтому у меня такое чувство, что я смотрю в неправильном направлении.
Если это вообще возможно, решение должно работать даже тогда, когда простая оболочка MS-DOS является стандартной системной оболочкой.
Любое предложение?
Имя переменной - $(.SHELLSTATUS), без _. gnu.org/software/make/manual/html_node/…
См. Также stackoverflow.com/a/59392005/491884, вы можете использовать хак (убить родительский процесс make с помощью || kill $$PPID).





Возможно, есть способ получше, но я попробовал следующее, и он работает:
$(if $(shell if your_command; then echo ok; fi), , $(error your_command failed))
Здесь я предположил, что your_command не дает никаких результатов, но в такой ситуации нетрудно обойтись.
Обновлено: чтобы заставить его работать с оболочкой Windows по умолчанию (и, возможно, с любой приличной оболочкой), вы можете написать your_command && echo ok вместо if в функции shell. Я не думаю, что это возможно для (старых) оболочек DOS. Для них вы, вероятно, захотите адаптировать your_command или написать сценарий-оболочку для печати чего-либо в случае ошибки (или успеха).
Спасибо, похоже, шаг в правильном направлении; Хотелось бы, чтобы его можно было сделать макросами, как sherr (), пока не удалось.
Просто выложите его там, если вы готовы предположить, что Unix (я полностью согласен), это был единственный вариант, который, как я обнаружил, работал. Я делал полную ерунду с define template, который позже был $(eval $(call template,arg1,arg2) ... что было ужасно. Но он полностью работает с вышеупомянутым, стараясь дублировать $$все. Надеюсь, что когда-нибудь это принесет пользу (@ в начале - это потому, что я нахожусь в целевом определении): @$$(if $$(shell if ./generate.sh $(2) $(1); then echo "score"; fi), ,$$(error Unable to generate [$(2)] from [$(1)]))
Для создания BuildRules.mk следует использовать обычную цель:
BuildRules.mk: collect_sources.py
python $< >$@
include BuildRules.mk
Это стандартный прием, который можно использовать при автоматическом создании зависимостей.
Джеспер, спасибо за ваш вклад, но я не понимаю, как ваше правило может решить мою проблему. Мне нужно, чтобы collect_sources.py запускался каждый раз, чтобы я мог обновлять список исходных файлов, правил и т. д. Или мне что-то не хватает?
Затем добавьте вверху ".PHONY: BuildRules.mk".
Возможно, мне здесь не хватает чего-то очевидного, но я не могу заставить это работать правильно. BuildRules.mk обновляется каждый раз (с использованием .PHONY), но включение происходит до того, как это будет выполнено. Фактически это означает, что вы всегда используете предыдущий BuildRules.mk.
Хм. .PHONY не позволяет Make перезагрузить сгенерированный файл, я это пропустил. BuildRules.mk требует правильной зависимости от чего-либо.
Как насчет использования $ (подстановочный знак ...), чтобы BuildRules.mk зависел от всех файлов, которые могут влиять на правила сборки?
Убедитесь, что вы не вызываете make / gmake с параметром -k.
Ваше предложение кажется логичным, но на самом деле опция -k не влияет на поведение make при сбое команд в функции shell.
Хорошо, вот мое собственное решение, которое, к сожалению, не основано на коде состояния скрипта 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.
Обратите внимание, что отступ в ifeq ... endif делается пробелами. Если используются вкладки, Make думает, что вы пытаетесь вызвать команду, и жалуется на это.
Исправление https://stackoverflow.com/a/226974/192373
.PHONY: BuildRules.mk
BuildRules.mk: collect_sources.py
echo Generating build rules...)
python $< >$@
$(MAKE) -f BuildRules.mk
1) .PHONY, а не %PHONY. 2) BuildRules.mk явно не самодостаточный make-файл. 3) рекурсивный make теряет весь граф зависимостей от своего родителя.
@VictorSergienko Спасибо за исправление и разъяснения.
Если у вас GNU make 4.2 или выше, вы можете проверить переменную
$(.SHELL_STATUS), которая будет содержать статус выхода последней оцененной функции$(shell ...).