make の使い方
これも昔書いたもの。
make で何ができるのか?
make の魂
Unix の世界ではソースファイルが命。
ソースファイルさえあれば実行モジュールは消えても、make しなおせばよい。
オブジェクトファイルや実行ファイルは版管理しない。
版管理されたソースファイルを make すれば、その版の実行ファイルができる。
世界で一番簡単な make の使い方
ソースファイルを用意する。
$ cat hello.c #includeint main() { printf("hello world.\n"); return 0; }
さっそく make を使ってみる。
$ make hello cc hello.c -o hello $ ./hello hello world. $ make hello make: `hello' is up to date.
とっても簡単だ。
世界で一番簡単な makefile
普通は makefile という名前のファイルに make への指示を書いておく。
$ cat Makefile hello:
make してみよう。
$ rm hello $ make cc hello.c -o hello $ ./hello hello world. $ make make: `hello' is up to date.
とっても簡単だ。
かなり初歩的な makefile
もう少し普通に makefile を書いてみる。
foo.c と bar.c から foobar を make する。
foo.c は foo.h と bar.h を参照し、bar.c は bar.h を参照する。
$ cat Makefile foobar: foo.o bar.o ${CC} ${CFLAGS} ${LDFLAGS} -o foobar foo.o bar.o foo.o: foo.c foo.h bar.h ${CC} ${CPPFLAGS} ${CFLAGS} -c foo.c bar.o: bar.c bar.h ${CC} ${CPPFLAGS} ${CFLAGS} -c bar.c
":" の前がターゲット名。
":" の後ろが依存するファイル群 (コンポーネント)。
例えば、ターゲット foobar は
foo.o と bar.o に依存する。
foo.o か bar.o のどちらかが
foobar よりも新しければ作りなおす。
ターゲットの依存関係の次の行には、そのターゲットを作るためのアクションを書く。
アクション行は、TAB で始める。
行頭が TAB でないとアクションとは見做さない。
アクション行は複数書ける。
make はカレントディレクトリから
makefile または Makefile を読み込む。
そして makefile の最初に出てくるターゲットを make する。
上記の例を明示的に指示すると "make -f Makefile foobar" となる。
変数
makefile にも変数 (マクロ) は使える。
シェルの要領で変数を定義できる。
シェルと違って = の前後に空白があっても OKay.
参照するときは $ を付け、
{ } または ( ) で囲む。
同様の記述で環境変数を参照することも可能。
$ cat Makefile OBJS = foo.o bar.o foobar: ${OBJS} ${CC} ${CFLAGS} ${LDFLAGS} -o foobar ${OBJS} foo.o: foo.c foo.h bar.h ${CC} ${CPPFLAGS} ${CFLAGS} -c foo.c bar.o: bar.c bar.h ${CC} ${CPPFLAGS} ${CFLAGS} -c bar.c
変数名は大文字で書くのが習慣。*1
CC, CFLAGS, LDFLAGS などは
make があらかじめ用意している変数。
make -p で確認できる。
サフィックスルール
「ファイルごと」ではなく「拡張子ごと」にアクションを定義できる。
これで .c の数だけアクションを書かずに済む。
$ cat Makefile OBJS = foo.o bar.o foobar: ${OBJS} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ ${OBJS} .c.o: ${CC} ${CPPFLAGS} ${CFLAGS} -c $< foo.o: foo.c foo.h bar.h bar.o: bar.c bar.h
ターゲットにはサフィックスルールで、.c から .o を作ることを指示する。
$@ や $< はアクションに使える特殊なマクロ。
もう少し洗練された makefile
上記の初歩的な (foo.c と bar.c を使う) makefile を洗練させてみる。
$ cat Makefile OBJS = foo.o bar.o foobar: ${OBJS} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ ${OBJS} foo.o: foo.c foo.h bar.h bar.o: bar.c bar.h
現在 使用していなくても
CFLAGS, LDFLAGS などのマクロを参照するのは重要。
例えばデバックオプションを指定して make するとき、いちいち
makefile を変更する必要がなくなる。
$ make 'CFLAGS=-g' cc -g -c -o foo.o foo.c cc -g -c -o bar.o bar.c cc -g -o foobar foo.o bar.o
ダミーターゲット
ターゲットそのものを作るわけではなく、一連の処理へのエントリを作る。
階層構造
コンパイルすべきソースファイルが複数のディレクトリ存在するとき、ひとつの makefile で別のディレクトリのソースファイルをコンパイルしてはいけない。
以下のディレクトリ構造なら、makefile はそれぞれのディレクトリごとにみっつ作る。
lib と src にある makefile はこれまで通り。
自分のディレクトリにあるターゲットだけ責任を持って make する。
上位層にある makefile は、lib と src を make するよう指示する。*3
$ cat Makefile all: make_lib make_src make_lib: (cd lib; make) make_src: (cd src; make)
同様に install や clean も下位の make を呼び出せるようにする。
上位層の makefile で設定した変数は、下位層の make には引き継がれない。
渡したい変数は明示する。
$ cat Makefile all: make_lib make_src make_lib: (cd lib; make "CFLAGS=${CFLAGS}") make_src: (cd src; make "CFLAGS=${CFLAGS}")
アクションはシェルスクリプト
make はルールに基づいて再生成が必要だと判断すると、アクションの各行を変数 SHELL で指定したシェルで処理する。
アクション行の変数を評価してから、それを表示しシェルを起動する。
SHELL には普通 /bin/sh が設定される。
実行した結果 ($?) が 0 でなければ、make は処理を中断する。
コマンドの前に "-" を書くと、エラーが起きても処理を中断しない。
コマンドの前に "@" を書くと、アクション行を評価した結果を表示せずに実行する。
$ cat Makefile target: echo "成功すれば次のアクションへ" -echo "失敗しても次のアクションへ" @echo "実行するコマンドを表示しない"
行ごとにシェルを起動するので、行をまたいでシェル変数を渡すことはできない。
行末が "\" なら、次のアクションを連結して、ひとつのアクションと見做す。
シェル変数を make に評価させないためには "$" を "$" で escape して "$$" と表記する。
$ cat Makefile TARGETS = foo bar install: ${TARGETS} for t in ${TARGETS}; do \ ${INSTALL_PROGRAM} $$t ${DESTDIR}/$$t; \ done