1. ホーム
  2. makefile

[解決済み] 変数が設定されていない場合、makefileを中断させるには?

2022-04-20 16:41:07

質問

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

解決方法は?

TL;DR : を使用します。 error 機能 :

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 条件付きで、空の値に定義された変数も "undefined"と見なされるようになります。しかし、これは単純な変数と明示的に空の再帰的変数にのみ当てはまります。

# 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) は、値が空でないかどうかをテストします。それは時々 変数が空の値で定義されていればOK . 私なら $(if $(filter undefined,$(origin $1)) ...

そして

さらに ディレクトリであり、それが存在しなければならない場合 チェックを実行するときに $(if $(wildcard $1)) . しかし、別の関数になる。

ターゲット別チェック

また、特定のターゲットが呼び出された場合にのみ変数を要求できるように、解決策を拡張することも可能である。

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

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

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

先頭の @ 記号はコマンドエコーをオフにし : は実際のコマンドで、シェルの ノーオペレーションスタブ .

ターゲット名の表示

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 マジックと 二次展開 のハック、その価値があるかどうかはわからないけど。