Как проверить возвращаемое значение из директивы оболочки - PullRequest
24 голосов
/ 13 сентября 2011

В моем Makefile мне нужно проверить, является ли текущий каталог репозиторием SVN или нет, и если это не так, я хочу указать ошибку, используя директиву $ (error) в Makefile.

Итак, япланирую использовать возвращаемое значение $ (shell svn info.), но я не уверен, как получить это значение из Makefile.

Примечание: я не пытаюсь получить возвращаемое значение врецепт, а точнее в середине Makefile.

Прямо сейчас я делаю что-то вроде этого, который работает только потому, что stdout пуст, когда это ошибка:

SVN_INFO := $(shell svn info . 2> /dev/null)
ifeq ($(SVN_INFO),)
    $(error "Not an SVN repo...")
endif

IМне все еще хотелось бы узнать, возможно ли получить возвращаемое значение вместо этого в Makefile.

Ответы [ 5 ]

25 голосов
/ 13 сентября 2011

Как насчет использования $? для отображения состояния завершения последней команды?

SVN_INFO := $(shell svn info . 2> /dev/null; echo $$?)
ifeq ($(SVN_INFO),1)
    $(error "Not an SVN repo...")
endif
11 голосов
/ 13 сентября 2011

Для меня это работало нормально - на основе ответа @eriktous с небольшой модификацией перенаправления stdout, а также для пропуска вывода из svn info действительного репозитория svn.

SVN_INFO := $(shell svn info . 1>&2 2> /dev/null; echo $$?)
ifneq ($(SVN_INFO),0)
    $(error "Not an SVN repo...")
endif
10 голосов
/ 21 ноября 2016

Если вы хотите сохранить исходный результат, вам нужно сделать несколько трюков. Если вам повезло, что в вашем распоряжении GNU Make 4.2 (выпущена 2016-05-22) или новее, вы можете использовать переменную .SHELLSTATUS следующим образом.

var := $(shell echo "blabla" ; false)

ifneq ($(.SHELLSTATUS),0)
  $(error shell command failed! output was $(var))
endif

all:
    @echo Never reached but output would have been $(var)

В качестве альтернативы вы можете использовать временный файл или играть с Make's eval, чтобы сохранить строку и / или код выхода в переменной Make. В приведенном ниже примере это сделано, но я бы, конечно, хотел бы увидеть лучшую реализацию, чем эта смущающе сложная версия.

ret := $(shell echo "blabla"; false; echo " $$?")
rc := $(lastword $(ret))
# Remove the last word by calculating <word count - 1> and
# using it as the second parameter of wordlist.
string:=$(wordlist 1,$(shell echo $$(($(words $(ret))-1))),$(ret))

ifneq ($(rc),0)
  $(error shell command failed with $(rc)! output was "$(string)")
endif

all:
    @echo Never reached but output would have been \"$(string)\"
6 голосов
/ 13 сентября 2011

Может как то так?

IS_SVN_CHECKED_OUT := $(shell svn info . 1>/dev/null 2>&1 && echo "yes" || echo "no")
ifne ($(IS_SVN_CHECKED_OUT),yes)
    $(error "The current directory must be checked out from SVN.")
endif
1 голос
/ 05 февраля 2018

Я использую .NOTPARALLEL и функцию make:

.NOTPARALLEL:   

# This function works almost exactly like the builtin shell command, except it
# stops everything with an error if the shell command given as its argument
# returns non-zero when executed.  The other difference is that the output
# is passed through the strip make function (the shell function strips only
# the last trailing newline).  In practice this doesn't matter much since
# the output is usually collapsed by the surroundeing make context to the
# same result produced by strip.
SHELL_CHECKED =                                                      \
  $(strip                                                            \
    $(if $(shell (($1) 1>/tmp/SC_so) || echo nonempty),              \
      $(error shell command '$1' failed.  Its stderr should be above \
              somewhere.  Its stdout is in '/tmp/SC_so'),            \
      $(shell cat /tmp/SC_so)))
...