make 改訂版(5章)

再帰的なmake

複数のディレクトリにまたがったコンパイルをする時に
make ってやると下位ディレクトリまで含めて依存関係を解消できる

[kobakoba0723@fedora13-intel64 recursive]$ make
cc    -c -o main.o main.c
cd hoge; \
	make all
make[1]: ディレクトリ `hoge' に入ります
cc    -c -o hoge1.o hoge1.c
cc    -c -o hoge2.o hoge2.c
make[1]: ディレクトリ `hoge' から出ます
cd piyo; \
	make all
make[1]: ディレクトリ `piyo' に入ります
cc    -c -o piyo1.o piyo1.c
cc    -c -o piyo2.o piyo2.c
make[1]: ディレクトリ `piyo' から出ます
cc  -o main main.o hoge/hoge1.o hoge/hoge2.o piyo/piyo1.o piyo/piyo2.o

ファイル構成とかMakefileの中身とか

top dir
- Makefile
- main.c
- hoge
- Makefile
- hoge1.c
- hoge2.c
- piyo
|- Makefile |- piyo1.c |- piyo2.c

hoge, piyoディレクトリのMakefile[piyoの場合は、hogeのかわりにpiyo]

all : hoge1.o hoge2.0

clean :
	rm -f *.o
	rm -f *~

トップディレクトリのMakefile

OBJS = main.o \
    hoge/hoge1.o \
    hoge/hoge2.o \
    piyo/piyo1.o \
    piyo/piyo2.o

main : main.o hoge_obj piyo_obj
	${CC} ${CFLAGS} -o $@ ${OBJS}

hoge_obj :
	cd hoge; \
	${MAKE} all

piyo_obj :
	cd piyo; \
	${MAKE} all

clean :
	rm main *.o *~
	cd hoge; make clean
	cd piyo; make clean

下位ディレクトリのMakefileが簡単に書けるのは、サフィックスルールを使えているから
この場合、各種オブジェクトファイルはソースファイルと同じパスにできるから、
トップディレクトリのMakefileのOBJSには、パスまで含めてオブジェクトファイルを記載する。
また、makeでなく${MAKE}と書いているのは、
コマンドラインで指定したマクロを下位のmakeコマンドにも自動的に反映させるため。

内部マクロを使ってもう少し簡単に...ならなかった

$?以外のマクロには、D(ディレクトリ)やF(ファイル)という修飾子をつけることが出来る
以下はFの時の意味だが、Dの場合は、ファイルをディレクトリに変える

マクロ 意味
${@F} ターゲット($@)のファイル名部分
${*F} コンンポーネントのファイル名からサフィックスを除いたファイル名

$<(コンポーネント($<)のファイル名部分)っていうのもあるけど、表組の中に書くとtdタグが追加されるのはなんでだ。

これを使うと、トップのMakefileは、

OBJS = main.o \
       hoge/hoge1.o \
       hoge/hoge2.o \
       piyo/piyo1.o \
       piyo/piyo2.o

main : main.o modules
	${CC} ${CFLAGS} -o $@ ${OBJS}

modules : hoge/hoge1.o hoge/hoge2.o piyo/piyo1.o piyo/piyo2.o
	cd ${<D}; \
	${MAKE} ${<F}

clean :
	rm -f main
	rm -f *.o
	rm -f *~
	cd piyo; make clean
	cd hoge; make clean

この状態でmakeすると

[kobakoba0723@fedora13-intel64 recursive]$ make
cc    -c -o main.o main.c
cc    -c -o hoge/hoge1.o hoge/hoge1.c
cc    -c -o hoge/hoge2.o hoge/hoge2.c
cc    -c -o piyo/piyo1.o piyo/piyo1.c
cc    -c -o piyo/piyo2.o piyo/piyo2.c
cd hoge; \
	make hoge1.o
make[1]: ディレクトリ `hoge' に入ります
make[1]: `hoge1.o' は更新済みです
make[1]: ディレクトリ `hoge' から出ます
cc  -o main main.o hoge/hoge1.o hoge/hoge2.o piyo/piyo1.o piyo/piyo2.o

makeが走る前に個々のオブジェクトが作成されちゃったよ。。。って、サフィックスルールかぁ。
じゃあ、このマクロを使おうとすると、サフィックスルールを無効化しないといかんのか?
そんな馬鹿な話はないだろうから、使い方が間違ってるんだろうけど、どうやって使えばいいんだ。。。

複数人で開発する

メインとなるソースファイルがどこかにあって、
自分が担当するソースだけローカルで修正して、それを使ってコンパイルしたい時にはVPATHマクロが役に立つ

VPATHマクロは、コンポーネントを検索するパスを指定することが出来る

/usr/src/hoge_prj
- Makefile(コンポーネント・実行ファイルは、相対パスで記述しておく)
- main.c
- hoge.c
- piyo.c
/home/kobakoba0723/hoge_prj
- hoge.c
この状態で以下のように実行すると、担当分のソースについてはローカルのファイル、 それ以外は正式なソースを使ってコンパイルした実行ファイルが、ローカルに作成される。
[kobakoba0723@fedora13-intel64 hoge_prj]$ make -f /usr/src/hoge_prj/Makefile VPATH=/home/kobakoba0723/hoge_prj:/usr/src/hoge_prj
cc    -c -o main.o /usr/src/hoge_prj/main.c
cc    -c -o hoge.o hoge.c
cc    -c -o piyo.o /usr/src/hoge_prj/piyo.c
cc  -o main main.o hoge.o piyo.o

コマンドラインから#ifdef用のシンボル定義

#ifdef とか #ifndef とか条件コンパイルをするときのシンボル情報をコンパイルの時に渡せる
CFLAGS=-Dシンボル名
例えば、デバッグ用の出力をしたい時なんかに、Makefileとmain.cを書いて、 (Makefile)
OBJS = main.o

main : ${OBJS}
	${CC} -o $@ ${OBJS}

clean :
	rm -f main *.o *~
(main.c)
#include <stdio.h>

int main(void) {
  fprintf(stderr, "hello world\n");

#ifdef DEBUG
  fprintf(stderr, "debug information\n");
#endif

  return 0;
}
make するときに CFLAGS を指定してやればシンボルがちゃんと渡る。
[kobakoba0723@fedora13-intel64 symbol]$ make
cc -c main.c
cc -o main main.o
[kobakoba0723@fedora13-intel64 symbol]$ ./main
hello world
[kobakoba0723@fedora13-intel64 symbol]$ make clean
rm -f main *.o *~
[kobakoba0723@fedora13-intel64 symbol]$ make "CFLAGS=-DDEBUG"
cc -DDEBUG -c main.c
cc -o main main.o
[kobakoba0723@fedora13-intel64 symbol]$ ./main
hello world
debug information
make cleanをやらないと再コンパイルできない。。。 そのうえ、このままだとシンボルをつけてコンパイルした実行ファイルか、つけてないのかが判らない。