Makefile で複数の依存項目 (prerequisite; 以降 prereq と表記) や複数のターゲット (target) を扱う場合のまとめ。複数の場合でも基本的に単数と同様に書けるが、中身を個別に扱う (multiple [foreach] と表記) 場合にはまとめて扱う (multiple [bulk] と表記) 場合と異なる書き方をしないといけない、という話。
自動変数 ($@
, $^
, $<
など)、組み込み関数、VPATH
等の詳細についてはここでは触れない。
prereq↓ \ target→ | single | multiple [bulk] | multiple [foreach] |
---|---|---|---|
single | 通常のルール | 複数ターゲット | 複数ターゲットで$@使用 |
multiple [bulk] | 複数依存項目 | 複数依存項目/ターゲット | 複数依存項目/ターゲットで$@使用 |
multiple [foreach] | (用途なし) | (用途なし) | パターンルール or 組み込み関数 |
以下、各項目の具体的な説明。
single → single
target: prereq
command $^ > $@
通常の Makefile ルール。
single → multiple [foreach]
同じコマンドを同じ依存項目に適用して複数のターゲットを生成するのは無意味(同じファイルを複数出力することになるから)なので、ターゲットに応じてコマンドが変わる場合についてのみ述べる。
各ターゲット名とコマンドに関連がある場合は、自動変数$@
を使えばよい。例えば
target1 target2: prereq
echo $@ $^ > $@
は
target1: prereq
echo target1 prereq > target1
target2: prereq
echo target2 prereq > target2
と同じになる。各ターゲット名とコマンドに関連がない場合は、仕方ないので最初からそれぞれ別のルールを書く(これはターゲットが multiple [foreach] であるような他のすべてのケースでも同じなので、以降は省略する)。
target1: prereq
echo hoge $^ > $@
target2: prereq
echo huga $^ > $@
single → multiple [bulk]
1 回のコマンド実行で複数のファイルが生成されるような場合。これは単に通常のルールのターゲットを複数にすればよい (ただし、自動変数 $@
を使うと上記の single → multiple [foreach] で解釈されてしまうので注意)。
[コメントにて内容の誤りを指摘していただいたのでそちらを参照。]
multiple [bulk] → single もしくは multiple [foreach] もしくは multiple [bulk]
複数の依存項目を一度にコマンドに与えるケースは自然によく起こりうるものであり、これらについては依存項目が 1 つだけ (single) だったものをそのまま複数にすればよい。自動変数 $^
を使える場合はコマンドは single の場合と同じになる:
target: prereq1 prereq2
echo $^ > $@
もしくは
target1 target2: prereq1 prereq2
echo $@ $^ > $@
もしくは
target1 target2: prereq1 prereq2
command $^
multiple [foreach] → single もしくは multiple [bulk]
複数の依存項目を別々に扱うのにターゲットが 1 つに固定されてしまっており、ナンセンスなのでこれらは用途なし。
multiple [foreach] → multiple [foreach]
複数の依存項目に対して別々に、同一のもしくはパターン化可能なコマンドを適用したい場合。
「ある拡張子を持つような全てのファイルに対して同一の処理を行いたい」というような場合にはパターンルール (型ルール) が便利。例えば .c
ファイルから .o
ファイルを生成する
%.o: %.c
$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@
は GNU Make のビルトイン型ルールとなっていて、最初から使用できる。
そうではなく、「特定のいくつかのファイルに対して同一の処理を行いたい」場合には、foreach
組み込み関数とマクロを使用する。例えば、
ORIGINAL_DIR = from/
OBJS = a b c
define COPY
$(1): $(2)
cp $(2) $(1)
endef
$(foreach OBJ, $(OBJS), $(eval $(call FUNC, $(OBJ), $(addprefix $(ORIGINAL_DIR), $(OBJ)))))
というルールでは、from/
ディレクトリにある 3 つのファイル a
, b
, c
をそれぞれカレントディレクトリにコピーするルールを生成する。読みにくいので、ファイル名に規則性があり上記のパターンルールで書ける場合はなるべくそちらで書く。