December 02, 2020
偽のターゲットと前提条件
タスクランナー的な make の用途には、本来のビルドツールとしての使い方の知識はほとんど必要ありません。 ですが、落とし穴を回避したり正しく使うためには正しい理解があるとよいです。 「偽のターゲット(Phony Target)」と「前提条件(Prerequisites)」が分かると make の特性を生かしたルールが書けるはずです。
up to date
陥りやすい落とし穴のひとつが up to date
です。
この Makefile は make install
すると当然 command
を出力します。
install:
echo "hello" > install
$ make install
echo "hello" > install
$ ls install
install
$ cat install
hello
しかし、ここで再度 make install
するとどうでしょうか。
make: 'install' is up to date.
となってしまい、command
が実行されません。これはどういうことでしょうか?
$ make install
make: 'install' is up to date.
make はターゲット名と同名のファイルが存在すると、既に成果物の生成が済んでいて再実行が不要と判断してコマンドを実行しません。
そのため、例えば test
ディレクトリがあるプロジェクトで make test
をしたくても up to date
になってしまう、といったことがあります。
PHONY:
こうした「成果物の生成に関わらないターゲット」を書くにはどうしたらいいでしょう?
答えは、PHONY:
を用いてターゲットを「偽のターゲット(Phony Target)」にすることです。
.PHONY: install
install:
echo "hello" > install
こうすることでターゲットと同名のファイルの有無に関わらずコマンドが実行されます(※1)。
$ make install
echo "hello" > install
$ make install
echo "hello" > install
前提条件
本来のビルドツールとしての使い方をする場合にも、同様に PHONY:
を書くかというと、そうではありません。
これは C言語のプログラムをビルドする Makefile の例です。
main.o: main.c
の :
の右側 main.c
が「必要条件(Prerequisites)」です。
main.o: main.c
gcc -o main.o main.c
このように必要条件が設定されている場合も、main.o
が生成されると up to date
になりますが、
$ make main.o
gcc -o main.o main.c
$ ./main.o
hello, girls
$ make main.o
make: 'main.o' is up to date.
必要条件のタイムスタンプが更新されると make は「成果物の再生成が必要」と判断してコマンドを実行します。
$ touch main.c
$ make main.o
gcc -o main.o main.c
このように何らかの成果物を作る場合は、前提条件のタイムスタンプを考慮する挙動を活かし、 そういった制御が不要であれば偽のターゲットとして定義する、というのがベーシックなタスクランナー的な Makefile の書き方です。