make で make ファイルを作る実践2006年07月12日 11時43分08秒

さて、GNU make で make ファイルを生成 で Makefile の例を上げたが、あのままでは実験するのは難しい。そこで、今回は実行するコマンドを変えて実験しやすいようにする。

余談になるが、実は %.o : %.c といった表記は、どの make でも使えるものだと思い込んでいた。今回の FreeBSD 6.1 上での実験で make と打っても動かない。BSD make では実装されていない機能みたいだ。GNU make だけでなく、Solaris に入っている /usr/ccs/bin/make と /usr/xpg4/bin/make 共に使えたので、気が付かなかった。Solaris の make は include がうまくできなくて、悩むことが多い。

まずは、Makefile である。最初に echo や cat 等に変えた。別に実際にコンパイルすることが目的ではないので、これで充分だ。また、make システムに組み込まれている .SUFFIXES を一度消去し、再設定する。そして、clean も追加した。


.SUFFIXES:
.SUFFIXES: .pm .list .obj .c

%.pm : %.list
    cat $< > $@

.make.% : %.list
    cat $< > $@

%.obj : %.c
    echo $< > $@

clean :
    rm -f *.pm *.obj .make.*

-include .make.prog

prog.list の中身はこうなっている。

prog.pm : prog.obj
prog.pm : submodule.obj
prog.pm : function.obj

さて、そこで c ファイルを生成した後、make を打つ。

% touch prog.c submodule.c function.c
% make prog.pm
cat prog.list > .make.prog
echo prog.c > prog.obj
echo submodule.c > submodule.obj
echo function.c > function.obj
cat prog.list > prog.pm

ご覧の通り、make が make ファイル生成し、自ら依存関係を取り込み、正しい順序で目標を作成する。つまり、prog.list を変更すると自動的に、make が依存関係が変更したことを検知し、自ら取り込むのだ。

しかし、このままだと prog.pm しか作れない。また、make だけを打ったときには期待するを動作しない。そこで、少し拡張する。


.SUFFIXES:
.SUFFIXES: .pm .list .obj .c

all : $(patsubst %.list, %.pm, $(wildcard *.list))

%.pm : %.list
    cat $< > $@

.make.% : %.list
    cat $< > $@

%.obj : %.c
    echo $< > $@

clean :
    rm -f *.pm *.obj .make.*

-include $(patsubst %.list, .make.%, $(wildcard *.list))

make を起動した時に、何も目標を設定しないときのために、all を作る。all は *.list から作るので、.list があるプログラムは全て作ると宣言していることになる。それに加えて、-include も同じように *.list から生成するようにした。

これで、gmake clean; gmake をやると、上記と同じように prog.pm を生成する。

すこし、捻りを加えてみよう。今度は、目標となるプログラムを一つ追加する。開発用の debug 用でも裏口でもいい。少しだけ動作を変えたいのだ。


% sed -e 's/prog/prog2/' -e 's/prog.obj/backdoor.obj/' prog.list | tee prog2.list
prog2.pm : backdoor.obj
prog2.pm : submodule.obj
prog2.pm : function.obj
% touch backdoor.c
% gmake
cat prog2.list > .make.prog2
echo backdoor.c > backdoor.obj
cat prog2.list > prog2.pm

make は新しいプログラム作られる必要があることを自動的に察知し、必要なソースファイルだけをコンパイルし、新しいプログラムを生成した。

例としては、とても単純だが、%.list から .make.% の変換を上手にすると、多彩なことが出来るようになる。今回の例のままだと、ライブラリの生成は出来ないが、この %.list から .make.% の変換次第で出来るようになるだろう。

前回