Переменная Makefile как необходимое условие

В Makefile рецепту deploy требуется переменная среды ENV для правильной работы, в то время как другим все равно, например:

ENV = 

.PHONY: deploy hello

deploy:
    rsync . $(ENV).example.com:/var/www/myapp/

hello:
    echo "I don't care about ENV, just saying hello!"

Как я могу убедиться, что эта переменная установлена, например: есть ли способ объявить эту переменную makefile как обязательное условие рецепта развертывания, например:

deploy: make-sure-ENV-variable-is-set

?

Спасибо.

108 голосов | спросил abernier 18 Jpm1000000pmTue, 18 Jan 2011 23:43:59 +030011 2011, 23:43:59

7 ответов


0

Это приведет к фатальной ошибке, если ENV не определено и что-то в этом нуждается (во всяком случае, в GNUMake).

.PHONY: deploy check-env

deploy: check-env
    ...

other-thing-that-needs-env: check-env
    ...

check-env:
ifndef ENV
  $(error ENV is undefined)
endif

(Обратите внимание, что ifndef и endif не имеют отступов, $ (error) имеет отступы, а не табуляцию - они управляют тем, что делает make" видит ", и действует до запуска Makefile .)

ответил Beta 19 Jam1000000amWed, 19 Jan 2011 06:37:45 +030011 2011, 06:37:45
0

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

guard-%:
    @ if [ "${${*}}" = "" ]; then \
        echo "Environment variable $* not set"; \
        exit 1; \
    fi

Затем вы добавляете цель guard-ENVVAR везде, где хотите утверждать, что переменная определена, например так:

change-hostname: guard-HOSTNAME
        ./changeHostname.sh ${HOSTNAME}

Если вы вызовете 'make change-hostname', не добавляя HOSTNAME = somehostname в вызове, вы получите ошибку, и сборка завершится неудачей.

ответил Clayton Stanley 10 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowSat, 10 Sep 2011 02:00:05 +0400 2011, 02:00:05
0

Встроенный вариант

В моих make-файлах я обычно использую выражение вроде:

deploy:
    test -n "$(ENV)"  # $$ENV
    rsync . $(ENV).example.com:/var/www/myapp/

Причины:

  • это простой однострочный текст
  • это компактно
  • он расположен рядом с командами, которые используют переменную

Не забудьте комментарий, который важен для отладки:

test -n ""
Makefile:3: recipe for target 'deploy' failed
make: *** [deploy] Error 1

... заставляет вас искать Makefile, пока ...

test -n ""  # $ENV
Makefile:3: recipe for target 'deploy' failed
make: *** [deploy] Error 1

... объясняет прямо, что не так

Глобальный вариант (для полноты, но не задан)

В верхней части вашего Makefile вы также можете написать:

ifeq ($(ENV),)
  $(error ENV is not set)
endif

Предупреждения:

  • не использовать вкладку в этом блоке
  • используйте с осторожностью: даже цель clean не будет выполнена, если ENV не установлен. В противном случае см. Более сложный ответ Гудона.
ответил Daniel Alder 7 MarpmMon, 07 Mar 2016 17:13:11 +03002016-03-07T17:13:11+03:0005 2016, 17:13:11
0

Как я вижу, самой команде нужна переменная ENV, чтобы вы могли проверить ее в самой команде:

.PHONY: deploy check-env

deploy: check-env
    rsync . $(ENV).example.com:/var/www/myapp/

check-env:
    if test "$(ENV)" = "" ; then \
        echo "ENV not set"; \
        exit 1; \
    fi
ответил ssmir 19 Jam1000000amWed, 19 Jan 2011 00:06:41 +030011 2011, 00:06:41
0

Одна из возможных проблем с данными ответами на данный момент заключается в том, что порядок зависимости в make не определен. Например, работает:

make -j target

когда target имеет несколько зависимостей, это не гарантирует, что они будут работать в любом заданном порядке.

Решением для этого (чтобы гарантировать, что ENV будет проверен до выбора рецептов) является проверка ENV во время первого прохода make вне любого рецепта:

## Are any of the user's goals dependent on ENV?
ifneq ($(filter deploy other-thing-that-needs-ENV,$(MAKECMDGOALS)),$())
ifndef ENV 
$(error ENV not defined)
endif
endif

.PHONY: deploy

deploy: foo bar
    ...

other-thing-that-needs-ENV: bar baz bono
    ...

Вы можете прочитать о различных используемых функциях /переменных здесь и $() - это просто способ явно заявить, что мы сравниваем с «ничем».

ответил Hudon 26 Mayam13 2013, 04:38:20
0

Я обнаружил, что лучший ответ не может быть использован как требование, за исключением других целей PHONY. При использовании в качестве зависимости для цели, которая является реальным файлом, использование check-env приведет к перестроению этой цели.

Другие ответы являются глобальными (например, переменная требуется для всех целей в Makefile) или использовать оболочку, например. если ENV отсутствует, make завершится независимо от цели.

Решение обеих проблем:

ndef = $(if $(value $(1)),,$(error $(1) not set))

.PHONY: deploy
deploy:
    $(call ndef,ENV)
    echo "deploying $(ENV)"

.PHONY: build
build:
    echo "building"

Вывод выглядит как

$ make build
echo "building"
building
$ make deploy
Makefile:5: *** ENV not set.  Stop.
$ make deploy ENV="env"
echo "deploying env"
deploying env
$

value есть несколько страшных предостережений, но я считаю, что для этого простого использования это лучший выбор.

ответил 23jodys 3 AMpTue, 03 Apr 2018 00:53:43 +030053Tuesday 2018, 00:53:43
0

Вы можете использовать ifdef вместо другой цели.

.PHONY: deploy
deploy:
    ifdef ENV
        rsync . $(ENV).example.com:/var/www/myapp/
    else
        @echo 1>&2 "ENV must be set"
        false                            # Cause deploy to fail
    endif
ответил Daniel Gallagher 18 Jpm1000000pmTue, 18 Jan 2011 23:57:35 +030011 2011, 23:57:35

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132