前述*1のように Makefile は非常に簡潔に記述できます.ただし,簡潔なMakefileを記述するためには make の仕組みを理解する必要があります.
結論から言うと, make は 簡潔な生成ルールのみを記述したMakefileから, 実際に必要となる詳細な生成ルールを自動的に生成します.
自動的に生成されたルールを確認するには
$ make -p
と "-p" オプションを付けて make を実行します.
以下,
の二つの具体例を挙げて,説明します.
make -p の実行
$ make -p > log
大量の情報が 標準出力に出力されるので,一旦 log というファイルに出力を保存します.
make -p の結果を眺める(その1)
ここからが,本題です.
まず,make は makefile に記述された”生成ルール”にしたがってビルドを進めます.生成ルールは以下のように記述されます.
ターゲット: ソース コマンド
これで,"ソース"から "コマンド"をつかって"ターゲット"を生成する,という意味になります.
また,ここからが重要なのですが,make にはデフォルトでいくつかのルールが登録されています.たとえば
hoge: hoge.c
とコマンドを省略したMakefileが与えられても,make は hoge.c から hoge を作るためのコマンドを自動的に補ったルールを生成します.
make コマンドを実行する際に”-p” オプションは,この自動的に生成したルールをみるためのオプションです.
それでは,"-p"オプションの結果を保存した log ファイルの中を眺めてみましょう.hoge をキーワードに検索を書けてみると見易いです.
hoge を検索すると以下のような部分が二つ見つかると思います.一つ目は all: hoge と,Makefile で与えたルールそのものです.
all: hoge # Implicit rule search has been done. # File does not exist. # File has been updated. # Successfully updated.
二つ目は,make が自動生成したルールです.
hoge: hoge.c # Implicit rule search has been done. # Implicit/static pattern stem: `hoge' # Last modified 2007-02-18 14:27:19 # File has been updated. # Successfully updated. # commands to execute (built-in): $(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $@
これが
ターゲット: ソース コマンド
の形式で,コマンドの部分が
$(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $@
と自動的に補われたかたちになっています
ここで,$^と$@はmakeが使う特別な変数で,この場合はそれぞれ $^が hoge.c $@ が hoge に展開されます.
一方, $(LINK.c) は LINK.c をキーワードに log ファイルを検索すると
LINK.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)
と定義されています.CC は,検索すると
CC = gcc
と定義されているはずです.また,他の変数$(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)は未定義なので,
LINK.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)
は
LINK.c = gcc
と展開されることになります.
同様の手順で make -p を眺めていくと最終的に
hoge: hoge.c $(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $@
は,
hoge: hoge.c gcc hoge.c -o hoge
という生成ルールに展開できることが判ると思います.
このような make が自動的に補ってくれるコマンドと,その内部で使われる変数達を把握できるようになると, Makefile は非常に簡潔に記述できるようになります.
make -p の結果を眺める(その2)
同じ手順で,次にhoge.c とfuga.c から hoge を生成するmakefileについてmake -p の結果を眺めてみます.
Makefile は以下のものを使います
all: hoge hoge: hoge.o fuga.o
make -p の結果から関連するところを抜き出すと
all: hoge hoge: hoge.o fuga.o $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@ hoge.o: hoge.c $(COMPILE.c) $(OUTPUT_OPTION) $< fuga.o: fuga.c $(COMPILE.c) $(OUTPUT_OPTION) $<
となります.LINK.o COMPILE.c はそれぞれ
COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c LINK.o = $(CC) $(LDFLAGS) $(TARGET_ARCH)
と定義されています.最終的にどのようなコマンドが実行されるのかは,冗長になるのでここでは割愛します.