2012年6月14日木曜日

make に無限ループ防止機能?

以下の Makefile は無限ループになるだろう、と思っているのだが、実際にやってみるとならない場合もあるみたいだ。。


$(warning restarting)
include foo.mk

all:
    echo $(BAR)

foo.mk: FORCE
    echo "BAR:=1" > $@

.PHONY: all FORCE
FORCE:


教科書的には make の動作は以下のようになります:

make は include 命令に出会うと、そのインクルードファイルを読み込みます。
ただし、インクルードファイルがなくても、エラーを報告した上で処理を続行します。
makefile を読み終わった時点で、インクルードファイルを更新するルールがないか探します。
もしルールが見つかると、通常のターゲットの更新として処理します。
ルールによりインクルードファイルが更新されると、make を最初からやりなおします。

この例の場合、
include foo.mk
がありますので、 foo.mk を構築するルールがないか探します。

foo.mk: FORCE
    echo "BAR:=1" > $@

が見つかりました。

そこで make はまず FORCE を更新し(といってもPHONYターゲットなので何もできませんが)、続いて foo.mk を更新するために
echo "BAR:=1" > $@
を実行します。

foo.mk が更新されたので、 make を最初からやりなおします。

ですが、  foo.mk: FORCE という依存関係があるので、またまた foo.mk を更新すべきと判断します。で foo.mk を更新し、また make を最初からやりなおし、といったループを繰り返すわけです。

理屈的にはこうなはずなのですが、手元の Ubuntu 11.10 マシンでやってみたら以下のようになりました。

$ make
Makefile:1: restarting
echo "BAR:=1" > foo.mk
Makefile:1: restarting
echo "BAR:=1" > foo.mk
Makefile:1: restarting
echo "BAR:=1" > foo.mk
echo 1
1

リスタート3回で止まった。不思議!



もう一回やってみると

$ make
Makefile:1: restarting
echo "BAR:=1" > foo.mk
Makefile:1: restarting
echo "BAR:=1" > foo.mk
Makefile:1: restarting
echo "BAR:=1" > foo.mk
Makefile:1: restarting
echo "BAR:=1" > foo.mk
Makefile:1: restarting
echo "BAR:=1" > foo.mk
echo 1
1

となった。

何回か同じことを繰り返すと、無限ループに入ったぞ、と判断してやめるのかな?
リスタート回数は毎回違うんですけど。。

make のバージョンは

$ make --version
GNU Make 3.81
Copyright (C) 2006  Free Software Foundation, Inc.
これはフリーソフトウェアです. 利用許諾についてはソースを
ご覧ください.
商業性や特定の目的への適合性の如何に関わらず, 無保証です.

This program built for x86_64-pc-linux-gnu








一方、別の RHEL マシンでやってみると、無限に繰り返すようです。
make のバージョンは同じく 3.81 です。



$ make --version
GNU Make 3.81
Copyright (C) 2006  Free Software Foundation, Inc.
これはフリーソフトウェアです. 利用許諾についてはソースを
ご覧ください.
商業性や特定の目的への適合性の如何に関わらず, 無保証です.


This program built for x86_64-redhat-linux-gnu


このあたりの挙動はディストリビューションによって違うんでしょうか??
よくわかりません。

0 件のコメント:

コメントを投稿