Makefile入門 中級者向け

GNU Makeの基本的な使い方は知っている前提です。
知っておくと便利な内容のまとめです。

なお、オライリー社の GNU Make が無料公開されているので詳細はそちらを見ましょう。

GNU Make 第3版

テキスト出力/表示: ($info ...), $(warning ...), $(error ...)

変数などをデバッグ用に出力したい場合によく使う。
$(error ...)は評価された時点でMakeが終了するので注意。

1
2
3
4
5
6
7
8
9
10
HOGE = hoge

$(info $HOGE)
$(warning $HOGE)
$(error $HOGE)

# Output
# hoge
# Makefile:4: hoge
# Makefile:5: *** hoge. Stop.

変数定義: =, :=

:=の方は、その変数定義式が評価された時点の右辺値が左辺値に入る。
=は左辺値を右辺値に紐付けるだけなので、左辺値が呼び出された時によって値が変化する可能性がある。

1
2
3
4
5
6
7
8
NAME         = Taro
HELLO = Hello $(NAME)
HELLO_FIXED := Hello $(NAME)

NAME = Hanako # <- Redefine NAME

$(info $(HELLO)) # <- Hello Hanako
$(info $(HELLO_FIXED)) # <- Hello Taro (Redefinition of NAME is not reflected)

シェルコマンドの実行: $(shell ...)

そのまんまです。

1
DIRS := $(shell find . -type d)  # . ./inc ./src ./src/package2 ./src/package1

ディレクトリ名/ファイル名/ファイル名(拡張子抜き)の取得: $(dir ...), $(notdir ...), $(basename ...)

1
2
3
4
5
FILEPATH = ./src/hoge.cpp ./src/foo.cpp

$(dir $(FILEPATH)) # ./src/ ./src/
$(notdir $(FILEPATH)) # hoge.cpp foo.cpp
$(basename $(FILEPATH)) # ./src/hoge ./src/foo

テキスト置換: $(patsubst PATTERN, REPLACE, TARGET)

TARGET内のPATTERNに該当する箇所をREPLACEに置換する。
名前が覚えづらいがPATternSUBSTituionだと勝手に思っている(合っているかは不明です)。

1
2
3
FILEPATH = ./src/hoge.cpp ./src/foo.cpp

$(patsubst %.cpp, %.o, $(FILEPATH)) # ./src/hoge.o ./src/foo.o

ワイルドカード: $(wildcard ...)

ワイルドカードは*であって%ではないので注意。

1
$(wildcard ./src/package1/*.cpp))  # ./src/package1/src1.cpp

マクロとforeach

1
2
3
4
5
6
7
8
9
10
PERSONS := Taro Hanako

define MACRO
$(warning $(1))
touch $(1)

endef

all:
$(foreach p, $(PERSONS), $(call MACRO, $(p)))

foreachの構文はPython風に書けば以下のようなもの。

1
2
for p in PERSONS:
call MACRO p

マクロ内部では引数を$(1), $(2) ...などと受け取れる。
マクロは単純な文字列展開なので、コマンドとしてマクロを使うならマクロ内部で直接コマンド(シェルコマンド)を書ける(上記例ではtouch.)

PHONYターゲット

Makeは基本的にはターゲットを生成するためのツールなのでターゲットが存在し、依存ファイルにも更新がない場合は何もしない。
以下のケースではもしtestディレクトリが存在していると実行されない(make: 'test' is up to dateと言われる)。

1
2
test:
./test_bin # Run tests... ?

Makeをタスクランナーとして使う場合はそれらに関わらず必ず実行してほしい。
そういう時はPHONYターゲットとする。phonyは偽物という意味。

1
2
3
.PHONY: test
test:
./test_bin # Run tests

生成コマンドのオプション

処理が失敗しても次を引き続き実行する

例が適当だが、mkdir hogeが失敗してもtouch hoge/foo.txtを実行したい場合、mkdir hoge-を付ける。

1
2
3
4
.PHONY: hoge
hoge:
-mkdir hoge
touch hoge/foo.txt

処理を標準出力に表示しない

Makeはデフォルトでは実行する内容(ここではrm *.o)を標準出力に表示する。表示させない場合は@を付ける。ちなみに@-は併用可能(-@でも@-でもOK)。

1
2
3
.PHONY: clean
clean:
@rm *.o

Makefileの自己文書化

Makeに与える引数にどんなものがあるかをMake自身に語らせたい場合がある。
make installmake cleanは慣習となっているが自分が定義した(主にタスクランナーとしての)ターゲット名はヘルプ表示しないとわかりづらい。

イメージ的には以下のようにmake(引数なし)で実行時に引数一覧が表示されるもの。

1
2
3
4
5
6
7
8
$ make

all make clean, build, and test
build Build test programs
clean Delete binaries
create_dirs Create neccesary directories to run
format Format with clang-format
test Run tests

詳細は以下のリンクを参照ください。

参考ページ