Makefileの書き方に関する備忘録 その2


このエントリーをはてなブックマークに追加

この記事は続き記事です。目次→Makefileの書き方に関する備忘録 - minus9dの日記

変数

ユーザが編集したりコマンドラインでカスタマイズしたりしたくなるもしれない変数は大文字、makefile内で閉じて使われる変数は小文字で書くのが慣例。

CC := gcc
sources = *.c

変数名の後の半角スペースに注意

以下のように、変数名の後にコメントを書くと、変数$(LIBRARY) は "libio.a "となり、半角スペースを巻き込んでしまう。

LIBRARY = libio.a #comment

変数のタイプ

変数のタイプには2種類ある。

expanded variables

expanded variablesは、コロン付きのイコールで定義される変数。定義式を評価するときに、右辺の変数が即時展開される。

CC = g++
MAKE_DEPEND := $(CC) -M

all:
	@printf "$(MAKE_DEPEND)"

CC = gcc

例えば上のmakefileを実行すると、2行目を読み込んだ時点で、変数$(MAKE_DEPEND)は"g++ -M"に確定する。よってmake allとしたときの出力は

g++ -M

となる。

recursively expanded variables

recursively expanded variablesは、コロン無しのイコールで定義される変数。実際に値が必要になった時に初めて定義式の右辺の変数が展開される。なので、recursively expanded variablesは、呼ばれるたびに異なる値となる可能性がある。

今度は下のMakefileを実行する。差分はコロンがなくなったことだけである。

CC = g++
MAKE_DEPEND = $(CC) -M

all:
	@printf "$(MAKE_DEPEND)"

CC = gcc

$(MAKE_DEPEND)変数は、それが必要になったときにしか決定されない。$(MAKE_DEPEND)が必要になるのはmake allを呼んだ時の@printfの中だが、その時点では$(CC)はgccに上書きされているので、出力は

gcc -M

と、先ほどと異なる結果になる。

特に理由がなければ、=ではなく:=を使うほうが、意図しない動作を含みにくくて良いように思う。

値がセットされていないときのみ変数に値を代入

?= を使う。

特定のターゲットにのみ特別な変数を使う

あるターゲットをビルドするときだけ、あるフラグをONにしたい、といったときに以下の書き方ができる。

gui.o: CPPFLAGS += -DUSE_NEW_MALLOC=1
gui.o: gui.h

@と-の意味

@はコマンド行の実行を表示しない、という意味。
-はコマンド行の実行が失敗しても無視する、という意味。

例:

clean:
	-@rm *.o

暗黙のルールが使えない!?

以下のMakefileではルールが空である。

sample: sample.o sub1.o sub2.o

しかし、暗黙のルールが適用されて、以下のように実行ファイルsampleが生成される。

cc    -c -o sample.o sample.c
cc    -c -o sub1.o sub1.c
cc    -c -o sub2.o sub2.c
cc   sample.o sub1.o sub2.o   -o sample

一方、以下のMakefileでは、暗黙のルールが適用されない。違いは何だろうか?

my_sample: sample.o sub1.o sub2.o

今回の場合、暗黙のルールが適用されるには、ターゲットの名前が、コロンの右側に羅列されたオブジェクトファイルのどれかと同じであることが必要なのであった。なので、最初の例では暗黙のルールが適用されたが、2番目の例では適用されなかった。