182

makefileの変数が設定/評価されていないことに基づいてmake/makefileの実行を中止するにはどうすればよいですか?

私はこれを思いついたが、呼び出し元がターゲットを明示的に実行していない場合(つまり、実行makeのみ)の場合にのみ機能します。

ifeq ($(MY_FLAG),)
abort:   ## This MUST be the first target :( ugly
    @echo Variable MY_FLAG not set && false
endif

all:
    @echo MY_FLAG=$(MY_FLAG)

このようなものは良い考えだと思いますが、makeのマニュアルには何も見つかりませんでした。

ifndef MY_FLAG
.ABORT
endif
4

6 に答える 6

343

TL; DRerror関数を使用します:

ifndef MY_FLAG
$(error MY_FLAG is not set)
endif

行をインデントしてはならないことに注意してください。より正確には、これらの行の前にタブを配置することはできません。


一般的なソリューション

多くの変数をテストする場合は、そのための補助関数を定義する価値があります。

# Check that given variables are set and all have non-empty values,
# die with an error otherwise.
#
# Params:
#   1. Variable name(s) to test.
#   2. (optional) Error message to print.
check_defined = \
    $(strip $(foreach 1,$1, \
        $(call __check_defined,$1,$(strip $(value 2)))))
__check_defined = \
    $(if $(value $1),, \
      $(error Undefined $1$(if $2, ($2))))

そして、これがそれを使用する方法です:

$(call check_defined, MY_FLAG)

$(call check_defined, OUT_DIR, build directory)
$(call check_defined, BIN_DIR, where to put binary artifacts)
$(call check_defined, \
            LIB_INCLUDE_DIR \
            LIB_SOURCE_DIR, \
        library path)


これにより、次のようなエラーが出力されます。

Makefile:17: *** Undefined OUT_DIR (build directory).  Stop.

ノート:

実際のチェックはここで行われます:

$(if $(value $1),,$(error ...))

これは条件の動作を反映しているifndefため、空の値に定義された変数も「未定義」と見なされます。ただし、これは単純な変数と明示的に空の再帰変数にのみ当てはまります。

# ifndef and check_defined consider these UNDEFINED:
explicitly_empty =
simple_empty := $(explicitly_empty)

# ifndef and check_defined consider it OK (defined):
recursive_empty = $(explicitly_empty)

コメントで@VictorSergienkoが示唆しているように、わずかに異なる動作が望まれる場合があります。

$(if $(value $1)値が空でないかどうかをテストします。変数が空の値で定義されていても問題ない場合があります。私が使用します$(if $(filter undefined,$(origin $1)) ...

と:

さらに、それがディレクトリであり、チェックの実行時に存在する必要がある場合は、を使用します$(if $(wildcard $1))。しかし、別の機能になります。

ターゲット固有のチェック

特定のターゲットが呼び出された場合にのみ変数を要求できるようにソリューションを拡張することもできます。

$(call check_defined, ...)レシピの中から

チェックをレシピに移動するだけです。

foo :
    @:$(call check_defined, BAR, baz value)

先頭の@記号はコマンドエコーをオフにし:、実際のコマンドであるシェルのno-opスタブです。

ターゲット名を表示しています

この関数は、ターゲット名(変数check_definedを介して提供される)も出力するように改善できます。$@

check_defined = \
    $(strip $(foreach 1,$1, \
        $(call __check_defined,$1,$(strip $(value 2)))))
__check_defined = \
    $(if $(value $1),, \
        $(error Undefined $1$(if $2, ($2))$(if $(value @), \
                required by target `$@')))

そのため、チェックに失敗すると、適切にフォーマットされた出力が生成されます。

Makefile:7: *** Undefined BAR (baz value) required by target `foo'.  Stop.

check-defined-MY_FLAG特別ターゲット

個人的には、上記のシンプルでわかりやすいソリューションを使用します。ただし、たとえば、この回答は、実際のチェックを実行するために特別なターゲットを使用することを示唆しています。それを一般化して、ターゲットを暗黙のパターンルールとして定義しようとすることができます。

# Check that a variable specified through the stem is defined and has
# a non-empty value, die with an error otherwise.
#
#   %: The name of the variable to test.
#   
check-defined-% : __check_defined_FORCE
    @:$(call check_defined, $*, target-specific)

# Since pattern rules can't be listed as prerequisites of .PHONY,
# we use the old-school and hackish FORCE workaround.
# You could go without this, but otherwise a check can be missed
# in case a file named like `check-defined-...` exists in the root 
# directory, e.g. left by an accidental `make -t` invocation.
.PHONY : __check_defined_FORCE
__check_defined_FORCE :

使用法:

foo :|check-defined-BAR

は注文のみ()の前提条件check-defined-BARとしてリストされている ことに注意してください。|...

長所:

  • (おそらく)よりクリーンな構文

短所:

evalこれらの制限は、いくつかの魔法と二次拡張ハックを使用して克服できると思いますが、それが価値があるかどうかはわかりません。

于 2012-06-01T22:57:53.963 に答える
47

シェル関数を使用しますtest

foo:
    test $(something)

使用法:

$ make foo
test 
Makefile:2: recipe for target 'foo' failed
make: *** [foo] Error 1
$ make foo something=x
test x
于 2017-01-18T14:35:57.010 に答える
16

IFを使用して次のことをテストできます。

check:
        @[ "${var}" ] || ( echo ">> var is not set"; exit 1 )

結果:

$ make check
>> var is not set
Makefile:2: recipe for target 'check' failed
make: *** [check] Error 1
于 2018-07-09T14:29:02.007 に答える
7

未設定の変数にはシェルエラー処理を使用します(doubleに注意してください$)。

$ cat Makefile
foo:
        echo "something is set to $${something:?}"

$ make foo
echo "something is set to ${something:?}"
/bin/sh: something: parameter null or not set
make: *** [foo] Error 127


$ make foo something=x
echo "something is set to ${something:?}"
something is set to x

カスタムエラーメッセージが必要な場合は、?:の後に追加してください。

$ cat Makefile
hello:
        echo "hello $${name:?please tell me who you are via \$$name}"

$ make hello
echo "hello ${name:?please tell me who you are via \$name}"
/bin/sh: name: please tell me who you are via $name
make: *** [hello] Error 127

$ make hello name=jesus
echo "hello ${name:?please tell me who you are via \$name}"
hello jesus
于 2018-06-01T11:29:31.300 に答える
5

簡潔さと簡潔さのために:

$ cat Makefile
check-%:
        @: $(if $(value $*),,$(error $* is undefined))

bar:| check-foo
        echo "foo is $$foo"

出力あり:

$ make bar
Makefile:2: *** foo is undefined. Stop.
$ make bar foo="something"
echo "foo is $$foo"
foo is something
于 2020-03-07T11:44:36.527 に答える
0

別のオプション:

MY_FLAG = $(error Please set this flag)

この変数をどこでも使用しようとすると、コマンドラインからオーバーライドされない限り、エラーが発生します。

環境変数も受け入れるには、次を使用します?=

MY_FLAG ?= $(error Please set this flag)
于 2022-02-23T19:49:03.990 に答える