はじめに
七尾百合子さん、お誕生日 227日目 おめでとうございます! nikkieです。
5年以上も Makefile を適切に書けていない罪を犯していました...
目次
コマンドを Makefile にまとめていて
技術書執筆中1の私。
Sphinx の Docker イメージを使って、原稿から PDF を生成します2。
長いのと、(今は履歴から何度も実行できたとしても)将来絶対思い出せないので Makefile に書きました。
pdf:
@docker run --rm -v $$PWD:/docs sphinxdoc/sphinx-latexpdf:8.2.3 bash -c 'kanji-config-updmap-sys haranoaji && sphinx-build -M latexpdf source build'
この時ふと思ったのです、「そういえば.PHONYってなんだ?」と3
『GNU Make 第3版』より「擬似ターゲット」
全章公開されています。
2章より
https://www.oreilly.co.jp/library/4873112699/ch02.pdf
実際のファイルを示していないターゲットは、擬似ターゲット(Phony Target)と呼ばれます。 (2.1.2 p.12)
解説されていた例はclean。
clean:
rm -f *.o lexer.c
ここでこのMakefileと同じディレクトリにcleanという名前のファイルがあったとすると、
例えば
cleanというファイルが作られていたとすると、make cleanを実行した結果は次のような紛らわしいメッセージ(「cleanは最新です」の意)が出ることになります。
rm -fが実行されないわけですね。
こうならないようにするために、.PHONYにcleanを指定して擬似ターゲットにします!
+.PHONY: clean
clean:
rm -f *.o lexer.c
冒頭の Makefile にも疑似ターゲットの指定を追加したほうがいいですね
+.PHONY: pdf
pdf:
@docker run --rm -v $$PWD:/docs sphinxdoc/sphinx-latexpdf:8.2.3 bash -c 'kanji-config-updmap-sys haranoaji && sphinx-build -M latexpdf source build'
落ち穂拾い
Makefileでコマンドをまとめてきました
Makefile は以下記事のようにコマンドをまとめる用途で使ってきました。
これは擬似ターゲットとしての用途なので、もっと早期から.PHONYを書くべきでしたね。
この記事を改めて見たところ、大元のテンプレートには.PHONYによる擬似ターゲットの指定がありました。
https://github.com/docker-science/cookiecutter-docker-science/blob/494427e0f41a4d4f06ee5d7796eb9356bc149b54/%7B%7B%20cookiecutter.project_slug%20%7D%7D/Makefile#L1
.PHONY自体は何なの?
『GNU Make 第3版』2章によると、.PHONYは特殊ターゲットの1つ(2.6)
例えば特殊ターゲットである
.PHONYについてはすでに扱いましたが、これは必須項目に指定されたものが実際のファイルとして存在せず、常に最新ではないことを示すためのものです。(p.29)
リンターで指摘できる?
これは GPT-5 に聞いただけですが、Go 製のリンターが見つかりました(未検証)
.PHONY忘れはminphonyルールで指摘されるようです。
https://github.com/checkmake/checkmake/tree/0.2.2?tab=readme-ov-file#usage
例:https://github.com/checkmake/checkmake/blob/0.2.2/fixtures/missing_phony.make
終わりに
Makefile をコマンドをまとめる用途で使うならば、.PHONYを書きましょう!(俺みたいになるな!)
擬似ターゲットとすることで、仮にターゲットと同名のファイルがあっても、コマンドを実行できます。