.PHONYターゲットの解説

Makefileにおける.PHONYを理解:その存在理由、使用すべきタイミング、パフォーマンスへの影響、phonyターゲットに関するよくある間違い。

Reference

詳細な説明

.PHONYを理解する

.PHONY宣言は、Makeで最も重要でありながら誤解されている機能の1つです。ターゲット名が実際のファイルを表さないことをMakeに伝えます。

.PHONYがない場合の問題

clean:
	rm -rf build/

プロジェクトにcleanという名前のファイルやディレクトリが存在する場合、make cleanを実行すると:

make: 'clean' is up to date.

Makeはcleanファイルが存在するかどうかと、それより新しい前提条件がないかをチェックします。存在し依存関係がないため、Makeは最新であると判断してレシピをスキップします。

解決策

.PHONY: clean
clean:
	rm -rf build/

.PHONYがあれば、Makeはcleanという名前のファイルが存在するかどうかに関係なく、常にレシピを実行します。

.PHONYを使用すべき場合

常に.PHONYを使用すべき:

  • アクションターゲット:allcleaninstalluninstall
  • ワークフローターゲット:testlintcheckdeploy
  • エイリアスターゲット:buildrundev

.PHONYを使用すべきでない:

  • ファイルを生成するターゲット:main.oapplibutils.a
  • パターンルール:%.o: %.c

.PHONY宣言のグループ化

# オプション1:単一の宣言
.PHONY: all build test lint clean install

# オプション2:ターゲットごとの宣言(大きなファイルではより読みやすい)
.PHONY: build
build:
	go build -o bin/app ./...

.PHONY: test
test:
	go test ./...

どちらのスタイルも有効です。単一の宣言は簡潔で、ターゲットごとの宣言は.PHONYをターゲットの近くに保ちます。

パフォーマンスへの影響

.PHONYターゲットは常に古いとみなされます。phonyターゲットがファイルを生成するターゲットの前提条件である場合、そのターゲットは常に再ビルドされます:

.PHONY: force
data.json: force
	curl -o $@ https://api.example.com/data

この技法は毎回data.jsonを無条件に再ビルドします。

よくある間違い

  • clean.PHONYを忘れる — cleanファイルが存在すると失敗する
  • ファイルを生成するターゲットを.PHONYにする — 不必要な再ビルドを強制する
  • all.PHONYとして宣言するが依存関係は宣言しない — 部分的な効果

ユースケース

アクションターゲットが常に実行され、ファイルを生成するターゲットが依存関係チェックを適切に使用するように、任意のMakefileで.PHONY宣言を理解し正しく適用する場合に使用します。

試してみる — Makefile Generator

フルツールを開く