Prevent Multiple Include in GNU Make2013年09月20日 12時50分03秒

GNU Make は随分と元の Make に手が加わっていて全く別物になっている。変数に値を設定する方法もいくつもあって、かなりややこしい。GNU Make を使いこなすには include が肝になる。

さて、この include だが、いわゆる C/C++ のヘッダーファイルの様に、無造作に読み込みたいが、複数回読み込むと問題が起きる。まず、変数に += を使っていると、無限に増えていくこと、また開けるファイルに上限があるなど、悩ましい。

GNU Make には条件式もあるのだが、この動作がややこしく、さらになやましいものにしている。なお、条件には ifndef の様に定義の有無を調べるものと、infeq の様に変数の値を調べる物がある。

そして、実験。四つのファイルを準備して、少しずつ違う式を書く。二つは ifndef で、あとのものは infeq で。そして、各々で :== を使う。:= は、読み込んでいる最中に評価され、読み込まれた時点で即刻、値が代入される。= の値の代入は遅延型で、全てのファイルを読み込んだ後になる。大きな違いは、VAR = $(VAR) 等と、自身に代入できないことだ。これは無限ループになり値を決められない。


% cat ifndef:=.mk
ifndef INCLUDED
INCLUDED := 1

include ifndef:=.mk

endif
% cat ifndef=.mk
ifndef INCLUDED
INCLUDED = 1

include ifndef=.mk

endif
% cat ifneq:=.mk
ifneq ( $INCLUDED, 1 )
INCLUDED := 1

include ifneq:=.mk

endif
% cat ifneq=.mk
ifneq ( $INCLUDED, 1 )
INCLUDED = 1

include ifneq=.mk

endif

さて、この四つの場合の各々の意図は汲めたであろうか。なるべく判りやすい様に、ファイルにそのままの名前を付けてみた。

同じ順に実行した結果はこうなる。


% gmake -f ifndef:=.mk
gmake: *** No targets.  Stop.
% gmake -f ifndef=.mk
gmake: *** No targets.  Stop.
% gmake -f ifneq=.mk
ifneq=.mk:4: ifneq=.mk: Too many open files
gmake: *** No targets.  Stop.
% gmake -f ifneq:=.mk
ifneq:=.mk:4: ifneq:=.mk: Too many open files
gmake: *** No targets.  Stop.

ifndef で既に定義されているかだと、一度しか読み込まれない。そのため、ターゲットが無く終了している。ifneq で変数の値を調べようとしたが、読み込んでいる最中はどちらの代入式でも効果が無いようだ。そして、ファイルが開けなくなって終了している。

つまり、C/C++ の様に複数回読み込まれるのを防ぐには ifndef を用いる必要がある。


ifndef INCLUDED
INCLUDED = 1

include ifndef=.mk

endif

実はがっかりした結果だった。ifneq を用いると、一回目に読み込まれる動作と二回目に読み込まれる動作を変えられるかと期待したが、狸の皮算用だった。