Как я могу перехватывать ошибки и прерывания в GNU make? - PullRequest
11 голосов
/ 10 июня 2009

Мне интересно, есть ли способ реализовать trap в GNU make, похожий на тот, который встроен в BASH?

Если пользователь нажимает CTRL-C, или если make сам не удается (выход не из нуля), я хотел бы вызвать конкретную цель или макрос.

Ответы [ 6 ]

9 голосов
/ 25 сентября 2015

На данный момент GNU make не имеет встроенной поддержки.

Однако существует надежный обходной путь:

.PHONY: internal-target external-target

external-target:
  bash -c "trap 'trap - SIGINT SIGTERM ERR; <DO CLEANUP HERE>; exit 1' SIGINT SIGTERM ERR; $(MAKE) internal-target"

internal-target:
  echo "doing stuff here"

Это ловит прерывания, завершения и любые ненулевые коды выхода.

Обратите внимание на $(MAKE), так что cmdline переопределяет и делает опции переданными в submake.

В ловушке:

  • Очистить обработчик ловушек (с -)
  • сделать уборку
  • выход с ненулевым состоянием выхода, поэтому инструменты автоматизации сборки сообщают о сбое сборки.

DELETE_ON_ERROR НЕ работает для каталогов, поэтому это ключ для очистки после mktemp -d, например

Заменить <DO CLEANUP HERE> действительным CMD.

8 голосов
/ 03 сентября 2016

Упрощенная версия ответа @ kevinf, которая кажется достаточно хорошей для основных случаев:

run:
    bash -c "trap 'docker-compose down' EXIT; docker-compose up --build"

(Этот пример по причине: docker-compose up говорит

Когда команда завершается, все контейнеры останавливаются.

но он не rm остановит контейнеры, как docker run --rm, поэтому вы все равно можете видеть их с помощью docker ps -a.)

3 голосов
/ 22 июля 2009

Нет. Обработка сигналов GNU make уже оставляет желать лучшего. Из своего обработчика сигнала он вызывает функции типа printf, которые небезопасно вызывать из обработчика сигнала. Я видел эту проблему, например, .DELETE_ON_ERROR правила не всегда выполняются, если stderr перенаправлен на stdout.

Например, на коробке CentOS 7.4:

  1. Создать следующее Makefile:

    .DELETE_ON_ERROR:
    
    foo:
            touch $@
            sleep 10
    
  2. Откройте его в vim и запустите :make,

  3. Пока он спит, нажмите Ctrl - C

Vim / сделать отпечатки

Press ENTER or type command to continue
touch foo
sleep 10
^C
shell returned 130

Interrupt: Press ENTER or type command to continue

Make был отправлен сигнал прерывания, но foo все еще существует.

2 голосов
/ 13 апреля 2010

Make не поддерживает его, но используя трюки BASH, вы можете сделать нечто подобное.

default: complete

complete: do_mount
        echo "Do something here..."

do_mount:
        mkdir -p "$(MOUNTPOINT)"
        ( while ps -p $$PPID >/dev/null ; do \
                sleep 1 ; \
        done ; \
        unmount "$(MOUNTPOINT)" \
        ) &
        mount "$(MOUNTSOURCE)" "$(MOUNTPOINT)" -o bind

«unmount» будет запущен после завершения «make». Обычно это удовлетворительное решение, если вы пытаетесь очистить операции, которые могут произойти во время сборки, но обычно не очищаются на выходе «make».

1 голос
/ 10 июня 2009

make выдает коды возврата. Насколько я помню сейчас, он возвращает 0 для успеха, 2 для неудачи (пожалуйста, проверьте документацию). Следовательно, вам будет достаточно, например, обернуть make внутри скрипта?

1 голос
/ 10 июня 2009

Нет. Насколько я знаю, такой функциональности нет.

...