Makefileを書いてみる.2

前回の復習

Makefileの基本的な文法は以下のようなものだった。

# Makefile
ターゲット: 依存ファイル1 依存ファイル2 依存ファイル3
	コマンド行1
	コマンド行2
	コマンド行3

そして一例として

#Makefile
hello: hello.o thank.o
	gcc -o hello hello.o thank.o
hello.o: hello.c
	gcc -c hello.c
thank.o: thank.c
	gcc -c thank.c

を作成してmakeした。このMakefileの実行ファイルhelloをビルドする箇所に注目すると、"hello"という文字列と"hello.c"という文字列が2回ずつ登場している。複数回書くのは面倒。

自動変数?

どうせコマンド行にはターゲットと依存ファイルが登場するのだから、GNU makeに自動的に指定してもらえば楽。その役割を担うのが自動変数らしい。わかりやすい自動変数に示す。

$@ ターゲットファイル名
$< 依存ファイル1
$^ すべての依存ファイル

(例)自動変数を使ってMakefileを書き直したい

Makefileを以下のように書き直してみる(beforeとafterを示す)。

#Makefile (before)
hello: hello.o thank.o
	gcc -o hello hello.o thank.o
hello.o: hello.c
	gcc -c hello.c
thank.o: thank.c
	gcc -c thank.c

#Makefile (after)
hello: hello.o thank.o
	gcc -o $@ $^
hello.o: hello.c
	gcc -c $<
thank.o: thank.c
	gcc -c $<

afterをmakeするとbeforeのときと同じ結果が得られる。

マクロの定義方法?

今までは、Makefileにファイル名を直接書いていたけれど、マクロを使うと他への流用がしやすくなる。マクロの定義の仕方は

マクロ名 = 文字列

で、マクロの参照の仕方は

$(マクロ名)

である。

(例)マクロを使ってMakefileを書き直したい

Makefileを以下のように書き直してみる。

#Makefile (before)
hello: hello.o thank.o
	gcc -o $@ $^
hello.o: hello.c
	gcc -c $<
thank.o: thank.c
	gcc -c $<

#Makefile (after)
OBJS = hello.o thank.o
hello: $(OBJS)
	gcc -o $@ $^
hello.o: hello.c
	gcc -c $<
thank.o: thank.c
	gcc -c $<

これをmakeするとbeforeのときと同じ結果が得られる。

定義済みマクロ?

Makefileで、コンパイラアセンブラなどのツールを何度も指定するのも面倒で流用しにくい。それを回避できるようGNU makeでは定義済みマクロが用意されている。いくつか紹介する。

AR アセンブラ
ARFLAGS ARの引数
CC Cコンパイラ
CFLAGS CCのオプションフラグ
RM ファイルの削除

(例)定義済みマクロを使ってMakefileを書き直したい

Makefileを以下のように書き直してみる(さっきまでと違って、beforeに中間ファイルを削除するcleanが追加されていることに注意)。

#Makefile (before)
OBJS = hello.o thank.o
hello: $(OBJS)
	gcc -o $@ $^
hello.o: hello.c
	gcc -c $<
thank.o: thank.c
	gcc -c $<
clean:
	rm -f $(OBJS)

#Makefile (after)
OBJS = hello.o thank.o
CC = gcc
hello: $(OBJS)
	$(CC) -o $@ $^
hello.o: hello.c
	$(CC) -c $<
thank.o: thank.c
	$(CC) -c $<
clean:
	$(RM) $(OBJS)

これをmakeしたりmake cleanするとbeforeのときと同じ結果が得られる。

サフィックスルール?

上のMakefileでは、cファイルを.oファイルに変換するコマンドをファイルごとに毎度書いていた。.しかし、cファイルから.oファイルを作るルールを決めてしまえば、何度も書く必要がなくなるはず。このルールをサフィックスルールという。サフィックスルールの定義の仕方は以下の通り(サフィックスルールは.cから.oへの変換だけでなく、任意の拡張子間の変換で定義できる)。

.SUFFIXES: .変換前の拡張子.変換後の拡張子

変換前の拡張子.変換後の拡張子:
	コマンド

(例)サフィックスルールを使ってMakefileを書き直したい

Makefileを以下のように書き直してみる。

#Makefile (before)
OBJS = hello.o thank.o
CC = gcc
hello: $(OBJS)
	$(CC) -o $@ $^
hello.o: hello.c
	$(CC) -c $<
thank.o: thank.c
	$(CC) -c $<
clean:
	$(RM) $(OBJS)

#Makefile (after)
OBJS = hello.o thank.o
CC = gcc
.SUFFIXES: .c.o

.c.o:
	$(CC) -c $<

hello: $(OBJS)
	$(CC) -o $@ $^
clean:
	$(RM) $(OBJS)

これで、「hello.oがない→依存ファイルはhello.cに違いない→hello.cから決められたルールでhello.oを作る」ということを自動でしてくるようになった。