make とシステムの limit が絡んだバグ2008年03月12日 12時42分01秒

Argument list too long で困った。この一般的な問題はワイルドカードが展開されたコマンドの引数の数が多すぎる為で、ほとんどの場合は ls * | xargs や find * -print0 | xargs -0 等と、xargs を組み合わせることで、回避できる。

ところが、今回はそうは単純にはいかない。問題の原因が、Makefile 内での変数が多くなりすぎた為だからだ。Makefile 内と言っても、make install などで * を使ったためだったら、結局のところ上の問題と等価なので問題にはならない。幾つかのオープンソースプロジェクトで、問題になったことがあるのを見つけたが、全部がこのケースだった。

しかし、Makefile で特殊変数 $? を使うと話が変わる。何せこの変数は、ターゲットより新しいファイル全てを表すからだ。簡単に問題を起こせるコードは以下の通り。再現させやすく記述した。test よりも新しい ports 以下にある Makefile を探し出す。


% cat Makefile

FILES=$(shell gawk -F\| '{printf("%s/Makefile\n", $$2)}' /usr/ports/INDEX

test: $(FILES)
        echo $?

実行すると、こうなる。

% gmake
11-wm/wm2/Makefile /usr/ports/x11-wm/wmDeskGuide/Makefile /usr/ports/x11-wm/wmak
erconf/Makefile /usr/ports/x11-wm/wmanager/Makefile /usr/ports/x11-wm/wmconfig/M
akefile /usr/ports/x11-wm/wmcp/Makefile /usr/ports/x11-wm/wmg/Makefile /usr/port
s/x11-wm/wmii/Makefile /usr/ports/x11-wm/wmthemeinstall/Makefile /usr/ports/x11-
wm/xcompmgr/Makefile /usr/ports/x11-wm/xfce/Makefile /usr/ports/x11-wm/xfce4/Mak
efile /usr/ports/x11-wm/xfce4-desktop/Makefile /usr/ports/x11-wm/xfce4-panel/Mak
efile /usr/ports/x11-wm/xfce4-session/Makefile /usr/ports/x11-wm/xfce4-wm/Makefi
le /usr/ports/x11-wm/xmonad/Makefile /usr/ports/x11-wm/yawm/Makefile
gmake: execvp: /bin/sh: Argument list too long
gmake: *** [test] エラー 127

一つ目の問題は$? はコマンドへの引数としてしか渡せない事。 二つ目の問題は、何らかの回避策をとると make を使っている意味がなくなること。つまり、何らかの回避策をとると言うことは、折角分かったファイルのリストを直接受け取る手段がないということ。

Make の更新時刻の比較の機能を殺さずに回避できる方法はない。