前提条件としてのMakefile変数


134

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

ありがとうございました。


「この変数が設定されていることを確認してください」とはどういう意味ですか?確認または確認するという意味ですか?以前に設定されていない場合は、make設定するか、警告を出すか、致命的なエラーを生成する必要がありますか?
ベータ版

1
この変数は、ユーザー自身が指定する必要があります。たとえば、彼は自分の環境(dev、prod ...)を知っている唯一のユーザーなので、たとえばを呼び出すことによって指定しますmake ENV=devが、を忘れるとENV=devdeployレシピは失敗します...
abernier

回答:


171

ENVが未定義で何かがそれを必要とする場合(とにかくGNUMakeで)、これは致命的なエラーを引き起こします。

.PHONY:check-envをデプロイする

デプロイ:check-env
	...

その他の必要な環境:check-env
	...

check-env:
ifndef ENV
	$(エラーENVは未定義)
endif

(ifndefとendifはインデントされていないことに注意してください。これらはmakefileが実行される前に有効になるmakeが「見る」ものを制御します。「$(error」はタブでインデントされているため、ルールのコンテキストでのみ実行されます。)


12
私は取得していENV is undefinedたタスクの実行時にしないの前提条件として、チェック-ENVを持っています。
2013

@rane:面白いですね。最小限の完全な例を挙げられますか?
ベータ版

2
@レインはスペースとタブ文字の違いですか?
2013

8
@esmit:はい。私はこれについて答えるべきだった。私の解決策では、行はタブで始まるので、それはcheck-envルールのコマンドです。makeは、ルールを実行するまで、またはルールを実行するまで展開しません。(@raneの例のように)TABで始まらない場合、Makeはそれがルールに含まれていないと解釈し、ターゲットに関係なく、ルールを実行する前に評価します。
2013

1
`` `私のソリューションでは、行はタブで始まるので、それはcheck-envルールのコマンドです;` ``どの行が話しているのですか?私の場合、ifndefの後の行がTABで始まる場合でも、if条件は毎回評価されます
Dhawal

103

次のように、ステム内の変数が定義されていることを確認する暗黙のガードターゲットを作成できます。

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通話中にエラーが発生しますよ、とビルドが失敗します。


5
それは賢い解決策です、私はそれが好きです:)
Elliot Chance

私はこれが古くからの返事であることを知っていますが、おそらく誰かがまだそれを見ていないと、新しい質問として再投稿するかもしれません...この暗黙のターゲット「ガード」を実装して、設定された環境変数をチェックしようとしていますただし、原則として、「guard-%」ルールのコマンドは実際にはシェルに出力されます。これを抑えたい。これはどのようにして可能ですか?
Genomicsio 2014年

2
OK。...解決策は自分自身... ruleコマンドラインの先頭に@が私の友人で見つかった
genomicsio

4
ワンライナー::if [ -z '${${*}}' ]; then echo 'Environment variable $* not set' && exit 1; fiD
c24w

4
これが選択された答えです。よりすっきりとした実装。
sb32134 2016年

46

インラインバリアント

私のメイクファイルでは、通常次のような式を使用します。

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が設定されていないと、ターゲットでさえ失敗します。それ以外の場合は、より複雑なHudonの回答を参照してください

ワオ。「そのブロックでタブを使用しない」が表示されるまで、これで問題が発生していました。ありがとうございました!
Alex K

これは良い代替手段ですが、成功しても「エラーメッセージ」が表示されるのは好ましくありません(行全体が出力されます)
Jeff

@Jeffそれはメイクファイルの基本です。行の先頭に@。-> gnu.org/software/make/manual/make.html#Echoing
Daniel Alder

試してみましたが、失敗してもエラーメッセージは表示されません。うーん、もう一度やってみます。確かにあなたの答えに賛成した。
ジェフ

1
私はテスト手法が好きです。私は次のようなものを使用しました@test -n "$(name)" || (echo 'A name must be defined for the backup. Ex: make backup name=xyz' && exit 1)
。– swampfox357

6

これまでの所与の回答で考えられる問題の1つは、makeの依存関係の順序が定義されていないことです。たとえば、次のように実行します。

make -j target

targetいくつかの依存関係がある場合、これらが特定の順序で実行されることは保証されません。

これの解決策(レシピが選択される前にENVがチェックされることを保証するため)は、レシピの外でmakeの最初のパス中にENVをチェックすることです。

## 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
    ...

ここで使用されているさまざまな関数/変数について読むことができ$()、「何もない」と比較していることを明示的に示すための手段にすぎません。


6

他の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 いくつかの恐ろしい警告がありますが、この単純な使用には、それが最良の選択だと思います。


5

コマンド自体には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

この問題deployは、必ずしもこの変数を必要とする唯一のレシピではないということです。このソリューションではENV、それぞれの状態をテストする必要があります...単一の(一種の)前提条件として扱いたいのですが。
アバニエ2011年

4

これは古いことはわかっていますが、私は少しすっきりしたIMHOなので、将来の訪問者のために自分の経験を取り入れたいと思いました。

通常、makeshデフォルトのシェルとして使用します(特殊SHELL変数を介して設定)。ではshその誘導体と、それがために些細だが設定またはヌルされていない場合は、環境変数を取得するときにエラーメッセージを表示して終了し実行して:${VAR?Variable VAR was not set or null}

これを拡張して、環境変数が設定されていない場合に他のターゲットを失敗させるために使用できる再利用可能なmakeターゲットを作成できます。

.check-env-vars:
    @test $${ENV?Please set environment variable ENV}


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


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

注意事項:

  • エスケープされたドル記号($$)は、シェル内ではなくシェルへの展開を延期するために必要ですmake
  • の使用はtest、シェルがコンテンツを実行しようとするのを防ぐためだけですVAR(他の重要な目的は果たしません)
  • .check-env-vars自明複数の環境変数をチェックするように拡張することができ、それぞれが(例えば一つだけの行を追加します@test $${NEWENV?Please set environment variable NEWENV}

ENVスペースが含まれている場合、これは失敗するようです(少なくとも私にとって)
eddiegroves

2

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

ねえ、あなたの答えはthxですが、提案が生成する重複コードのためにそれを受け入れることはできません... 状態変数deployをチェックする必要があるレシピは1つだけではありませんENV
アバニエ

その後、リファクタリングします。ifdefブロックの前に.PHONY: deployand deploy:ステートメントを使用して、重複を削除します。(ところで、正しい方法を反映するように回答を編集しました)
ドワイトスペンサー、
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.