Тестирование, если файл существует в целевом файле makefile, и завершение, если нет
Есть ли способ выйти с условием ошибки, если файл не существует? В настоящее время я делаю что-то вроде этого:
all: foo
foo:
test -s /opt/local/bin/gsort || echo "GNU sort does not exist! Exiting..." && exit
Запуск make
запускает цель all
, которая запускает foo
.
Ожидается, что если условие test -s
не выполнено, то выполняются операторы echo/exit
.
Однако, даже если /usr/bin/gsort
существует, я получаю результат оператора echo
, но команда exit
не запускается. Это противоположность тому, что я надеюсь выполнить.
Каков правильный способ сделать что-то вроде выше?
Ответы
Ответ 1
exit
возвращает статус последней выполненной команды. В этом случае он возвращает ноль, что означает, что все в порядке.
Это потому, что ||
и &&
имеют равный приоритет, и оболочка интерпретирует команду так, как если бы она была написана
( test ... || echo ... ) && exit
Если вы хотите подать сигнал об ошибке, вы должны выйти с ненулевым значением, например. exit 1
.
И если вы хотите эхо и выйти, просто поместите команды в последовательности, разделенные ;
all: foo
foo:
test -s /opt/local/bin/gsort || { echo "GNU sort does not exist! Exiting..."; exit 1; }
Ответ 2
Я понимаю, что это немного устарело на данный момент, но вам не нужно даже использовать подоболочку, чтобы проверить, существует ли файл в Make.
Это также зависит от того, как вы хотите/ожидаете его запуска.
Использование подстановочной функции, например:
all: foo
foo:
ifeq (,$(wildcard /opt/local/bin/gsort))
$(error GNU Sort does not exist!)
endif
- один из лучших способов сделать это. Обратите внимание, что предложение ifeq не имеет отступ, потому что оно оценивается до самой цели.
Если вы хотите, чтобы это произошло безоговорочно для каждой цели, вы можете просто переместить его за пределы цели:
ifeq (,$(wildcard /opt/local/bin/gsort))
$(error GNU Sort does not exist!)
endif
Ответ 3
Каждая командная строка в make работает в своей собственной суб-оболочке. Таким образом, запуск exit
просто завершает эту под-оболочку, а не make файл в целом. По умолчанию выполнение make
прекратится, если какая-либо суб-оболочка вернет неудачный статус выхода (по соглашению 0 означает успех, так что все остальное остановит выполнение). Простейшим методом было бы просто использовать статус выхода команды test
:
all: foo
foo:
test -s /opt/local/bin/gsort
Печать диагностического сообщения немного усложняет ситуацию, потому что команды типа echo
возвращают статус выхода 0, заставляя make
думать, что все в порядке. Чтобы обойти это, вам нужно запустить команду после нее, которая предоставит суб-оболочке ненулевой статус выхода:
all: foo
foo:
test -s /opt/local/bin/gsort || { echo "GNU sort does not exist! Exiting..."; exit 1; }
или даже просто
all: foo
foo:
test -s /opt/local/bin/gsort || { echo "GNU sort does not exist! Exiting..."; false; }
Ответ 4
Просто выполните:
all: /opt/local/bin/gsort
и если /opt/local/bin/gsort
отсутствует, вы получите сообщение об ошибке "no rule to target target//local/bin/gsort".
Но если вы также хотите, чтобы с ним было приятное объяснение:
/opt/local/bin/gsort:
echo "GNU sort does not exist! Exiting..."
false
В GNU/Make, если цель не объявлена .PHONEY
и не имеет каких-либо зависимостей, правило будет вызываться, если файл, соответствующий этой цели, не существует.
Приведенный выше код запускает команду false
только тогда, когда /opt/local/bin/gsort
не существует, будет возвращать значение не 0, и make будет терпеть неудачу.
Ответ 5
Поскольку вы проверяете, существует ли исполняемый файл gsort
, вы можете использовать команду оболочки which
или type
для этого, например:
all: foo
:
foo:
which gsort || exit 1
# or
type gsort || exit 1
Вам не требуется сообщение об ошибке, так как оно автоматически распечатает:
/bin/sh: строка 0: type: gsort
: не найден
что очевидно.
В качестве альтернативы используйте test
или [
(см. help test
/help [
для синтаксиса), например
test -x /opt/local/bin/gsort || { echo Error msg; exit 1; }
который проверяет, существует ли данный файл и его исполняемый файл, в противном случае отобразите сообщение и выйдите из него. Скобки важны для переопределения обычного приоритета операторов (слева направо) путем группировки команд (см. Раздел Compound Commands
в man bash
для дополнительной информации).
Другим способом является использование целевых значений правил для проверки наличия файла и добавления в качестве зависимости от all
, например.
all: /opt/local/bin/gsort
@echo Success.
/opt/local/bin/gsort:
@echo "GNU sort does not exist! Exiting..."
exit 1
Результат:
$ make
GNU sort does not exist! Exiting...
exit 1
make: *** [/opt/local/bin/gsort] Error 1