.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を使用すべき:
- アクションターゲット:
all、clean、install、uninstall - ワークフローターゲット:
test、lint、check、deploy - エイリアスターゲット:
build、run、dev
.PHONYを使用すべきでない:
- ファイルを生成するターゲット:
main.o、app、libutils.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宣言を理解し正しく適用する場合に使用します。