GNU makeとinclude
ずっとmakefileでわからなかったことがあったのだが、今日まじめに調べてようやく分かった。
makefileでソースの依存関係をいちいち手書きするのが面倒なので、
SRC=$(shell ls *.cc) dep: g++ -MM -MG $(SRC) >makefile.depend
というルールを作っておき、makefileの最後で
-include makefile.depend
としておく。こうすると
$ make dep
とやればmakefile.dependができる。さて、makefile.dependが古かったり存在しなかったりした場合に自動的に作りたくて、
SRC=$(shell ls *.cc) makefile.depend: g++ -MM -MG $(SRC) >makefile.depend -include makefile.depend
とかやっていると、全然関係のないルール、たとえばcleanをやろうとしてもmakefile.dependを作ろうとしてしまう。これがずっと謎だった(無論 cleanは PHONYにしてある)。
で、もしかしたらincludeしているのが原因かと思い、まずはこんなmakefileを作ってみた。
FOO=foo foo: echo $(FOO) -include hoge
そして、以下の内容のhogeを作っておく。
FOO=bar
この状態でmake fooすると、
$ make foo echo bar bar
となる。つまり、先にinclude処理が行われている。さて、ここでhogeを消し、makefileを以下のように書き換える。
FOO=foo foo: echo $(FOO) hoge: echo "FOO=bar" > hoge -include hoge
makeをしてみる。
$ls makefile $ make echo "FOO=bar" > hoge echo bar bar $ ls hoge makefile $ make echo bar bar
これでようやく合点がいった。まとめると以下のような感じ。
- GNU makeはinclude処理を一番最初にやる。
- その際、includeするためのファイルは暗黙的に全てのルールに必要だと仮定される。
- したがって、includeしたいファイルが存在せず、かつそのファイルの作り方を知っていたら、必ず作りに行く。
- ただし、ファイルが存在せず、かつ作り方を知らなくてもエラーは出さない。
というわけで、makefile.dependをインクルードしている場合、そのファイルが無くて、かつ作り方を知っていれば、たとえcleanのような関係ないルールであってもmakefile.dependを作りに行く。なぜならmakefile.dependがcleanの定義を書き換えるかもしれないから。 make cleanやmake tarでmakefile.dependが作られるのは気持ち悪いが、
makefile.depend: $(SRC) $(HED) g++ -MM -MG $(SRC) >makefile.depend
としておけば、とりあえずソースに変更があれば必ずmakefile.dependが作り直されるようになると。