ロクでもない仕様とロクでもないメッセージ:レシピがないとき
[追記]記述が混乱しているから取り消ししておく。[/追記]
Makeにとってゴールと認識できない項目(ノード)が初期ゴールまたは前提項目(導出されたゴール)として出現すると:
make: *** No rule to make target `XXXXX'. Stop.
となる。これはいい。ゴールとして認識できないとは:
まったく未知で存在もしない項目。どのルールのターゲットとしても出現しない(前提には入っている)。
認識可能なゴールに関してレシピがないと
make: Nothing to be done for `XXXXX'.
を出す。擬似ターゲットの場合、特に別名として使っている擬似ターゲットなら、このメッセージは出すべきじゃない。だが、Makeはリソース生成ルールとタスク定義ルールと別名定義ルールの区別ができないので、常にこのメッセージを出す。
- リソース定義(生成する)ルールなら、レシピがないならエラーにすべき。だが、リソース定義という概念がない。
- タスク定義ならレシピがないならエラーにすべき。だが、タスク定義という概念がない。
- 項目または項目リストに対する別名定義なら、Up to dateだとメッセージすべき。だが、別名定義の概念がない。
要するに、エラーにされると困る別名定義の技法的擬似ターゲット(なんちゃってタスクでPHONYされてない)の場合に合わせて、他の状況でもエラーにしてないだけ(消極的で致し方ないな理由)。分かりにくく、人為的ミスを発見しにくい仕様になっている。
もっと酷いのは空レシピ。パターンルールからのレシピ補完を排除したり、明示的に「何もしない」を表す空レシピは妥当だ。だが、なんと空レシピを指定するとターゲットが存在しなくても存在する扱いにする、という狂った仕様になっている。
.PHONYと空レシピを組み合わせると別名が定義できることにはなるが、行き当たりばったりでヒドすぎる。[追記].PHONYと空レシピを組み合わせても効果なしと判明! 参照[/追記]
[追記]以下、事実誤認があったので取り消し。クソであることに変わりはない。[/追記]
「Nothing to be done for `XXXXX'.」は、ゴールである項目(ノード)XXXXXをルートノードとする実行計画DAG(処理すべきノードからなる逆向きのDAG)のどのノードにも非空なレシピがないときに表示される。ひとつでも非空なレシピがあれば、それが実行されて、Makeからのメッセージも出ない。大変にクソなアルゴリズム。
全般にグチャグチャで腐っているとしか言いようがないが、多少でも合理化するなら、
- 空レシピはレシピではない(と考える)。ターゲットノードに付けられたDontCareフラグである。
- DontCareフラグの効果により、そのノードは常に(リソース実体の存在・非存在に関わらず)up-to-dateとみなされる。
- DontCareフラグがONのノードは実質的なレシピを持ってはならない。
- DontCareフラグにより、パターンルールからのレシピの供給は拒否される。「ほっといてくれ!」というわけだ。
- 空レシピはレシピではないので、レシピ検索には引っかからない。
- DontCareフラグがなくレシピもない項目(ノード)はエラーとはしないが何もしない(何もできないから)。
事実とプラクティスとしては:
- Nothing to be done for `XXXXX'. は仕様上は警告だがエラーメッセージとみなす!ただし、どうしても“エラー”を避けられないことがある。
- .PHONYしても、別名擬似ターゲットではこの“エラーメッセージ”が出てしまうので、空レシピというDontCareフラグを併用する。[追記]併用してもダメだと判明! 参照[/追記]
- ゴール自体ではなくて、その上流に Nothing to be done なノード(レシピを持たないノード)があっても、Makeはゴールをup-to-dateとみなす。up-to-dateなんて実は判断できないのでイイカゲンにメッセージしているだけ。メッセージは信用出来ない。
- つまり、ビルドフローの上流に上記の“エラー”を起こす項目(ノード)があっても、Makeはエラーとして検出できず何もしてくれないので、レシピ内でエラーが起きるようにする。
- 情けないが、レシピを防衛的に書くのが実効性がある手法。