温故知新:マニュアルはちゃんと読もう

先週、GNU make の拡張機能について取り上げましたが、その後 make.info を頭から読み直していたら衝撃の事実を発見してクラクラしたので、懺悔しつつここに記します。

静的パターンルールを使う

複数ターゲットに対して共通のルールを設定する「静的パターンルール」という記述法がありました。

$(PROGS): %: %.o $(LIB)
	$(CXX) -o $@ $< $(LDFLAGS)

$(PROGS) が複数ターゲットだとすると、各ターゲットが % で取り出され、その依存関係を : 以降に書けば OK。しかもこの機能はずいぶん昔から使えたもののようです。衝撃。マクロでこねくりまわしてたのが滑稽ですね。

依存関係を自動生成する

今まで依存関係は当然のように手でメンテナンスしていたのですが、g++ -MM で依存関係を吐き出せることを知りました。衝撃。自分で自分のことが心配になってきました。恐しい。ということで、info のサンプルを見て、依存関係を自動生成するようにします。

.depend/%.d: %.cpp .depend
	$(CXX) -MM $(CPPFLAGS) $< | sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' > $@

.depend:
	@mkdir .depend

ifneq ($(MAKECMDGOALS), clean)
-include $(addprefix .depend/,$(LIBOBJS:.o=.d) $(OBJS:.o=.d))
endif

sed でゴチャゴチャやってるのは、依存関係ファイルが依存しているソースの依存関係を、依存関係ファイルの依存関係にも追加するものです。例えば a.cpp が a.h に依存している時に、.depend/a.d の依存関係に a.h を追加します。結果、

a.cpp .depend/a.d : a.h

という依存関係が出来上がります。素晴しい。ただ、make clean した時にも .depend/*.d を生成するのが気持ち悪かったので、clean の時には include しないことで依存関係の生成を抑制してみました。

その他

VPATH の設定は find を使わずともできそうだったので、以下のようにしてみました。

VPATH	= $(filter-out %/CVS,$(wildcard ../*)) ../..

こちらのほうがスマートですね。

まとめ

先週の日記を書く時も make.info は読んでいたのですが、Menu から「* Functions::」を見つけてジャンプし、そこだけ読んで全てをわかった気になっていたのでした。やはりマニュアルは読んだほうがいいですね。ちゃんと書かれているものならば、ですが。今では Makefile のメンテナンスはライブラリオブジェクトを追加するだけ。make の知識は更新できましたが、苦い後味です。