Как сделать прерывание команды $ (shell) при сбое Make

У меня есть 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 является стандартной системной оболочкой.

Любое предложение?

Если у вас GNU make 4.2 или выше, вы можете проверить переменную $(.SHELL_STATUS), которая будет содержать статус выхода последней оцененной функции $(shell ...).

MadScientist 29.08.2017 15:48

Имя переменной - $(.SHELLSTATUS), без _. gnu.org/software/make/manual/html_node/…

user3159253 06.03.2018 16:24

См. Также stackoverflow.com/a/59392005/491884, вы можете использовать хак (убить родительский процесс make с помощью || kill $$PPID).

jmuc 18.12.2019 15:27
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
22
3
6 992
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Возможно, есть способ получше, но я попробовал следующее, и он работает:

$(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 (), пока не удалось.

Michael Shigorin 20.01.2015 18:13

Просто выложите его там, если вы готовы предположить, что 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)]))

svenevs 12.03.2017 17:34

Для создания BuildRules.mk следует использовать обычную цель:

BuildRules.mk: collect_sources.py
        python $< >$@

include BuildRules.mk

Это стандартный прием, который можно использовать при автоматическом создании зависимостей.

Джеспер, спасибо за ваш вклад, но я не понимаю, как ваше правило может решить мою проблему. Мне нужно, чтобы collect_sources.py запускался каждый раз, чтобы я мог обновлять список исходных файлов, правил и т. д. Или мне что-то не хватает?

Carl Seleborg 22.10.2008 22:46

Затем добавьте вверху ".PHONY: BuildRules.mk".

JesperE 23.10.2008 21:01

Возможно, мне здесь не хватает чего-то очевидного, но я не могу заставить это работать правильно. BuildRules.mk обновляется каждый раз (с использованием .PHONY), но включение происходит до того, как это будет выполнено. Фактически это означает, что вы всегда используете предыдущий BuildRules.mk.

mweerden 24.10.2008 01:45

Хм. .PHONY не позволяет Make перезагрузить сгенерированный файл, я это пропустил. BuildRules.mk требует правильной зависимости от чего-либо.

JesperE 25.10.2008 13:35

Как насчет использования $ (подстановочный знак ...), чтобы BuildRules.mk зависел от всех файлов, которые могут влиять на правила сборки?

JesperE 25.10.2008 13:44

Убедитесь, что вы не вызываете make / gmake с параметром -k.

Ваше предложение кажется логичным, но на самом деле опция -k не влияет на поведение make при сбое команд в функции shell.

Kristian Spangsege 06.11.2013 05:40
Ответ принят как подходящий

Хорошо, вот мое собственное решение, которое, к сожалению, не основано на коде состояния скрипта 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 теряет весь граф зависимостей от своего родителя.

Victor Sergienko 15.05.2019 05:12

@VictorSergienko Спасибо за исправление и разъяснения.

Alex Cohn 15.05.2019 12:18

Другие вопросы по теме